-1

I'm attempting to make a hangman game in C. I encountered this segmentation fault at the first line of this code block.

while (fgets(buf, LEN, fp)) {
        int i = 0;

        char buf[LEN];
        FILE *fp = fopen("dictionary.txt", "r");
        struct diction_t *dictionary = malloc(sizeof(struct diction_t));
        assert(dictionary);

        dictionary->nval = INIT;
        dictionary->max = INIT;
        dictionary->words = NULL;
        /* uses doubling reallocation system */
        while (fgets(buf, LEN, fp)) {
                if (dictionary->words == NULL) {
                        dictionary->words = malloc(sizeof(char *));
                        assert(dictionary->words);
                } else if (dictionary->nval > dictionary->max) {
                        dictionary->words = realloc(dictionary->words, GROW * dictionary->max *sizeof(char *));
                        assert(dictionary->words);
                        dictionary->max = GROW * dictionary->max;
                }
                dictionary->words[i] = malloc(sizeof(char) * LEN);
                assert(dictionary->words[i]);

                strncpy(dictionary->words[i], strtok(buf, "\n"), LEN);
                i++;
                dictionary->nval++;
        }
        dictionary->nval--;
        fclose(fp);

        return dictionary;
}

Never encountered this before so I honestly do not know where to look. Any help is appreciated!

user16217248
  • 3,119
  • 19
  • 19
  • 37
IV6IX
  • 3
  • 2

1 Answers1

0

The most likely explanation to your problem is that on the line

FILE *fp = fopen("dictionary.txt", "r");

the function call to fopen failed, so that fp gets the value NULL. Therefore, when you attempt to use this invalid value NULL on the line

while (fgets(buf, LEN, fp)) {

you get a segmentation fault.

For this reason, I suggest that you replace the line

FILE *fp = fopen("dictionary.txt", "r");

with the following code:

FILE *fp = fopen("dictionary.txt", "r");
if ( fp == NULL )
{
    fprintf( stderr, "Error: Unable to open file!\n" );
    exit( EXIT_FAILURE );
}

My guess is that after performing that change, instead of getting a segmentation fault, you will now get the error message:

Error: Unable to open file!

The most common reason for this kind of failure is that the file does not exist in the current working directory.

Although the ISO C standard does not require this, on most platforms, fopen sets errno to indicate the reason for the failure. In order to print out this reason if it is provided by the platform, you can add #include <errno.h> to the top of the file and use the following code instead:

errno = 0;
FILE *fp = fopen("dictionary.txt", "r");
if ( fp == NULL )
{
    if ( errno == 0 )
    {
        fprintf( stderr, "Error: Unable to open file!\n" );
    }
    else
    {
        perror( "Error opening file" );
    }
    exit( EXIT_FAILURE );
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • I ended up moving the file into the correct directory, thought it was already in there but guess not. However, now i'm getting another fault at a line further down in the same block. The line that has "strncpy(dictionary->words[i], strtok(buf, "\n"), LEN);" – IV6IX Apr 08 '23 at 21:50
  • @IV6IX: My guess is that `strtok` is returning `NULL`, which you are then passing to `strncpy`, which causes your program to cause a segmentation fault. Therefore, I suggest that you check the return value of `strtok` before passing the returned value to `strncpy`. – Andreas Wenzel Apr 08 '23 at 22:02
  • So, 'strtok' doesn't have a return value. Is that what I need to do then to fix it is give it one? This is the only instance it is used in the code – IV6IX Apr 08 '23 at 22:38
  • @IV6IX: The function `strtok` **does** have a return value. It returns a pointer to the next token, or `NULL` if there is no next token. In this case, you appear to be using `strtok` only to remove the newline character, but if the line is empty, then it will not give you a pointer to an empty string, but will rather simply return `NULL`. Therefore, I do not recommend using `strtok` for this purpose. Instead, I recommend that you simply pass `buf` instead of `strtok(buf, "\n")` to the function `strncpy` and remove the newline character beforehand, using `buf[strcspn[buf,"\n"] = '\0';`. – Andreas Wenzel Apr 08 '23 at 23:17
  • @IV6IX: See the following question for further information on how to remove the newline character from the result of `fgets`: [Removing trailing newline character from fgets() input](https://stackoverflow.com/q/2693776/12149471) Note that you will have to `#include ` to use that function. – Andreas Wenzel Apr 08 '23 at 23:17
  • @IV6IX: Also, beware that using the function `strncpy` can be extremely dangerous, because if there is not enough space to write the entire string, then the written string will not be terminated by a null character. This will likely cause a segmentation fault if you later treat that string as if it were null-terminated. – Andreas Wenzel Apr 08 '23 at 23:23
  • Got it. Thank you for all your help. I also found it weird since my code works on an online c compiler but not in VSC. – IV6IX Apr 09 '23 at 00:59