Хакерранк: C - Запрос документа - PullRequest
0 голосов
/ 21 февраля 2020

Я застрял с неопознанной ошибкой сегментации.

Моя ошибочная функция получает строку text. Он должен преобразовать его в document и вернуть. document изготовлен из paragraphs (разделен '\ n' ), который сделан из sentences (отделен '.' ), который сделан из words (разделяется '' ). Вы можете сослаться на полную формулировку проблемы здесь .

Вот соответствующая часть моего кода:

char**** get_document(char* text) {
    int p = 0, s = 0, w = 0, c = 0;
    char**** document;
    document = malloc(sizeof(char***));
    document[0] = malloc(sizeof(char**));
    document[0][0] = malloc(sizeof(char*));
    document[0][0][0] = malloc(sizeof(char));
    while (*text)
    {
        if (*text == ' ')
        {
            c = 0;
            ++w;
            document[p][s] = realloc(document[p][s], sizeof(char*) * (w + 1));
        }          
        else if (*text == '.')
        {
            c = 0;
            w = 0;
            ++s;
            document[p] = realloc(document[p], sizeof(char**) * (s + 1));
        } 
        else if (*text == '\n')
        {
            c = 0;
            w = 0;
            s = 0;
            ++p;
            document = realloc(document, sizeof(char***) * (p + 1));
        }
        else
        {
            ++c;
            document[p][s][w] = realloc(document[p][s][w], sizeof(char) * (c + 1));
            document[p][s][w][c - 1] = *text;
            document[p][s][w][c] = '\0';
        }
        ++text;
    }
    return document;
}

После отладки я узнал, что программа падает когда

w = 1 в document[p][s][w][c - 1] = *text;

Я понятия не имею, почему это происходит. Я проверил значения p, s, w и c перед выполнением этого оператора и правильно ли выполнялись операторы reallo c.

Но напрасно!

Что может быть не так в моем коде?

1 Ответ

1 голос
/ 21 февраля 2020

Вам нужно выделить память для новых абзацев, предложений и слов. Путем перераспределения вы увеличили фактический размер измерения, но новый элемент был нулевым указателем, который вызвал ошибку segfault.

char**** get_document(char* text) {
    int p = 0, s = 0, w = 0, c = 0;
    char**** document;
    document = malloc(sizeof(char***));
    document[0] = malloc(sizeof(char**));
    document[0][0] = malloc(sizeof(char*));
    document[0][0][0] = malloc(sizeof(char));
    while (*text)
    {
        if (*text == ' ')
        {
            c = 0;
            ++w;
            document[p][s] = realloc(document[p][s], sizeof(char**) * (w + 1));
            document[p][s][w] = malloc(sizeof(char*));
        }          
        else if (*text == '.')
        {
            c = 0;
            w = 0;
            ++s;
            document[p] = realloc(document[p], sizeof(char**) * (s + 1));
            document[p][s] = malloc(sizeof(char**));
            document[p][s][w] = malloc(sizeof(char*));
        } 
        else if (*text == '\n')
        {
            c = 0;
            w = 0;
            s = 0;
            ++p;
            document = realloc(document, sizeof(char****) * (p + 1));
            document[p] = malloc(sizeof(char***));
            document[p][s] = malloc(sizeof(char**));
            document[p][s][w] = malloc(sizeof(char*));
        }
        else
        {
            ++c;
            document[p][s][w] = realloc(document[p][s][w], sizeof(char) * (c + 1));
            document[p][s][w][c - 1] = *text;
            document[p][s][w][c] = '\0';
        }
        ++text;
    }
    return document;
}

Кроме того, ваш метод печати в основном не работает, потому что вы не сохранили пробелы (вам не нужно в любом случае). Итак, я исправил это:

int main()
{
    char* text = "New word.No space before a sentence.\nThis is a new paragraph.";
    char**** doc = get_document(text);
    int p = 0, s = 0, w = 0, c = 0;
    char ch;
    while (ch = *text)
    {
        if (ch == ' ')
        {
            putchar(' ');
            c = 0;
            ++w;
        }
        else if (ch == '.')
        {
            putchar('.');
            c = 0;
            w = 0;
            ++s;
        }
        else if (ch == '\n')
        {
            putchar('\n');
            c = 0;
            w = 0;
            s = 0;
            ++p;
        }
        else putchar(doc[p][s][w][c++]);;
        text++;
    }

    return 0;
}

Вывод кажется правильным:

Новое слово. Пробел перед предложением.
Это новый абзац.

Я думаю, вам не нужно освобождать doc, потому что вы возвращаетесь из основного после него, и Hackerrank справится с этим в случае необходимости. Но только учтите, что вы должны позаботиться об этом иначе.

...