Is it possible to convert a single dimensional array into a two dimensional array?
i first tought that will be very easy, just set the pointer of the 2D array to the beginning of the 1D array like this:
int foo[] = {1,2,3,4,5,6};
int bla[2][3] = foo;
because i can easily create an two dimensional array like this:
int bla[2][3] = {1,2,3,4,5,6};
so the question is now, is there a way to convert it via the pointer?
You can't initialise an int bla[2][3] with an int* (what foo becomes in that context).
You can achieve that effect by declaring a pointer to arrays of int,
int (*bla)[3] = (int (*)[3])&foo[0];
but be sure that the dimensions actually match, or havoc will ensue.
I know you specificed pointers... but it looks like you're just trying to have the data from an array stored in a 2D array. So how about just memcpy() the contents from the 1 dimensional array to the two dimensional array?
int i, j;
int foo[] = {1, 2, 3, 4, 5, 6};
int bla[2][3];
memcpy(bla, foo, 6 * sizeof(int));
for(i=0; i<2; i++)
for(j=0; j<3; j++)
printf("bla[%d][%d] = %d\n",i,j,bla[i][j]);
yields:
bla[0][0] = 1
bla[0][1] = 2
bla[0][2] = 3
bla[1][0] = 4
bla[1][1] = 5
bla[1][2] = 6
That's all your going for, right?
int (*blah)[3] = (int (*)[3]) foo; // cast is required
for (i = 0; i < 2; i++)
for (j = 0; j < 3; j++)
printf("blah[%d][%d] = %d\n", i, j, blah[i][j]);
Note that this doesn't convert foo from a 1D to a 2D array; this just allows you to access the contents of foo as though it were a 2D array.
So why does this work?
First of all, remember that a subscript expression a[i] is interpreted as *(a + i); we find the address of the i'th element after a and dereference the result. So blah[i] is equivalent to *(blah + i); we find the address of the i'th 3-element array of int following blah and dereference the result, so the type of blah[i] is int [3].
Yes, if you can use an array of pointers:
int foo[] = {1,2,3,4,5,6};
int *bla[2]={foo, foo+3};
You could use union to alias one array into the other:
#include <stdio.h>
union
{
int foo[6];
int bla[2][3];
} u = { { 1, 2, 3, 4, 5, 6 } };
int main(void)
{
int i, j;
for (i = 0; i < 6; i++)
printf("u.foo[%d]=%d ", i, u.foo[i]);
printf("\n");
for (j = 0; j < 2; j++)
{
for (i = 0; i < 3; i++)
printf("u.bla[%d][%d]=%d ", j, i, u.bla[j][i]);
printf("\n");
}
return 0;
}
Output (ideone):
u.foo[0]=1 u.foo[1]=2 u.foo[2]=3 u.foo[3]=4 u.foo[4]=5 u.foo[5]=6
u.bla[0][0]=1 u.bla[0][1]=2 u.bla[0][2]=3
u.bla[1][0]=4 u.bla[1][1]=5 u.bla[1][2]=6
Related
I have some data stored in a one dimensional array of size say 'M'. Now I need to treat it as a two dimensional array with dimension NxP, where the product of N and P is equal to M. I know the values of N and P only at runtime. How can I implement such a function in C?
int array[M]; /* one dimensional array where some data is stored*/
int** newArray; /* the dimension of newArray should be NxP such that we can access the data in 'array' as a two-dimensional array*/
Just cast it to the appropriate array pointer type:
int (*newArray)[N] = (int (*)[N])array;
After that, you can access the array with:
for(int y = 0; y < P; y++) {
for(int x = 0; x < N; x++) {
array[y][x] = 42;
}
}
This is equivalent to the following indexing:
for(int y = 0; y < P; y++) {
for(int x = 0; x < N; x++) {
newArray[y*N + x] = 42;
}
}
This works even if N is only known at run time since C99. Note that you do not need to set up an index array that way, as you would have to do if you used an int**.
You don't need to define a new array. You can use the existing one.
Assuming you know N and P, and N is the number of rows, you can access item (i,j) as:
array[i*N + j]
You could do it like this:
int ** newArray = malloc(sizeof(int*) * N);
for (i = 0; i < N; ++i) {
newArray[i] = array[i * J];
}
This will make an array that "looks" just like a dynamically allocated 2D array of N rows and J columns, but in fact points to the rows of the 1D array.
That way if you have functions to operate on 2D arrays already, you don't need to rewrite them to use the 1D syntax described in other answer.
The runtime makes this a little harder, but :-
newArray = malloc( sizeof( int*) * N ); /* create an array of pointers.
{
size_t i;
for( i = 0; i < N; i++ ) {
newArray[i] = &array[ i* P];
}
}
/* Now newArray[i][j] is usable */
You can just cast the 1d array as the 2d array you want. It's just a block of memory.
int _tmain(int argc, _TCHAR* argv[])
{
int oneDArray[12] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
int(*twoDArray)[3] = (int(*)[3])&oneDArray[0]; // This is the magic line!
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
printf("i: %d j: %d value: %d\r\n", i, j, twoDArray[i][j]);
}
}
_getch();
return 0;
}
Also see question Convert Array Question
There's some inherent unsafeness in doing this, but your question states that NxP=M, so if that's true it will work. People will frown at it though.
I'm practicing pointers and want to substitute pointer operations in place of the arrays to traverse through the elements of the array. I have read numerous articles and cannot grasp this concept. Can someone explain?
Here I made a 2D array and iterated through it using a basic nested for-loop, but want to use pointers;
int test[3][2] = {1,4,2,5,2,8};
for (int i = 0 ; i < 3; i++) {
for (int j = 0; j < 2; j++) {
printf("%d\n", test[i][j]);
}
}
int test[3][2] = {{1,4},{2,5},{2,8}};
// Define a pointer to walk the rows of the 2D array.
int (*p1)[2] = test;
// Define a pointer to walk the columns of each row of the 2D array.
int *p2 = NULL;
// There are three rows in the 2D array.
// p1 has been initialized to point to the first row of the 2D array.
// Make sure the iteration stops after the third row of the 2D array.
for (; p1 != test+3; ++p1) {
// Iterate over each column of the arrays.
// p2 is initialized to *p1, which points to the first column.
// Iteration must stop after two columns. Hence, the breaking
// condition of the loop is when p2 == *p1+2
for (p2 = *p1; p2 != *p1+2; ++p2 ) {
printf("%d\n", *p2);
}
}
In some compilers you can also use a single loop, treating a multidimensional array as a one-dimensional array read in row-major order.
This is mentioned in King's C Programming: A Modern Approach (2nd ed., p268).
#include <stdio.h>
int main(void)
{
int test[3][2] = {{1,4},{2,5},{2,8}}, *p;
for(p = &test[0][0]; p <= &test[2][1]; p++)
{
printf("%d\n", *p);
}
return 0;
}
Try the following and investigate
#include <stdio.h>
int main(void)
{
int test[3][2] = { { 1,4 }, { 2,5 }, { 2,8 } };
for ( int ( *p )[2] = test ; p != test + 3; ++p )
{
for ( int *q = *p; q != *p + 2; ++q ) printf( "%d ", *q );
puts( "" );
}
return 0;
}
The putput is
1 4
2 5
2 8
The first pointer is a pointer to an object of type int[2] that is it points to the first "row" of the array and then due to increments it points to other rows.. The second pointer is a pointer to an object of type int. It points to the first element of each row in the inner loop.
Treating a 2d array as 1d array is very easy using pointer arithmetic to iterate.
void print_2d_array(int *num, size) {
int counter = 0;
while (counter++ < size) {
printf("%i ", *num);
num++;
}
printf("\n");
}
int main() {
int matrix[2][3] = {{2, 11, 33},
{9, 8, 77}};
int matrix_size = sizeof(matrix) / sizeof(int); // 24 bytes / 4 (int size) = 6 itens
print_2d_array(matrix, matrix_size);
return 0;
}
If pointer declaration is the goal of your practice, use the following initialization:
int (*pTest)[rmax][cmax] = test;
Once you do that, the syntax of using pointer indexing mirrors that of array indexing, except that you have to use the * de-referencing operator.
for (int i= 0; i < 3; i++) {
for (int j= 0; j < 2; j++) {
printf ("%d ", *(pTest[i][j]));
}
printf ("\n");
}
However, if pointer arithmetic is the goal of your practice, then the following will work too:
int *res = &test;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
printf ("%d ", *(res + i*2 + j));
}
printf ("\n");
}
OUTPUT
1 4
2 5
2 8
I was writing a code the other day and I found it rather strange, that int** and int[][] does not behave the same way. Can anyone point out the differences between them? Below is my sample code, which fails with a segmentation fault, if I pass constant size 2d array, while it does work fine when I pass a dinamically allocated 2d array.
I am confused mainly because ant int[] array works the same as int*.
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int **t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[0][j] < t[0][j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k][j];
t[k][j] = t[k][j+1];
t[k][j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
So based on the below answers I realize, that a multidimensional array is stored continuously in a row major order. After some modification, the below code works:
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int *t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[j] < t[j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k*m + j];
t[k*m + j] = t[k*m + j+1];
t[k*m + j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
My new question is this: How to modify the code, so that the procedure works with int[][] and int** also?
Realize that int **t makes t a pointer to a pointer, while int t[3][6] makes t an array of an array. In most cases, when an array is used in an expression, it will become the value of the address of its first member. So, for int t[3][6], when t is passed to a function, the function will actually be getting the value of &t[0], which has type pointer to an array (in this case, int (*)[6]).
The type of what is being pointed at is important for how the pointer behaves when indexed. When a pointer to an object is incremented by 5, it points to the 5th object following the current object. Thus, for int **t, t + 5 will point to the 5th pointer, while for int (*t)[M], t + 5 will point to the 5th array. That is, the result of t + 5 is the same as the result of &t[5].
In your case, you have implemented void sort_by_first_row(int **t, int n, int m), but you are passing it an incompatible pointer. That is, the type of &t[0] (which is what t will become in main) is not the same as what the function wants, a int **t. Thus, when the sorting function starts to use that address, it will think its indexing into pointers, when the underlying structure is an array of arrays.
int** is quite different from int[][]. int** is simply a pointer to a pointer and would appear like the following:
in reality, you can access the entire multidimensional array with simply int* pointing to the first element, and doing simple math from that.
Here is the result of the separate allocations (in your commented code):
However when you allocate a multidimensional array, all of the memory is contiguous, and therefore easy to do simple math to reach the desired element.
int t[3][6];
int *t = (int*) malloc((3 * 6) * sizeof(int)); // <-- similarly
This will result in a contiguous chunk of memory for all elements.
You certainly can use the separate allocations, however you will need to walk the memory differently.
Hope this helps.
int t[3][6] is very nearly the same thing as int t[18]. A single contiguous block of 18 integers is allocated in both cases. The variable t provides the address of the start of this block of integers, just like the one-dimensional case.
Contrast this with the case you have marked as "working", where t gives you the address of a block of 3 pointers, each of which points to a block of memory with 6 integers. It's a totally different animal.
The difference between t[3][6] and t[18] is that the compiler remembers the size of each dimension of the array, and automatically converts 2D indices into 1D offsets. For example, the compiler automatically converts t[1][2] into *(t + 1*6 + 2) (equivalent to t[8] if it were declared as a one-dimensional array).
When you pass a multi-dimensional array to a function, there are two ways to handle it. The first is to declare the function argument as an array with known dimension sizes. The second is to treat your array like a 1D array.
If you are going to declare the size of your array, you would declare your function like this:
void sort_by_first_row(int t[][6], int n)
or this
void sort_by_first_row(int t[3][6])
You either have to declare all array dimension sizes, or you can leave out the first size. In both cases, you access elements of t using t[i][j]; you've given the compiler enough information to do the offset math that converts from 2D notation to a 1D index offset.
If you treat it as a 1D array, you have to pass the array dimensions and then do the offset math yourself.
Here's a full working example, where f and f2 both generate the same output:
void f(int* t, int m, int n)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
std::cout << t[i * n + j] << " ";
std::cout << std::endl;
}
void f2(int t[][6], int m)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < 6; j++)
std::cout << t[i][j] << " ";
std::cout << std::endl;
}
int main()
{
int t[3][6];
int val = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 6; j++)
{
t[i][j] = val;
val++;
}
}
f(&(t[0][0]), 3, 6);
f2(t, 3);
return 0;
}
One thing to note is the hack-ish way I had to pass t to f. It's been a while since I wrote in C/C++, but I remember being able to pass t directly. Maybe somebody can fill me in on why my current compiler won't let me.
A int ** is a pointer to a pointer to an int, and can be a pointer to an array of pointers to arrays of ints. A int [][] is a 2-dimensional array of ints. A two-dimensional array is exactly the same as a one-dimensional array in C in one respect: It is fundamentally a pointer to the first object. The only difference is the accessing, a two-dimensional array is accessed with two different strides simultaneously.
Long story short, a int[][] is closer to an int* than an int**.
I'm having an array, that has arrays in every cell. For example, the big array is called arr:
int a[3] = {3, 2, 1};
int b[2] = {2, 1};
int *arr[2] = {a, b}
Now the problem is, if I want to print the small arrs, inside the big array.
Here is my code:
#include <stdio.h>
void printArr(int arr [], int n)
{
for (int i = 0 ; i < n ; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
}
int main()
{
int a[5] = {1, 8, 4, 2, 0};
int b[3] = {1, 4, 2};
int *arr [2] = {a, b};
int n = 0;
for (int i = 0 ; i < 2 ; i++)
{
printArr(*(arr + i), n);
}
}
The output is supposed to be something like this:
1 8 4 2 0
1 4 2
But I can't get the size of each array, since sizeof(*(arr + i) gives me 4, which is the size of the pointer (the name of the array), and not all the array it self.
So what can I do?
Thanks!
The Problem:
The C language only provides a way of finding the size of types.
This gives the subtle differences between applying sizeof to:
1) An array of a type such as:
int a[3];
sizeof(a); // => 3 * sizeof(int)
2) A pointer to the type:
int *ptr;
sizeof(ptr); // => sizeof(int *)
or
int a[3] = {3, 2, 1};
int b[2] = {2, 1};
int *arr[2] = {a, b};
sizeof(arr[1]); // => sizeof(int *)
Some solutions:
Store the size
As jfly proposes store the size of the arrays.
Makes finding the size a constant time operation.
Append an end marker
Adding a end marker like '\0' as used for c-style strings.
You might use INT_MAX or INT_MIN in this case.
The printArr implementation would need to change to:
void printArr(int *arr)
{
int *it = arr;
while(arr != INT_MIN);
{
printf("%d ", *it);
}
printf("\n");
}
Disadvantages:
Finding the size of the array requires iterating over the full array.
Gives the risk of an actual value colliding with the end marker value.
Advantages:
The varying sized array can be passed as a single argument.
Using iterators
Store the pointer to the first and one past the last value.
void printArr(int *begin, int *end)
{
for (int *it = begin; it != end; it++)
{
printf("%d ", *it);
}
printf("\n");
}
int *end_arr[2] = {a + 3, b + 2};
for (int i = 0 ; i < 2 ; i++)
{
printArr(arr[i], end_arr[i]);
}
Can be extended to other data structures.
Since arr is an array of pointers, so you can't get the size of array from the pointer which points to an array, you need additional size info:
int size_arr[2] = {sizeof(a) / sizeof(int), sizeof(b) / sizeof(int)};
for (int i = 0 ; i < 2 ; i++)
{
printArr(arr[i], size_arr[i]);
}
I've written the following generic function:
void* scramble(void* arr, int ElemSize, int n, int* indArr){
void * res = malloc(n * ElemSize);
int i;
for (i = 0 ; i < n ; i++)
memcpy((BYTE*)res+i*ElemSize, (BYTE*)arr+indArr[i]*ElemSize, ElemSize);
return res;
}
The function gets an array, the size of each element, and number of elements in the array.indArr is an array with indexes running from 0 to n-1 in any order.The function returns a new array arranged according to indArr.How can I use it to work with two dimensional arrays (or more)? I tried this, but it doesn't work:
int indArr[] = {2, 0, 1};
char names[][10] = {{"David"}, {"Daniel"}, {"Joni"}};
char **res;
res = (char**)scramble(names, sizeof(char*), 3, indArr);
for (i = 0 ; i < 3 ; i++)
printf("%s ", res[i]);
Any thoughts? Thanks
names is an array of arrays.
The scrambler referrs to the outer array. The elements of the latter are the "strings". The size of each string is 10.
So call the scrambler like this:
res = (char**)scramble(names, 10, 3, indArr);
or
res = (char**)scramble(names, sizeof(*names), 3, indArr);
Update:
To be able to access the single elements of the inner array do as follows:
char (*res)[10] = (char (*)[10]) scramble(names, sizeof(*names), 3, indArr);
for (int i = 0; i < 3; ++i)
printf("res[%d] = '%s'\n", i, res[i]);