- 论坛徽章:
- 0
|
本帖最后由 changyongID 于 2010-03-23 00:13 编辑
贴上代码之后,贴子显得比较长,但问题并不复杂。请各位看一下,问题描述如下
函数scandir一般是用来对指定目录排序中的。其在glibc中源码如下:- #include <dirent.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <bits/libc-lock.h>
- #ifndef SCANDIR
- #define SCANDIR scandir
- #define READDIR __readdir
- #define DIRENT_TYPE struct dirent
- #endif
- #ifndef SCANDIR_CANCEL
- #define SCANDIR_CANCEL
- struct scandir_cancel_struct
- {
- DIR *dp;
- void *v;
- size_t cnt;
- };
- static void
- cancel_handler (void *arg)
- {
- struct scandir_cancel_struct *cp = arg;
- size_t i;
- void **v = cp->v;
- for (i = 0; i < cp->cnt; ++i)
- free (v[i]);
- free (v);
- (void) __closedir (cp->dp);
- }
- #endif
- int
- SCANDIR (dir, namelist, select, cmp)
- const char *dir;
- DIRENT_TYPE ***namelist;
- int (*select) (const DIRENT_TYPE *);
- int (*cmp) (const void *, const void *);
- {
- DIR *dp = __opendir (dir);
- DIRENT_TYPE **v = NULL;
- size_t vsize = 0;
- struct scandir_cancel_struct c;
- DIRENT_TYPE *d;
- int save;
- if (dp == NULL)
- return -1;
- save = errno;
- __set_errno (0);
- c.dp = dp;
- c.v = NULL;
- c.cnt = 0;
- __libc_cleanup_push (cancel_handler, &c);
- while ((d = READDIR (dp)) != NULL)
- {
- int use_it = select == NULL;
- if (! use_it)
- {
- use_it = select (d);
- /* The select function might have changed errno. It was
- zero before and it need to be again to make the latter
- tests work. */
- __set_errno (0);
- }
- if (use_it)
- {
- DIRENT_TYPE *vnew;
- size_t dsize;
- /* Ignore errors from select or readdir */
- __set_errno (0);
- if (__builtin_expect (c.cnt == vsize, 0))
- {
- DIRENT_TYPE **new;
- if (vsize == 0)
- vsize = 10;
- else
- vsize *= 2;
- new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v));
- if (new == NULL)
- break;
- v = new;
- c.v = (void *) v;
- }
- dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d;
- vnew = (DIRENT_TYPE *) malloc (dsize);
- if (vnew == NULL)
- break;
- v[c.cnt++] = (DIRENT_TYPE *) memcpy (vnew, d, dsize);
- }
- }
- if (__builtin_expect (errno, 0) != 0)
- {
- save = errno;
- while (c.cnt > 0)
- free (v[--c.cnt]);
- free (v);
- c.cnt = -1;
- }
- else
- {
- /* Sort the list if we have a comparison function to sort with. */
- if (cmp != NULL)
- qsort (v, c.cnt, sizeof (*v), cmp);
- *namelist = v;
- }
- __libc_cleanup_pop (0);
- (void) __closedir (dp);
- __set_errno (save);
- return c.cnt;
- }
复制代码 其中可以看到,在函数退出时,调用了 __libc_cleanup_pop (0); 也就是要调用下面这个函数
static void
cancel_handler (void *arg)
{
struct scandir_cancel_struct *cp = arg;
size_t i;
void **v = cp->v;
for (i = 0; i < cp->cnt; ++i)
free (v);
free (v);
(void) __closedir (cp->dp);
}
其中free(v)即将v所指向的内存释放掉了,这里的v是cp->v。而在主代码中可以看到 c.v = (void *) v;
看到这里,即scandir函数结束后,会将所有内存释放掉。连 new = (DIRENT_TYPE **) realloc (v, vsize * sizeof (*v)) 这一句所分配的内存也
释放了。
但主函数后面又有 *namelist = v; 使用scandir函数时通过这个namelist来访问排序过后的内存。
但上面的代码里明明就是把分配的内存释放掉了呀。
使用scandir的实例有- #include <dirent.h>
- int
- main(void)
- {
- struct dirent **namelist;
- int n;
- n = scandir(".", &namelist, 0, alphasort);
- if (n < 0)
- perror("scandir");
- else {
- while (n--) {
- printf("%s\n", namelist[n]->d_name);
- free(namelist[n]);
- }
- free(namelist);
- }
- }
复制代码 可以看到上面 free(namelist); 又将namelist指向的内存释放了一遍。。
这样一来不就free了两次了吗?
请指点!谢谢各位。 |
|