Thread: dynamic allocation of 2-D array

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    16

    dynamic allocation of 2-D array

    Hello,
    I want to read in integers in txt file into 2-D matrix. I found normal way to do this type of job is to 1) get known dimension of the matrix, or 2) define the row-column dimensions bigger enough to hold the possible size of the matrix ahead of time, but I want dynamic allocation of the matrix on the fly.
    The reason I want to do this is 1) trying to understand pointer and 2-D array, 2) to remove the restriction of "known" row- or column-numbers ahead of time so that any 2-D array can be read in without pre-defined dimension of the array.
    In general my idea is:
    1) read in a line by fgets(); increment the row number; realloc() matrix[i];
    2) parse the line with strtok(); increment the column number and realloc() the matrix[i][j];
    3) read in the individual value to matrix[i][j].
    My code was compiled without warning or error, but did not do the thing I expected.
    Here is my code:
    Code:
    #include <stdio.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <string.h>
    
    //What I am trying to do is scanning from file an integer 2-D array of unknown row/column
    /* 
    matrix_4by3.tab
    11 12 13
    21 22 23
    31 32 33
    41 42 43
    
    matrix_4by5.tab
    11 12 13 14 15
    21 22 23 24 25
    31 32 33 34 35
    41 42 43 44 45
    
    
    http://stackoverflow.com/questions/18943735/read-matrix-in-txt-file-and-store-it-in-array-2d
    matrix_mbyn.tab
    255  50  9  50  1  50  50  1
    50  255  50  50  50  50  50 50
    50  50  255  50  50  50 50  50
    8  50  50  255  50 50  50  50
    50  50  50  50 255 50  50  50
    50  50  50 50  50  255  50  50
    1  50 50  50  50  50  255  50
    2 50  50  50  50  50  50  255 
    
    
    Similarly, I want dynamically allocate memory for rows and columns
    
    char **array = malloc(sizeof(char *) * row)        // **array = mat[row][col] 
    
    And each row like:
    
    array[r] = malloc(sizeof(char) * col)
    
    */
    
    size_t chomp(char *);
    
    int main(int argc, char *argv[])
    {
        int i = 0, j = 0;
        FILE *fptr = fopen(argv[1], "r");
    
        char seps[] = " ,;\t";
        char line_buffer[1024];
        char *token;
        int var;
    
    //    int matrix[1000][100];            // I want this dynamically allocated as below
    
    /**************************************************************/
        int **matrix = malloc(2 * sizeof(int *));    // the matrix is at least two rows, otherwise it is not a 2-D array.
    
        if (!fptr) {
        printf("Couldn't open file %p for reading.\n", fptr);
        return 1;
        }
    
        while (fgets(line_buffer, 1024, stdin) != NULL) {
    
        if (line_buffer[0] == '\n')    // skipp blank row
            continue;
    
        chomp(line_buffer);    //chop newline
    
        matrix[i] = realloc(matrix[i], (i+1) * sizeof(int *));    //increment by row number i, but seems wrong with this line
    
        token = strtok(line_buffer, seps);
        while (token != NULL) {
            sscanf(token, "%d", &var);
            j++;
            matrix[i] = realloc(matrix[i], j * sizeof(int *));    //increment by column number j; not sure with this line either.
            matrix[i][j] = var;
            printf("%d\t", matrix[i][j]);
            token = strtok(NULL, seps);
        }
        printf("\n");
        i++;
        }
    /***************************************************************/
    // free(matrix);    //but I am not sure this is correct for 2-D array
    
    int count;
    
    for ( count = 0; count < i; count++)
    free (matrix[count]);
    
    free (matrix);
    
        return 0;
    }
    
    size_t chomp(char *str)
    {
        size_t len = strlen(str);
    
        while ((len > 0) && isspace(str[len - 1]))
        str[--len] = '\0';
    
        return (len);
    }
    Code:
    $ ./a.out < matrix_4by3.tab
    And I am expecting:
    Code:
    11 12 13
    21 22 23
    31 32 33
    41 42 43
    Nothing showed up but segmentation fault!
    Thanks for any help!
    Last edited by Yifangt; 03-16-2016 at 11:31 AM. Reason: more info for the code

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    This is correct:
    Code:
    int **matrix = malloc(2 * sizeof(int *));
    However, this is better style:
    Code:
    int **matrix = malloc(2 * sizeof(matrix[0]));
    This is wrong because sizeof(int*) should have been sizeof(int):
    Code:
    matrix[i] = realloc(matrix[i], (i+1) * sizeof(int *));
    It would have been avoided if you had used the better style:
    Code:
    matrix[i] = realloc(matrix[i], (i+1) * sizeof(matrix[i][0]));
    Are you guaranteed that the input will form a matrix, i.e., a 2D array where each inner array has the same number of elements? If not, then you are not really dealing with a matrix, but rather with a "jagged" 2D array. Assuming that you have such a guarantee, you do not need to resize the inner dynamic array after reading the first row (you only need to resize for that very first read). You just need to resize the number of outer dynamic arrays. Hence, you could declare:
    Code:
    struct Matrix
    {
        int **data;
        size_t rows;
        size_t cols;
        size_t row_capacity;
    };
    The row_capacity member keeps track of the number of outer dynamic arrays that have been allocated, whether or not they are in use, allowing you to increase the allocation by a factor rather than very inefficiently one by one. The rows member of course is the number of rows that have been read.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Dec 2015
    Posts
    16

    Read only the first line, then aborted

    Thanks laserlight!
    Are you guaranteed that the input will form a matrix, i.e., a 2D array where each inner array has the same number of elements?
    Yes!
    I am aware of the jagged the 2-D array you mentioned (and I had gone thru your old post in this forum), but this exercise is to get more catch of the relationship of pointer for 2-D array that I usually get confused. Dynamic allocation is purposely used to help my understanding. Your correction helped me lots. Thank you!
    After your correction, the program seems only succeeded reading the first line, and aborted. See my attachment for the corrected version. 1) Could you please have a look at it with one of the sample files I provided?
    BTW, do you have 2) an implementation example with your struct Matrix ?
    Thanks again!
    Last edited by Yifangt; 03-16-2016 at 01:50 PM. Reason: Duplicate attachments

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,662
    Perhaps if you renamed i and j to be row and col, you would be able to see more clearly what is going on.

    Some issues to think about.
    1. j (or more accurately col) is never reset to 0 at the start of each row
    2. malloc does NOT clear the memory. So realloc(matrix[row] is going to crash if it contains uninitialised data.

    Your free code is right, if everything else is fixed.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Dec 2015
    Posts
    16

    Corrected version with segmentation fault

    Thanks Salem!
    Corrected version according to your suggestion is attached. After reading 3 rows, the program crashed with "Segmentation fault!"
    Can you have a look at it for me?
    Thanks again!
    Attached Files Attached Files
    • File Type: c .c (2.4 KB, 153 views)

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,662
    Roughly
    Code:
    matrix = realloc( matrix, (row+1) * sizeof(*matrix) );
    matrix[row] = NULL; // so bootstrap realloc works
    col = 0;
    while ( strtok.... ) {
      matrix[row] = realloc( matrix[row], (col+1) * sizeof(*matrix[row]) );
      matrix[row][col] = val;
    }
    row++;
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Dec 2015
    Posts
    16
    Two questions after change:
    1) col was initialized 0, and increment was done at the inner loop at parsing each line;
    2) Compiled well but run into infinite loop after the 2nd number.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamic array allocation
    By abhishekd18 in forum C Programming
    Replies: 7
    Last Post: 10-22-2012, 08:01 PM
  2. Dynamic array allocation
    By Maulrus in forum C++ Programming
    Replies: 7
    Last Post: 03-09-2010, 06:08 PM
  3. dynamic 2D array allocation
    By deprekate in forum C Programming
    Replies: 5
    Last Post: 03-03-2009, 04:25 AM
  4. dynamic allocation of 2d array
    By owi_just in forum C Programming
    Replies: 4
    Last Post: 05-09-2005, 12:50 AM
  5. Dynamic 3D array allocation
    By Vulcan in forum C++ Programming
    Replies: 4
    Last Post: 11-21-2001, 02:51 AM

Tags for this Thread