3

像往常一样,我在这里阅读了很多帖子。我发现了一篇关于总线错误的特别有用的帖子,请参见此处。我的问题是我无法理解为什么我的特定代码给了我一个错误。

我的代码是尝试自学 C。它是对我学习 Java 时制作的游戏的修改。我的游戏目标是获取一个 5049 x 1 的巨大文字文件。随机选择一个单词,将其混杂并尝试猜测它。我知道如何做到这一切。所以无论如何,文本文件的每一行都包含一个单词,例如:

   5049
   must
   lean 
   better 
   program 
   now
   ...

所以,我在 C 中创建了一个字符串数组,尝试读取这个字符串数组并将其放入 C 中。我没有做任何其他事情。一旦我将文件放入 C 中,其余的应该很容易。更奇怪的是它符合要求。当我用./blah命令运行它时,我的问题就来了。

我得到的错误很简单。它说:

zsh: bus error ./blah

我的代码如下。我怀疑这可能与内存或缓冲区溢出有关,但这是完全不科学和直觉的。所以我的问题很简单,为什么这个 C 代码会给我这个总线错误消息?

#include<stdio.h>
#include<stdlib.h>

//Preprocessed Functions 
void jumblegame();
void readFile(char* [], int);


int main(int argc, char* argv[])
{
    jumblegame();

}

void jumblegame()
{
    //Load File 
        int x = 5049; //Rows
        int y = 256; //Colums
        char* words[x]; 
        readFile(words,x);

    //Define score variables 
        int totalScore = 0;
        int currentScore = 0; 

   //Repeatedly pick a random work, randomly jumble it, and let the user guess what it is

}

void readFile(char* array[5049], int x) 
{
    char line[256]; //This is to to grab each string in the file and put it in a line. 
    FILE *file;
    file = fopen("words.txt","r");

    //Check to make sure file can open 
    if(file == NULL)
    {
        printf("Error: File does not open.");
        exit(1);
    }
    //Otherwise, read file into array  
    else
    {
        while(!feof(file))//The file will loop until end of file
        {
           if((fgets(line,256,file))!= NULL)//If the line isn't empty
           {
               array[x] = fgets(line,256,file);//store string in line x of array 
               x++; //Increment to the next line 
           }    
        }
    }

}
4

6 回答 6

5

这条线有几个问题:

array[x] = fgets(line,256,file);//store string in line x of array 
  • 您已经在前if一条语句的条件下读取了该行:您要操作的当前行已经在缓冲区中,现在您可以使用它fgets来获取下一行。

  • 您每次都尝试分配给相同的数组槽:相反,您需要为数组索引保留一个单独的变量,该变量每次通过循环递增。

  • 最后,您尝试使用=. 这只会复制引用,不会制作字符串的新副本。所以数组的每个元素都将指向同一个缓冲区:line,当你的函数退出时,它将超出范围并变得无效。要使用字符串填充您array的字符串,您需要为数组制作每个字符串的副本:使用 为每个新字符串分配空间malloc,然后使用strncpy将每个字符串复制line到新字符串中。或者,如果您可以使用strdup,它将负责为您分配空间。

但我怀疑这是您的总线错误的原因:您将数组大小传递为x,并且在您的循环中,您分配给array[x]. 问题在于array[x]它不属于数组,数组只有0to的可用索引(x - 1)

于 2012-07-30T18:35:49.427 回答
2

您正在为 x 传递值 5049。第一次说行

array[x] = ... 

执行时,它正在访问一个不存在的数组位置。

看起来你正在学习 C。太棒了!您需要尽早掌握的一项技能是基本的调试器使用。在这种情况下,如果你编译你的程序

gcc -g myprogram.c -o myprogram

然后运行它

gdb ./myprogram

(我假设是 Linux),您将获得一个堆栈转储,其中显示发生总线错误的行。这应该足以帮助您自己找出错误,从长远来看,这比问别人要好得多。

调试器还有许多其他有用的方法,但这是最重要的。它为您提供了一个了解正在运行的程序的窗口。

于 2012-07-30T18:37:15.400 回答
0

您将行存储在 readFile 函数内部定义的行缓冲区中,并将指向它的指针存储在数组中。这样做有两个问题:每次读取新字符串并且缓冲区在堆栈中时,您都会覆盖该值,并且一旦函数返回就无效。

于 2012-07-30T18:38:31.047 回答
0
char* array[5049], int x
array[x] = fgets(line,256,file)

您分配给array[x],这是一个长度= 1的内存位置,您分配一个指针(4个字节)。

另一方面,您读取了 2 次 256 字节,并且丢失了前 256 个字节。

但是最大的错误是你设置了最终条件!feof(),它检查了字符串数组的限制是否溢出。

于 2012-07-30T18:43:32.197 回答
0

你至少有几个问题:

  • array[x] = fgets(line,256,file)

    这将地址存储line到每个数组元素中。linein 在返回时不再有效readFile(),因此您将拥有一组无用的指针。即使line有更长的生命周期,让所有数组元素都具有相同的指针也没有用(它们每个都指向最后写入缓冲区的任何内容)

  • while(!feof(file))

    这是读取文件的反模式。请参阅http://c-faq.com/stdio/feof.html“错误使用 feof()”。这种反模式可能导致您的程序循环比您在读取文件时预期的要多。

  • 您分配数组来保存 5049 个指针,但您只需读取文件中的任何内容 - 没有检查您是否读取了预期的数字或防止读取太多。您应该考虑在读取文件时动态分配数组,或者有一种机制来确保您读取正确数量的数据(不要太少也不要太多)并在错误时处理错误。

于 2012-07-30T18:48:54.920 回答
-1

我怀疑问题出在(fgets(line,256,file))!=NULL). 读取文件的更好方法是使用fread()(参见http://www.cplusplus.com/reference/clibrary/cstdio/fread/)。指定FILE*(C 中的文件流)、缓冲区的大小和缓冲区。该例程返回读取的字节数。如果返回值为零,则已达到 EOF。

char buff [256]; 
fread (file, sizeof(char), 256, buff); 
于 2012-07-30T18:35:01.460 回答