2016-11-26 35 views
-1

這裏是代碼。我是C語言的初學者,所以任何縮短我的代碼的建議都將不勝感激。我檢查了所有50張圖片,他們看起來很完美,但代碼沒有通過cs50檢查。我的recover.c代碼正確恢復jpegs,但沒有通過cs50檢查

int main(void) 
{ 
    FILE* source = fopen("card.raw", "r"); 



    uint8_t jpg[512]; 
    int direct = 0; 
    int jpgcounter = 0; 
    uint8_t checkjpg[4]; 
    FILE* outputfile ; 
    char filename[7] ; 

    while(feof(source) == 0) 
    { 
     fread(jpg,512,1,source); 

     for (int i = 0 ; i < 4 ; i++) 
     { 
      checkjpg[i] = jpg[i]; 
     } 

     if(checkjpg[0] == 0xff && checkjpg[1] == 0xd8 && checkjpg[2] == 0xff && checkjpg[3] >= 0xe0 && checkjpg[3] <= 0xef) 
     { 

      if (direct == 0) 
      { 
       sprintf(filename, "%03d.jpg" , jpgcounter); 
       outputfile = fopen(filename, "w"); 
       fwrite(jpg,512,1,outputfile); 
       direct = 1; 
      } 
      else 
      { 
       fclose(outputfile); 
       jpgcounter++; 
       sprintf(filename, "%03d.jpg" , jpgcounter); 
       outputfile = fopen(filename, "w"); 
       fwrite(jpg,512,1,outputfile); 
      } 

     } 
     else 
     { 
      fwrite(jpg,512,1,outputfile) ; 
     } 
    } 
    fclose(outputfile); 
    fclose(source); 
    return 0; 
} 

現在的主要問題是,它沒有通過CS50檢查,因此必須有一些數據,我錯過了card.raw或別的東西和人眼無法察覺圖像中的這些錯誤,但電腦也能。

+1

'char filename [7];'對於3 + 1 + 3 + 1個字符太小。 – wildplasser

+0

如果我使用char文件名[8]我得到一個段錯誤 – mithilesh

+1

如果您查看格式化的代碼,您可以看到檢查選定內容的可怕if語句中的差異。這可能會解釋您的部分或全部問題。你應該考慮重構你的代碼;通過'checkjpg16'變量'checkjpg1'肯定看起來像一個僞裝成我的陣列。避免像這樣寫東西;使用數據結構(例如數組 - 一個非常基本的數據結構)來封裝重複。仔細觀察數據時,應該將前3個字節與已知序列進行比較,並檢查第4個是否在範圍內。 –

回答

1

我想我知道問題是什麼。你永遠不會初始化outputfile。作爲初學者,您應該在聲明變量時始終初始化變量。從來不寫

int i; 

int i = ...; 

,並給它一個初始值(0-1INT_MAX,不管你喜歡)。這對於指針來說非常重要。如果你寫

FILE * outputfile; 

這是指向哪裏的指針?那是隨機的。它可能指向任何地方或無處。這是一個「無效」指針,在任何情況下您都不能使用outputfile,因爲任何使用的結果都是未定義的。但你怎麼知道它已經初始化?那麼,你不能!你不能,因爲你從來沒有分配任何值你可以檢查。

更好的代碼將

FILE * outputfile = NULL; 

像現在outputfile已定義的值,它是NULL,這意味着你可以測試,如果它是你的代碼草簽

if (outputfile == NULL) { 
    // Not initialized 
} else { 
    // Initialized 
} 

外觀和思考以下內容:
如果循環第一次運行,並且第一個512字節的塊與0xffd8ff..的if-test不匹配,會發生什麼情況?那麼你在其他情況下結束,這種情況下,以下內容

fwrite(jpg,512,1,outputfile) ; 

但在這裏有什麼值outputfile?沒有價值,它完全沒有定義。您在任何地址訪問內存,這很可能會導致您的應用程序崩潰,這正是發生在您身上的事情。如果你已經初始化outputfileNULL,正確的代碼將是:

} else if (outputfile != NULL) { 
    fwrite(jpg,512,1,outputfile); 
} 

這裏來美化超,清理的代碼版本。代碼未經測試,我只知道它編譯。我知道它也變得更大,但請考慮也有很多評論,代碼正在檢查和處理所有預期的錯誤,甚至打印到STDERR出了什麼問題。如果我想我可以壓縮很容易down to 58 lines,這比在問題你的代碼更只有7行,但您的代碼不捕獲或打印所有這些錯誤:

#include <stdio.h> 
#include <stdint.h> 
#include <stdbool.h> 

int main (void) { 
    FILE * inputFile = fopen("card.raw", "r"); 
    if (!inputFile) { // Same as "if (inputFile == NULL)" 
     fprintf(stderr, "Cannot open input file!\n"); 
     // Don't close it, it didn't open! 
     return 1; 
    } 

    // Always declare variables in the smallest possible scope! 
    // Don't declare anything here you only need in the loop and 
    // whose value doesn't need to survive a loop iteration. 
    int fileCounter = 0; 
    FILE * outputFile = NULL; 
    bool writeError = false; 

    for (;;) { // Endless loop, will never terminate on its own 
     uint8_t cluster[512]; 
     // It will read one cluster or nothing at all. 
     if (fread(cluster, sizeof(cluster), 1, inputFile) != 1) { 
      // If we have an open output file, close it. 
      if (outputFile) { 
       fclose(outputFile); 
       outputFile = NULL; // Not required but good style. 
      } 
      break; // Terminates the loop! 
      // Not reached, code flow continues after the loop. 
     } 

     // Check if start of new _or first_ JPG file. 
     if (cluster[0] == 0xFF && cluster[1] == 0xd8 
      && cluster[2] == 0xFF && cluster[3] >= 0xE0 && cluster[3] <= 0xEF 
     ) { 
      char filename[8]; 
      snprintf(filename, sizeof(filename), "%03d.jpg", fileCounter++); 

      // Start nof an new JPG file. 
      // If we have an "old" one, time to close it 
      if (outputFile) { 
       fclose(outputFile); 
      } 
      // Open new file 
      outputFile = fopen(filename, "w"); 
      if (!outputFile) { 
       // Cannot create output file. 
       writeError = true; 
       break; // Terminates the loop! 
       // Not reached, code flow continues after the loop. 
      } 
     } 

     // If we have an output file, write the cluster to it. 
     if (outputFile) { 
      if (fwrite(cluster, sizeof(cluster), 1, outputFile) != 1) { 
       // Write error. 
       writeError = true; 
       // Close the file. 
       fclose(outputFile); 
       break; // Terminates the loop! 
       // Not reached, code flow continues after the loop. 
      } 
     } 
    } 

    // If we end up here, we ran into one of the "breaks" 
    // and now need to find out which one. 
    bool exitWithError = false; 
    if (writeError) { 
     exitWithError = true; 
     fprintf(stderr, "Counldn't create/write to output file!\n"); 
    } else if (ferror(inputFile) != 0) { 
     exitWithError = true; 
     fprintf(stderr, "Counldn't read from input file file!\n"); 
    } 
    // Otherwise input file was just at the end. 

    // Final clanup: 
    fclose(inputFile); 

    return (exitWithError ? 1 : 0); 
} 

我與你分享這個代碼因爲學習某些編碼概念可能是最簡單的,只要看看其他人編寫代碼的方式。

+0

偉大的建議。我的教訓,爲什麼初始化是重要的。謝謝很多@Mecki – mithilesh

+0

@mithilesh我還添加了一個清理版本的代碼與適當的錯誤處理 - 如「我將如何編碼」。也許這給你一些想法如何改進你的代碼在未來我不能測試它,但我知道它編譯。 – Mecki

+0

不僅它教我的文體正確性,而且還有一些新的概念。非常感謝.Wish我有足夠的代表upvote:p – mithilesh