C 从函数readdir释放(删除)分配的内存
我在Linux环境中使用C编程语言读取目录中的文件。我的代码中有includeC 从函数readdir释放(删除)分配的内存,c,linux,stack,malloc,free,C,Linux,Stack,Malloc,Free,我在Linux环境中使用C编程语言读取目录中的文件。我的代码中有include#include,我正在使用函数readdir() 根据Linux联机页面,它说不要对指向dirent结构的结果指针调用free() 你能帮我理解这是怎么回事吗?我不明白为什么我们不必删除struct-dirent。什么时候删除,谁删除 这是我所说的摘录: 成功时,readdir()返回指向dirent结构的指针。(此结构可能是静态分配的;不要尝试释放(3)它。)如果到达目录流的末尾,则返回NULL,并且errno不会
#include
,我正在使用函数readdir()
根据Linux联机页面,它说不要对指向dirent
结构的结果指针调用free()
你能帮我理解这是怎么回事吗?我不明白为什么我们不必删除struct-dirent
。什么时候删除,谁删除
这是我所说的摘录:
成功时,readdir()
返回指向dirent
结构的指针。(此结构可能是静态分配的;不要尝试释放(3)
它。)如果到达目录流的末尾,则返回NULL
,并且errno
不会更改。如果发生错误,则返回NULL
,并适当设置errno
man readdir
字面意思是:
成功时,readdir()
返回指向dirent结构的指针。
(此结构可以静态分配;不要尝试
free(3)
it。)
(添加了代码格式化程序。)
这意味着它的空间在运行时没有被分配,比如堆栈或空闲存储内存,而是静态的
:它本身就在可执行文件中,与字符串文本相当,区别在于写入字符串文本是未定义的行为
设想实现如下:
struct dirent *readdir(DIR *dirp) {
static struct dirent dir;
/* Fill dir with appropriate values. */
return &dir;
}
dir
在此处静态分配。返回它的地址并没有错,因为它存在于程序的整个运行时中
以下是我的glibc 2.22实现上的readdir
的实际源代码(路径是/sysdeps/posix/readdir.c
):
对我们来说似乎最有趣<据我所知,code>dirp->data
是这里的静态
数据
这就是为什么存在可重入替代方案
readdir\u r
和readdir
是不可重入的设想两个线程同时执行
readdir
。这两个函数都将尝试填充所有readdir
调用中共享的dir
,同时导致不连续的内存读/写。您只需释放()
先前通过调用malloc()
和family分配的内存即可。这是,从堆区域开始
OTOH,非动态分配(参见)无需单独处理。一旦变量超出范围,堆栈内存将被回收并根据需要重新使用。您的引用提醒您,struct dirent
是无效的。因此,free()
不是必需的
专为与函数一起使用而设计,这些函数都从发出内存请求。(与堆栈相反)您不需要释放/释放由
readdir()
获取的条目。它使用静态内部缓冲区,因此不需要动态释放,因为它不是动态分配的。请注意,编译器可以预测所需的空间,因为一次只使用一个条目,只需要一个条目来存储结果。这就是为什么它不是可重入的。有一个接受用户分配的缓冲区,当然是可重入的
您需要在
DIR*
指针上调用closedir()
,以释放opendir()
使用的资源struct dirent
在逻辑上是DIR
的一部分。它可以在同一DIR
的后续readdir()
调用中重用(但不能在不同DIR
的readdir()
调用中重用),并在closedir()
时释放
一些文档指出readdir()
不是线程安全的。在所有实现中,除了真正奇特的实现外,只要最后一次访问上一个struct dirent
发生在下一次readdir()
调用之前,它就是线程安全的。不建议使用readdir\u r()
有关readdir\u r()
问题的更多详细信息,请访问。因为这是指向函数中的静态变量的指针,您不需要释放它。线索是数据在后续调用中被覆盖。
DIRENT_TYPE *
__READDIR (DIR *dirp)
{
DIRENT_TYPE *dp;
int saved_errno = errno;
#if IS_IN (libc)
__libc_lock_lock (dirp->lock);
#endif
do
{
size_t reclen;
if (dirp->offset >= dirp->size)
{
/* We've emptied out our buffer. Refill it. */
size_t maxread;
ssize_t bytes;
#ifndef _DIRENT_HAVE_D_RECLEN
/* Fixed-size struct; must read one at a time (see below). */
maxread = sizeof *dp;
#else
maxread = dirp->allocation;
#endif
bytes = __GETDENTS (dirp->fd, dirp->data, maxread);
if (bytes <= 0)
{
/* On some systems getdents fails with ENOENT when the
open directory has been rmdir'd already. POSIX.1
requires that we treat this condition like normal EOF. */
if (bytes < 0 && errno == ENOENT)
bytes = 0;
/* Don't modifiy errno when reaching EOF. */
if (bytes == 0)
__set_errno (saved_errno);
dp = NULL;
break;
}
dirp->size = (size_t) bytes;
/* Reset the offset into the buffer. */
dirp->offset = 0;
}
dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];
#ifdef _DIRENT_HAVE_D_RECLEN
reclen = dp->d_reclen;
#else
/* The only version of `struct dirent*' that lacks `d_reclen'
is fixed-size. */
assert (sizeof dp->d_name > 1);
reclen = sizeof *dp;
/* The name is not terminated if it is the largest possible size.
Clobber the following byte to ensure proper null termination. We
read jst one entry at a time above so we know that byte will not
be used later. */
dp->d_name[sizeof dp->d_name] = '\0';
#endif
dirp->offset += reclen;
#ifdef _DIRENT_HAVE_D_OFF
dirp->filepos = dp->d_off;
#else
dirp->filepos += reclen;
#endif
/* Skip deleted files. */
} while (dp->d_ino == 0);
#if IS_IN (libc)
__libc_lock_unlock (dirp->lock);
#endif
return dp;
}
dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];