亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? apr-tutorial-19.html

?? 跨平臺windowsunixlinux的c語言編程解決方案
?? HTML
?? 第 1 頁 / 共 2 頁
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD> <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.21"> <TITLE>libapr(apache portable runtime) programming tutorial: Container APIs</TITLE> <LINK HREF="apr-tutorial-20.html" REL=next> <LINK HREF="apr-tutorial-18.html" REL=previous> <LINK HREF="apr-tutorial.html#toc19" REL=contents></HEAD><BODY><A HREF="apr-tutorial-20.html">Next</A><A HREF="apr-tutorial-18.html">Previous</A><A HREF="apr-tutorial.html#toc19">Contents</A><HR><H2><A NAME="s19">19.</A> <A HREF="apr-tutorial.html#toc19">Container APIs</A></H2><P>libapr provides some container(a.k.a. collection) APIs.</P><H2><A NAME="ss19.1">19.1</A> <A HREF="apr-tutorial.html#toc19.1">dynamic array</A></H2><P>Array is the most general container type in C language. However, array size is noramally fixed. It's not flexible. libapr provides dynamic-sized array. The APIs are declared in apr_tables.h.</P><P>As container type, dynamic array has the following features.</P><P><BR><CENTER><TABLE BORDER><TR><TD>append</TD><TD>efficient(API support)</TD></TR><TR><TD>insert/prepend</TD><TD>inefficient(no API support)</TD></TR><TR><TD>delete</TD><TD>inefficient(no API support)</TD></TR><TR><TD>delete(only the first element)</TD><TD>efficient(API support)</TD></TR><TR><TD>search(lookup)</TD><TD>inefficient, but depends(no API support)</TD></TR><TR><TD>iteration</TD><TD>efficient(no API support)</TD></TR></TABLE><CAPTION>array</CAPTION></CENTER><BR></P><P>'No API support' above means that you have to touch apr_array_header_t::elts directly. This is not a good attitude as a progammer, but we should accept it as a pragmatic programmer.</P><P>The dynamic array type is apr_array_header_t. The object is created by apr_array_make() as follows:</P><P>/* excerpted from <A HREF="../sample/array-sample.c">array-sample.c</A> */<BLOCKQUOTE><CODE><PRE>apr_array_header_t *arr;arr = apr_array_make(mp, ARRAY_INIT_SZ, sizeof(const char*));</PRE></CODE></BLOCKQUOTE></P><P>The first argument is memory pool to use. Both array itself and elements are allocated in the memory pool. The second argument is an initial size of the array. The third argument is the size of element. The third argument is important for code readers, because it tells them what the container's type objects are. Unlike STL, apr_array_header_t is not type-safe. Therefore, it is important to declare the type clearly. In the sample above, we know that the array is an array of string pointers(const char*).</P><P><EM>REMARK</EM>: If you're familiar with the other libapr's APIs, you would feel weird because it doesn't use a result argument for a newly created object. Don't care.</P><P>We have to call apr_array_push() to append a new elememnt to the array.</P><P>/* excerpted from <A HREF="../sample/array-sample.c">array-sample.c</A> */<BLOCKQUOTE><CODE><PRE>*(const char**)apr_array_push(arr) = "123";</PRE></CODE></BLOCKQUOTE></P><P>Iteration is important interface for array. We can do as follows:</P><P>/* excerpted from <A HREF="../sample/array-sample.c">array-sample.c</A> */<BLOCKQUOTE><CODE><PRE>apr_array_header_t *arr;int i;for (i = 0; i &lt; arr->nelts; i++) {    const char *s = ((const char**)arr->elts)[i];    printf("%d: %s\n", i, s);}</PRE></CODE></BLOCKQUOTE></P><P>I have to say that the APIs above are not so intuitive. Fortunately they are very small interfaces, so you become familiar with them soon. Here, I show you generic form of array APIs. </P><P><BLOCKQUOTE><CODE><PRE>/* generic form of apr_array_header_t usages. 'T' is a type name. */apr_array_header_t *arr = apr_array_make(mp, ARRAY_INIT_SZ, sizeof(T));/* array of T objects *//* add an element */T elem;*(T*)apr_array_push(arr) = elem;/* iteration */for (i = 0; i &lt; arr->nelts; i++) {    T elem = ((T*)arr->elts)[i];}</PRE></CODE></BLOCKQUOTE></P><P>Let's take a look at <A HREF="../sample/array-sample.c">array-sample.c</A>. In <A HREF="../sample/array-sample.c">array-sample.c</A>, the array is an array of pointer. The array elements are allocated in the memory pool passed to apr_array_make(), but only pointer's memories are allocated. The objects that the pointers refer to are not allocated. So, the following sample code has a bug, because the strings in the array are not persistent.</P><P><BLOCKQUOTE><CODE><PRE>/* BUGGY sample of apr_array_header_t usage */void func(apr_array_header_t *str_arr){    char str[32];    strcpy(str, "foobar");    *(const char**)apr_array_push(str_arr) = str;/* BUG, if function caller uses this array */    return;}</PRE></CODE></BLOCKQUOTE></P><P>In most cases, the array itself and the elements are same lifetime, so that it might be better to allocate the objects in the same memory pool as follows:</P><P><BLOCKQUOTE><CODE><PRE>/* fix example of above bug */void func(apr_array_header_t *str_arr){    const char *str = apr_pstrdup(str_arr->pool, "foobar");    *(const char**)apr_array_push(str_arr) = str;}</PRE></CODE></BLOCKQUOTE></P><P>As you have seen, apr_array_header_t works with arbitrary type. Obviously, string array becomes more powerful than others. The reason is apr_array_pstrcat(). It works with string array, i.e. 'T is char*' or 'T is const char*' in the generic form above. apr_array_pstrcat() concatenates all the elements in the array and make a new string. The following example shows how to make one string from string chunks.</P><P><BLOCKQUOTE><CODE><PRE>/* pseudo code to make one string from string chunks */apr_array_header_t *html_arr = apr_array_make(mp, ARRAY_INIT_SZ, sizeof(const char*));*(const char**)apr_array_push(html_arr) = "&lt;html&gt;";*(const char**)apr_array_push(html_arr) = "&lt;head&gt;&lt;title&gt;foo&lt;/title&gt;&lt;/head&gt;";*(const char**)apr_array_push(html_arr) = "&lt;body&gt;&lt;ul&gt;";for (i = 0; i &lt; NUM_LIST; i++) {    *(const char**)apr_array_push(html_arr) = apr_psprintf(mp, "&lt;li&gt;%d&lt;/li&gt;", i);}*(const char**)apr_array_push(html_arr) = "&lt;/ul&gt;&lt;/body&gt;";*(const char**)apr_array_push(html_arr) = "&lt;/html&gt;";const char *html_str = apr_array_pstrcat(mp, html_arr, '\0');</PRE></CODE></BLOCKQUOTE></P><P>You might intend to sort the elements in the array. I mentioned that search on array isn't so effiecient above, but it can be efficient by bsearch(3) if it's sorted. I show you how to use qsort(3) with array.</P><P><BLOCKQUOTE><CODE><PRE>/* qsort(3) sample with array *//* we assume arr is an array of string */qsort(arr->elts, arr->nelts, arr->elt_size, cmp_string);/* compare function for qsort(3) */static int cmp_string(const void *v1, const void *v2){    const char *s1 = *(const char**)v1;    const char *s2 = *(const char**)v2;    return strcmp(s1, s2);}</PRE></CODE></BLOCKQUOTE></P><P>There is one more API that I have to point out. It is apr_array_pop(). By apr_array_pop(), we can use array as stack, which is known as first-in, last-out container. Please take a look at <A HREF="../sample/array-sample.c">array-sample.c</A> about the usage.</P><H2><A NAME="ss19.2">19.2</A> <A HREF="apr-tutorial.html#toc19.2">table</A></H2><P>Table is container of key-value pairs. It assumes key is character string. Value is allowed to be any type, but it is almost assumed to be character string. In the following description, we assume both key and value are character strings.</P><P>As container type, table has the following features.</P><P><BR><CENTER><TABLE BORDER><TR><TD>append</TD><TD>efficient(API support)</TD></TR><TR><TD>insert/prepend</TD><TD>inefficient(API support)</TD></TR><TR><TD>delete</TD><TD>inefficient(API support)</TD></TR><TR><TD>search(lookup)</TD><TD>almost efficient(API support)</TD></TR><TR><TD>iteration</TD><TD>efficient(API support)</TD></TR></TABLE><CAPTION>table</CAPTION></CENTER><BR></P><P>As you see, the features are almost same as array. This is natural, because table internally relies on array. Table has additional better features, though. First, table has better API supports. Second, table is more efficient for search(lookup). Table uses internal checksums for efficient search. Although it is not so efficient as hash table described later, it is better enough.</P><P>Table type is apr_table_t. We call apr_table_make() to create a new object as follows:</P><P>/* excerpted from <A HREF="../sample/table-sample.c">table-sample.c</A> */<BLOCKQUOTE><CODE><PRE>apr_table_t *tab;tab = apr_table_make(mp, TABLE_INIT_SZ);</PRE></CODE></BLOCKQUOTE></P><P>The first argument is memory pool to use. Like apr_array_header_t, both table itself and elements are allocated in the memory pool. The second argument is an initial size of table. As same as dynamic array, table size is dynamic. So, the initial size is just a hint.</P><P>There are four API to append elements to table as follows:</P><P>/* excerpted from apr_tables.h */<BLOCKQUOTE><CODE><PRE>APR_DECLARE(void) apr_table_set(apr_table_t *t, const char *key, const char *val);APR_DECLARE(void) apr_table_setn(apr_table_t *t, const char *key, const char *val);APR_DECLARE(void) apr_table_add(apr_table_t *t, const char *key, const char *val);APR_DECLARE(void) apr_table_addn(apr_table_t *t, const char *key, const char *val);</PRE></CODE></BLOCKQUOTE></P><P>The difference between 'set' and 'add' is that we allow multiple values for the same key or not. By 'set' calls, we don't allow multiple values for the same key. So, if another value already exists for the key, both apr_table_set() and apr_table_setn() over-write the old value. In contrast, both apr_table_add() and apr_table_addn() allow multiple values for the same key. Thus, the old values are still left.</P><P>The difference between 'with-n' and 'without-n' is that key and value's memories are duplicated or not. By 'without-n' calls, APIs duplicate both key and value string's memory. By 'with-n' calls, APIs don't duplicate them. 'With-n' APIs are more efficient, so when you know the string duplication is not necessary, you should use apr_table_setn() or apr_table_addn(). I show such examples:</P><P><BLOCKQUOTE><CODE><PRE>/* examples we can call apr_table_setn() or apr_table_addn() */apr_table_setn(tab, "foo", "bar"); /* string literals don't require duplication */apr_table_setn(tab, apr_pstrdup(mp, "foo"), apr_pstrdup(mp, "bar")); /* since the strings are already allocated in the same memory pool, we don't need double duplications */</PRE></CODE></BLOCKQUOTE></P><P>To search value by key, we call apr_table_get(). The prototype declaration is as follows:</P><P>/* excerpted from apr_tables.h */<BLOCKQUOTE><CODE><PRE>APR_DECLARE(const char *) apr_table_get(const apr_table_t *t, const char *key);</PRE></CODE></BLOCKQUOTE></P><P>If the key exists in the table, the associated value is returned. Otherwise, the return value is NULL. As mentioned earlier, 'add' APIs allow multiple values for a key. However, apr_table_get() can't return multiple values. It just returns the first value. Allowing multiple values does make sense when we iterate over the table, which I'll describe later.</P><P><EM>REMARK</EM>: Table key is case-insensitive. Historically, table was developed for HTTP headers.</P><P>apr_table_get()'s return value is just a pointer. I mean it doesn't duplicate the value string. So, the following sample code is buggy code.</P><P><BLOCKQUOTE><CODE><PRE>/* BUGGY sample */apr_table_setn(tab, "mykey", strdup("myval"));/* apr_table_setn() doesn't duplicate the strings */const char *v = apr_table_get(tab, "mykey");assert(strcmp(v, "myval") == 0);  /* v's value should be "myval" *//* v is a string allocated by strdup(3), so calling free(v) is a proper operation. * However, since the element still exists in the table, free(v) leaves an invalid memory in the table */free(v);</PRE></CODE></BLOCKQUOTE></P><P>On the other hand, when you remove an element from the table, you must free the string memory to get around memory leak.</P><P><BLOCKQUOTE><CODE><PRE>/* The similar situation above */const char *v = apr_table_get(tab, "mykey");apr_table_unset(tab, "mykey");free(v);/* XXX If we forget this, it causes memory leak... */</PRE></CODE></BLOCKQUOTE></P><P>A simple solution is to use memory pool. If all keys and values strings are allocated in the same memory pool of the table, all you have to do is to call apr_pool_destroy().</P><P>There are two ways to do iteration over table. One is to use callback function. The other is to use internal apr_array_header_t directly.</P><P>To use callback function for iteration, we call apr_table_do(). The prototype declaration and usage are as follows:</P><P>/* excerpted from apr_tables.h */<BLOCKQUOTE><CODE><PRE>APR_DECLARE_NONSTD(int) apr_table_do(apr_table_do_callback_fn_t *comp,                                     void *rec, const apr_table_t *t, ...);</PRE></CODE></BLOCKQUOTE></P><P>/* excerpted from <A HREF="../sample/table-sample.c">table-sample.c</A> */<BLOCKQUOTE><CODE><PRE>apr_table_do(tab_cb, "label1", tab, NULL);apr_table_do(tab_cb, "label2", tab, "key1", "key2", NULL);/* iteration with filters *//* table iteration callback */static int tab_cb(void *data, const char *key, const char *value){    const char *label = data;    printf("callback[%s]: %s %s\n", label, key, value);    return TRUE;/* TRUE:continue iteration. FALSE:stop iteration */}</PRE></CODE></BLOCKQUOTE></P><P>The first argument of apr_table_do() is callback function. The second argument is context object passed to callback function. The third argument is table object. The remained arguments work as filters for keys.</P>

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美精选一区二区| 亚洲午夜激情av| 一区二区三区在线播| 日产国产欧美视频一区精品| 岛国av在线一区| 日韩三级免费观看| 亚洲综合成人在线视频| 成人午夜免费电影| 日韩精品资源二区在线| 亚洲精品中文字幕乱码三区| 国产美女一区二区三区| 日韩免费高清av| 午夜精品成人在线视频| 91精品福利视频| 自拍视频在线观看一区二区| 国产成人在线观看| 国产亚洲一区二区三区在线观看 | 美女一区二区三区在线观看| eeuss国产一区二区三区| 国产亚洲1区2区3区| 国产一区二区电影| 久久久精品人体av艺术| 久久99精品久久久| 精品国产伦一区二区三区观看体验| 亚洲永久精品国产| 日本韩国一区二区| 亚洲欧美日本在线| 欧洲亚洲国产日韩| 一区二区三区精品久久久| 91色|porny| 18成人在线观看| voyeur盗摄精品| 亚洲人被黑人高潮完整版| a亚洲天堂av| 亚洲免费观看高清| 欧美在线视频全部完| 亚洲国产精品人人做人人爽| 欧美色图一区二区三区| 亚瑟在线精品视频| 宅男噜噜噜66一区二区66| 日韩国产精品久久久| 日韩精品中文字幕一区二区三区| 九九九精品视频| 国产欧美日韩亚州综合| 9人人澡人人爽人人精品| 亚洲男人的天堂在线观看| 欧洲国内综合视频| 捆绑调教一区二区三区| 久久久99免费| av电影在线观看完整版一区二区| 亚洲免费观看高清在线观看| 欧美欧美午夜aⅴ在线观看| 免费在线观看一区| 国产农村妇女毛片精品久久麻豆| 91色在线porny| 男人的j进女人的j一区| 国产午夜精品在线观看| 99国产精品久久| 天天综合色天天| 国产色婷婷亚洲99精品小说| 91麻豆精品一区二区三区| 首页欧美精品中文字幕| 国产色91在线| 欧美色综合网站| 国产黑丝在线一区二区三区| 亚洲自拍与偷拍| 国产三级久久久| 在线不卡中文字幕| 成人一区二区三区中文字幕| 亚洲一二三专区| 久久色中文字幕| 欧美日韩一区二区电影| 国产精品亚洲专一区二区三区| 国产精品久久久久久久久果冻传媒 | 亚洲bt欧美bt精品777| 久久综合久久99| 国产成人在线观看免费网站| 亚洲高清视频在线| 国产人成一区二区三区影院| 欧美丝袜丝交足nylons| 国产裸体歌舞团一区二区| 亚洲制服欧美中文字幕中文字幕| 久久婷婷色综合| 这里只有精品99re| 欧美在线视频全部完| 成人国产免费视频| 国产一区二区在线观看视频| 亚洲国产欧美在线| 久久精品无码一区二区三区| 欧美揉bbbbb揉bbbbb| aa级大片欧美| 成人一区二区视频| 国产一区福利在线| 日韩不卡一区二区三区| 香蕉久久夜色精品国产使用方法| 中文在线资源观看网站视频免费不卡| 欧美一区二区三区视频免费| 欧美日韩中文精品| 欧洲激情一区二区| 91黄色激情网站| 91丨porny丨中文| 成人免费毛片a| 国产成人av影院| 精品一区二区综合| 国模无码大尺度一区二区三区| 日产国产欧美视频一区精品| 偷拍与自拍一区| 日韩精品一级二级 | 亚洲人成伊人成综合网小说| 欧美国产成人精品| 中文字幕高清一区| 久久久91精品国产一区二区精品 | 国产成人三级在线观看| 麻豆国产精品一区二区三区| 天天影视涩香欲综合网| 午夜不卡在线视频| 日韩精品免费专区| 九九国产精品视频| 国产东北露脸精品视频| av一二三不卡影片| 91尤物视频在线观看| 欧美做爰猛烈大尺度电影无法无天| 91香蕉视频mp4| 91福利在线播放| 欧美喷潮久久久xxxxx| 欧美变态tickle挠乳网站| 久久久久99精品国产片| 中文字幕免费不卡| 亚洲日韩欧美一区二区在线| 一区二区三区免费在线观看| 日韩影院免费视频| 韩国成人福利片在线播放| 国产福利电影一区二区三区| 91网站最新网址| 3d成人h动漫网站入口| 亚洲精品一区二区三区影院 | 日韩成人av影视| 国产成人免费av在线| 91麻豆国产在线观看| 6080午夜不卡| 久久影院视频免费| 一区二区在线观看免费| 免费高清在线视频一区·| 国产成人在线观看| 精品视频免费在线| 久久先锋影音av| 亚洲综合色婷婷| 蜜臀av性久久久久蜜臀aⅴ| 成人精品国产福利| 欧美一区二区网站| 国产色综合久久| 天天操天天干天天综合网| 国产精品88888| 精品视频在线免费看| 欧美激情综合五月色丁香小说| 一区二区三区欧美久久| 国产精一品亚洲二区在线视频| 色综合亚洲欧洲| 欧美精品一区二区高清在线观看| 自拍偷拍国产精品| 国产毛片精品一区| 911国产精品| 亚洲免费色视频| 国产精品一区二区在线观看不卡 | 中文字幕在线不卡一区二区三区| 日本成人在线电影网| 国产成a人无v码亚洲福利| 欧美欧美午夜aⅴ在线观看| 国产精品美女久久久久久2018| 免费不卡在线观看| 欧美系列日韩一区| 国产精品成人在线观看| 激情成人午夜视频| 欧美一区二区网站| 亚洲一区在线看| 91蜜桃传媒精品久久久一区二区| 久久久久久久久岛国免费| 午夜电影久久久| 欧美色图天堂网| 亚洲一区二区三区中文字幕在线 | 欧美色综合网站| 日韩理论片一区二区| 成人免费观看男女羞羞视频| 久久综合色一综合色88| 蜜桃av一区二区在线观看 | 亚洲va欧美va人人爽| 日本久久电影网| 亚洲精品成人少妇| 91在线无精精品入口| 国产精品久久午夜夜伦鲁鲁| 国产成人午夜视频| 久久综合色婷婷| 国产91高潮流白浆在线麻豆 | 26uuu国产一区二区三区| 日韩精品欧美精品| 日韩亚洲欧美一区二区三区| 日韩成人av影视| 欧美电视剧免费观看| 狠狠色综合播放一区二区| 2021久久国产精品不只是精品|