I was doing the assignment to use pointer to transpose matrices. My code can successfully transpose the first row of the matrix but fail to transpose other rows and columns. I suspect there's some problems with for loops but I cannot find where the problem is. The following attached is my code.
void transposeMatrix(int matrix[ROWS][COLS]){
int** transpose=(int **)malloc(ROWS*sizeof(int*));
for(int i=0; i< ROWS; i++)
transpose[i]=(int*)malloc(COLS*sizeof(int));
for(int i=0; i<ROWS;i++){
puts("");
for(int j=0; j<COLS;j++){
*(transpose+i*ROWS+j)= *(matrix+j*COLS+i);
printf("%d ",transpose[j][i]);
}
puts("");
}
}
The matrix generates random numbers and the problems looks like this:
Original Matrix:
10 20 30
40 50 60
70 80 90
Transpose Matrix:
10 0 43009213
20 3401401 910429
30 0 134910124
I cannot attach the image so the above is just an elaboration of the problem I faced, the real situation is not exactly like that but very similar.
Thank you for your help!
*(transpose+i*ROWS+j) is not the correct way to access elements of an array of pointers. That's the way to access a 2-dimensional array that's stored contiguously in row-major order in an int[] array or through an int* pointer.
The way to access an element of a 2-dimensional array that's implemented as an array of pointers is with *(*(transpose + i)+j). *(transpose + i) returns the pointer to row i, adding j to that returns the address of the j'th column in the row, and deferencing that gets or sets the value.
This will also work with an array declared as
int matrix[ROWS][COLS];
because of the way arrays decay to pointers.
So your assignment line should be:
*(*(transpose + i)+j) = *(*(matrix + j)+i);
Then you need to change the printf() line, because it's not printing the same element you just assigned. It should be:
printf("%d ", transpose[i][j]);
The full working function is:
void transposeMatrix(int matrix[ROWS][COLS]){
int** transpose=(int **)malloc(ROWS*sizeof(int*));
for(int i=0; i< ROWS; i++)
transpose[i]=(int*)malloc(COLS*sizeof(int));
for(int i=0; i<ROWS;i++){
puts("");
for(int j=0; j<COLS;j++){
*(*(transpose + i)+j) = *(*(matrix + j)+i);
printf("%d ",transpose[i][j]);
}
puts("");
}
}
You have problem with identifying memory location for row and col of each cells
Here is the way using them:
i-th rows of transpose = *(transpose + i)
j-th col in i-th row of transpose = *(*(transpose+i) + j)
Similar to matrix:
i-th rows of matrix= *(matrix + i)
j-th col in i-th row of matrix = *(*(matrix+i) + j)
So here is my solution:
void transposeMatrix(int matrix[ROWS][COLS]) {
int** transpose = (int **)malloc(ROWS * sizeof(int*));
for (int i = 0; i < ROWS; i++)
transpose[i] = (int*)malloc(COLS * sizeof(int));
for (int i = 0; i < ROWS; i++) {
puts("");
for (int j = 0; j < COLS; j++) {
*(*(transpose + i) + j) = *(*(matrix + j) + i);
printf("%d ", transpose[i][j]);
}
puts("");
}
}
It's not necessary for you to allocate a new matrix row by row. Also, the functions that do the transpose and printing can be passed straight int * rather than preshaped arrays like int [3][2] etc.
It's even possible to reshape the matrix in place (i.e. without allocating new space). If you like I can post example code for that later.
For instance:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int M[2][3] = { {1, 2, 3}, {7, 8, 9} };
int N[3][3] = { {1, 2, 3}, { 4, 5, 6 }, {7, 8, 9} };
int *alloc_transpose(const int *matrix, size_t rows, size_t cols);
void print_matrix(const int *matrix, size_t rows, size_t cols);
int main()
{
int *t_matrix;
print_matrix(&M[0][0], 2, 3);
fprintf(stderr, "----\n");
t_matrix = alloc_transpose(&M[0][0], 2, 3);
if (t_matrix) {
print_matrix(t_matrix, 3, 2);
}
free(t_matrix);
t_matrix = alloc_transpose(&N[0][0], 3, 3);
if (t_matrix) {
fprintf(stderr, "----\n");
print_matrix(t_matrix, 3, 3);
}
free(t_matrix);
return 0;
}
void print_matrix(const int *matrix, size_t rows, size_t cols)
{
size_t r, c;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
printf("%d ", *((matrix + r * cols) + c));
}
putchar('\n');
}
}
int *alloc_transpose(const int *matrix, size_t rows, size_t cols)
{
int *tm;
int r, c; /* relative to transposed matrix */
tm = malloc(sizeof(int) * cols * rows); /* contiguous is okay */
if (!tm)
return NULL;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
*((tm + c * rows) + r) =
*((matrix + r * cols) + c);
}
}
return tm;
}
Related
Let's say my array looks like this. The number of rows will always match the number of columns in this program.
[0] [1] [2]
[3] [4] [5]
[6] [7] [8]
I would need to turn this into the reversed form:
[2] [1] [0]
[5] [4] [3]
[8] [7] [6]
I know that multidimensional arrays are just arrays of arrays, which hopefully shortens the scale of my question to just reversing a 1D array, but I don't know how to apply that same idea to a 2D array. The size will not always be a 3 by 3 array, but again the rows and columns will always be the same number.
Try following code, here n is the number of rows and m is the number of columns. Hopefully this will solve your problem. Happy coding!
for(i = 0; i < n; i++) {
for(j = 0; j < m/2; j++) {
int temp = arr[i][j];
arr[i][j] = arr[i][m-j-1];
arr[i][m-j-1] = temp;
}
}
If you are looking for a function to reverse 2D array, then you can use a function declaration like this: void reverse_2d_arr(int , int (*)[]);
where,
void reverse_2d_arr(int size, int arr[size][size]) {
int i = 0, j, k, temp;
while(i < size) {
j = 0;
k = size - 1;
while(j < k) {
temp = arr[i][j];
arr[i][j] = arr[i][k];
arr[i][k] = temp;
k--;
j++;
}
i++;
}
}
and call it using, reverse_2d_arr(3, arr); where arr is your 2d array and 3 its size.
Using Standard Arrays
From an efficiency standpoint, swap two-elements per-iteration when iterating over the column values. Since your array has a fixed width, start with the beginning and end elements, swap them, and continue working from the end to the middle, e.g.
void rev2d (int (*a)[COLS], int rows, int cols)
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
(above the ..[j] and ..[k] elemnts are each swapped per-iteration of the inner-loop)
Or if you wanted to do the same thing using while loops and pointers to the beginning and end elements in each row (aside from iterating over the rows in reverse), you could do the following:
void rev2dptrs (int (*a)[COLS], int rows, int cols)
{
while (rows--) {
int *beg = *(a + rows), *end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
In each case, for example if you had:
#define ROWS 3
#define COLS ROWS
...
int a[][COLS] = {{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }};
Your function call would be:
rev2d (a, ROWS, COLS);
or in the second case:
rev2dptrs (a, ROWS, COLS);
Just a twist on a normal reversal.
Using Variable Length Arrays
The original intent was to avoid examples with VLA due to C11 Standard - 6.7.6.2 Array declarators(p4) "Variable length arrays are a conditional feature that implementations need not support;" and C11 Standard - 6.10.8.3 Conditional feature macros __STDC_NO_VLA__
However as pointed out in the comments, and with the real-world practicality that virtually all major compilers will continue to provide VLA, you can provide a bit more flexibility by reversing the declarations and specifying the rows and cols sizes fist and then passing the array as a VLA. The benefit is that it frees you from a constant size. For example, but functions can be re-written passing the array as a VLA:
void rev2dvla (int rows, int cols, int a[rows][cols])
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
and with pointers:
void rev2dptrsvla (int rows, int cols, int a[rows][cols])
{
while (rows--) {
int *beg = *(a + rows),
*end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
Here, the benefit is you are freed from the integer constant constraint on the number of elements per-row. By specifying the rows and cols parameters before the array parameter, the rows and cols values are known before the array int a[rows][cols] is specified as a parameter allowing the VLA to be a complete type.
The function calls would then be:
rev2dvla (rows, COLS, a);
and
rev2dptrsvla (rows, COLS, a);
If you understand each of the ways and how they differ from the others -- then you have sorting a 2D array under control. Let me know if you have further questions.
Putting the full example together to exercise each function above at least once and adding a print2D function, you could do something like the following:
#include <stdio.h>
#define COLS 3
void rev2d (int (*a)[COLS], int rows, int cols)
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
void rev2dptrs (int (*a)[COLS], int rows, int cols)
{
while (rows--) {
int *beg = *(a + rows),
*end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
void rev2dvla (int rows, int cols, int a[rows][cols])
{
for (int i = 0; i < rows; i++)
for (int j = 0, k = cols - 1; j < k; j++, k--) {
int tmp = a[i][j];
a[i][j] = a[i][k];
a[i][k] = tmp;
}
}
void rev2dptrsvla (int rows, int cols, int a[rows][cols])
{
while (rows--) {
int *beg = *(a + rows),
*end = *(a + rows) + cols - 1;
while (end > beg) {
int tmp = *beg;
*beg++ = *end;
*end-- = tmp;
}
}
}
void prn2d (int (*a)[COLS], int rows, int cols)
{
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++)
printf (" %2d", a[i][j]);
putchar ('\n');
}
}
int main (void) {
int a[][COLS] = {{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }},
rows = sizeof *a / sizeof **a;
puts ("original:");
prn2d (a, rows, COLS); /* print original */
rev2d (a, rows, COLS); /* reverse col values using indexes */
puts ("\nreversed using indexes:");
prn2d (a, rows, COLS); /* print reversed array */
rev2dptrs (a, rows, COLS); /* reverse reversed array to restore original */
puts ("\nrestore original using pointers:");
prn2d (a, rows, COLS); /* print original */
rev2dptrs (a, rows, COLS); /* reverse col values using pointers */
puts ("\nreverse again using pointers:");
prn2d (a, rows, COLS); /* print reversed array */
rev2dvla (rows, COLS, a); /* reverse col values restoring original */
puts ("\nrestore original using VLA w/indexes:");
prn2d (a, rows, COLS); /* print original */
rev2dvla (rows, COLS, a); /* reverse col values using indexes */
puts ("\nreversed with VLA using indexes:");
prn2d (a, rows, COLS); /* print reversed array */
rev2dptrsvla (rows, COLS, a); /* reverse reversed array to restore original */
puts ("\nrestore original using VLA w/pointers:");
prn2d (a, rows, COLS); /* print original */
rev2dptrsvla (rows, COLS, a); /* reverse col values using pointers */
puts ("\nreverse again using VLA w/pointers:");
prn2d (a, rows, COLS); /* print reversed array */
}
Example Use/Output
$ ./bin/revarr2d
original:
0 1 2
3 4 5
6 7 8
reversed using indexes:
2 1 0
5 4 3
8 7 6
restore original using pointers:
0 1 2
3 4 5
6 7 8
reverse again using pointers:
2 1 0
5 4 3
8 7 6
restore original using VLA w/indexes:
0 1 2
3 4 5
6 7 8
reversed with VLA using indexes:
2 1 0
5 4 3
8 7 6
restore original using VLA w/pointers:
0 1 2
3 4 5
6 7 8
reverse again using VLA w/pointers:
2 1 0
5 4 3
8 7 6
I'm studying the C language and data structures. I wish to get some detailed explanation about why we cannot use dynamic arrays as parameters of functions that use static array parameters.
#include <stdio.h>
int sumAry2D_f1(int ary[][3], int rows, int cols);
void freeAry2D(int **ary, int rows);
int main(void)
{
int ary2D[][3] = { {1, 2, 3}, {4, 5, 6} }; // static array
int r, c;
int **ary = (int**)malloc(sizeof(int*) * 2); // dynamic array
for (r = 0; r < 2; r++)
ary[r] = (int*)malloc(sizeof(int)*3);
for (r = 0; r < 2; r++)
for (c = 0; c < 3; c++)
ary[r][c] = r + c; // 0, 1, 2, 1, 2, 3
printf("sumAry2D_f1() %d\n", sumAry2D_f1(ary2D, 2, 3));
// why we can`t function like this?
// printf("sumAry2D_f1~3() %d\n", sumAry2D_f1(ary, 2, 3));
freeAry2D(ary, 2); // free function of dynamic array
return 0;
}
int sumAry2D_f1(int ary[][3], int rows, int cols)
{
int i, j, sum = 0;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
sum += ary[i][j];
return sum;
}
void freeAry2D(int **ary, int rows)
{
int i;
for (i = 0; i < rows; i++)
free(ary[i]);
free(ary);
}
// why we can`t function like this?
// printf("sumAry2D_f1~3() %d\n", sumAry2D_f1(ary, 2, 3));
Your function specifically expects a pointer to an integer pointer that points to a sequence of 3 integers, or an array of 3-element integer arrays, not just any pointer to integer pointer. ary is just a pointer to integer pointer. Although you made your int ** have the same structure as your int [][3], it could have been different and the compiler can't tell because the memory allocation occurs at run-time, hence if you uncomment the code it probably won't compile, and even if it does the behavior will be undefined.
Unfortunately, you would need 2 functions to do what you want:
int sumAry2D_f1(int ary[][3], int rows, int cols);
and
int sumAry2D_f12(int** ary, int rows, int cols);
The code inside each function would be the same.
I want max to have the content of tmp_max. max is dynamically allocated. tmp_max size is known.
Copying the values is working correctly when I hardcode it but it doesn't work when I create a function to copy the values. Why is that?
//This code works
int** max;
init2D(&max,3,4);
int tmp_max[3][4] = {{3,3,2,2}, {1,2,3,4}, {1,3,5,0}};
for(int i = 0 ; i < 3; i++)
for(int j = 0 ; j < 4; j++)
max[i][j] = tmp_max[i][j];
assert(max[0][1] == 3);
//This one crashes
void copyArray2D(int a, int b, int*** tab,int*** tab2){
for(int i = 0 ; i < a; i++)
for(int j = 0 ; j < b; j++)
tab2[i][j] = tab[i][j];
}
int** max;
init2D(&max,3,4);
int tmp_max[3][4] = {{3,3,2,2}, {1,2,3,4}, {1,3,5,0}};
copyArray2D(3,4,&tmp_max,&max); //crash
assert(max[0][1] == 3);
Note:
Using void copyArray2D(int a, int b, int** tab,int** tab2){and copyArray2D(3,4,max,tmp_max); isn't working either.
Using void copyArray2D(int a, int b, int** tab,int** tab2){and copyArray2D(3,4,&max,&tmp_max); isn't working either.
void init2D(int ***data_ptr, int x, int y) {
int **data = (int **) malloc(sizeof(int *) * x);
for (int k = 0; k < x; k++)
data[k] = (int *) malloc(sizeof(int) * y);
*data_ptr = data;
}
Your compiler should complain about copyArray2D(3,4,&tmp_max,&max).
You must fix any issues identified by your compiler before trying to run your code (running any such executable based on broken code is meaningless).
One problem is that copyArray2D says int*** when it should say int**.
After fixing that, the main issue here is that you have written copyArray2D so that it only works with an array of pointers. (You are simulating a 2-D array by allocating an array of pointers, and then making each pointer point to a separate allocation representing each row).
This works when you use init2D because the init2D function allocates an array of pointers etc.
However int tmp_max[3][4] is a block of 12 contiguous ints. There are no pointers. This is not compatible with copyArray2D.
Your options are:
Use int **tmp_max and use init2D to allocate it, instead of int tmp_max[3][4]
Make another version of copyArray2D which works on a contiguous 2-D array.
Use an ugly macro
Your second function has too many stars. You hadn't shown the init2D function when I first wrote an answer, so I had to guess what you'd done with that (but the code is now in the question and is close enough to what I produced that the difference is immaterial — except I do error check the allocations). Here's a (rewritten) version of the code (the first version hadn't been near a compiler, and I completely missed a crucial detail). Note that int ** is not the same as int arr[N][M] or variations on the theme — even if you use the same notation to access both.
#include <stdio.h>
#include <stdlib.h>
static void copyArray2D(int a, int b, int **dst, int src[a][b])
{
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
dst[i][j] = src[i][j];
}
static void oom(void)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
static void init2D(int ***arr, int a, int b)
{
(*arr) = malloc(a * sizeof((*arr)[0]));
if (*arr == 0)
oom();
for (int i = 0; i < a; i++)
{
(*arr)[i] = malloc(b * sizeof((*arr)[0][0]));
if ((*arr)[i] == 0)
oom();
}
}
static void dump_2d_array(int a, int b, int arr[a][b])
{
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
printf(" %2d", arr[i][j]);
putchar('\n');
}
}
static void dump_2d_pointers(int a, int b, int **arr)
{
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
printf(" %2d", arr[i][j]);
putchar('\n');
}
}
int main(void)
{
int **max;
init2D(&max, 3, 4);
int tmp_max[3][4] = { { 3, 3, 2, 2 }, { 1, 2, 3, 4 }, { 1, 3, 5, 0 } };
copyArray2D(3, 4, max, tmp_max);
printf("2D array:\n");
dump_2d_array(3, 4, tmp_max);
printf("List of pointers:\n");
dump_2d_pointers(3, 4, max);
return 0;
}
Output from running that code:
2D array:
3 3 2 2
1 2 3 4
1 3 5 0
List of pointers:
3 3 2 2
1 2 3 4
1 3 5 0
Note that I've not written a free function, so the memory is leaked.
Be wary of 3-Star Programming.
void copyArray2D(int a, int b, int tab[a][b],int*** tab2){
for(int i = 0 ; i < a; i++)
for(int j = 0 ; j < b; j++)
(*tab2)[i][j] = tab[i][j];
}
copyArray2D(3,4,tmp_max,&max);
I was experimenting some basic C code that defines an int matrix with pointers.
typedef int **Matrix;
Matrix createMatrix(int lines, int columns) {
int i, j;
Matrix m = (Matrix) malloc(sizeof(int) * lines * columns);
for (i = 0; i < lines; ++i) {
for (j = 0; j < columns; ++j) {
m[i][j] = 0;
}
}
return m;
}
int main(int argc, char**argv) {
Matrix m = createMatrix(5, 10);
// ...
if (m[2][3] == 20) {
// ...
}
return 0;
}
However, these m[i][j] accesses are throwing segmentation faults. What's wrong here? Too many asterisks?
I was convinced that a pointer to a pointer to an int was effectively the same as a matrix.
Your allocation of the Matrix data item assumes you're accessing it linearly with a single index. If you want to access it with two indices, e.g., m[1][1] you need to allocate each dimension:
Matrix m = malloc(sizeof(int *) * lines);
for ( int i = 0; i < lines; i++ )
m[i] = malloc(sizeof(int) * columns);
Note also that you should not type cast malloc.
I get a compile error on printf("%d ", arr[rows][cols]); line with compiler error:
//error C2109: subscript requires array or pointer type
I want the convenience of rows by cols. What is the easiest way to access?
#include <stdio.h>
void print_matrix(int* arr, int numrows, int numcolumns) {
for(int rows = 0; rows < numrows; ++rows) {
for(int cols = 0; cols < numcolumns; ++cols)
printf("%d ", arr[rows][cols]); //error C2109: subscript requires array or pointer type
printf("\n");
}
}
int main() {
const int rows = 3;
const int cols = 2;
int arr[rows][cols] = { {1,2}, {3,4}, {5,6} };
int* p = &arr[0][0];
print_matrix(p, rows, cols);
return 0;
}
UPDATE:
For a bit of completeness, I thought about H2C03's comment and I should have thought it through a bit more thoroughly. The following is another way to achieve the same thing and is simpler in that the function takes a simple pointer.
#include <stdio.h>
void print_matrix(int* arr, int rows, int cols) {
int row, col;
for( row = 0; row < rows; ++row) {
for(col = 0; col < cols; ++col)
printf("%d ", *(arr + row * cols + col));
printf("\n");
}
}
void print_transpose(int* arr, int rows, int cols) {
int row, col;
for(row = 0; row < cols; ++row) {
for( col = 0; col < rows; ++col)
printf("%d ", *(arr + col * cols + row));
printf("\n");
}
}
int main() {
const int rows = 3;
const int cols = 2;
int arr[3][2] = { {1,2}, {3,4}, {5,6} };
int* p = arr;
printf("matrix:\n");
print_matrix(p, rows, cols);
printf("transposed:\n");
print_transpose(p, rows, cols);
return 0;
}
You need to pass the pointer as a two-dimensional array pointer:
void print_matrix(size_t numrows, size_t numcolumns, int (* arr)[numcolumns]);
And pass as
print_matrix(rows, cols, arr);
Since p is a pointer to the first element of arr i.e. p = &arr[0][0], if we dereference p we get the value at &arr[0][0]. Now arr is the duplicate of pointer p in function print_matrix and hence if we dereference arr, we get the value at arr[0][0]. i.e. *arr gives arr[0][0] but arr[rows][cols] evaluates to *(*(arr+rows) + cols). This is a problem because *(arr+rows) gives a value which CANNOT be dereferenced again. I suggest a simpler solution:
void print_matrix(int* arr, int numrows, int numcolumns)
{
int totalelements = numrows * numcolumns, i ;
for(i = 0; i < totalelements; ++i)
{
printf("%d\t ", arr[i]);
if((i+1) % numcolumns == 0)
printf("\n");
}
}