Home > OS >  Problem with memory allocation 3d char array C
Problem with memory allocation 3d char array C

Time:10-14

I am trying to read a 2d array of values from a file and then trying to copy that to a 2d array of Strings in C. When I ran my code using gdb I got an error that said "munmap_chunk(): invalid pointer" for the line where I "free( tmval )". Then when I ran the code using valgrind I get several "Invalid write size of 8" that happen whenever I try to read or write a string in the 2d array.

The problem happens during this portion of the code:

  //allocate memory for transition matrix
  tm = (char ***) malloc( numstates*NUM_CLASSES-1*4*sizeof( char ) );

  //initialize variables needed for loop
  int i = 0;
  char *tmval = (char *) calloc( 4, sizeof( char ) );

  // read and process all the remaining lines from the file
  while( fgets(buf, MAXBUF, fp) != NULL ) {
    //add comment detection
    if( buf[0] !='#' ){
      
      //allocate transition states for each row using calloc
      tm[i] = (char **) calloc( NUM_CLASSES-1, (4*sizeof( char )) );
    
      //strok first with space to skip row number
      ptr = strtok( buf, " " );
      
      for( int j = 0;j<NUM_CLASSES-1;j   ){
        //allocate space for string in array
        tm[i][j] = (char *) calloc( 4, sizeof( char ) );
        tm[i][j] = "-1d";
      }

      //loop through line to get class numbers and corresponding states
      ptr = strtok( NULL, " " );
      while( ptr!=NULL ){
        int cls = strtol( ptr, end, 10 );
        tmval = *end 1;
        tm[i][cls] = tmval;
        ptr = strtok( NULL, " " );
      }
      
      //iterate i
      i  ;
    }
  }

  //free up tmval and file
  fclose( fp );
  free( tmval );
  free( end );

I believe this maybe the root of the problem, but I'm not sure how to fix it:

tm[i] = (char **) calloc( NUM_CLASSES-1, (3*sizeof( char )) );

The input file for the program is formatted like this

0  0/0d  1/0d  2/1s  3/3s  4/2s  5/2s  6/5s  7/4s  8/4s  10/9d
1  0/9d  1/9d  2/1s  3/1s  4/1s  5/1s  10/9d

The first number is the row number and the number before the / column number for the value that comes after the /.

I think that many of the Valgrind errors are happening because my memory allocation sizes don't match, but I'm not sure how I can fix that because to me they look ok. Also what is causing the error when I try to free up the space for tmval.

CodePudding user response:

You have the line char *tmval = (char *) calloc( 4, sizeof( char ) ); , which allocates some memory and assigns its address to tmval. You later have the line tmval = *end 1; which reassigns tmval the address of some memory that is in buf. Reassigning the value discards your only copy of the address of the memory that the calloc allocated, and is effectively a memory leak. The subsequent free(tmval) is invalid, because the memory that tmval now addresses was not created by calloc, but is inside buf.

Assigning to a pointer does not copy memory. You need memcpy or strcpy (or something similar) to make a copy of the data.

CodePudding user response:

The allocation size in tm = (char ***)malloc( numstates*NUM_CLASSES-1*4*sizeof(char)) is bogus because

  • NUM_CLASSES-1 must be parenthesized.
  • you compute the size of a 3D packed array but use types that are inconsistent with this: char ***tm has nothing to do with char tm[numstates][NUM_CLASSES-1][4];

Parsing the line of input is incorrect too:

  • tmval = *end 1; makes tmval point inside the array buf, so the next statement tm[i][cls] = tmval; makes the entry in the pseudo-2D array point inside the buf array, which will be overwritten immediately upon reading the next line.

Here is a modified version:

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

#define NUM_CLASSES  20
#define MAXBUF  1024

// load_matrix allocates and returns a 3D matrix loaded with the transition states
char (*load_matrix(FILE *fp, int numstates))[NUM_CLASSES - 1][4] {
    char buf[MAXBUF];
    //allocate memory for transition matrix
    char (*tm)[NUM_CLASSES - 1][4] = calloc(sizeof(*tm), numstates);

    //initialize transition states for all rows
    for (int i = 0; i < numstates; i  ) {
        for (int j = 0; j < NUM_CLASSES - 1; j  )
            strcpy(tm[i][j], "-1d");
    }
    // read and process all the remaining lines from the file
    while (fgets(buf, MAXBUF, fp) != NULL) {
        char *ptr, *end;

        //add comment detection
        if (buf[0] == '#')
            continue;

        //strok first with space to skip row number
        ptr = strtok(buf, " \t\n");
        if (!ptr)
            continue;

        int row = strtol(ptr, &end, 10);
        if (ptr == end || row < 0 || row >= numstates) {
            // invalid row
            continue;
        }

        //loop through line to get class numbers and corresponding states
        while ((ptr = strtok(NULL, " \t\n")) != NULL) {
            int cls = strtol(ptr, &end, 10);
            if (end > ptr && *end   == '/' && strlen(end) < 4 && cls >= 0 && cls < NUM_CLASSES - 1)
                strcpy(tm[row][cls], end);
        }
    }
    return tm;
}

The matrix is allocated in a single call to calloc() and can be freed with free(tm). Here is an example:

int main() {
    char (*tm)[NUM_CLASSES - 1][4] = load_matrix(stdin, 100);
    [...]
    free(tm);
    return 0;
}
  • Related