C 从函数readdir释放(删除)分配的内存

C 从函数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不会

我在Linux环境中使用C编程语言读取目录中的文件。我的代码中有include
#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];