Reputation: 3794
I want to read a file and write each line to array of char. As I don't know the amount of lines, therefore I thought the most efficient way is to use 2D array of char pointer. However I get segmentation fault.
My question might be duplicate of this one : 2D array of char pointers --> Segmentation fault?
But I couldn't figure the correct syntax for C so I couldn't try.
Here's my code:
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
char line [ 128 ]; /* or other suitable maximum line size */
char **new_line;
int i = 0;
while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
{
strcpy(new_line[i], line);
i++;
}
Upvotes: 2
Views: 6061
Reputation: 13464
Memory is not allocated for new_line
which causes the segmentation fault.
If you know the no of lines, then you can declare that as local array itself. In that case your accessing method will works fine.
#define MAX_LINES 20
#define MAX_CHARS 128
...
char new_line[MAX_LINES][MAX_CHARS] = {0};
...
Your problem here is you dont know the maximum number of lines. So you have selected double pointer. In that case you need to first malloc
with some n
number of lines and then you need to keep on using realloc
to increase the buffer size.
#define MAX_CHARS 128
#define N_NO_OF_LINES 10
...
char line[MAX_CHARS] = {0};
char **new_line = NULL;
int noOfLines = 0;
int lineCount = 0;
new_line = malloc(sizeof(char*) * N_NO_OF_LINES);
noOfLines = N_NO_OF_LINES;
while (fgets (line, sizeof line, file) != NULL) /* read a line */
{
if (lineCount >= noOfLines)
{
new_line = realloc(new_line, (sizeof(char*)*(noOfLines+N_NO_OF_LINES)));
noOfLines += N_NO_OF_LINES;
}
new_line[lineCount] = strdup(line);
lineCount++;
}
Note : Take care of null check for malloc
and realloc
Upvotes: 2
Reputation: 1214
You need to alloc space for your strings. Malloc returns a memory slot with the size you want but doesn't allow memory reallocation. For that you have realloc.
With malloc you would end up with a fixed size for your table, just like if you had only declared it has static but with later initialization (Well, I'm a bit agains this sentence because malloc is much more than that, but for this purpose it is safe to say it).
Realloc does that, reallocates memory, but it can be pretty dangerous if you don't use i correctly. And, in my opinion, is not the most correct way to do it.
When you want to save something that you don't know the size, dynamic structures are the way to go. You can use 'linked lists like' data structures so you can have as many words as you want and then convert that list to an array.
I would go with something like this:
typedef struct _words{ //Structure to the dynamic insertion of words
char *word;
struct _words *next;
}words;
words *last; //Easier implementation for this case. Not always the best solution
words *init(){ //Is good practice to start with an empty structure for reference passing
words *new = malloc(sizeof(words));
if(new == NULL) exit(0);
new->next = NULL; //A good end/next reference
return new;
}
void insertWord(char *word){
words *new = malloc (sizeof(words));
if(new == NULL) exit(0);
new->word = malloc(strlen(word)*sizeof(char));
if(new->word == NULL) exit(0);
new->next = NULL; //Or new->next = last->next; wich is also null.
last->next = new;
last = new;
}
int main(){ //Or the name of your function
FILE *file = fopen ( filename, "r" );
words *list = init();
last = list;
if ( file != NULL )
{
char line [ 128 ]; /* or other suitable maximum line size */
int i = 0;
while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
{
insertWord(line);
i++;
}
//Here, you already have all the words in your dynamic structure. You can now save them into an array
char **array = malloc(i*sizeof(char*)); //i is the number of words.
if(array == NULL) exit(0);
word *aux = list->next;
if(aux != NULL){
for(int j=0;j<i && aux != NULL;j++){
array[j] = malloc(strlen(aux->word)*sizeof(char));
if(array[j] == NULL) exit(0);
strcpy(array[j], aux->word);
aux = aux->next; // jump to the next word
}
}
...
}
I think this might work but I didn't try it. Is just to give you an idea on how to implement dynamic structures.
It misses frees and is not an actual stack, even if is close.
Hope this helps.
Upvotes: 0
Reputation: 446
new_line is not initialized to a valid chunk of memory.
Roughly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
FILE *file = fopen ( "test.txt", "r" );
if ( file != NULL )
{
#define MAXLINES 128
#define MAXLINELEN 100
char line [ MAXLINELEN ]; /* or other suitable maximum line size */
char **new_line = (char **)malloc(sizeof(char *) * MAXLINES);
int i = 0;
if (!new_line) exit(-1);
while ( i < MAXLINES && (fgets ( line, sizeof line, file ) != NULL )) /* read a line */
{
new_line[i] = strdup(line);
i++;
}
printf("read %d lines\n", i);
}
exit(0);
}
Upvotes: 1
Reputation: 67273
You declare new_line
as a pointer to char *
, but it is never initialized so it points to some invalid memory address. You get the error when you write to that address.
You will probably want to allocate the memory, assign it to new_line
, and then you can copy strings to it.
Upvotes: 0
Reputation: 225042
You didn't allocate any memory for the new_line
array. You need something like:
char **new_line = malloc(sizeof(char *) * MAX_LINES);
And then for each line, don't use strcpy
, which will copy into a garbage pointer (the uninitialized new_line
array). You probably want strdup(3)
:
new_line[i] = strdup(line);
Upvotes: 0