lhay86
lhay86

Reputation: 716

fscanf in C with a text file with no spaces

I have a text file with names that looks as follows:

"MARY","PATRICIA","LINDA","BARBARA","ELIZABETH","JENNIFER","MARIA","SUSAN","MARGARET",

I have used the following code to attempt to put the names into an array:

char * names[9];
int i = 0;
FILE * fp = fopen("names.txt", "r");

for (i=0; i < 9; i++) {
  fscanf(fp, "\"%s\",", names[i]);
}

The program comes up with a segmentation fault when I try to run it. I have debugged carefully, and I notice that the fault comes when I try and read in the second name.

Does anybody know why my code isn't working, and also why the segmentation fault is happening?

Upvotes: 0

Views: 1232

Answers (3)

Some programmer dude
Some programmer dude

Reputation: 409136

You have undefined behavior in your code, because you don't allocate memory for the pointers you write to in the fscanf call.

You have an array of nine uninitialized pointers, and as they are part of a local variable they have an indeterminate value, i.e. they will point to seemingly random locations. Writing to random locations in memory (which is what will happen when you call fscanf) will do bad things.

The simplest way to solve the problem is to use an array of arrays, like e.g.

char names[9][20];

This will gives you an array of nine arrays, each sub-array being 20 characters (which allows you to have names up to 19 characters long).

To not write out of bounds, you should also modify your call so that you don't read to many characters:

fscanf(fp, "\"%19s\",", names[i]);

There is however another problem with your use of the fscanf function, and that is that the format to read a string, "%s", reads until it finds a whitespace in the input (or until the limit is reached, if a field width is provided).

In short: You can't use fscanf to read your input.

Instead I suggest you read the whole line into memory at once, using fgets, and then split the string on the comma using e.g. strtok.


One way of handling arbitrarily long lines as input from a file (pseudoish-code):

#define SIZE 256

size_t current_size = SIZE;
char *buffer = malloc(current_size);
buffer[0] = '\0';  // Terminator at first character, makes the string empty

for (;;)
{
    // Read into temporary buffer
    char temp[SIZE];
    fgets(temp, sizeof(temp), file_pointer);

    // Append to actual buffer
    strcat(buffer, temp);

    // If last character is a newline (which `fgets` always append
    // if it reaches the end of the line) then the whole line have
    // been read and we are done
    if (last_character_is_newline(buffer))
        break;

    // Still more data to read from the line
    // Allocate a larger buffer
    current_size += SIZE;
    buffer = realloc(buffer, current_size);

    // Continues the loop to try and read the next part of the line
}

// After the loop the pointer `buffer` points to memory containing the whole line

[Note: The above code snippet doesn't contain any error handling.]

Upvotes: 2

BLUEPIXY
BLUEPIXY

Reputation: 40145

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

int main(void) {
    char *names[9], buff[32];
    int i = 0;
    FILE *fp = fopen("names.txt", "r");

    for(i = 0; i < 9; i++) {
        if(1==fscanf(fp, "\"%31[^\"]\",", buff)){//"\"%s\"," does not work like that what you want
            size_t len = strlen(buff) + 1;
            names[i] = malloc(len);//Space is required to load the strings of each
            memcpy(names[i], buff, len);
        }
    }
    fclose(fp);
    //check print & deallocate
    for(i = 0; i< 9; ++i){
        puts(names[i]);
        free(names[i]);
    }
    return 0;
}

Upvotes: 1

Anbu.Sankar
Anbu.Sankar

Reputation: 1346

try this...

for (i=0; i < 9; i++) 
{
   names[i]=malloc(15);// you should take care about size
   fscanf(fp, "\"%s\",", names[i]);
}

Upvotes: 0

Related Questions