2016-07-20 4 views
-1

Я разбираю текстовый файл - я могу его открыть, прочитать и удалить ненужные фрагменты из строки.
Однако, я не в состоянии получить этот код, чтобы работать:Аргумент Out не работает

size_t read_lines(const char *file_name, char **buffer) { 
    size_t n_lines = 0; 

    FILE *file = open_file(file_name); 

    while (1) { 
     char *ln = _read_line(file); 

     if (ln == NULL) { 
      break; 
     } 

     n_lines++; 
    } 

    fclose(file); 

    file = open_file(file_name); 

    buffer = calloc(n_lines, sizeof(char *)); 

    for (int i = 0; i < n_lines; i++) { 
     buffer[i] = read_line(file); 
    } 

    fclose(file); 

    return n_lines; 
} 

int main(int argc, const char *argv[]) { 
    char **lines; 

    size_t length = read_lines("/Users/honzik/Documents/Xcode/BoioVM/BoioVM/test_file.bic", lines); 

    for (int i = 0; i < length; i++) { 
     printf("%s\n", lines[i]); 
    } 

    free(lines); 

    return 0; 
} 

Я знаю, что это, вероятно, дерьмовый код, но он просто должен работать.
Или, может быть, нет? lines равны NULL, но как получить указатель, обновленный функцией?

PS: Не беспокойтесь обо всех этих функций (open_file, read_line, _read_line, ...) они работают :)

+1

Можем ли мы увидеть '_read_line()'? – babon

+0

Вы написали три функции с именем: 'read_lines',' _read_line' и 'read_line'. Зачем? – babon

+0

Да, это довольно опасно, так как это может привести к путанице. Это сбивает с толку. Лучше, если вы дадите им больше * явных * имен. Как 'read_line_with_something()' или что-то в этом роде. –

ответ

1

Предполагая, что read_line() работает, как ожидалось, что вы хотите достичь, это возможно только с указателем на три звезды, IMHO это один случай, когда вы можете использовать его, потому что это не трехзначный указатель, это двухзвездочный указатель, адрес которого передан функции.

Двойной char указатель в функции read_lines() является локальной переменной функции, так что сохранение адреса, возвращаемый calloc() в нем не будет сохранена, когда функция возвращает, вместо этого вы должны передать адрес указателя и хранить возвращать значение calloc() разыменования указателя и присвоения его реальных два указателя звезды, определенных в main(), Somethin как этого

size_t read_lines(const char *file_name, char ***buffer) 
{ 
    size_t n_lines = 0; 
    FILE *file = open_file(file_name); 
    // FIXME: check if `file != NULL' before reading 
    while (1) { 
     char *ln = _read_line(file); 
     if (ln == NULL) 
      break; 
     n_lines++; 
    } 
    fclose(file); 

    file = open_file(file_name); 
    // FIXME: check if `file != NULL' before reading 
    *buffer = malloc(n_lines * sizeof(**buffer)); 
    // FIXME: check that `malloc' did not return `NULL' 
    for (int i = 0; i < n_lines; i++) 
     (*buffer)[i] = read_line(file); 
    fclose(file); 
    return n_lines; 
} 

Обратите внимание, что:

  1. Я заменил calloc() на malloc(), так как строка должна быть null завершена внутри read_line(). Использование calloc() в этом случае может скрыть некоторые ошибки, которые было бы очень сложно отладить. Если вы используете malloc(), вы можете легко выявить потенциальные ошибки с помощью инструмента, такого как valgrind.

  2. Я добавил комментарии smoe, чтобы вы могли видеть, что ваш код очень опасен.

На main() вы могли бы сделать это

#define PLEASE_AVOID_SUCH_LONG_LINES "/Users/honzik/Documents/Xcode/BoioVM/BoioVM/test_file.bic" 

size_t length = read_lines(PLEASE_AVOID_SUCH_LONG_LINES, &lines); 
/* long lines make the code hard to read even on modern editors */ 
+0

Спасибо, это сработало - но это небезопасно, так как функции 'open_file' проверяют, возвращает ли' fopen' 'NULL'. Если это так, это 'exit (1)' s. –

+0

Вы не должны обрабатывать ошибки запутанным способом, и вы, конечно, НЕ ДОЛЖНЫ «выходить (1)» на любую ошибку. Сделайте свою функцию повторно используемой, не выходите из нее. Просто верните то, что позволяет вызывающему абоненту узнать, что есть ошибка. Как 'NULL', почему вы думаете,' malloc() 'возвращает' NULL' вместо простого вызова 'exit (0)'. –

+0

Ну, возврат 'NULL' приводит к' if (result == NULL) 'везде. Я бы, вероятно, никогда не использовал 'open_file' нигде, и возврат« NULL »из него приведет к простому отказу всей программы, поэтому мне придется« выйти (1) »в другое место. И мой код не предназначен для повторного использования кем-то. Если это так, он должен иметь дело с этим фактом. –

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