2012-03-27 82 views
0

我正在從fgets中獲取細分,但有時只是。這是別人的代碼,我不懂makefile,所以我用printf語句進行調試......我把它放在主函數的兩個部分:(我只創建變量* f並且只寫一行,但是我FOPEN和FCLOSE文件兩次)fgets上的segfault ...有時

FILE *f = NULL; 
char line[1000]; 
if ((f=fopen(filename,"r+"))==NULL) 
{ 
    printf("Error opening file\n"); 
    f=0;//...handle error... //(usually just call abort() or return -1 
} 
//f = rfopen(fname, "r+"); 
printf("f from eval_args: %d, filename %s\n",f,filename); 
printf("trying to read from file...\n"); 
printf("%s\n",fgets(line, sizeof (line), f)); 
printf("...succeeded\n"); 
fclose(f); 

這給了我兩個不同的輸出:

f from eval_args: 4609600, filename /correct/path/to/file 
trying to read from file... 
100 

...succeeded 

f prior to entering density profile: 4609600, filename /correct/path/to/file 
trying to read from file... 
Segmentation fault (core dumped) 

我檢查文件被正確打開,謹防閱讀更多的字符比將適合'線'。我在一個論壇上看到,文件名不應超過49個字符......但a)這是一個奇怪的限制,以及b)爲什麼它第一次工作?

有誰知道我還能檢查什麼?

+0

沒有的printf()打印'(空)'當遇到一個空字符串是否? – 2012-03-27 13:42:37

+0

你能發佈一個能夠重現問題的小型可編譯程序嗎? – hmjd 2012-03-27 13:46:58

+0

首先,你應該把'fgets'作爲一個單獨的語句,然後你應該使用調試器來幫助你定位和檢查錯誤。 – 2012-03-27 13:47:27

回答

0

從您的描述中,可能的原因可能是第二個fgets不成功,所以它返回NULL,這導致了段錯誤。那麼爲什麼第二個fgets失敗?你可以看看它......

參考fgets規格:

成功時,該函數返回相同的海峽參數。 如果遇到文件結束並且沒有讀取任何字符,則str的內容保持不變,並返回空指針。 如果發生錯誤,則返回空指針。 使用ferror或feof來檢查是否發生錯誤或已達到文件結束。 http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

所以通常這不是一個很好的做法,直接使用的fgets返回值。

+0

感謝您的提示,我已經把fgets和printf調用放在了不同的行上,看起來fgets函數根本不會返回。 (Segfaults甚至在輸出NULL之前) – craq 2012-03-27 14:41:22

+0

@craq - 確保你在fgets調用之前沒有無意中關閉或覆蓋你的文件句柄'f'。 – 2012-03-27 15:36:46

+0

@John - 故意關閉它,覆蓋它並再次打開應該沒問題,對吧? – craq 2012-03-28 08:00:06

1

如果不是很麻煩你可以,但猜你知道,做一些事情;

可以美化一點,但

#include <stdio.h> 
#include <stdarg.h> 

#define MAX_LINE 1024 

void dbg_fprnt(FILE *fh, char *fmt, ...) 
{ 
    char buf[MAX_LINE]; 
    char inf[MAX_LINE] = {0}; 
    va_list args; 

    if (fmt && *fmt) { 
     va_start(args, fmt); 
     va_end(args); 
     vsprintf(inf, fmt, args); 
    } 

    buf[0] = '\n'; 
    buf[1] = '\0'; 
    if (ferror(fh)) { 
     fprintf(stderr, " * ERR, ferror() --- \n"); 
    } else if (fh == NULL) { 
     fprintf(stderr, 
      " * DBG PRNT ERR;; Trying to print from NULL ---\n"); 
    /* else if (and so forth) */ 
    } else { 
     if (fgets(buf, MAX_LINE, fh) == NULL) { 
      perror(" * ERR DBG PRNTF FGETS, --"); 
     } 
    } 
    printf("%-15s FC:: %s", inf, buf); 
} 

int main(void) 
{ 
    char *fn = "lorem_ipsum"; 
    FILE *fh; 

    if ((fh = fopen(fn, "r")) == NULL) { 
     fprintf(stderr, 
      "Unable to open '%s' for read.\n", 
      fn); 
     return 1; 
    } 

    setbuf(stdout, NULL); 

    dbg_fprnt(fh, "SOME LINE: %d", 123); 
    dbg_fprnt(fh, "%s", "SASA"); 
    dbg_fprnt(fh, ""); 
    dbg_fprnt(fh, NULL); 
    dbg_fprnt(fh, "%s %d !", "Woot", 33); 
    dbg_fprnt(fh, "@%d :::", __LINE__); 
    fclose(fh); 
    dbg_fprnt(fh, "@%d :::", __LINE__); 


    return 0; 
} 

輸出示例:

./fe 
SOME LINE: 123 FC:: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 
SASA   FC:: tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 
       FC:: quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 
       FC:: consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 
Woot 33 !  FC:: cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 
@52 :::   FC:: proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 
* ERR DBG PRNTF FGETS, --: Bad file descriptor 
@54 :::   FC:: 
+0

哇,謝謝你,我確實學到了一點。我給你的輸出略有不同,但這可能並不重要。特別是因爲它不適用於fgets。對我來說,輸出的最後3行看起來像:'@ 62 ::: FC :: proident,在工作中不需要太多的工作量。「#:ERR DBG PRNTF FGETS, - :Bad file數字' '@ 64 ::: FC ::' – craq 2012-03-28 09:14:17

+0

@craq:'__LINE__','__FILE__'等是預處理宏,並在_your_文件中生成linenumber等。因此,在_my_文件中,第52行中的「'dbg_fprnt(fh,」@%d :::「,__LINE __);'」在fclose(fh)之前,'_your_文件中的第62行。 – Morpfh 2012-03-29 12:55:23

0

從您的打印出來:

f from eval_args: 4609600, filename /correct/path/to/file 
trying to read from file... 
100 

...succeeded 

f prior to entering density profile: 4609600, filename /correct/path/to/file 
trying to read from file... 
Segmentation fault (core dumped) 

你有「F之前進入到密度分佈「而不是」來自eval_args的f「,而是」在進入密度分佈之前「文件「不存在於您提供的源代碼中,我認爲您沒有運行相同的代碼。

以及註釋「//...handle error ...」(通常只是調用abort()或者返回-1)「沒有代碼來處理它,所以它仍然可以下載並且coredump。

根據從與fgets返回的描述:

成功完成後,與fgets()應返回■如果流是在結束的文件,該流結束文件指示符應被設置。而fgets()應該返回一個空指針。如果發生讀錯誤,應設置流的錯誤指示符,fgets()應返回一個空指針,並設置errno來指示錯誤。

所以EOF或任何不好的東西都會使printf coredump。

我建議沿着線的東西:

FILE *f = fopen(filename,"r+"); 
    if (f) { 
     char line[1000]; 
     printf("f from eval_args: %p, filename %s\n",f,filename); 
     printf("trying to read from file...\n"); 
     while(fgets(line, sizeof (line), f)) printf("%s",line); 
     fclose(f); 
    } 
    else printf("Error opening file\n"); 
+0

yes,字符串輸出,所以我可以很容易地告訴輸出來自哪裏。是的,懶惰不去處理錯誤,但如果這是我至少知道的情況,因爲printf語句。只是爲了重申,這是fgets調用,而不是生成段錯誤的printf。我現在有'char * dummy; dummy = fgets(line,sizeof(line)-1,f); printf(「fgets已經返回\ n」); ...'和段錯誤發生在打印該行之前。 – craq 2012-03-28 10:30:50