Reputation: 716
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
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
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
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