Ошибка сегментации при поиске самого длинного слова на входе - PullRequest
0 голосов
/ 13 мая 2019

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

int main(void)
{
char *longest = malloc(1);
size_t size = 1;
do {
    char word[20];
    if (scanf("%s", word) > 0) {
        if (strlen(word) > size) {
        longest = realloc(longest,strlen(word)+1);
        strcpy(longest,word);
        size = strlen(word);
        }
    }
} while (getchar() != EOF);
printf("%zu characters in longest word: %s\n", strlen(longest),longest);
free(longest);
return 0;
}

Ответы [ 2 ]

2 голосов
/ 13 мая 2019

Ваша проблема в строке char word[20]; и способе scanf чтения слов.С точки зрения scanf слово - это любая последовательность непробелов.Например, realloc(longest,strlen(word)+1); обрабатывается как одно слово, и оно само по себе длиннее 20 символов.

Вы должны использовать более надежную функцию для чтения слов и выделения места для них.Наиболее экономичное решение - getline() для чтения строки, за которой следует strsep() для извлечения слов.

0 голосов
/ 13 мая 2019

Не полагаясь на роскошь POSIX-функций, только стандартный C для переменной длины слова:

#include <assert.h>   // assert()
#include <stddef.h>   // size_t
#include <stdbool.h>  // bool, true, false
#include <stdlib.h>   // EXIT_FAILURE, realloc(), free()
#include <stdio.h>    // fscanf(), fgetc(), ungetc(), printf(), fputs()
#include <ctype.h>    // isspace()
#include <string.h>   // strlen(), strcat(), strcpy()

#define WORD_BUFFER_SIZE 20

#define STRING(value) #value
#define STRINGIFY(value) STRING(value)

// reads and discards whitespace, returns false on EOF
bool skip_ws(FILE *stream)
{
    int ch;
    while ((ch = fgetc(stream)) != EOF && isspace(ch));
    if(!isspace(ch) && ch != EOF)  // if it was not whitespace and not EOF
        ungetc(ch, stream);        // pretend we were never here.
    return ch != EOF;
}

bool read_word(char **dst, FILE *stream)
{
    assert(dst);
    char chunk_buffer[WORD_BUFFER_SIZE + 1];

    if (!skip_ws(stream))  // if we encounter EOF before any other non-whitespace
        return false;

    // read chunk by chunk
    for (size_t i = 0; fscanf(stream, "%" STRINGIFY(WORD_BUFFER_SIZE) "s", chunk_buffer) == 1; ++i)
    {
        size_t chunk_length = strlen(chunk_buffer);
        // adjust *dst's size
        char *tmp = realloc(*dst, (i * WORD_BUFFER_SIZE + chunk_length + 1) * sizeof(*tmp));
        if (!tmp) {
            free(*dst);
            *dst = NULL;
            return false;
        }
        *dst = tmp;
        if (i == 0)         // zero terminate it if it is the first junk
            **dst = '\0';  // for strcat() to behave well.
        strcat(*dst, chunk_buffer);  // add the current chunk to *dst.

        int next_char = fgetc(stream);
        ungetc(next_char, stream);

        if (chunk_length < WORD_BUFFER_SIZE || isspace(next_char) || next_char == EOF)
            return true;
    }

    return true;
}

int main(void)
{
    char *word = NULL;
    char *longest_word = NULL;
    size_t longest_length = 0;

    while (read_word(&word, stdin)) {
        size_t length = strlen(word);
        if (length > longest_length) {
            char *tmp = realloc(longest_word, (length + 1) * sizeof *tmp);
            if (!tmp) {
                fputs("Not enough memory. :(\n\n", stderr);
                free(longest_word);
                free(word);
                return EXIT_FAILURE;
            }
            longest_length = length;
            longest_word = tmp;
            strcpy(longest_word, word);
        }       
    }
    free(word);

    printf("%zu characters in the longest word: \"%s\"\n\n", longest_length, longest_word);
    free(longest_word);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...