Home > Software design >  Dynamic arrays clarification in C
Dynamic arrays clarification in C

Time:10-08

I create a dynamic int array and I read from a file numbers and passing them in the array using malloc and realloc, when the while in the function is finished the printing is correct but when I go back to the main after the function readNames the printf prints addresses instead of the values.

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

void readNames(FILE *, int *, char **, int *);

void readNames(FILE *fpN, int *numbers, char **names, int *total){
    char sentence[512];

     while (fgets(sentence, sizeof(sentence), fpN)){
    
    char *token = strtok(sentence, " "); //grab the number
    numbers[*total] = atoi(token); //add it to the array
        
    token = strtok(NULL, " \n");
    
    //names[*total] = malloc(strlen(token) 1);
    //strcpy(names[*total], token);
    
    (*total)  ;
    // printf("TOTAL:%d",*total);

    numbers = (int*)realloc(numbers,*(total 1)*sizeof(int)); //allocate more space for the int array
     //names = (char**)(realloc(names, (*total 1)*sizeof(char*)));
     //printf("%d", sizeof(names));
     //allocate more space for the string array
   
 }
 
printf("%d ", (*(numbers 2)));
printf("%d ", (numbers[1]));

printf("%d ", (numbers[2]));

}


int main(int argc, char **argv){
    FILE *fpN = NULL;
    FILE *fpG = NULL;

    if(argc!=3){
        printf("Wrong arguments");
        exit(0);
    }

    if ((fpN = fopen(argv[1], "r")) == NULL)
        { // check if the file exists
            printf("File not found!");
            exit(0);
        }

    if ((fpG = fopen(argv[2], "r")) == NULL)
        { // check if the file exists
            printf("File not found!");
            exit(0);
        }

int total = 0;
int *numbers = (int*)malloc(sizeof(int)); //array will initially have 1 element

char **names = (char**)malloc(sizeof(char*));
readNames(fpN, numbers, names, &total);

printf("%d ", (numbers[0]));
printf("Enter");
printf("%d ", (numbers[1]));

printf("%d ", (numbers[2]));
printf("Enter");

    // char sentence[512];

// int diagram[total][total];
// memset(diagram, 0 , sizeof(diagram));
//  while (fgets(sentence, sizeof(sentence), fpG)){
//     char *token = strtok(sentence, " ->\n:\n");
//         int row = atoi(token);
//             while(token = strtok(NULL, " ->\n:\n")){
//                 int col = atoi(token);
//                  diagram[row][col] = atoi(strtok(NULL, " ->\n:\n"));
                 
//             }
//  }

}

CodePudding user response:

You are passing your pointers "by value", that means a copy of the current value is passed to the function. Whatever you do to that copy inside your function, will be lost once you return from the function.

Furthermore the allocated memory you passed, may be invalid after calling realloc.

Instead of passing your pointers, you must pass the addresses of your pointer variables: (Also note a fixed typo in the size used for realloc).

void readNames(FILE *fpN, int **numbers, char ***names, int *total){
    char *my_numbers = *numbers;
    char **my_names = *names;

    char sentence[512];

    while (fgets(sentence, sizeof(sentence), fpN)) {
    
      char *token = strtok(sentence, " "); //grab the number
      my_numbers[*total] = atoi(token); //add it to the array
        
      token = strtok(NULL, " \n");
    
      //my_names[*total] = malloc(strlen(token) 1);
      //strcpy(my_names[*total], token);
    
      (*total)  ;
      // printf("TOTAL:%d",*total);

      my_numbers = realloc(my_numbers, (*total 1)*sizeof(int)); //allocate more space for the int array
     //my_names = realloc(my_names, (*total 1)*sizeof(char*));
     //printf("%zu", sizeof(my_names));  // << this will only print size of a pointer. 
     //allocate more space for the string array
  }

  // Copy local pointers back to caller's variables
  *numbers = my_numbers;
  *names = my_names;
 
  printf("%d ", (*(numbers 2)));
  printf("%d ", (numbers[1]));
  printf("%d ", (numbers[2]));

}

Then update your caller:

    int total = 0;
    int *numbers = malloc(sizeof(int)); //array will initially have 1 element
    char **names = malloc(sizeof(char*));
    readNames(fpN, &numbers, &names, &total);

You could improve that code a bit more:

  • You allocate memory for next element in advance. That means you have 1 unused element allocated. You could initialize your pointers to NULL and only realloc when you found a new line to parse.
  • Unless you have a specific need to handle the 2 arrays you pass, separately, it would be better to create a struct for both values and pass only one pointer to an array of these structs.

With these 2 changes your code would look like this:


struct element {
    int number;
    char *name;
};

void readNames(FILE *fpN, struct elemen **elements, int *total){
    struct element *my_elements = *elements;

    char sentence[512];

    while (fgets(sentence, sizeof(sentence), fpN)) {
       my_elements= realloc(my_elements, (*total 1)  *sizeof(*my_elements)); //allocate space for the new entry
   
      char *token = strtok(sentence, " "); //grab the number
      my_elements[*total].number = atoi(token); //add it to the array
        
      token = strtok(NULL, " \n");
      //my_elements[*total].name = malloc(strlen(token) 1);
      //strcpy(my_elements[*total].name, token);
    
      (*total)  ;
      // printf("TOTAL:%d",*total);
  }

  // Copy local pointer back to caller's variable
  *elements= my_elements;
 
  printf("%d ", my_elements[1].number);
  printf("%d ", my_elements[2].number);
}

and the caller:

    int total = 0;
    struct element *elements = NULL;  // Allcation will be done later
    readNames(fpN, &elements, &total);
  • Related