【问题标题】:Why does opendir() change the file path string passed to it?为什么 opendir() 会更改传递给它的文件路径字符串?
【发布时间】:2019-12-03 23:25:39
【问题描述】:

在给定当前工作目录的情况下,我正在尝试编写一个函数,它将打印该目录的所有内容以及 cwd 中子目录中的内容。

void printDir(char *cwd)
{
  printf("file path after printdir call: %s\n",cwd);
  DIR *dirPtr = opendir(cwd);
  struct dirent *dirEnt;

  char *slash = "/";
  char *dot = ".";
  char *dotdot = "..";
  char *pathPrefix = malloc(sizeof(cwd) + sizeof(slash)+1);
  pathPrefix = strcat(cwd,slash);

  if (dirPtr != NULL)
  {
      while((dirEnt = readdir(dirPtr)) != NULL)
      {
          char *temp = dirEnt->d_name;
          if (strcmp(temp,dot) != 0 && strcmp(temp,dotdot) != 0)
          {

             char *tempFullPath = malloc(sizeof(pathPrefix) + sizeof(temp) + 1);
             tempFullPath = strcpy(tempFullPath, cwd);
             strcat(tempFullPath, temp);

             printf("file path before we try to openthedir: %s\n",tempFullPath);
             DIR *tempSubDirPtr = opendir(tempFullPath);

             printf("filePath after we try to open this shit: %s\n",tempFullPath2);
             if (tempSubDirPtr != NULL)
             {
                  printf("file path right before a recursive call: %s\n",tempFullPath);
                  closedir(tempSubDirPtr);
                  printDir(tempFullPath);
           }
           printf("%s\n",tempFullPath);
        }
    }
}
else
{

使用调试 printf() 的控制台输出是:

current working directory string after getcwd: /home/TTU/canorman/testUtil
file path after printdir call: /home/TTU/canorman/testUtil
file path before we try to openthedir: /home/TTU/canorman/testUtil/find.c
filePath after we try to open this shit: /home/TTU/canorman/testUtil/find.c
/home/TTU/canorman/testUtil/find.c
file path before we try to openthedir: /home/TTU/canorman/testUtil/find2.c
filePath after we try to open this shit: /home/TTU/canorman/testUtil/find2.c
/home/TTU/canorman/testUtil/find2.c
file path before we try to openthedir: /home/TTU/canorman/testUtil/find
filePath after we try to open this shit: /home/TTU/canorman/testUtil/find
/home/TTU/canorman/testUtil/find
file path before we try to openthedir: /home/TTU/canorman/testUtil/testDir
filePath after we try to open this shit: /home/TTU/canorman/testUA
file path right before a recursive call: /home/TTU/canorman/testUA
file path after printdir call: /home/TTU/canorman/testUA
Could not open specified working directory
/home/TTU/canorman/testUA/

所以你可以在输出的最后几行看到文件字符串来自

/home/TTU/canorman/testUtil/testDir

/home/TTU/canorman/testUA

我在 opendir(3) 手册页中找不到任何关于这种情况的信息。 关于为什么会这样的任何想法。

【问题讨论】:

  • 您想要发生什么?实际的目录结构是什么?换句话说,有什么问题?
  • 你正在覆盖内存,因为你没有以正确的大小调用malloc(你写的比你分配的多)。例如,sizeof(cwd) 给你 4(或者可能是 8),而不是你想要的长度,你可以用strlen(cwd) 计算。 (我怀疑还有其他类似的问题;这只是我确认的第一个问题。)
  • char *pathPrefix = malloc(sizeof(cwd) + sizeof(slash)+1); 不会分配您认为的内存量。 sizeof(cwd) 是指针的大小,与字符串的长度无关。
  • pathPrefix = strcat(cwd,slash) 实际上是在 修改 cwd 指向的缓冲区,而且还不清楚这是允许的。缓冲区中是否有空间容纳额外的斜杠和尾随 NUL ?这将在我们看不到它的调用者中分配。

标签: c linux opendir


【解决方案1】:

这段代码肯定是错的:

char *pathPrefix = malloc(sizeof(cwd) + sizeof(slash)+1);
pathPrefix = strcat(cwd,slash);

正如@Steve 和@William 所指出的,sizeof 应用于 指针 而不是字符串,因此它每个分配 4 或 8 个字节(加一个),这不太可能是足够的。 strlen(s) 统计字符串中活动字符的个数;您必须自己为 NUL 字节添加 +1。

但更大的问题是strcat() 的使用,它将第二个字符串附加到第一个字符串的尾部,从而修改了第一个字符串。这不是为您创建新的连接字符串,而是将其填充到新分配的(太小)内存中。

这应该表现得更好:

char *pathPrefix = malloc(strlen(cwd) + strlen(slash) + 1);
strcpy(pathPrefix, cwd);   // cwd goes to the start of the new buffer
strcat(pathPrefix, slash); // append the slash to the end of cwd

...然后在其余代码中进行类似的更改。

编辑:在进行此类工作时,最好将 const 限定您不打算修改的任何 char * 变量(从您的角度来看,字符串是只读的) )。这样做会为您的代码添加有用的文档,并且编译器会警告您常见的错误。

例子:

void printDir(const char *cwd)
{
  ...
  const char *slash = "/";
  const char *dot   = ".";
  const char *dotdot = "..";

  ...

无论如何修改字符串文字都是不合法的,但如果 cwd 参数是 const 限定的,编译器会反对 strcat(cwd, slash),因为它知道第一个参数被写入。

这并没有真正改变代码的行为,但这是一个养成的好习惯。 const 是你的朋友。

【讨论】:

  • 谢谢!这帮助了很多!
【解决方案2】:

存在一些与字符串操作相关的错误。请记住,str*() 函数(strcat()、strcopy() 等)将结果放入缓冲区,该指针作为第一个参数传递。 所以:

1) 关于开头的代码:

char *pathPrefix = malloc(sizeof(cwd) + sizeof(slash)+1);
pathPrefix = strcat(cwd, slash);

你应该使用 mallocated 缓冲区指针作为第一个参数,当然你需要在 strcat() 之前将 cwd 复制到这里。下面是正确的代码:

char *pathPrefix = malloc(sizeof(cwd) + sizeof(slash)+1);
strcpy(pathPrefix, cwd);
strcat(pathPrefix, slash);

2) 在 'while' 循环中的第一个 'if' 块内:你做得正确,但没有必要通过从 'strcpy()' 返回的值来分配 'tempFullPath' - 你已经将此指针作为第一个参数,所以复制将被执行到这个缓冲区中。 所以,替换:

char *tempFullPath = malloc(sizeof(pathPrefix) + sizeof(temp) + 1);
tempFullPath = strcpy(tempFullPath, cwd);
strcat(tempFullPath, temp);

与:

char *tempFullPath = malloc(sizeof(pathPrefix) + sizeof(temp) + 1);
strcpy(tempFullPath, cwd);
strcat(tempFullPath, temp);

3) 不要忘记释放由“malloc()”分配的内存!!!!(每个“malloc()”必须有相应的“free()”)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 2019-09-28
    • 1970-01-01
    • 2014-09-15
    • 2017-08-24
    • 1970-01-01
    相关资源
    最近更新 更多