Ошибка сегмента при чтении простого файла CSV - C - PullRequest
0 голосов
/ 21 мая 2018

Я читаю csv-файл с двумя столбцами в массив структур:

struct unused_s{
    char col1[MAX_ARG_LENGTH];
    char col2[MAX_ARG_LENGTH];
};

struct unused_s unused[MAX_USEABLE];

Но я получаю "Segmentation fault: 11" во время выполнения.Я старался изо всех сил отлаживать это самостоятельно через перераспределение памяти, но я боюсь, что мои способности не соответствуют задаче.Я, однако, указал, что где-то в этом разделе кода возникает ошибка:

void readCSV(FILE *file){
    int i = 0;

    char line[MAX_LINE_LENGTH];

    while (fgets(line, 1024, file))
    {
        char* tmp = strdup(line);
        strcpy(unused[i].col1, getunused(tmp, FIRST_COLUMN));
        strcpy(unused[i].col2, getunused(tmp, SECOND_COLUMN));
        free(tmp);
        i++;
    }

    fclose(file);

}

const char* getunused(char* line, int n)
{
    const char* tok;
    for (tok = strtok(line, ";");
            tok && *tok;
            tok = strtok(NULL, ";\n"))
    {
        if (!--n)
            return tok;
    }
    return NULL;
}

Любая помощь в решении этой проблемы / указании мне правильного направления для решения этой проблемы будет принята с благодарностью!

1 Ответ

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

Как отмечено в комментариях от John3136, вы возвращаете NULL из getunused(), например

const char* getunused(char* line, int n)
{
    const char* tok;
    for (tok = strtok(line, ";");
            tok && *tok;
            tok = strtok(NULL, ";\n"))
    {
        if (!--n)
            return tok;
    }
    return NULL;
}

Из ваших звонков на strtok, похоже, у вас есть входной файл, который приведет кв tmp аналогично:

tmp = "somevalue; othervalue\n"

После вашего первого вызова getunused(), strtok заменит каждый разделитель в tmp на нуль-символ в порядкечтобы токенизировать строку, теперь tmp будет содержать:

tmp = "somevalue\0 othervalue\0"

При вызове getunused(tmp, SECOND_COLUMN) (где SECOND_COLUMN предположительно 2), !--n tests false и NULL возвращается.

Зачем токенизировать?

Редко вам потребуется токенизировать поля из файла .csv (или в вашем случае a точка с запятой отдельный файл) Почему?В этом и заключается цель файла с разделенными значениями - поэтому вы можете прочитать файл как ввод, используя отформатированную функцию ввода для разделения полей, а не для разграничения на разделители.(что вы можете сделать - это просто не обязательно).В вашем случае, если формат файла .csv соответствует приведенному выше, вы можете полностью исключить getunused и просто использовать sscanf для разделения строк ввода, например,

void readCSV (FILE *file) {
    int i = 0;

    while (fgets(line, 1024, file))
        if (sscanf (line "%49[^;] %49[^;\n]", unused[i].col1, unused[i].col2) == 2)
            i++;

    fclose(file);
}

(примечание: как и в моем комментарии, вы должны включить модификатор field-width MAX_ARG_LENGTH-1 (число) как часть вашего format-спецификатора - как отредактировано вышепосле вашего последнего комментария)

Кроме того, если ваше второе значение заканчивается на '\n', тогда отбросьте ';' из класса символов , например, %49[^\n] подойдет для2-е значение.

...