编译代码时,我没有错误。但是,当我尝试运行它时,我遇到了分段错误(核心转储)。这是我的主要内容:
void main(int argc, char *argv[]){
if(argc < 3){
return;
}
char *stop_list_name = argv[1];
char *doc_names[argc - 2];
int i;
for(i = 0; i < argc; i++){
doc_names[i] = argv[i];
}
//create the array of stop words
char *stopWords[50];
char *word;
int word_counter = 0;
FILE *fp;
fp = fopen(stop_list_name, "r");
if(fp != NULL){
while(!feof(fp)){
fscanf(fp, "%s", word);
stopWords[word_counter] = word;
word_counter++;
}
}
fclose(fp);
for(i = 0; stopWords[i] != '\0'; i++){
printf("%s", stopWords[i]);
}
}
我很确定我的while
循环中有问题,但我不确切知道是什么,或者如何修复它。
看到答案后,我修改了我的代码,看起来像这样,但它仍然崩溃了。现在怎么了?
int main(int argc, char *argv[]){
if(argc < 3){
return;
}
char *stop_list_name = argv[1];
char *doc_names[argc - 2];
int i;
for(i = 2; i < argc; i++){
doc_names[i-2] = argv[i];
}
//create the array of stop words
enum {MAX_STOP_WORDS = 50};
char *stopWords[MAX_STOP_WORDS];
int word_counter = 0;
FILE *fp = fopen(stop_list_name, "r");
if(fp != NULL){
char word[64];
int i;
for(i = 0; i < MAX_STOP_WORDS && fscanf(fp, "%63s", word) == 1; i++){
stopWords[i] = strdup(word);
}
word_counter = i;
fclose(fp);
}
for(i = 0; stopWords[i] != '\0'; i++){
printf("%s", stopWords[i]);
}
}
答案 0 :(得分:3)
问题的一个可能来源是:
char *doc_names[argc - 2];
int i;
for(i = 0; i < argc; i++){
doc_names[i] = argv[i];
}
您为argc-2
指针分配空间,然后继续将argc
指针复制到该空间。这是一个缓冲区溢出(在这种情况下,堆栈溢出)。它很容易造成麻烦。一个看似合理的解决方案是:
for (i = 2; i < argv; i++)
doc_names[i-2] = argv[i];
但是,你真的不需要复制参数列表;你可以只处理从索引2到结尾的参数。我注意到显示的代码实际上并没有使用doc_names
,但是越界分配仍然会造成麻烦。
您没有为每个停用词分配空间来读取单词,也没有为每个停用词分配新空间,也没有确保不会溢出存储单词的数组范围。
考虑使用:
enum { MAX_STOP_WORDS = 50 };
char *stopWords[MAX_STOP_WORDS];
int word_counter = 0;
FILE *fp = fopen(stop_list_name, "r");
if (fp != NULL)
{
char word[64];
for (i = 0; i < MAX_STOP_WORDS && fscanf(fp, "%63s", word) == 1; i++)
stopWords[i] = strdup(word);
word_counter = i;
fclose(fp);
}
这个被诊断出来的问题绝对是导致崩溃的原因。我在循环中使用了i
(在代码中早先声明),因为word_counter
使得循环控制线对于SO来说太长了。
严格来说,strdup()
不是标准C的一部分,但它是POSIX的一部分。如果您没有POSIX,您可以自己编写:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str) + 1;
char *result = malloc(len);
if (result != 0)
memmove(result, str, len);
return result;
}
您还有其他一些不良做法:
while (!feof(file))
is always wrong。main()
return in C and C++? fclose(fp)
有效,您应该致电fopen()
,因此您需要将fclose()
移到if
声明正文中。修正后的代码中有一个重要问题和几个非常小的问题:
打印停用词的循环取决于空指针(奇怪地拼写为'\0'
- 它是一个有效但非常规的空指针拼写),但初始化代码不是设置一个空指针。
有(至少)两种方法可以解决这个问题:
添加空指针:
for (i = 0; i < MAX_STOP_WORDS-1 && fscanf(fp, "%63s", word) == 1; i++)
stopWords[i] = strdup(word);
stopWords[i] = 0;
fclose(fp);
}
for (i = 0; stopWords[i] != '\0'; i++)
printf("%s\n", stopWords[i]);
请注意,上限现在是MAX_STOP_WORDS - 1
。
或者您可以使用wordCount
代替条件:
for (i = 0; i < wordCount; i++)
printf("%s\n", stopWords[i]);
我选择第二个选项。
这样做的一个原因是它避免了关于wordCount
被设置和未被使用的警告 - 这是一个小问题。
doc_names
也已设置但未使用。
我担心这些因为我的默认编译器选项会为未使用的变量生成错误 - 因此代码在我修复之前不会编译。这导致:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc < 3)
{
fprintf(stderr, "Usage: %s stop-words docfile ...\n", argv[0]);
return 1;
}
char *stop_list_name = argv[1];
char *doc_names[argc - 2];
int i;
for (i = 2; i < argc; i++)
{
doc_names[i - 2] = argv[i];
}
int doc_count = argc - 2;
// create the array of stop words
enum { MAX_STOP_WORDS = 50 };
char *stopWords[MAX_STOP_WORDS];
int word_counter = 0;
FILE *fp = fopen(stop_list_name, "r");
if (fp != NULL)
{
char word[64];
int i;
for (i = 0; i < MAX_STOP_WORDS && fscanf(fp, "%63s", word) == 1; i++)
stopWords[i] = strdup(word);
word_counter = i;
fclose(fp);
}
for (i = 0; i < word_counter; i++)
printf("stop word %d: %s\n", i, stopWords[i]);
for (i = 0; i < doc_count; i++)
printf("document %d: %s\n", i, doc_names[i]);
return 0;
}
并且,给出一个包含以下内容的停用词文件
help
able
may
can
it
should
do
antonym
prozac
并使用:
编译它(源文件sw19.c
,程序sw19
)
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror sw19.c -o sw19
并将其作为:
运行$ ./sw19 stopwords /dev/null
stop word 0: help
stop word 1: able
stop word 2: may
stop word 3: can
stop word 4: it
stop word 5: should
stop word 6: do
stop word 7: antonym
stop word 8: prozac
document 0: /dev/null
$
答案 1 :(得分:1)
您正尝试将扫描的字符串存储到未初始化的指针
fscanf(fp, "%s", word);
和word
甚至没有初始化。
您可以使用静态缓冲区,就像这样
char word[100];
if (fscanf(fp, "%99s", word) != 1)
word[0] = '\0'; /* ensure that `word' is nul terminated on input error */
此外,while (!feof(fp))
是错误的,因为EOF
标记在fscanf()
尝试读取超过文件末尾之前不会被设置,因此代码将迭代一次额外的时间。在这种情况下,您将存储两次相同的word
。
请注意,您还需要为指针数组分配空间,也许您可以使用malloc()
。