Set pointers on Dynamic Matrix

I'm trying to make a dynamic size matrix of 1-byte elements. To do so I defined the following function. The problem comes when I try to set the first "nrows" elements of the matrix to point the corresponding row (so I can do matrix[i][j]). It looks like that matrix[i] = matrix[nrows + i * single_row_elements_bytes]; doesn't work well enough (the program compiles but throws an core-segment-violation error). How can I make this work?

uint8_t **NewMatrix(unsigned nrows, unsigned ncols) { uint8_t **matrix; size_t row_pointer_bytes = nrows * sizeof *matrix; size_t single_row_elements_bytes = ncols * sizeof **matrix; matrix = malloc(row_pointer_bytes + nrows * single_row_elements_bytes); unsigned i; for(i = 0; i < nrows; i++) matrix[i] = matrix[nrows + i * single_row_elements_bytes]; return matrix; }

Answer1:

Apart from various bugs mentioned in another answer, you are allocating the 2D array incorrectly. You are actually not allocating a 2D array at all, but instead a slow, fragmented look-up table.

The correct way to allocate a 2D array dynamically is described at How do I correctly set up, access, and free a multidimensional array in C?. Detailed explanation about how this works and how array pointers work is explained at Function to dynamically allocate matrix.

Here is an example using the above described techniques, for your specific case:

#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <inttypes.h> void NewMatrix (size_t nrows, size_t ncols, uint8_t (**matrix)[nrows][ncols]) { *matrix = malloc ( sizeof (uint8_t[nrows][ncols]) ); } int main (void) { size_t r = 3; size_t c = 4; uint8_t (*arr_ptr)[r][c]; NewMatrix(r, c, &arr_ptr); uint8_t (*matrix)[c] = arr_ptr[0]; uint8_t count=0; for(size_t i=0; i<r; i++) { for(size_t j=0; j<c; j++) { matrix[i][j] = count; count++; printf("%2."PRIu8" ", matrix[i][j]); } printf("\n"); } free(arr_ptr); }

Answer2:

I think there are a couple of problems with your code.

    <li>

    You can simplify this line:

    matrix = malloc(row_pointer_bytes + nrows * single_row_elements_bytes);

    to:

    matrix = malloc(row_pointer_bytes);

    Which allocates space for uint8_t* many rows in the matrix.

    The malloc() function only requires size_t amount of bytes needed to allocate requested memory on the heap, and returns a pointer to it.

    and that can simply be allocated by knowing how many rows are needed in the matrix, in this case nrows.

    </li> <li>

    Additionally, your for loop:

    for(i = 0; i < nrows; i++) matrix[i] = matrix[nrows + i * single_row_elements_bytes];

    Doesn't allocate memory for matrix[i], since each row has n columns, and you need to allocate memory for those columns.

    This should instead be:

    for(i = 0; i < nrows; i++) matrix[i] = malloc(single_row_elements_bytes); </li> <li>

    Another issue is how are allocating single_row_elements_bytes. Instead of:

    size_t single_row_elements_bytes = ncols * sizeof **matrix; //**matrix is uint8_t**

    This needs allocate uint8_t bytes for n columns, not uint8_t** bytes. It can be this instead:

    size_t single_row_elements_bytes = ncols * sizeof(uint8_t); </li> </ul>

    Having said this, your code will compile if written like this. This is an example I wrote to test the code.

    #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <inttypes.h> uint8_t **NewMatrix(unsigned nrows, unsigned ncols); int main(int argc, char *argv[]) { uint8_t **returnmatrix; unsigned nrows = 2, ncols = 2; int i, j; returnmatrix = NewMatrix(nrows, ncols); for (i = 0; i < nrows; i++) { for (j = 0; j < ncols; j++) { printf("Enter number for row %d column %d: ", i+1, j+1); /* format speficier for uint8_t, from <inttypes.h> */ if (scanf("%"SCNu8"", &returnmatrix[i][j]) != 1) { printf("Invalid 8 bit number.\n"); exit(EXIT_FAILURE); } } } printf("\nYour matrix:\n"); for (i = 0; i < nrows; i++) { for (j = 0; j < ncols; j++) { printf("%d ", returnmatrix[i][j]); } printf("\n"); } /* Good to free at the end */ free(returnmatrix); return 0; } uint8_t **NewMatrix(unsigned nrows, unsigned ncols) { int i; uint8_t **matrix; size_t row_pointer_bytes = nrows * sizeof * matrix; size_t column_row_elements_bytes = ncols * sizeof(uint8_t); matrix = malloc(row_pointer_bytes); /* Good to check return value */ if (!matrix) { printf("Cannot allocate memory for %d rows.\n", nrows); exit(EXIT_FAILURE); } for(i = 0; i < nrows; i++) { matrix[i] = malloc(column_row_elements_bytes); if (!matrix[i]) { printf("Cannot allocate memory for %d columns.\n", ncols); exit(EXIT_FAILURE); } } return matrix; }

    Input:

    Enter number for row 1 column 1: 1 Enter number for row 1 column 2: 2 Enter number for row 2 column 1: 3 Enter number for row 2 column 2: 4

    Output:

    Your matrix: 1 2 3 4

    Compiled with:

    gcc -Wall -o matrix matrix.c

    Answer3:

    for (i=0;i<nrows;i++) matrix[i] = (uint8_t *)malloc(ncols * sizeof(uint8_t));

    The below 2 lines have to be replaced by the above 2 lines

    for(i = 0; i < nrows; i++) matrix[i] = matrix[nrows + i * single_row_elements_bytes];

    with (nrows + i * single_row_elements_bytes) as the allocation size, and with nrows = 5 and ncols =5, say, a total of 65 bytes are allocated. This include 40 bytes to store row pointers(assuming a 64bit pointer size) and rest 25 bytes to store contents of each r,c element. But the memory for column pointer (pointer to each element in that row) is not allocated.

    So, dereferencing matrix[i][j] will seg fault.

    人吐槽 人点赞

Recommend

Comment

用户名: 密码:
验证码: 匿名发表

你可以使用这些语言

查看评论:Set pointers on Dynamic Matrix