В C strtok () работает для "," (запятые), но не для пробелов "". Получение ошибки сегмента при работе с пробелами - PullRequest
1 голос
/ 04 августа 2020

Я здесь новенький. Это мой первый пост! Поэтому я написал код в C, чтобы взять текстовый файл, разделенный запятыми, и прочитать его в 2D-массив. Для этого я использовал strtok (). Это сработало. Ниже приведен код:

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

int main (int argc, char *argv[])
{
    FILE *data = fopen(argv[1], "r");

    if (data == NULL)
    {
        printf("Could not open 11.txt\n");
        return 1;
    }

    char table[20][20][3];
    char buffer[60];

    int i = 0;
    while (fscanf(data, "%s", buffer) != EOF)
    {
        int j = 0;
        for (char *s = strtok(buffer, ","); s != NULL; s = strtok(NULL, ","))
        {
            for (int k = 0; k < strlen(s) + 1; k++)
            {
                table[i][j][k] = s[k];
            }
            j++;
        }
        i++;
    }
    printf("%s\n", table[19][0]);
    return 0;
}

Данные, которые я пытаюсь прочитать в 2D-массив, выглядят так:

08,02,22,97
49,49,99,40
81,49,31,73
52,70,95,23

Это матрица 20x20 с числами, разделенными запятыми. Вышеупомянутая программа работает нормально (я распечатываю элемент этого 2D-массива, чтобы проверить, работает ли программа). Но когда числа разделены пробелами:

08 02 22 97 
49 49 99 40 
81 49 31 73 
52 70 95 23 

и когда я заменяю «,» на «» в функции strtok (), я получаю ошибку seg. Я не понимаю, почему это так. Спасибо за помощь!

РЕДАКТИРОВАТЬ: Ошибка исправлена! @Vlad из Москвы очень правильно указал, что fcanf () не является правильной функцией для используйте для чтения в буфер строки с пробелом. Он предложил вместо этого использовать fgets (), который может читать пробелы. Я все еще сталкивался с ошибкой seg, потому что первый токен, возвращаемый strtok (), был указателем на NULL. Я не уверен, почему он это делает, потому что, когда я подавал strtok () массив с той же строкой без использования fgets () через некоторое время l oop, как показано, проблем не было:

char str[] = "08 02 22 97";

Итак, чтобы исправить это, я поместил условие в for l oop, чтобы перейти к следующей итерации, если strtok () вернула указатель NULL. Вторая проблема заключалась в том, что мой буфер был недостаточно большим (пробелы составляют 4 байта по сравнению с 1 байтом для символа). Исправив эти две проблемы, я заставил код работать!

Ниже приведен исправленный код:

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

int main (int argc, char *argv[])
{
    FILE *data = fopen(argv[1], "r");

    if (data == NULL)
    {
        printf("Could not open 11.txt\n");
        return 1;
    }

    char table[20][20][3];
    char buffer[61];

    int i = 0;
    while (fgets(buffer, sizeof(buffer), data) != NULL)
    {
        int j = 0;
        for (char *s = strtok(buffer, " "); s != NULL; s = strtok(NULL, " "))
        {
            if (s == NULL)
            {
                continue;
            }
            else
            {
                for (int k = 0; k < strlen(s) + 1; k++)
                {
                    table[i][j][k] = s[k];
                }
                j++;
            }
        }
        i++;
    }
    printf("%i\n", atoi(table[19][19]));
    return 0;
}

1 Ответ

4 голосов
/ 04 августа 2020

Функция fscanf со спецификатором формата %s считывает данные, пока не встретится символ пробела. Таким образом, вы не можете использовать функцию fscanf, как вы используете ее в инструкции while

while (fscanf(data, "%s", buffer) != EOF)

, для чтения строк, содержащих встроенные пробелы.

Вместо этого используйте стандартную функцию C fgets.

Обратите внимание, что вместо этого для l oop

for (int k = 0; k < strlen(s) + 1; k++)
{
    table[i][j][k] = s[k];
}

вы можете использовать стандартную строковую функцию strcpy, например,

strcpy( table[i][j], s );

Также этот вызов

printf("%s\n", table[20][0]);

вызывает неопределенное поведение, потому что для массива, объявленного как

char table[20][20][3];

, допустимый диапазон первого индекса составляет] 0, 20). То есть вы не можете использовать в качестве индекса значение 20.

...