【问题标题】:Depth First Directory Traversing resulting in Segmentation Fault in C深度优先目录遍历导致 C 中的分段错误
【发布时间】:2012-12-03 07:56:20
【问题描述】:

我正在编写代码以使用depth first 算法遍历目录。问题是程序没有显示任何内容并给出Segmentation Fault error。我试图调试它,但它毫无价值,因为我还在学习东西。所以现在我需要专家的帮助。代码如下:

void func(char path[]);

int main(int argc, char *argv) {
    char buf[255];

    scanf("%s",buf);
    func(buf);
    return 0;
}

void func(char path[]) {
    DIR *dirp;
    struct stat states;
    struct dirent *direntp;
    printf("Inside\n");
    dirp=opendir(path);
    stat(path, &states);

    while ((direntp=readdir(dirp)) != NULL) {
        if (S_ISDIR(states.st_mode)) {
            printf("Calling Func\n");
            func(direntp->d_name);
            chdir("..");
        } else if (!S_ISDIR(states.st_mode)) {
            printf("  %s\n", direntp->d_name);
        } else if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) {
            continue;
        }
    }
    return ;
}

【问题讨论】:

  • if(!S_ISDIR)if(S_ISDIR) 部分应该交换(更不用说if (cond) { } else if (!cond) 是多余的......)
  • 也请正确缩进。
  • 如果一个目录被传递给func():难道你在这个目录中缺少chdir()
  • 使用-Wall -g编译你的代码,修复它直到没有更多的警告。如果出现段错误,请使用gdb 查看位置。

标签: c unix directory depth-first-search


【解决方案1】:

在func里面,while前面,放那个:

dirp=opendir (path);
if (!dirp)
  return;

顺便说一句,它的int main (int argc, char *argv[])

【讨论】:

  • 对不起,主要论点是错字
  • 但它仍然没有显示任何文件名。
  • 嗯,您正在检查状态,该状态由投入 func 的路径的 stat 设置,并且在此期间永远不会更新。相反,您应该检查 direntp,它会遍历所有条目。
  • 我已经尝试使用direntp->d_type 代替states.st_mode,但仍然没有显示文件名。
  • 如果您将printf(" %s %d\n",direntp->d_name, direntp->d_type); 作为第一个语句放在 while 中,您会看到 d_type 为 4 表示目录或 8 表示文件。
【解决方案2】:

调试打印,打印到stderr;它是行缓冲的,因此看起来更可靠。

概括地说,你的功能是:

void func(char path[])
{
    DIR *dirp;
    struct stat states;
    struct dirent *direntp;
    printf("Inside\n");
    dirp=opendir(path);
    stat(path,&states);

    while ((direntp = readdir(dirp)) != NULL)
    {
        if (S_ISDIR(states.st_mode))
        {
            printf("Calling Func\n");
            func(direntp->d_name);
            chdir("..");
        }
        else if (!S_ISDIR(states.st_mode))
        {
            printf("  %s\n",direntp->d_name);
        }
        else if (!strcmp(direntp->d_name,".") || !strcmp(direntp->d_name,".."))
        {
            continue;
        }
    }
}

chdir("..") 是不明智的;您既没有对相关目录执行chdir(),也没有确保该目录是当前目录的直接子目录,这意味着这段代码将会变得混乱......如果它曾经到达那个位。

您执行stat(path, &states);,但不检查它是否有效。

您可以使用dirp = opendir(path);,但不要检查它是否有效。

您不会在每个条目上都使用stat();您不断使用来自path 的初始统计信息。这可能是您测试时的一个目录,因此您然后递归调用该函数,该函数将读取.,这是一个目录,如果您没有用完@,您可能最终会用完堆栈987654332@指针优先。

您在循环中的测试顺序错误,即使您安排到 stat() 文件 - 这是一个不平凡的操作,因为您刚刚读取的名称必须附加到目录的路径才能形成正确的文件名。你的代码是:

if (is a directory)
else if (is not a directory)
else if (name is . or ..)
else ...missing...

首先,if 和下面的 else if 涵盖了所有选项,因此名称 test 和 final(不存在)else 永远不会被执行。您可能首先需要名称 test(伪代码):

if (name is a "." or "..")
    print "Skipping";
else if (name is a directory)
{
    create "path/name" as string;
    recurse with "path/name";
}
else
    print "Skipping non-directory";

请注意,这总是在每次迭代中打印一些内容。这在调试时非常重要。您不希望代码在执行您不期望的事情时保持安静。

注意不要调用closedir();这意味着您将用完目录描述符,在 dirp 中获得一个 NULL 值,当您使用它时会崩溃。

请注意,伪代码不包含任何chdir() 操作。使用它们时要非常、非常、非常谨慎。了解fchdir()的使用。

阅读ftw()nftw();有关于这些函数面临的复杂性的注释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多