[英]Segmentation Fault when finding longest word in input
I have written a program to find the longest word in the input. 我编写了一个程序来查找输入中最长的单词。 I get no errors when using valgrind or running tests locally, but the grading program I email the code to reports a segmentation fault.
使用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;
}
Your problem is in the line char word[20];
您的问题出在
char word[20];
行char word[20];
and the way scanf
reads words. 以及
scanf
读取单词的方式。 From scanf
's point of view, a word is any sequence of non-spaces. 从
scanf
的角度来看,单词是任何非空格序列。 For example, realloc(longest,strlen(word)+1);
例如,
realloc(longest,strlen(word)+1);
is treated as one word, and that alone is longer than 20 characters. 被视为一个单词,仅一个单词就超过20个字符。
You should use a more robust function to read words and allocate space for them. 您应该使用更强大的功能来读取单词并为其分配空间。 The most cost-efficient solution is
getline()
for reading the line followed by strsep()
for extracting words. 最具成本效益的解决方案是使用
getline()
读取行,然后使用strsep()
提取单词。
Without relying on the luxurities of POSIX-functions, only standard-C for variable word-length: 在不依赖于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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.