0

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

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

(有两个文件一起编译)

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

2 回答 2

3

这段代码有相当高的问题率。我将只剖析前几行以给出一个想法:

无效的主要(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)应该 return 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,然后将行分成单词,并在插入时计算每个单词将它添加到您的索引中。哦,您几乎肯定也不想使用链表作为索引。树或哈希表对这项工作更有意义。

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

于 2012-04-09T08:41:41.770 回答
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++;
}

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

  1. *我认为s 与s的数量有误&(我通常不会使用那么多级别的指针间接进行编程,以避免不得不如此努力地考虑它们;-)。 &str[j]是该数组元素的地址,但该数组元素是指向指针的指针;现在你有一个指向指针的指针。如果你有char *str[wCount+1],并读到str[j],我认为它可能会匹配。(而且我用fscanf的不多,所以也许有人可以确认如何最好地使用它。)

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

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

于 2012-04-09T05:12:39.460 回答