Search code examples
cdynamic-arrays

C - Why are first few elements distorted when I read a matrix from file?


I am quite new to C programming and I wish to read a matrix from given file, in the file, elements are space separated. I tried with the following code, note that it compiled swiftly, but when I examine the content in my matrix, the first 2 elements in each row is distorted to -2145378576 22099:

typedef struct matrix {
  int nrow;
  int ncol;
  int** data;
} matrix;

matrix* mread(char* filename) {
  FILE* f = fopen(filename, "r");
  char line[256];

  matrix* result = malloc(sizeof(matrix));
  int** data = malloc(0);
  int ncol, nrow = 0;

  while (fgets(line, sizeof(line), f)) {
    char* token = strtok(line, " ");
    int* temp = malloc(sizeof(int));
    ncol = 0;
    while (token != NULL) {
      temp = realloc(temp, ++ncol * sizeof(int));
      temp[ncol - 1] = strtol(token, NULL, 10);
      token = strtok(NULL, " ");
    }

    data = realloc(data, ++nrow * sizeof(temp));
    data[nrow - 1] = temp;
    free(temp);
  }
  result->ncol = ncol;
  result->nrow = nrow;
  result->data = data;
  free(data);
  fclose(f);
  return result;
}

Now that I tried to read the matrix from project Euler #11, I find that the first 2 elements in each row is distorted. However, I cannot figure out where the problem is (I know it is somewhere around the realloc for data...)

Thanks in advance!


Solution

  • Your program is having undefined behavior because you are freeing the pointer after assigning it to the result structure member variable data and later returning result from the function mread() [assuming you must be accessing the result->data returned by mread()] :

        data[nrow - 1] = temp;
        free(temp);
    ....
    ....
    result->data = data;
    free(data);
    

    You should not free the temp and data here. They should be freed when you are done with the result pointer returned by mread(). Make sure to first free all the nrow of data and then free the data.

    Also, you don't need to allocate malloc(0) to data. Instead, assign NULL to data. The realloc behavior is the same as calling malloc(new_size) when the pointer passed to it is NULL.