Sarp Kaya
Sarp Kaya

Reputation: 3794

Using 2D array of char pointer in C

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

Answers (5)

rashok
rashok

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

Afonso Tsukamoto
Afonso Tsukamoto

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

jeffmurphy
jeffmurphy

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

Jonathan Wood
Jonathan Wood

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

Carl Norum
Carl Norum

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

Related Questions