C中seg故障的原因

时间:2012-04-09 04:55:43

标签: c memory

在我的程序中,我遇到了一个段错误,我不确定原因或如何找出原因。任何帮助将不胜感激!

在代码中我试图逐字阅读,但我需要跟踪行号。然后我试图创建一个链表,其中数据是单词和行号。

(有两个文件一起编译)

void main(int argc, char **argv){
    file = fopen(argv[1],"r");
    struct fileIndex *fIndex = NULL;
    delimiters = " .,;:!-";/*strtok chars to seperate*/
    int wCount = wordcount(file);/*number of words in file*/
    char **str[wCount+1];/*where the lines are being stored*/
    int j=0;
    while(!feof(file)){/*inserting lines*/
        fscanf(file, "%s", &str[j]);
        j++;
    }

    char *token, *cp;
    int i;
    int len;
    for(i = 0; str[i]; i++){/*checking to insert words*/
        len = strlen(*str[i]);
        cp = xerox(*str[i]);
        token = strtok(cp, delimiters);
        if(!present(fIndex, token)){
            insert(fIndex, i+1,token);
        }

        while(token!=NULL){
            token = strtok(NULL, delimiters);
            if(!present(fIndex, token)){
                insert(fIndex, i+1,token);
            }
        }
        i++;
    }
    fclose(file);
}

int strcmpigncase(char *s1, char *s2){/*checks words*/
    for(;*s1==*s2;s1++,s2++){
        if(*s1=='\0')
            return 0;
    }
    return tolower(*s2)-tolower(*s2);
}

present(struct fileIndex* fIndex, char *findIt){/*finds if word is in structure*/
    struct fileIndex* current = fIndex;
    while(current!=NULL){
        current = current -> next;
        if(strcmpigncase(current -> str, findIt)==0){
            return current -> lineNum;
        }
    }
    return 0;
}

void insert(struct fileIndex *head, int num, char *insert){/*inserts word into structure*/
    struct fileIndex* node = malloc(sizeof(struct fileIndex));

    node -> str = insert;
    node -> lineNum = num;

    node -> next = head;
    head = node;
}

#define IN_WORD 1
#define OUT_WORD 0

int wordcount(FILE *input)/*number of words in file*/
{
    FILE *open = input;
    int cur;         /* current character */
    int lc=0;      /* line count */
    int state=OUT_WORD;
    while ((cur=fgetc(open))!=EOF) {
        if (cur=='\n')
            lc++;
        if (!isspace(cur) && state == OUT_WORD) {
            state=IN_WORD;
        }
        else if (state==IN_WORD && isspace(cur)) {
            state=OUT_WORD;
        } 
    }
    return lc;
}

char *xerox(char *s){
    int i = strlen(s);
    char *buffer = (char *)(malloc(i+1));
    if(buffer == NULL)
        return NULL;

    char *t = buffer;
    while(*s!='\0'){
        *t=*s;
        s++; t++;
    }
    *t = '\0';
    return buffer;
}

2 个答案:

答案 0 :(得分:3)

此代码的问题率相当高。我将解剖前几行来提出一个想法:

  

void main(int argc,char ** argv){

main应该返回int,而不是void。可能不会导致你的问题,但也不对。

file = fopen(argv[1],"r");

在尝试使用argc之前,您确实需要检查argv[1]的值。在没有参数的情况下调用程序可能会导致问题。根据您调用它的方式,这可能是您遇到问题的原因。

struct fileIndex *fIndex = NULL;

除非你已经包含了一些你没有显示的标题,否则这不应该编译 - struct fileIndex似乎没有被定义(它似乎也没有定义在我能看到的任何地方代码你发布了。)

delimiters = " .,;:!-";/*strtok chars to seperate*/
int wCount = wordcount(file);/*number of words in file*/

此(wordcount)读取到文件的末尾,但之后不会回滚文件。

char **str[wCount+1];/*where the lines are being stored*/

根据您的描述,您根本不需要存储行(复数)。您可能想要的是读取一个行,然后将其标记化并将单个标记(以及行号)插入索引,然后读取下一行。但是,根据你所说的,没有真正的理由一次存储多条原始线。

int j=0;
while(!feof(file)){/*inserting lines*/

如上所述,您之前已阅读过该文件的末尾,并且永远不会倒回该文件。因此,此循环内部不应该执行任何内容,因为只要您到达此处,feof(file)就应该返回true。当/如果你处理它,这个循环将无法正常工作 - 事实上,形式while (!feof(file))的循环基本上总是错误的。在这种情况下,您希望检查fscanf的结果,例如:

while (1 == fscanf(file, "%1023s", line))

...所以你在尝试阅读失败时退出循环。

    fscanf(file, "%s", &str[j]);

你在这里所拥有的基本上等同于臭名昭着的gets - 你没有做任何事情来限制输入到缓冲区的大小。如上所示,您通常希望使用%[some_number]s,其中some_number小于您正在使用的缓冲区的大小(当然,要做到这一点,您需要一个缓冲区,你也没有。)

您也没有做任何事情来将行数限制为您分配的空间量(但是,与单独的行一样,您没有分配任何行)。然而,我几乎毫不犹豫地提到这一点,因为(如上所述)你的描述中似乎没有任何理由存储多条线路。

您的代码也泄露了它分配的所有内存 - 您呼叫malloc,但没有任何地方拨打free

实际上,上面的一些建议(最后或多或少)是错误的。它正在研究如何修复单独的代码行,但实际上,您可能希望在一般情况下对代码的结构有所不同。而不是两次读取文件,一次计算单词,然后再次读取它来索引单词,你可能想要一次读取一行(可能是fgets,然后将行分成单词,并计数将每个单词插入到索引中。哦,你几乎肯定会想要为你的索引使用链表。树或哈希表会做得更多对工作的感觉。

我也不同意在此代码上使用调试器的建议。调试器不太可能导致明显更好的代码 - 它可能会帮助您找到一些本地化问题,但不太可能导致明显更好的程序。相反,我建议用铅笔和一张纸作为你真正需要使用的工具。我相信你当前遇到的问题主要是因为没有充分考虑这个问题才能真正理解实现目标需要哪些步骤,调试器不太可能帮助找到这个问题的答案。

答案 1 :(得分:2)

如果你没有一个好的调试器,一个好的后备是在代码的步骤中简单地添加一些printf语句,这样你就可以看到它在崩溃之前得到了多远。

在此代码中:

char **str[wCount+1];/*where the lines are being stored*/
int j=0;
while(!feof(file)){/*inserting lines*/
   fscanf(file, "%s", &str[j]);
   j++;
}

str是指向char *的指针数组。在循环中,您正在将每条输入读入其中的一个插槽中。有几个问题。

  1. 我认为* s与&的数量存在误差(我通常不会用那么多级别的指针间接编程来避免这么难以思考关于他们 ;-)。 &str[j]是该数组元素的地址,但该数组元素是指向指针的指针;现在你有一个指向指针的指针。如果您改为char *str[wCount+1]并阅读str[j],我认为它可能会匹配。 (我也不会使用fscanf,所以也许有人可以确认如何最好地使用它。)

  2. 更明显的是,您实际上并没有为字符串数据分配任何内存。你只是为数组本身分配它。您可能希望为每个分配固定金额(您可以在每次fscanf调用之前在循环中执行此操作)。请记住,您fscanf实际上可以读取更多而不是固定大小,从而导致另一个内存错误。同样,解决这个问题需要fscanf使用专家。

  3. 希望这有助于一个开始。如果printf建议在代码中找到失败的更具体点,请将其添加到问题中。