при чтении файла с использованием fgets strtok вызывает ошибку сегментации - PullRequest
0 голосов
/ 12 сентября 2018

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

InputVector:0(1,3,4,2,40)

Код:

FILE *file = fopen(filename, "r");
char buff[26];
char *token;

while(fgets(buff, 26, (FILE*)file) != NULL) {

    buff[strlen(buff)] = '\0';

    printf("%s\n", buff);
    token = strtok(buff, INV_DELIM1);
    printf("%s\n", token);
    token = strtok(NULL, INV_DELIM2);
    printf("%s\n", token);

    while(token != NULL) {
        token = strtok(NULL, INV_DELIM3);
        printf("%s\n", token);
    }
}

Я предполагаю, что в цикле whilestrtok() не вернул NULL после последнего номера и продолжил работу, что вызвало ошибку сегментации.Я попытался добавить "\0" в конец buff после fgets(), но ничего не получилось.

delim1: ":",
delim2: "(",
delim3: ",)"

вывод, который я получил, был

InputVector:0(1,3,4,2,40)
InputVector
0
1
3
4
2
40
segfault

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Не экономьте на размере буфера .Если ваша самая длинная строка может быть 25 символов, тогда не используйте 26 символов в качестве размера буфера, вместо этого:

#define MAXC 1024  /* constant for max characters in buf */
...
    char buff[MAXC] = 1024;

(Вам решать, 128 работает как любой другойзначение, которое гарантирует, что при любом изменении длины ввода вы не будете писать за пределами вашего массива. Я бы предпочел, чтобы буфер был на 1000 символов длиннее, чем на 1 символ слишком коротким.)

Затем проверьтекаждый вызов fgets проверяется по длине и что последний символ в buff является символом '\n', например,

    while(fgets(buff, MAXC, file) != NULL) {
        size_t len = strlen (buff);
        if (len == MAXC - 1 && buff[len - 1] != '\n') {
            fputs ("error: line too long.\n", stderr);
            /* handle error - generally by reading and dicarding
             * characters until '\n' or EOF encounterd and 
             * then either calling continue or break
             */
        }

. Это обеспечит наличие правильной строки перед вызовом strtok.

Вам не нужны множественные разделители

Затем, как уже упоминалось в комментариях, нет необходимости в разделителях.Достаточно одного delim, определенного с #define DELIM ":(,)\n" или объявленного с const char *delim = ":(,)\n".Затем вы можете просто зациклить все токены с помощью:

    for (token = strtok(buff, delim); token; token = strtok(NULL, delim))
        printf ("%s\n", token);

Краткий пример

#include <stdio.h>
#include <string.h>

#define MAXC 1024

int main (int argc, char **argv) {

    char buff[MAXC] = "";
    char *token = NULL;
    const char *delim = ":(,)\n";
    FILE *file = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!file) {    /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while(fgets(buff, MAXC, file) != NULL) {
        size_t len = strlen (buff);
        if (len == MAXC - 1 && buff[len - 1] != '\n') {
            fputs ("error: line too long.\n", stderr);
            /* handle error - generally by reading and dicarding
             * characters until '\n' or EOF encounterd and 
             * then either calling continue or break
             */
        }

        for (token = strtok(buff, delim); token; token = strtok(NULL, delim))
            printf ("%s\n", token);
    }
    if (file != stdin) fclose (file);   /* close file if not stdin */

    return 0;
}

(вы можете настроить delim, если вам нужен другой результат)

Пример использования / Вывод

$ echo "InputVector:0(1,3,4,2,40)" | ./bin/strtok_delims
InputVector
0
1
3
4
2
40

Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 12 сентября 2018

У вас постоянно есть код, подобный следующему:

token = strtok(NULL, INV_DELIM2);
printf("%s\n", token);

Если strtok() возвращает NULL, то он передается в printf(), который ожидает получить указатель на действительную строку с нулем в конце из-за%s в аргументе формата.NULL не является указателем на допустимую строку с нулем в конце, и поэтому случаются плохие вещи, что проявляется как сбой в вашем случае.

Решение: убедитесь, что указатель, возвращаемый strtok(), не равен NULL, прежде чем пытаться

Совет на будущее: узнайте, как использовать отладчик для пошагового выполнения кода, и привыкните к использованию valgrind , чтобы помочь отследить проблемы с памятью.,Вам не нужно делать неправильные предположения о том, что происходит, когда вы можете использовать инструмент, чтобы выяснить, в чем проблема, и точно понять, в чем дело.

...