2014-06-14 42 views
-1

我的C程序出现问题,意味着要从根目录打印指定文件的路径。例子:用于打印指定文件路径的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 $* 

回答

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()函数可以在不再需要时将该内存返回给堆,这是调用者的工作。

+0

对你已知的同一个字符串重复调用'strlen' *正好*一个字符比你上次调用它时更宽[教科书画家算法](http://en.wikipedia.org/wiki/Painter' s_algorithm)。在循环之后使用第二个指针'char * q = rootPath;'和'* q ++ = * p ++;'和'* q = 0;'。这个答案的其余部分我可以加入。 – WhozCraig

+0

@WhozCraig,更好? –

+0

Yah。在给定的上下文中,它可能从0开始,而不是'strlen()',但这与实际目标无关,摆脱了n(n + 1)/ 2扫描场景。 +1。谢谢。 – WhozCraig