c - 用于打印给定文件路径的 C 程序错误

标签 c cstring stat dirent.h

我的 C 程序遇到问题,该程序旨在打印从根目录到给定文件的路径。示例:

./pathto
/users/cs/a1066199/
./pathto .
/users/cs/a1066199/
./pathto file.txt
/users/cs/a1066199/file.txt
./pathto ..
/users/cs/
./pathto ../teaching/somefile.c
/users/cs/teaching/somefile.c

正在使用的算法如下,我必须用递归来实现它:

let d be a directory.
open the parent of d (ie d/..)
loop
    Get next entry, e, in the parent diretory
    get the status of e, using stat, into es
    until es.device==d.device and es.inum==d.inum
endloop

我已经编写了程序并运行了该程序,但是虽然第一次有效,但任何后续的递归函数 seg 调用都会出现错误。

我不确定问题出在哪里。

感谢任何帮助。

代码:

#define _BSD_SOURCE
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<dirent.h>
#include<string.h>

char* compare(char currDir[1024], char newDir[1024], struct stat D){
    int found = 0;
    struct stat Dnew;
    struct stat ES;
    struct dirent* direntp;
    DIR* dirp;
    char* p;
    char dirName[1024];
    char filePath[1024];
    char newDir2[1024];
    char rootPath[1024];

    dirp = opendir(newDir);//open parent directory
    while ((direntp = readdir(dirp)) != NULL){//read parent
        //printf("%s\n", direntp->d_name);
        strcpy(filePath, newDir);//create path to the file in the parent
        strcat(filePath, "/");
        strcat(filePath, direntp->d_name);
        if(stat(filePath, &ES) == -1){//read into stat
            perror("stat");
        }
        if(ES.st_dev == D.st_dev){//check es.device == d.device
            //printf("st_dev are the same\n");
            if(ES.st_ino == D.st_ino){//check es.inum == d.inum
                //printf("st_ino are the same\n");
                printf("The child Dir is %s\n", direntp->d_name);//print this if they are the same
                found = 1;
                if(ES.st_mode & S_IFDIR){//if its a directory, put / on the end
                    strcpy(dirName, direntp->d_name);
                    strcat(dirName, "/");
                } else {
                    strcpy(dirName, direntp->d_name);
                }
            } else {
                found = 0;
            }
        } else {
            found = 0;
        }
    }
    closedir(dirp);

    if(D.st_ino == 2){
        //strcpy(dirName, "/");//if root, return /
        return "/";
    } else {
        dirp = opendir(newDir);
        while ((direntp = readdir(dirp)) != NULL){
            if (strcmp(direntp->d_name, "..") == 0){//find ..
                strcpy(filePath, newDir);
                strcat(filePath, "/");
                strcat(filePath, direntp->d_name);
                if(stat(filePath, &Dnew) == -1){//read .. into Dnew
                    //perror("stat");
                }
            }
        }
        closedir(dirp);

        strcpy(newDir2, newDir);//make new dir
        strcat(newDir2, "/..");

        printf("%s\n", newDir);
        printf("%s\n", newDir2);

        strcpy(rootPath, "");
        /*strncpy(rootPath, */p = compare(newDir, newDir2, Dnew)/*, 1024)*/;//call recursivly
        while(*p != '\0'){
            strcat(rootPath, *p);
            p++;
        }
        strcat(rootPath,dirName);
        return rootPath;
    }
}

int main(int argc, char* argv[]){
    struct stat D;
    //struct stat E;
    //struct stat ES;
    //struct dirent* direntp;
    //DIR* dirp;
    //char filePath[1024];
    char* p;
    char rootPath[1024];
    char currDir[1024];
    char newDir[1024];

    strcpy(currDir, argv[1]);
    if(stat(argv[1], &D) == -1){
        //perror("stat");
    }

    strcpy(newDir, currDir);
    strcat(newDir, "/..");

    printf("%s\n", currDir);
    printf("%s\n", newDir);

    /*strncpy(rootPath, */p = compare(currDir, newDir, D)/*, 1024)*/;
    while(*p != '\0'){
        strcat(rootPath, *p);
        p++;
    }
    printf("%s", rootPath);
    /*if(D.st_mode & S_IFDIR){
        printf("/\n");
    }*/

    return 0;
}

终端输出:

/usr
/usr/..
The child Dir is usr
/usr/..
/usr/../..
The child Dir is ..
The child Dir is .
./pathto: line 6: 27236 Segmentation fault      (core dumped) ./pathto.o $*

最佳答案

问题代码中有一些内容需要修复。

1) 考虑以下问题代码片段(在问题代码中出现两次):

        while(*p != '\0'){
        strcat(rootPath, *p);
        p++;
    }

strcat() 函数需要两个字符串的地址。变量'p'被定义为一个char ptr,它可以存储这样的地址。但是,“*p”引用字符串的第一个字符值,因此通常会导致编译器警告警告:传递“strcat”的参数2使指针来自整数而不进行强制转换。仅此一点就可能并且很可能确实导致了段错误。也许下面的代码会更好?

        size_t len = strlen(rootPath);
        while(*p != '\0')
           { 
           rootpath[len++] = *p++;
           } 
       rootpath[len] = '\0';         

2)现在考虑以下事项:

char* compare(char currDir[1024], char newDir[1024], struct stat D){
    ...
    char rootPath[1024];
    ...

    ... 
    return rootPath;
    }

显然,compare() 函数已经努力计算值 rootPath,将有值(value)的值返回给调用者很重要。但这里有一个缺陷。变量“rootPath”仅存在于compare()函数的大括号内。在“返回”之后,变量和分配给变量的存储空间都不能存在。因此,编译器通常会发出警告:警告:函数返回局部变量的地址 这也会(最终)导致段错误。

为了返回有值(value)的值,必须将其放置在比compare()函数更持久的存储中。也许是这样的:

char* compare(char currDir[1024], char newDir[1024], struct stat D){
    ...
    char rootPath[1024];
    ...

    ... 
    return strdup(rootPath);
    }

strdup() 函数将为该值分配“堆”内存(可以比函数更持久),并将该内存的地址返回给调用者。请记住,调用者的工作是在不再需要该内存时调用 free() 将其返回到堆。

关于c - 用于打印给定文件路径的 C 程序错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24216174/

相关文章:

c - 调用 pthread_spin_destroy() 时,到底释放了什么 "resources"?

c++ - NULL 终止字符串及其长度

C++:如何将 ASCII 或 ANSI 转换为 UTF8 并存储在 std::string 中

C - do/while 循环和 switch(int)。输入 char 值会导致 inf。环形

c - 如何循环打印scanf数据的所有结果

c - 关于未定义的行为

c++ - C 字符串到宽 C 字符串赋值

linux - 如何按上次更新日期列出父目录,包括该文件夹的所有文件

C 编程 - Stat 系统调用 - 错误

c - 用C语言区分linux上的文件和目录