简体   繁体   中英

Linked List C program results in segmentation fault:11

I have a program which I am working on for an assignment. This has to be a linked list which reads character by character from a file and then creates words which then get written to the output file. I am able to compile the code with just warnings and no errors. When I try to run the program with an input.txt and output.txt the program runs and then terminal produces the first line which is file opened followed by segmentation fault:11 I have no idea how to fix this or work around it to get it fixed.

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

typedef struct s_words {
    char *str;
    int count;
    struct s_words* next;  
}
words;

words *create_words(char *word) {
    //allocate space for the structure
    words *newWord = malloc(15);
    if (NULL != newWord) {
        //allocate space for storing the new word in "str"
        //if str was array of fixed size, storage would be wasted
        newWord->str = (char *)malloc(strlen(word));
        strcpy(newWord->str, word); //copy word into newWord->str
        newWord->str[strlen(word)] = '\0';
        newWord->count = 1;   //initialize count to 1;
        newWord->next = NULL; //initialize next;
    }
    return newWord;
}

words *add_word(words *wordList, char *word) {
    int found = 0;
    words *temp = wordList;
    // search if word exists in the list; if so, make found=1
    while (temp != NULL) {
        if (strcmp(temp, word)) {  //use strcmp command
            found = 1;
            wordList->count++; //increment count;
            return wordList;
        } else {
            temp = temp->next;  //update temp
        }
    }
    if (found == 0) {  //new word
        words *newWord = create_words(word); 
        if (NULL != newWord) {
            wordList = newWord;
            newWord->next = temp;
            //??  Insert new word at the head of the list
        }
        return newWord;
    }
}

int main(int argc, char *argv[]) {
    words *mywords;  //head of linked list containing words
    mywords = NULL;

    FILE *myFile;
    myFile = fopen(argv[0], "r");  //first parameter is input file
    if (myFile == 0) {
        printf("file not opened\n");
        return 1;
    } else {
        printf("file opened \n");
    }

    //start reading file character by character;
    //when word has been detected; call the add_word function
    int ch, word = 0, k = 0;
    char thisword[100];
    while ((ch = fgetc(myFile)) != EOF) {
        if (ch == ' ') { //detect new word? Check if ch is a delimiter
            if (word == 1) { //make sure previous character was not delimiter
                printf("hi");
                word = 0;
                thisword[k] = '\0'; //make the kth character of thisword as \0

                add_word(mywords, thisword);   //now call add_word to add thisword into the list
                mywords = NULL;
                k = 0;
            }
        } else {
            word = 1;
            thisword[k] = ch; //make the kth character of thisword equal to ch
            k++;
        }
    }
    fclose(myFile); 

    words *currword;
    printf("printing list\n");

    words *temp;
    //Traverse list and print each word and its count to outputfile
    //output file is second parameter being passed

    FILE *outputFile;
    outputFile = fopen(argv[1], "w");
    if (outputFile == 0) {
        printf("file not opened\n");
        return 1;
    } else {
        printf("file opened \n");
    }

    currword = mywords;

    while (currword != NULL) {
        fprintf(outputFile, "HI");
        fprintf(outputFile, "%s %d" , currword, currword->count);
        temp = currword;
        currword = temp->next;
    }
    return 0;
}

Any help would be greatly appreciated

EDIT Here is the updated code: CODE

The new output is now this: here are the files test.txt results.txt file opened hihihihihihihihihihihihihihihiprinting list file not opened Abort trap: 6

The way you allocate the string in the word structure is incorrect:

        newWord->str = (char *)malloc(strlen(word));
        strcpy(newWord->str, word); //copy word into newWord->str
        newWord->str[strlen(word)]='\0';

You must allocate one more byte for the '\\0' terminator:

        newWord->str = malloc(strlen(word) + 1);
        strcpy(newWord->str, word);

You can simplify this with a single call to strdup() :

        newWord->str = strdup(word);

Furthermore, you call strcmp(temp, word) to compare the word with the string of the current entry, this is incorrect, and the compiler must have issued a warning for this error. You should instead write:

    if (strcmp(temp->str, word)) {

In main() , you call add_word() incorrectly:

    add_word(mywords, thisword);   //now call add_word to add thisword into the list
    mywords = NULL;

You should write:

    mywords = add_word(mywords, thisword);   //now call add_word to add thisword into the list

In the print loop, you pass currword to printf for %s instead of currword->str . You do not need an extra temp variable either:

while (currword != NULL) {
    fprintf(outputFile, "HI");
    fprintf(outputFile, "%s %d" , currword->str, currword->count);
    currword = currword->next;
}

EDIT : your function add_word does not always return a value to the caller, and it does not correctly insert the newWord at the head of the list.

Here is a modified version:

words *add_word(words *wordList, char *word) {
    // search if word exists in the list; if update count and return
    for (words *temp = wordList; temp != NULL; temp = temp->next) {
        if (strcmp(temp, word)) {  //use strcmp command
            wordList->count++; //increment count;
            return wordList;
        }
    }
    words *newWord = create_words(word); 
    if (newWord != NULL) {
        // Insert new word at the head of the list
        newWord->next = wordList;
        wordList = newWord;
    }
    return newWord;
}

Finally, the reason you get a segfault might be that you do not check the array size when adding characters to it as you read from the input file. You may wonder why, since the input file probably has small words in it... but you are not reading the input file passed as the first command line argument, you are reading the executable file itself as you do this:

myFile = fopen(argv[0], "r");  //first parameter is input file

argv[0] is the name of the executing program.

You should also change the other fopen , otherwise you will overwrite your input.txt file:

myFile = fopen(argv[1], "r");  //first parameter is input file
...
outputFile = fopen(argv[2], "w"); // second parameter is output file

Learning to debug yourself is important. There are some debugging tools available that you should take advantage of.

Compile your program with the -g flag, then run it with one of these to explore your problem. Also take your commenter's advice in fixing your warnings.

GDB https://www.gnu.org/software/gdb/

Valgrind http://valgrind.org/

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