2016-08-23 6 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 (Aborted). Для основного, 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

Смежные вопросы