2012-03-29 55 views
0

我有以下代碼打開了一個輸入和輸出文件:奇怪ç行爲具有的fopen和測試NULL

if ((source_file_ptr = fopen(source_filename, "rb")) == NULL) { 
    error("unable to open input file"); 
} 
if ((output_file_ptr = fopen(output_filename, "wb")) == NULL) { 
    error("unable to open output file"); 
} 

這是goood簡單的辦法趕上在打開的文件中的錯誤。

但是,在對我的程序進行一些編輯後,程序現在崩潰而不是捕獲無效的輸出文件。

我試了幾件事情沒有成功,但有趣的是,當我試試這個:

if ((output_file_ptr = fopen(output_filename, "wb")) == NULL) printf("fail"); 
exit(0); 
if ((source_file_ptr = fopen(source_filename, "rb")) == NULL) { 
    error("unable to open input file"); 
} 
if ((output_file_ptr = fopen(output_filename, "wb")) == NULL) { 
    error("unable to open output file"); 
} 

這將打印「失敗」(顯然退出而不更加深入瞭解)。

但是,如果我將exit(0)行註釋掉,它將再次顯示相同的崩潰行爲,而不打印「失敗」,也不會捕獲錯誤。

我無法解釋爲什麼這是...我懷疑是一個懸掛指針,但函數內的唯一前面的代碼行已經包含在if-else if-else all with括號中。上面只有其他幾個函數,但我已經檢查並確保它們都被括在括號內。

我還在學習C,關於這裏發生了什麼的任何想法?
非常感謝!

注意:用括號括住printf(「fail」)不會改變我觀察到的行爲。

編輯:額外的代碼如下上面:

if (fread(&file_struct, sizeof(file_struct), 1, source_file_ptr) < 1) { 
    error("unable to read %s", source_filename); 
} 
else { 
    error_check(file_struct); 

    if (fwrite(&file_struct, sizeof(file_struct), 1, output_file_ptr) < 1) { 
    error("unable to write file header"); 
    } 
} 
+0

你可以在這些if後面發佈後續代碼嗎?如果遇到故障,這些'if's將打印消息,但文件指針仍可能被使用。 – hmjd 2012-03-29 11:11:49

+0

使用'perror()'來描述錯誤。 – pmg 2012-03-29 11:14:48

+0

您可能需要在printf()和exit()周圍使用一些{}。 – wildplasser 2012-03-29 11:15:11

回答

2

我檢查的第一件事是,source_filename是一個有效的C字符串。然後我會以同樣的方式檢查output_filename

如果發現您的更改以某種方式損壞了其中一個或兩個,您將進入未定義的區域行爲。

調試器的使用將是理想的,因爲您可以在該代碼的開始處設置一個斷點,然後單步執行,檢查即將使用的變量。

你應該檢查的另一件事是你的電話error實際返回(而不是,例如,呼叫exit)。

如果他們不那麼,即使fopen調用返回NULL,你還是會通過,以fread和/或fwrite,一個明確的禁忌。

由於你的第二個案例打印"fail",這是一個給定的問題,你打開輸出文件時有一些問題。從那裏使用NULL句柄不是一件好事。

如果功能確實回報,那麼你就應該使用類似:

if ((source_file_ptr = fopen(source_filename, "rb")) == NULL) { 
    error("unable to open input file"); 
    return; 
} 
if ((output_file_ptr = fopen(output_filename, "wb")) == NULL) { 
    fclose (source_file_ptr); 
    error("unable to open output file"); 
    return; 
} 
+0

我可以驗證我沒有設置output_filename(指針)指向任何內容,並且output_filename == NULL返回false。如果我不提供source_filename,它將返回錯誤消息。它只是不會做輸出。即使我切換if語句的順序。 – xlm 2012-03-29 11:29:54

+0

道歉我應該補充說,錯誤打印消息,也退出(-1) – xlm 2012-03-29 11:32:55

+0

@xlm,那麼你需要或者_print_值來確認他們的內容,包括之後刷新,以確保你不會因爲丟失核心轉儲)或通過調試器運行它。嚴重的是,如果可能的話,做後者。它應該告訴你_完全問題是什麼,而不是我們試圖猜測(不管這些猜測是否合理)。 – paxdiablo 2012-03-29 11:40:54

2

「故障」不會,必須,顯示如果你有緩衝輸出 - 因爲它崩潰,也不要退出並刷新輸出緩衝區。

如果你

則setbuf(標準輸出,NULL);

我猜你會得到fail印,也沒有exit

正如@caf下文提到的,還要檢查是否fflush()更適合:

stdio.h


編輯:
這可能是有點混亂,但是,既然你確認的Linux + gcc我會添加它,一個非常短的gdb介紹,並在??%最佳攻擊方式:

  1. -ggdb添加到您的編譯行3.9 Options for Debugging Your Program or GCC。如果您使用的參數

    • $ gdb -args my_prog arg1 arg2
    • 否則:$ gdb my_prog
    • 參數也GDB內部提供

  2. 啓動GDB會話斷點:

    • (gdb) break 112,< - 其中112是行號,或
    • (gdb) break main,< - 其中主要是功能
    • (gdb) break foo.c:bar,< - 在foo.c是文件,bar是功能
    • 也有不少其他方法

  3. 開始執行:(gdb) run

  4. 當程序遇到斷點停止,從這裏可以即:

    • (gdb) print output_filename,< - 文件名
    • (gdb) print *source_file_ptr,<的打印值 - 打印什麼這點到
    • (gdb) list,單 - ,列表行號等< - 打印源
    • 和廣闊其他物品清單

  5. 要繼續,您可以這樣做:例如:
    • (gdb) next,< - 通過子例程調用進行步驟。
    • (gdb) step,< - 步驟直至不同的源極線,(即,在給一個函數)
    • (gdb) continue,< - 繼續execuition,直到下一個斷點,程序或其它的結束。
    • 如此反覆

  6. 要退出:(gdb) quit

最常使用gdb的指令有一個字母的縮寫。即r對於run,b對於break,n對於next等。它也具有對已知變量的標籤填充。

很多命令還需要數字或其他參數。即next 8

使用手冊,手冊頁等,在運行時也可以發出幫助命令。即(gdb) help run

+0

而不是完全刪除緩衝區,您可以在'printf'調用刷新緩衝區後簡單地將一個調用添加到'fflush(stdout);'。 – caf 2012-03-29 11:38:27

+0

@caf確實。想到這一點,但認爲在調試的情況下,關閉它比較簡單,例如,如果有多個測試printf的話。但我應該提到它。懶惰的我。 – Morpfh 2012-03-29 11:59:04

+0

+1感謝gdb的簡介!剛剛下載;正在尋找一個介紹 – xlm 2012-03-29 13:21:38