Bruce
Bruce

Reputation: 23

How to strcpy strings into a two dimension array

I run the program in unix. It had segmentation faults. I found out it is from the for loop in read_names function. When I disabled the loop and set i = 0, it worked. However, when I set i = 1 or other number, it showed segmentation fault again. I think the way I store string might be wrong. Could anyone help me figure out this problem?

Besides, could I use strtok to save strings into a two dimension array?

Thank you.

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

void alloc(char ***surname, char ***first, char **mid_init, int num);
void read_names(FILE *inp, char ***surname, char ***first, char **mid_init, int num );
void free_memory(char ***surname, char ***first, char **mid_init, int num);

int main(int argc, char *argv[])
{
  int num;
  char **surname, **first, *mid_init;
  FILE *inp = fopen(argv[1], "r");  
  FILE *outp = fopen(argv[2], "w");
  char array[79];

  fgets(array, 79, inp);
  fgets(array, 79, inp);
  fgets(array, 79, inp);
  printf("%s", array);

  fscanf(inp, "%d", &num);
  fprintf(outp, "%d \n\n", num+10);

  alloc(&surname, &first, &mid_init, num);
  read_names(inp, &surname, &first, &mid_init, num);
  free_memory(&surname, &first, &mid_init, num);



  fclose(inp);
  fclose(outp);

  return 0;
}

void alloc(char ***surname, char ***first, char **mid_init, int num)
{
  int i;

  *surname = (char**)malloc(num * sizeof(char*));
  *first = (char**)malloc(num * sizeof(char*));
  *mid_init = (char*)malloc(num * sizeof(char));

  for(i=0; i<num; i++)
  {
    (*surname)[i] = (char*)malloc(15*sizeof(char));
    (*first)[i] = (char*)malloc(10*sizeof(char));
  }
}

void read_names(FILE *inp, char ***surname, char ***first, char **mid_init, int num )
{
  char *token, array[79];
  char delim[6] = ", .\n";
  int i=0/*, k=0*/;

  printf("loop begins\n");

  for(i=0; i<num; i++)
  {
      fgets(array, 79, inp);
      printf("%s\n", array);

      fgets(array, 79, inp);
      printf("%s\n", array);

      token = strtok(array, delim);
      strcpy( *(*(surname+i)+0), token);
      printf("%s   ", *(*(surname+i)+0));

      token = strtok(NULL, delim);  
      strcpy( *(*(first+i)+0), token);
      printf("%s  ", *(*(first+i)+0));

      token = strtok(NULL, delim);
      **mid_init = token[0];
      printf("%s\n", *mid_init);


  }
     printf("\nloop ends\n");
}

void free_memory(char ***surname, char ***first, char **mid_init, int num)
{
  int i;

  free((*mid_init));

  for(i=0;i<num;i++)
  {
    free((*surname)[i]);
    free((*first)[i]);
  }
}

Upvotes: 0

Views: 5025

Answers (2)

alk
alk

Reputation: 70971

First of all, the code misses error checking for all relevant system calls:

  • fopen()
  • fgets()
  • fscanf()
  • malloc()

Also do not cast the result of malloc/calloc/realloc as in C it is not necessary or recommanded.


Now for the major issues:

Change

strcpy( *(*(surname+i)+0), token);

to be

strcpy((*surname)[i]), token);

The same for how first is used.


This line

**mid_init = token[0];

does not make sense as you save a pointer to memory allocared local to the function which is invalid as soon as the function had been left.


In free_memory() add

free(*surname);
free(*first);

after the loop to avoid a memory leak.

Upvotes: 0

dmitri
dmitri

Reputation: 3294

Your read function should be defined as:

void read_names(..., char **surname, char **first, ...)

You pass ***surname pointer to alloc() function because you are changing the outer variable surname. Read function doesn't do that, it accesses memory.

Then replace this scary :) code:

strcpy( *(*(first+i)+0), token);

with

strcpy(*(first+i), token);

more readable (as suggested by alk)

strcpy(first[i], token);

Actually for readability I'd suggest using char *pointer[]; declarations.

You use strtok to separate a string into tokes. Use strcpy with strtok to fill in your 2 dimensional array.

Also, you have a memory leak.

You need to add in free_memory() function

free(*surname);

But it can be simplified by changing free_function definition

void free_memory(char **surname, ..., int num)
{
  ...
  for(i=0;i<num;i++)
  {
    free(surname[i]);
    ...
  }
  free(surname);
}

Upvotes: 2

Related Questions