2016-08-23 237 views
-2

我遇到了一些與此代碼有關的問題,並且會介意獲得一些幫助。此功能從文件讀取到動態分配的內存從文件讀取字符數組,C

感謝@JonathanLeffler尋求幫助 - 功能縮進功能完美!但是又出現了一個問題:使用函數read_file從文件讀取到char數組,稍後傳遞給縮進。

============================================== ===========================

//--------------- read_file valgrind validations -------------------- 
==396== 144 bytes in 1 blocks are definitely lost in loss record 62 of 66 
==396==    at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==396==    by 0x401AC1: read_file (polisher.c:24) 
==396==    by 0x4025CE: test_indent (test_source.c:174) 
==396==    by 0x406BC7: srunner_run (in /tmc/test/test) 
==396==    by 0x402C67: tmc_run_tests (tmc-check.c:134) 
==396==    by 0x402902: main (test_source.c:235) 
==396==  

================ =====================================

char *read_file(const char *filename) 
{ 
    FILE *f = fopen(filename, "r"); 
    if(!f) 
     return NULL; 
    int n = 0, c = 0; 
    char *a = NULL; 
    c = fgetc(f); 
    while(c != EOF) 
    { 
     n++; 
     c = fgetc(f); 
    } 
    freopen(filename, "r", f); 
    a = calloc(n + 1, sizeof(char)); 
    c = fgetc(f); 
    n = 0; 
    while(c != EOF) 
    { 
     a[n] = c; 
     n++; 
     c = fgetc(f); 
    } 
    a[n] = '\0'; 
    fclose(f); 
    return a; 
} 

====== ================================================== ========

START_TEST(test_indent) 
{ 
    char *str = read_file("testifile.c"); 
    if (!str) str = read_file("test/testifile.c"); 
    if (!str) { 
     fail("[M6.01.c] read_file(\"testifile.c\") returned NULL"); 
    } 
    char *res = indent(str, " "); 
    if (!res) { 
     free(str); 
     free(res); 
     fail("[M6.01.c] indent(\"testifile.c\") returned NULL"); 
    } 

    char buf[OUTPUTLEN]; 
    if (mycompare_new(res, ref61c, buf, OUTPUTLEN)) { 
     free(res); 
     free(str); 
     fail("[M6.01.c] Invalid string from indent(\"testifile.c\"): %s", buf); 
    } 
    free(str); 
    free(res); 
    test_complete(); 
} 
END_TEST 
+0

的就是你得到的第一個問題的錯誤?對於valgrind輸出,你能指出哪一行出現錯誤(哪一行代碼是行116,127,...)? – Garf365

+0

@ Garf365'strncpy(dest + dest_offset,pad,pad_len + 1);'是116.'dest [dest_offset ++] = c; '127。當我嘗試發送這個函數到服務器時,它說「提前返回值1」。第一個問題的錯誤信息是「接收信號:SIGABRT(中止)。對於主,PID 9424」 – JasonUrban

+0

請編輯您的問題以添加此信息。此外,檢查每次函數'indent'被提及到valgrind輸出中,並添加關於每行的信息 – Garf365

回答

1

您的基本問題是添加si的代碼ngle字符到輸出緩衝區不檢查是否有空間用於多餘的字符,並且可能沒有。您可以通過使用更長的縮進(例如" /* Look Ma! */ ",它是16個字符)來更快地修復錯誤。

如果您目前有:

 continue; 
    } 
    dest[dest_offset++] = c;   
    input++; 
} 

蠻力和粗心解決方案增加了:

 continue; 
    } 
    if (dest_offset >= dest_len) 
    { 
     printf("XX: DO = %zu, DL = %zu, PL = %zu, LV = %zu\n", dest_offset, dest_len, pad_len, pad_level); 
     putchar('@');fflush(0); 
     char *ptr = realloc(dest, dest_len * 2); 
     if(!ptr) 
     { 
      free(dest); 
      return NULL; 
     } 
     dest_len *= 2; 
     dest = ptr; 
    } 
    putchar('.');fflush(0); 
    dest[dest_offset++] = c; 
    input++; 
} 

哦,我留下了一些調試代碼,我結束了使用上的顯示。我添加了很多相似的打印代碼。在循環頂部的斷言也有幫助:assert(dest_offset <= dest_len);。當它開始發射時,情況變得更加清晰(但我花了一段時間才知道它爲什麼發射)。我還屠殺了測試的換行處理代碼:

 if (dest_offset >= dest_len || (pad_len * pad_level + 1) >= (dest_len - dest_offset)) 
     { 
      printf("YY: DO = %zu, DL = %zu, PL = %zu, LV = %zu\n", dest_offset, dest_len, pad_len, pad_level); 
      putchar('@');fflush(0); 
      char *ptr = realloc(dest, dest_len * 2); 
      if(!ptr) 
      { 
       free(dest); 
       return NULL; 
      } 
      dest_len *= 2; 
      dest = ptr; 
     } 

realloc()從來沒有發射,這是驚喜之一。

我認爲你需要一個函數來添加一個字符到你的輸出緩衝區,並且你需要將輸出緩衝區控制包裝到一個結構體中(struct Buffer { char *buffer; size_t maxlen; size_t curlen; }或其附近),並且你有一個函數處理(重新)分配需要的空間。這將避免「蠻力和粗心」解決方案的明顯重複。如果你願意,你可以使它成爲一個static inline函數 - 編譯器可以避免一些開銷,而不會影響代碼的可讀性。這兩個循環還有一個令人討厭的重複,即將多個縮進添加到緩衝區中。當然,最好用另一個函數來處理 - 但它會與'加一個字符'不同,因爲你可以明智地檢查足夠的空間並重新分配一次。或者編寫函數來獲取長度和指向非空終止的緩衝區的指針(因此單個字符的長度爲1,填充字符串的長度爲pad_len),並且單個函數可以完成大量工作 - 可能是更好的解決方案。我仍然將控件打包到一個結構中,並讓編譯器進行優化。

測試main()

int main(void) 
{ 
    char data[] = "#include <stdio.h>\nint main(void)\n{\nputs(\"Hello World!\\n\");\nreturn 0;\n}\n"; 
    printf("Before: [[%s]]\n", data); 
    fflush(0); 
    char *reformatted = indent(data, " /* Look Ma! */ "); 
    printf("Indent: -complete-\n"); 
    fflush(0); 
    printf("Source: [[%s]]\n", data); 
    fflush(0); 
    printf("Target: [[%s]]\n", reformatted); 
    free(reformatted); 
    return 0; 
} 
+0

非常感謝你,我已經編輯了我的代碼和問題,但現在有一個小問題... intend函數完美工作,服務器說我已經通過了這個練習,但現在它抱怨read_file,但一切看起來都很完美...... – JasonUrban