-1

我的 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

我已经编写了程序并运行了程序,但是当第一次工作时,递归函数的任何后续调用都会出错。

我不确定问题出在哪里/哪里。

任何帮助表示赞赏。

代码:

#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 $*
4

1 回答 1

2

问题代码中有几处需要修复。

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

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

strcat() 函数需要两个字符串的地址。变量'p'被定义为一个char ptr,它可以存储这样一个地址。但是,'*p' 引用字符串的第一个 char 值,因此通常会导致编译器警告警告:传递 '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 的值时付出了很大的努力,重要的是要将有价值的值返回给调用者。不过这里有一个缺陷。变量 'rootPath' 仅存在于 compare() 函数的大括号内。在“返回”之后,变量和分配给变量的存储都不能存在。因此,编译器通常会发出警告:警告:函数返回局部变量的地址 这也将(最终)导致段错误。

为了返回珍贵的值,它必须放在一个比 compare() 函数更耐用的存储中。也许是这样的:

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

    ... 
    return strdup(rootPath);
    }

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

于 2014-06-14T03:15:27.477 回答