2016-08-23 42 views
-2

私はこのコードにいくつかの問題があり、少し助けてもらえます。この関数は、ファイルから動的に割り当てられたメモリへの援助のための@JonathanLefflerファイルから文字配列への読み込み、C

感謝を読み込み - 関数インデントは完璧に動作します!しかし、もう一つの問題が出てきました。関数read_fileを使って、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で早期終了」と表示されます。最初の質問のエラーメッセージは "Received signal:SIGABRT(Aborted)"です。メインの場合、PID 9424 " – JasonUrban

+0

この情報を追加するために質問を編集してください。また、関数 'indent'がvalgrind出力に記述されるたびにチェックし、それぞれの行の行に関する情報を追加します。 – Garf365

答えて

1

あなたの基本的な問題は、siを追加するコード文字を出力バッファに追加しても、余分な文字のスペースがあるかどうかはチェックされません。長い字下げを使用すると、バグをすばやくくすぐることができます(例:" /* Look Ma! */ "、16文字)。あなたが現在持っている

 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++; 
} 

ああ、と私は、ディスプレイ上で使用して終了デバッグコードの一部を残した:

 continue; 
    } 
    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()は驚きの一つだった、解雇することはありません。

出力バッファに1文字を追加する関数が必要で、出力バッファコントロールを構造体(struct Buffer { char *buffer; size_t maxlen; size_t curlen; }またはその周辺)にまとめて、その1つの関数が(再)割り付けを処理する必要があると思います必要に応じてスペースを確保します。そうすれば、「力ずくで不注意な」解決策が激しく繰り返されるのを避けることができます。もしあなたが好きなら、それをstatic inlineの関数にすることができます。コンパイラは、コードの可読性を損なうことなくオーバーヘッドを避けるかもしれません。また、バッファにインデントの倍数を追加するために、2つのループで厄介な繰り返しがあります。それはもちろん別の関数で処理するのが最善でしょうが、十分なスペースを賢明にチェックし、再割り当てを一度行うことができるという点で、 'add one char'とは異なります。または、長さとヌル終端されていないバッファへのポインタを取る関数を書いてください(1文字​​は長さ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関数は完全に機能し、サーバーはこの演習に合格したと言いますが、しかし、すべてが完璧に動作するように見えました... – JasonUrban

関連する問題