简体   繁体   中英

Cause of seg fault in C

In my program I am getting a seg fault and I'm not sure the cause or how to find out the cause. Any help would be greatly appreciated!

In the code I am trying to read word by word, but I need to keep track of the line numbers. Then I am trying to create a linked list where the data is the word and line number.

(there are two files compiled together)

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

This code has a fairly high rate of problems. I'll dissect just the first few lines to give an idea:

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

main should return int , not void . Probably not causing your problem, but not right either.

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

You really need to check the value of argc before trying to use argv[1] . Invoking the program without an argument may well lead to a problem. Depending on how you've invoked it, this could be the cause of your problem.

struct fileIndex *fIndex = NULL;

Unless you've included some headers you haven't shown, this shouldn't compile -- struct fileIndex doesn't seem to have been defined (nor does it seem to be defined anywhere I can see in the code you'e posted).

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

This ( wordcount ) reads to the end of the file, but does not rewind the file afterward.

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

From your description, you don't really have any need to store lines (plural) at all. What you probably want is to read one line, then tokenize it and insert the individual tokens (along with the line number) into your index, then read the next line. From what you've said, however, there's no real reason to store more than one raw line at a time though.

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

As noted above, you've previously read to the end of the file, and never rewound the file. Therefore, nothing inside this loop should ever execute, because as soon as you get here, feof(file) should return true . When/if you take care of that, this loop won't work correctly -- in fact, a loop of the form while (!feof(file)) is essentially always wrong. Under the circumstances, you want to check the result of your fscanf , with something like:

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

...so you exit the loop when attempting to read fails.

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

What you have here is basically equivalent to the notorious gets -- you've done nothing to limit the input to the size of the buffer. As shown above, you normally want to use %[some_number]s , where some_number is one smaller than the size of the buffer you're using (though, of course, to do that you do need a buffer, which you don't have either).

You've also done nothing to limit the number of lines to the amount of space you've allocated (but, as with the individual lines, you haven't allocated any). I almost hesitate to mention this, however, because (as mentioned above) from your description you don't seem to have any reason to store more than one line anyway.

Your code also leaks all the memory it allocates -- you have calls to malloc , but not a single call to free anywhere.

Actually, some of the advice above is (at last more or less) wrong. It's looking at how to fix an individual line of code, but in reality you probably want to structure the code a bit differently in general. Rather than read the file twice, once to count the words, then read it again to index the words, you probably want to read a line at a time (probably with fgets , then break the line into words, and count each word as you insert it into your index. Oh, and you almost certainly do not want to use a linked-list for your index either. A tree or a hash-table would make a great deal more sense for the job.

I also disagree with the suggestion(s) in the direction of using a debugger on this code. A debugger is not likely to lead toward significantly better code -- it may help you find a few of the localized problems, but is unlikely to lead toward a significantly better program. Instead, I'd suggest a pencil and a piece of paper as the tools you really need to use. I believe your current problems stem primarily for not having thought about the problem enough to really understand what steps are needed to accomplish the goal, and a debugger isn't likely to help much in finding an answer to that question.

If you don't have a good debugger handy, a good fallback is to simply add a few printf statements at steps through the code, so you can see how far it gets before crashing.

In this code:

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 is an array of pointers to char * s. In your loop you are reading each piece of input into a slot in it. There are a couple of problems.

  1. I think there's a miscount in the number of * s vs. & s (I don't usually program with that many levels of pointer indirection to avoid having to think so hard about them;-). &str[j] is the address of that array element, but that array element is a pointer to a pointer; now you have a pointer to a pointer to a pointer. If you had instead char *str[wCount+1] , and read into str[j] , I think it might match up. (Also I don't use fscanf much, so perhaps someone can confirm how best to use it.)

  2. More obviously, you're not actually allocating any memory for the string data. You're only allocating it for the array itself. You probably want to allocate a fixed amount for each one (you can do that in the loop before each fscanf call). Remember that you're fscanf could in practice read more than that fixed size, resulting in another memory error. Again, working around that requires an expert in fscanf usage.

Hope this helps for a start. If the printf suggestion finds a more specific point in the code where it fails, add that to the question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM