Вложенный в цикл fprintf не записывает первый элемент - PullRequest
0 голосов
/ 17 мая 2018

Описание

Я пытаюсь написать таблицу csv, tablepath, и мне нужно включить в нее имена переменных, которые находятся в текстовом файле, filepath.Я использую первую функцию read_par для извлечения имен из filepath и вторую функцию store для записи в таблицу.

Задача

В созданной таблице систематически отсутствует имя первой переменной из текстового файла .Функция read_par является функциональной и выдает ожидаемый результат: строку, содержащую имя переменной, я также включил ее для контекста.

filepath

  • Вотструктура текстового файла:

par1 0 1 0.5 par2 1 1 1 par3 0 1 1 par4 0 1 1 par5 0 1 1 par6 0 1 1

store

  • Вот функция store:

    int store(int par_num, float sim_num, float **tab_param, char *filepath, char *tablepath){
    
    int j;
    char *name = NULL;
    FILE* sim_table = NULL;
    sim_table = fopen(tablepath, "w");  
    
    // Start the first line in the table
    fprintf(sim_table,"simulation_number");
    
    for(j=1; j < par_num+1; j++){
    
        // If it is the last parameter -> create a new line
        if(j == par_num){
    
            name = read_name(j, filepath);
            fprintf(sim_table,",%s\n", name);
        }else{
            /* If it is not the last parameter -> continue writing on 
             * the same line */
            name = read_name(j, filepath);
            fprintf(sim_table,",%s", name);
        }
    }
    fclose(sim_table);
    return 0;
    }
    

read_name

  • Вот функция read_name:

    char *strtok(char *line, char *eof);    
    
    char *read_name(int par_id, char *filepath){
    
    char *par_name;
    int count = 0;
    
    FILE *file = fopen(filepath, "r");
    
    if ( file != NULL ){
    
        char line[256]; /* or other suitable maximum line size */
        while (fgets(line, sizeof line, file) != NULL){ /* read a line */
    
            if (count == (2*par_id)-2){
    
                // strtok removes the \n character from the string line
                strtok(line, "\n");
                par_name = line;
    
                fclose(file);
            }
            else{
                count++;
            }
        }
    }
    else
    {
        printf("\n\n ERROR IN FUNCTION READ_PAR\n\nTEXT FILE IS EMPTY\n\n");
    }
    return par_name;
    }
    

tablepath

Таблица, которую я получаю, выглядит следующим образом:

┌─────────────────┬┬────┬────┬────┬────┬────┐
│simulation_number││par2│par3│par4│par5│par6│
└─────────────────┴┴────┴────┴────┴────┴────┘

С отсутствующим именем par1, но все остальные имена переменных успешно напечатаны.Я не знаю, где проблема.Это проблема в условиях цикла for или что-то связанное с самой строкой par1?

Спасибо за любую помощь по этому вопросу.

1 Ответ

0 голосов
/ 22 мая 2018

Проблема в том, что read_name возвращает адрес локальной переменной (line).Эта локальная переменная выходит из области видимости (и технически перестает существовать), когда функция возвращается.Таким образом, использование возвращенного указателя приводит к неопределенному поведению .

. Чтобы увидеть проблему более ясно, вот упрощенная версия read_name с отображением только соответствующих строк:

char *read_name(int par_id, char *filepath){

    char *par_name;

        char line[256];             // line is a local variable
        while (fgets(line, sizeof line, file) != NULL){

                par_name = line;    // par_name now points to the local variable
        }
    }
    return par_name;                // returning the address of the local variable
}

В комментариях к вопросу было отмечено, что read_name был протестирован и признан работоспособным.Так как это может быть неправильно?Это самое плохое в неопределенном поведении в C. Иногда код работает во время тестирования, даже если он технически некорректен.А под технически неверным я подразумеваю, что в какой-то момент он сломается .Например, в функции store, если вы добавите еще один вызов функции между вызовом read_name и вызовом fprintf, есть большая вероятность, что name будет поврежден и не будет печататься должным образом.

Простым решением в этом случае является объявление line с ключевым словом static:

static char line[256];

Таким образом, line имеет статическую продолжительность хранения, что означает, что он будет продолжатьсясуществовать после возвращения read_name.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...