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
Related
I have been working on this problem for a while now: basically I need to put the for loop in a function so I can call for it, but I don't how to to make a function return a 2D array, I want to solve this by creating a 1D array, but the problem is that my task is to compute the sum of numbers under the diagonal of a matrix, so I need it to be 2D first, then it can only become 1D. Does anyone have a solution?
Maybe my thought process is just wrong and somebody could just recommend how to put the for loops in functions? If it was without the if clause inside then I might have an idea, but now I really don't.
#include <math.h>
#include <stdio.h>
#include <stdlib.h> // libraries added from example
#include <time.h>
//(*) For a square matrix calculate the sum of elements under the main diagonal excluding it.
#define A -10
#define B 10
int main() {
void enter(int *x, int *y);
int get_random(int lbound, int ubound); // telling the programs that functions are declared
int r;
int c;
int row, col, sum = 0;
enter(&r, &c); // calling the function
srand48(time(NULL)); //Call srand48 with current time reported by `time` casted to a long integer.
// srand48 is used to reinitialize the most recent 48-bit value in this storage
int array[r][c]; // we decided its gonna be r rows and c columns
int line[r * c]; // turning 2d into 1d array
for (row = 0; row < r; ++row) // we cycle numeration of rows of matrix
{
for (col = 0; col < c; col++) // we cycle numeration of columns of matrix
{
array[row][col] = get_random(B, A);// filling array with random numbers, taken from example
printf("%d ", array[row][col]);
if (row > col) { //since we want the sum numbers below the diagonal row>col must be true
sum = sum + array[row][col];// if row>col then we add the number to our sum;
};
}
printf("\n"); // this is to break line after row 1,2 col 3, so it looks nicer
}
for (row = 0; row < r; ++row) // we cycle numeration of rows of matrix
{
for (col = 0; col < c; col++) // we cycle numeration of columns of matrix
{
line[row * r + col] = array[row][col];
}
}
printf("the array in 1D: ");
for (row = 0; row < r * c; row++) {
printf("%d ", line[row]);
}
printf("\n");
printf("sum of array below the diagonal: %d\n", sum);
return 0;
}
void enter(int *x, int *y) { // we have to use pointers if we want more then one return from a function
printf("How man rows in array? "); // just like the last lab we decide how big the matrix will be
scanf("%d", x); // we use x instead of &x because we need the address of the number not the value
printf("How man columns in array? ");
scanf("%d", y); // we use y instead of &y because we need the address of the number not the value
}
int get_random(int lbound, int ubound) {
return mrand48() % (ubound - lbound + 1) + lbound; // function for generating random numbers
}
Conditions have to be met:
the user decides size of square matrix
the matrix has to be filled with random numbers
the array is called by the function has to be 1D using i*N+j, 2D array can't be passed
Let's consider your assignment
Conditions have to be met:
the user decides size of square matrix
the matrix has to be filled with random numbers
the array is called by the function has to be 1D using i*N+j, 2D
array can't be passed
Firstly the matrix must be square.
So this your function
void enter(int *x, int *y) { // we have to use pointers if we want more then one return from a function
printf("How man rows in array? "); // just like the last lab we decide how big the matrix will be
scanf("%d", x); // we use x instead of &x because we need the address of the number not the value
printf("How man columns in array? ");
scanf("%d", y); // we use y instead of &y because we need the address of the number not the value
}
does not make sense. The user can enter different values for the numbers of rows and columns of the matrix. You need to enter only one positive value.
Secondly as we are speaking about a matrix then it means that you have to define a two-dimensional array.
Also you need to write a function that will calculate the sum of elements under the main diagonal of a matrix. The function is declared such a way that it can accept only a one-dimensional array. This means that you need to pass your matrix to the function casting it to a pointer of the type int *. There is no need to create an auxiliary one-dimensional array,
Here is a demonstration program that shows how the function can be declared and defined and how the matrix can be passed to the function.
#include <stdio.h>
long long int sum_under_dioganal( const int a[], size_t n )
{
long long int sum = 0;
for (size_t i = 1; i < n; i++)
{
for (size_t j = 0; j < i; j++)
{
sum += a[i * n + j];
}
}
return sum;
}
int main( void )
{
enum { N = 5 };
int a[N][N] =
{
{ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 2, 3, 0, 0, 0 },
{ 4, 5, 6, 0, 0 },
{ 7, 8, 9, 10, 0 }
};
printf( "sum of elements under the main diagonal = %lld\n",
sum_under_dioganal( ( int * )a, N ) );
}
The program output is
sum of elements under the main diagonal = 55
Another approach to define the function and call it is the following
#include <stdio.h>
long long int sum_under_dioganal( const int a[], size_t n )
{
long long int sum = 0;
size_t m = 0;
while (m * m < n) ++m;
if (m * m == n)
{
for (size_t i = 1; i < m; i++)
{
for (size_t j = 0; j < i; j++)
{
sum += a[i * m + j];
}
}
}
return sum;
}
int main( void )
{
enum { N = 5 };
int a[N][N] =
{
{ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 2, 3, 0, 0, 0 },
{ 4, 5, 6, 0, 0 },
{ 7, 8, 9, 10, 0 }
};
printf( "sum of elements under the main diagonal = %lld\n",
sum_under_dioganal( ( int * )a, N * N ) );
}
The program output is the same as shown above.
sum of elements under the main diagonal = 55
2d arrays don't really exist. The compiler just allows you to write a[i][j] so that you can believe in them. Here's some simple code to demonstrate a few methods:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void *
make_array(size_t size)
{
int *a = malloc(sizeof *a * size * size);
int *t = a;
if( a == NULL ){
perror("malloc");
exit(1);
}
for( int row = 0; row < size; row += 1 ){
for( int col = 0; col < size; col += 1 ){
*t++ = rand() % 32 - 16;
}
}
return a;
}
int
trace(void *v, size_t s)
{
int *a = v;
int sum = 0;
for( size_t i = 0; i < s; i += 1 ){
sum += *a;
a += s + 1;
}
return sum;
}
int
main(int argc, char **argv)
{
srand(time(NULL));
size_t s = argc > 1 ? strtol(argv[1], NULL, 0) : 5;
void *v = make_array(s);
/* a, b, c, and d will demonstrate different access techniques */
int *a = v; /* a is the conventional "1-d array" (1)*/
int (*b)[s] = v; /* b is a "two-d" array */
int *c = v; /* c iterates through each element */
int *d = v; /* d treats each row as a 1-d array */
for( int i = 0; i < s; i += 1 ){
for( int j = 0; j < s; j += 1 ){
printf("%3d ", b[i][j]);
assert( a[i * s + j] == b[i][j] );
assert( *c == b[i][j] );
assert( d[j] == b[i][j] );
c += 1;
}
d += s;
putchar('\n');
}
printf("trace: %d\n", trace(v, s));
}
/* (1) These comments are not strictly accurate. `a` is *not* an
* array, and `b` is *not* a 2-d array. `a` is a pointer, and `b` is
* an array of pointers. Arrays are not pointers, and pointers are
* not arrays.
*/
Given array A[3][2] ={(1,2),(3,4),(5,6)}
I want to traverse through the first column elements i.e 1,3,5 and next column elements, 2,4,6. All this must be done using a single pointer. How to do this?
If you have 2 array indices, use two for loops.
uint32_t m, n, sum = 0U;
for(n = 0U; n < 2; ++n){ // For each column [n]
for(m = 0U; m < 3; ++m){ // For each row [m] in column [n]
sum += A[m][n];
}
}
Edit: There's not really a difference when using pointers (especially once passed into a function, when it decays). But you have to deal with dereferencing the pointer. This code is more type obfuscating, and could lead one to improperly type/reference, if you don't compile with sufficient warning flags.
uint32_t A[3][2] = {{1,2},{3,4},{5,6}};
uint32_t m, sum = 0U;
uint32_t (*pa2_n)[2];
uint32_t * p_m;
for(pa2_n = &A[0]; pa2_n < &A[3]; ++pa2_n){ // For each column [n]
for(m = 0U; m < 2U; ++m){ // For each row [m] in column [n]
sum += (*pa2_n)[m];
}
// Or
for(p_m = &(*pa2_n)[0]; p_m < &(*pa2_n)[2]; ++p_m){ // For each row [m] in column [n]
sum += *p_m;
}
}
printf("Hello World %u\n", sum);
//
// a method using only 1 pointer could rely on pointer math
//
#include <stdio.h>
#define ROWS 3
#define COLS 2
int
main(void)
{
int matrix[ROWS][COLS] = {
{ 1, 2 },
{ 3, 4 },
{ 5, 6 },
};
int *ptr = &matrix[0][0];
while (1) {
printf("%d,", *ptr);
// point into the next row, same col
ptr += COLS;
// now pointing at least 1 row too many?
if (ptr >= &matrix[ROWS][0]) {
printf("\n");
// at least 1 row too many, last col?
if (ptr >= &matrix[ROWS][COLS - 1])
break;
// backup by total element count - 1 (first row, next col)
ptr -= (ROWS * COLS) - 1;
}
}
return (0);
}
If you want to traverse in the given array int A[3][2] using single pointer you should look at this code:
#include <stdio.h>
int main(void)
{
int arr[3][2] = { 1, 2, 3, 4, 5, 6 };
int *ptr = arr[0], i, j;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
{
printf("%4d", *(ptr+j*2+i));
}
putchar('\n');
}
return 0;
}
I assume you know about the memory representation of a 2D array. If you don't then I'll tell you in short.
A 2D array is stored in the computer's memory on consecutive locations, i.e. one row after another.
That is elements of arr in the above code, will be stored as first 1, second 2, and so on. Using this *(ptr+j*2+i) statement we are traversing through the array. In 1st iteration we are printing ptr+0 then ptr+2 and so on.
Or you can make it simple by declaring a pointer to an array
int (*ptr)[2]; ptr = arr;
and now you can access elements of arr using ptr just like a 2D array.
printf("%4d", ptr[j][i]); or printf("%4d", *(*(ptr+j)+i));
I hope you'll understand the answer.
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;
}
Part of my assignment is to sort a 2D array into ascending order, and I cannot figure out how to do it for the life of me.
What I have so far:
int Sort2DArray(int A[][COL], unsigned int rowsize, unsigned int colsize)
{
int i, j, k, temp;
for (i=0; i<rowsize-1; i++){
for (k=0; k<colsize; k++){
for (j=0; j<rowsize-1; j++){
do {
temp = A[k][j];
A[k][j] = A[k][j+1];
A[k][j+1] = temp;
} while (A[k][j]>A[k][j+1]);
}
}
}
}
This will take an array this and return:
3 2 1 1 2 3
5 8 7 ---->>> 5 7 8
4 9 3 3 4 9
However, I need it to return:
1 2 3
4 5 6
7 8 9
So, is there any way you guys can help me? Thanks!
EDIT:
#include <stdio.h>
#include <stdlib.h>
#define COL 20
#define ROW 20
void PopulateArray2DUnique (int [][COL], unsigned int, unsigned int, int, int);
void DisplayArray2D(int [][COL], unsigned int, unsigned int);
int FindLargest(int [][COL], unsigned int, unsigned int);
int FindColSum(int [][COL], unsigned int, unsigned int, unsigned int);
int Sort2DArray(int [][COL], unsigned int, unsigned int);
int main()
{
int A[ROW][COL];
int min=1, max=99;
unsigned int rowsize, colsize, col_to_sum;
printf ("Input your desired row and column size: \n");
scanf ("%u%u", &colsize, &rowsize);
PopulateArray2DUnique(A, rowsize, colsize, min, max);
DisplayArray2D(A, rowsize, colsize);
FindLargest(A, rowsize, colsize);
printf ("Which column would you like to find sum of?\n");
scanf ("%d", &col_to_sum);
FindColSum(A, rowsize, colsize, col_to_sum);
Sort2DArray(A, rowsize, colsize);
DisplayArray2D(A, rowsize, colsize);
return 0;
}
Is it possible?
Yes, it's possible. The most important thing to understand is that your sort routine, and all of the basic sort routines you see in examples, generally sort a 1D array.[1] The same routine can be used to sequentially sort a 2D array as you are attempting to do, but you have to recognize you want to pass your 2D array to the sort function as a pointer-to-type (simple 1D array, e.g. 'int *'), rather than as a pointer-to-array of X elements (your 2D array, e.g. 'int (*)[NCOLS]')
The key to passing the array is to simply pass the address to the first element in your array. Regardless of whether you declared it as a 1D or 2D array (1) that is the address where the values begin in memory; and (2) all array values are sequential. Meaning that you can address every value in a 1D or 2D array by start_address + offset.
Take for example your simple bubble-sort routine:
void bubblesort (int *a, size_t n)
{
size_t i, j;
int temp;
for (i = 0; i < n; i++) {
for (j = 0; j < (n-1); j++) {
if (a[j] > a[j + 1]) {
temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
}
}
}
If you had declared a 2D array (e.g. int array[][NCOL];, not pointer-to-pointer-to-type int **array;) that you wished to sequentially sort, you could call your sort routine by simply passing the start address as follows:
bubblesort (*array, nelem);
or
bubblesort (&array[0][0], nelem);
(both are equivalent, with 'nelem' being the total number of elements)
If you attempt to declare your sort function by passing a pointer to array (e.g. bubblesort (int (*array)[NCOL], size_t n); you will run difficulty immediately attempting to loop over the indexes because using the traditional nested loop layout, there is no easy way to compare array[i][j] with array[i+1][0], etc..
The following is a short example putting it all together. Look it over and let me know if you have questions:
#include <stdio.h>
#include <stdlib.h>
#define NCOL 3
void bubblesort (int *a, size_t n);
int main ()
{
int array[][NCOL] = {{3,2,1},
{5,8,7},
{4,9,3}};
int i, j, nrows, nelem;
nrows = sizeof array/sizeof *array;
nelem = sizeof array/sizeof **array;
printf ("\noriginal:\n\n");
for (i = 0; i < nrows; i++) {
for (j = 0; j < NCOL; j++)
printf (" %2d", array[i][j]);
putchar ('\n');
}
bubblesort (*array, nelem);
printf ("\nsorted:\n\n");
for (i = 0; i < nrows; i++) {
for (j = 0; j < NCOL; j++)
printf (" %2d", array[i][j]);
putchar ('\n');
}
return 0;
}
void bubblesort (int *a, size_t n)
{
size_t i, j;
int temp;
for (i = 0; i < n; i++) {
for (j = 0; j < (n-1); j++) {
if (a[j] > a[j + 1]) {
temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
}
}
}
Output
$ ./bin/qsort_2d_linear
original:
3 2 1
5 8 7
4 9 3
sorted:
1 2 3
3 4 5
7 8 9
Note: you can do the same thing with qsort rather easily with the standard integer compare function and calling qsort (array, nelem, sizeof **array, icompare);
footnote[1]: all arrays in C are 1D arrays, the 2D array is simply addressed in a way to allow 2D indexing. It is still a sequential block of 'type' values in memory.)
I'm not sure if I have the best method here, however what I would do, is store each value from the array into one large 1D array, sort that and then assign them to the 2D array.
int Sort2DArray(int A[][COL], unsigned int rowsize, unsigned int colsize)
{
int arraySize = rowsize * colsize;
int sortingArray[arraySize];
int i = 0, row, col, temp, prevPos;
//Fills the sortingArray with all the values in the 2D array
for (col = 0; col < colsize; ++col) {
for (row = 0; row < rowsize; ++row) {
sortingArray[i] = A[row][col];
++i;
}
}
//Sorts the 1D array (Insertion Sort)
for (i = 1; i < arraySize; ++i)
{
temp = sortingArray[i];
prevPos = i - 1;
while (j >= 0 && sortingArray[prevPos] > temp)
{
sortingArray[prevPos+1] = sortingArray[prevPos];
prevPos = prevPos - 1;
}
sortingArray[prevPos + 1] = temp;
}
//Writes data back into 2D array
i = 0;
for (row = 0; row < rowsize; ++row) {
for (col = 0; col < colsize; ++col) {
A[row][col] = sortingArray[i];
++i;
}
}
}
I hope I didn't get too confusing with all those dimensions, but you get the idea. If you spot anything incorrect, let me know.
It smells like homework to me, thus, I will only help you a little, and leave the rest to yourself.
When I was very new to C, and my first programming language, I had solved a lot of problems, and one of them was this.
The code I am pasting here is taken from here, a website, which I used to use a lot.
It is up to you to understand the algorithm, and program, and use it in your program.
#include<stdio.h>
int main( )
{
int a[][6]={
{25,64,96,32,78,27}, //Desired solution : {25,27,32,64,78,96},
{50,12,69,78,32,92} // {50,92,78,12,32,69}
};
int i, j, k, temp, temp1 ;
//Bubble sorting is applieed on one first row while the other row is swapped
for(j=1;j<6;j++)
{
for(i=0; i<5; i++)
{
if(a[0][i]>a[0][i+1])
{
temp=a[0][i];
a[0][i]=a[0][i+1];
a[0][i+1]=temp;
temp1 = a[1][i];
a[1][i] = a[1][i+1];
a[1][i+1]=temp1;
}
}
}
printf ( "\n\nArray after sorting:\n") ;
for ( i = 0 ; i <2; i++ )
{
for(j=0; j<6; j++)
{
printf ( "%d\t", a[i][j] ) ; //printing sorted array
}
printf("\n");
}
}
It is a bit different from the code on the site, as I used to always used to work in Ubuntu, and linux never had conio.h. Also, if you are angry for me only providing the code used everywhere, and not doing all your work, keep in mind that homework assignments are for making the student think, and if I spoon-feed you, the purpose will be lost.
NOTE: Always post your full code which can be compiled successfully, as the code you have posted does not compile, as you have not declared all your functions. Thus, it is very difficult to understand you code.
Also, do not try to fool us, as the input you have mentioned does not have a 6, and you want a 6 also to be returned so actually even you have not compiled your code.
I have been asked in an interview how do i allocate a 2-D array and below was my solution to it.
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
}
I thought I had done a good job but then he asked me to do it using one malloc() statement not two. I don't have any idea how to achieve it.
Can anyone suggest me some idea to do it in single malloc()?
Just compute the total amount of memory needed for both nrows row-pointers, and the actual data, add it all up, and do a single call:
int **array = malloc(nrows * sizeof *array + (nrows * (ncolumns * sizeof **array));
If you think this looks too complex, you can split it up and make it a bit self-documenting by naming the different terms of the size expression:
int **array; /* Declare this first so we can use it with sizeof. */
const size_t row_pointers_bytes = nrows * sizeof *array;
const size_t row_elements_bytes = ncolumns * sizeof **array;
array = malloc(row_pointers_bytes + nrows * row_elements_bytes);
You then need to go through and initialize the row pointers so that each row's pointer points at the first element for that particular row:
size_t i;
int * const data = array + nrows;
for(i = 0; i < nrows; i++)
array[i] = data + i * ncolumns;
Note that the resulting structure is subtly different from what you get if you do e.g. int array[nrows][ncolumns], because we have explicit row pointers, meaning that for an array allocated like this, there's no real requirement that all rows have the same number of columns.
It also means that an access like array[2][3] does something distinct from a similar-looking access into an actual 2d array. In this case, the innermost access happens first, and array[2] reads out a pointer from the 3rd element in array. That pointer is then treatet as the base of a (column) array, into which we index to get the fourth element.
In contrast, for something like
int array2[4][3];
which is a "packed" proper 2d array taking up just 12 integers' worth of space, an access like array[3][2] simply breaks down to adding an offset to the base address to get at the element.
int **array = malloc (nrows * sizeof(int *) + (nrows * (ncolumns * sizeof(int)));
This works because in C, arrays are just all the elements one after another as a bunch of bytes. There is no metadata or anything. malloc() does not know whether it is allocating for use as chars, ints or lines in an array.
Then, you have to initialize:
int *offs = &array[nrows]; /* same as int *offs = array + nrows; */
for (i = 0; i < nrows; i++, offs += ncolumns) {
array[i] = offs;
}
Here's another approach.
If you know the number of columns at compile time, you can do something like this:
#define COLS ... // integer value > 0
...
size_t rows;
int (*arr)[COLS];
... // get number of rows
arr = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < COLS; j++)
arr[i][j] = ...;
}
If you're working in C99, you can use a pointer to a VLA:
size_t rows, cols;
... // get rows and cols
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
arr[i][j] = ...;
}
How do we allocate a 2-D array using One malloc statement (?)
No answers, so far, allocate memory for a true 2D array.
int **array is a pointer to pointer to int. array is not a pointer to a 2D array.
int a[2][3] is an example of a true 2D array or array 2 of array 3 of int
To allocate memory for a true 2D array, with C99, use malloc() and save to a pointer to a variable-length array (VLA)
// Simply allocate and initialize in one line of code
int (*c)[nrows][ncolumns] = malloc(sizeof *c);
if (c == NULL) {
fprintf(stderr, "out of memory\n");
return;
}
// Use c
(*c)[1][2] = rand();
...
free(c);
Without VLA support, if the dimensions are constants, code can use
#define NROW 4
#define NCOL 5
int (*d)[NROW][NCOL] = malloc(sizeof *d);
You should be able to do this with (bit ugly with all the casting though):
int** array;
size_t pitch, ptrs, i;
char* base;
pitch = rows * sizeof(int);
ptrs = sizeof(int*) * rows;
array = (int**)malloc((columns * pitch) + ptrs);
base = (char*)array + ptrs;
for(i = 0; i < rows; i++)
{
array[i] = (int*)(base + (pitch * i));
}
I'm not a fan of this "array of pointers to array" to solve the multi dimension array paradigm. Always favored a single dimension array, at access the element with array[ row * cols + col]? No problems encapsulating everything in a class, and implementing a 'at' method.
If you insist on accessing the members of the array with this notation: Matrix[i][j], you can do a little C++ magic. #John solution tries to do it this way, but he requires the number of column to be known at compile time. With some C++ and overriding the operator[], you can get this completely:
class Row
{
private:
int* _p;
public:
Row( int* p ) { _p = p; }
int& operator[](int col) { return _p[col]; }
};
class Matrix
{
private:
int* _p;
int _cols;
public:
Matrix( int rows, int cols ) { _cols=cols; _p = (int*)malloc(rows*cols ); }
Row operator[](int row) { return _p + row*_cols; }
};
So now, you can use the Matrix object, for example to create a multiplication table:
Matrix mtrx(rows, cols);
for( i=0; i<rows; ++i ) {
for( j=0; j<rows; ++j ) {
mtrx[i][j] = i*j;
}
}
You should now that the optimizer is doing the right thing and there is no call function or any other kind of overhead. No constructor is called. As long as you don't move the Matrix between function, even the _cols variable isn't created. The statement mtrx[i][j] basically does mtrx[i*cols+j].
It can be done as follows:
#define NUM_ROWS 10
#define NUM_COLS 10
int main(int argc, char **argv)
{
char (*p)[NUM_COLS] = NULL;
p = malloc(NUM_ROWS * NUM_COLS);
memset(p, 81, NUM_ROWS * NUM_COLS);
p[2][3] = 'a';
for (int i = 0; i < NUM_ROWS; i++) {
for (int j = 0; j < NUM_COLS; j++) {
printf("%c\t", p[i][j]);
}
printf("\n");
}
} // end of main
You can allocate (row*column) * sizeof(int) bytes of memory using malloc.
Here is a code snippet to demonstrate.
int row = 3, col = 4;
int *arr = (int *)malloc(row * col * sizeof(int));
int i, j, count = 0;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
*(arr + i*col + j) = ++count; //row major memory layout
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
printf("%d ", *(arr + i*col + j));