gpt4 book ai didi

c - 我在 C 中出现段错误的原因是什么?

转载 作者:太空宇宙 更新时间:2023-11-04 06:23:40 25 4
gpt4 key购买 nike

当我编译我的代码时,我没有得到任何错误。但是,当我尝试运行它时,出现段错误(核心已转储)。这是我的主要内容:

原始代码

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]);
}
}

最佳答案

原始代码中的问题

一个可能的问题来源是:

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;
}

您还展示了一些其他不良做法:


修改后的代码中的问题

修改后的代码中有一个重要的问题和几个非常小的问题:

  • 打印停用词的循环取决于一个空指针(奇怪地拼写为 '\0' — 这是一个有效但非常规的空指针拼写),但是初始化代码没有设置空指针。

    (至少)有两个选项可以解决这个问题:

    1. 添加一个空指针:

         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

    2. 或者您可以使用 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
$

关于c - 我在 C 中出现段错误的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29908550/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com