当列表增长超过100个元素时,链表头部的值会静默更改

时间:2012-08-01 05:57:46

标签: c pointers linked-list

我需要对具有特定扩展名(* .bob)的文件列表进行一些操作,所有这些操作都存储在同一目录中。文件是图像帧,其名称格式为frame_XXXX.bob。我不知道先验帧的数量,我需要确保按顺序处理它们(从第0帧到最后一帧)。我用struct dirent *readdir(DIR *dirp)读取了文件夹的内容,但由于它不保证文件将按字母顺序读取(即使它似乎总是如此),我想将它们放入单个链表中,然后在进一步处理之前对它们进 我将列表的头部保存到指针filesListStart之前保存,然后读取整个文件夹内容,如果它具有“.bob”扩展名,则将每个条目添加到列表中。当我有多达100帧时,这一切都很有效,但由于某种原因,它突破了 - 指针filesListStart所指向的值不再包含列表中第一个条目的文件名。代码不使用任何数字,所以我不知道超过100个元素的重要性。 在我开始填充列表之前,我写了filesListStart的内存地址,之后,它们是相同的,但是它们在神奇地改变时显示的值。当我设置filesListStart时,它指向对象,字段fileName等于“frame_0000.bob”(这是预期的),但在填充列表后,它指向的名称变为“e_0102.bob”。

列表结构定义为

// List structure
struct FilesList {
  char *fileName ;
  struct FilesList *next ;
} ;

有问题的代码是:

DIR *moviesDir ;
moviesDir = opendir("movies") ;

if(moviesDir == NULL)
{
  printf("Make Movie failed to open directory containing bob frames\n") ;
  return ;
}

struct dirent *dirContent ;

// Get first .bob frame name from the directory
dirContent = readdir(moviesDir) ;
// isBobFile(dirContent) returns 1 if entry has ".bob" extension and 0 otherwise
while( !isBobFile(dirContent) )
{
  dirContent = readdir(moviesDir) ;
}

struct FilesList *filesList = (struct FilesList*)
    malloc( sizeof(struct FilesList) ) ;

// Initialize the list start at that first found .bob frame
filesList->fileName = dirContent->d_name;
// And save the head of the list
struct FilesList *filesListStart = filesList ;
printf("FilesListStart: %s\n", filesListStart->fileName) ;
printf("Address is: %p\n", filesListStart) ;

// For all other bob frames
while( (dirContent = readdir(moviesDir) ) != NULL )
{
  if( isBobFile(dirContent) )
  {
    struct FilesList *temporaryNode = (struct FilesList*)
        malloc( sizeof(struct FilesList) );
    temporaryNode->fileName = dirContent->d_name ;
    filesList->next = temporaryNode ;
    filesList = temporaryNode ;
  }
}
// Set the 'next' pointer of the last element in list to NULL
filesList->next = NULL ;
// close stream to directory with .bob frames
closedir(moviesDir) ;

// Check what FilesListStart points at
printf("FilesListStart: %s\n", filesListStart->fileName) ;
printf("Address is: %p\n", filesListStart) ;

// Rest of the code

1 个答案:

答案 0 :(得分:2)

您应该制作dirContent->d_name副本,而不是使用实际值。

每当您调用dirent时,运行时库都可以自由更改readdir结构的内容,如果您存储的是它的地址,则底层内存可能会发生变化。从POSIX手册页:

  

readdir()返回的指针指向可能被同一目录流上另一个readdir()调用覆盖的数据。

换句话说,替换以下行:

filesList->fileName = dirContent->d_name;
temporaryNode->fileName = dirContent->d_name ;

使用:

filesList->fileName = strdup (dirContent->d_name);
temporaryNode->fileName = strdup (dirContent->d_name);

假设您有类似strdup的功能,如果没有,您可以获得一个便宜的here

如果它只是在100次调用后发生变化,那么可能是运行时尝试更加智能,但即使它不能存储无限数量,所以它可能设置了合理的限制。

请记住在释放链接列表节点之前释放所有这些char指针(大概在“其余代码”部分的某处)。