Let's say I have 2 2-dimensional arrays:
int a1[][2] = { {1,2}, {3,4}, {5,6} };
int a2[][2] = { {7,8}, {9,0}, {1,1} };
and a pointer:
int *a;
The pointer will point to one of the arrays and at some point point to the other (back and forth). After each reassignment of the pointer I want to read from the array, what is the easiest way to do that?
I can achieve what I want using the following way:
a = (int *)a1;
printf("D: %d\n", (int)(*a)+(x*2)+(y)));
a = (int *)a2;
printf("D: %d\n", (int)(*a)+(x*2)+(y)));
Output (assuming x = 0 and y = 1):
D: 2
D: 8
Is there another easier way to access the arrays I.e. by using the standard [] operator? If not, then how would you make this more "beautiful"... would you create a macro or a function or what would be the preferred way of doing it?
You can make use of [] if you always have pairs and turn the pointer to
int (*a)[2];
This should make it possible to write
a = a1;
printf("D: %d\n", a[x][y]);
First off, this is wrong:
a = (int *)a1;
a1 is a double pointer, as it is an array of int arrays, whereas a is a pointer to an int.
To access individual array values, you can use the [] operator as follows:
int a1[][2] = { {1,2}, {3,4}, {5,6} };
assert( 2 == a[0][1] );
assert( 4 == a[1][1] );
Not so nice, but one way to do it:
int a1[][2] = { {1,2}, {3,4}, {5,6} };
int a2[][2] = { {7,8}, {9,0}, {1,1} };
int (*a)[][2];
a = &a1;
printf("value = %d \n", (*a)[x][y] );
a = &a2;
printf("value = %d \n", (*a)[x][y] );
Using a table of operator precedence you could write
*(a+x*2+y)
by omiting superflous parenthesis.
Related
Is this a correct way to define array of pointers to array in C programming language?
int* ptr[2];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = &n1;
ptr[1] = &n2;
I am getting errors like:
epi_2.c:20:12: warning: incompatible pointer types assigning to 'int *' from 'int (*)[5]' [-Wincompatible-pointer-types]
ptr[1] = &n2;
You have to write
ptr[0] = n1;
ptr[1] = n2;
Array designators used in expressions with rare exceptions are converted to pointers to their first elements.
That is in the above statements expressions n1 and n2 have the type int * - the type of the left side expressions.
As for these statements
ptr[0] = &n1;
ptr[1] = &n2;
then the right side expressions have the type int ( * )[5] that is not compatible with the type int * of the left side expressions. So the compiler issues messages.
Otherwise you need to declare the array of pointers like
int ( * ptr[2] )[5];
//...
ptr[0] = &n1;
ptr[1] = &n2;
Here is a demonstration program.
#include <stdio.h>
int main( void )
{
int* ptr[2];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = n1;
ptr[1] = n2;
for ( size_t i = 0; i < 2; ++i )
{
for ( size_t j = 0; j < 5; j++ )
{
printf( "%d ", ptr[i][j] );
}
putchar( '\n' );
}
}
The program output is
2 3 4 5 6
2 3 4 5 6
And here is another demonstration program.
#include <stdio.h>
int main( void )
{
int ( * ptr[2] )[5];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = &n1;
ptr[1] = &n2;
for ( size_t i = 0; i < 2; ++i )
{
for ( size_t j = 0; j < 5; j++ )
{
printf( "%d ", ( *ptr[i] )[j] );
}
putchar( '\n' );
}
}
The program output is the same as shown above
2 3 4 5 6
2 3 4 5 6
Is this a correct way to define array of pointers to array?
&n1 does return a pointer to an array.
But ptr[0] is not a pointer to an array. It's a pointer to an int.
You have two options.
Change ptr[0] to be a pointer to an array
By using the following, ptr becomes an array of pointers to arrays of 5 ints.
int ( *ptr[2] )[5] = { &n1, &n2 };
Change &1n to something that returns a pointer to int
But we rarely deal with pointer to arrays. We usually work with pointers to the first element of the array.
int *ptr[2] = { &( n1[0] ), &( n2[0] ) };
Because an array degenerates into a pointer to its first element, the following is equivalent but shorter:
int *ptr[2] = { n1, n2 };
In both cases, you end up with a pointer to the same address. But the type of the pointer is different. About the only difference is that sizeof( *ptr[0] ) will vary.
#include <stdio.h>
int main( void ) {
int ( *ptrA[2] )[5];
int *ptrB[2];
printf( "%zu\n", sizeof( *ptrA[0] ) ); // 20, size of array of 5 `int`.
printf( "%zu\n", sizeof( *ptrB[0] ) ); // 4, size of one `int`.
}
In C, there are two kinds of pointers to arrays:
Pointers that point to the first element of the array.
Pointers that point to the array as a whole.
If you have an array
int arr[5] = { 2,3,4,5,6 };
then you can create a pointer to the first element of the array the following way:
int *ptr = arr;
In the line above, the expression arr will automatically decay to &arr[0], i.e. to a pointer to the first element of the array.
You can create a pointer to the array as a whole the following way:
int (*ptr)[5] = &arr;
In C, it is more common to use the first kind of pointer. However, which kind of pointer you want depends on the situation.
For example, do you want sizeof *ptr to evaluate to the size of the entire array? Or do you want that expression to evaluate to the size of a single element of the array?
Also, how do you want ptr++ to behave? Do you want the pointer jump to the next element of the array? Or do you want the pointer to jump over the entire array (for example because you are using an array of arrays and want to jump to the next element of the outer array)?
If you want sizeof *ptr to evaluate to the size of a single element and want ptr++ to jump to the next element of the array, then you want the first kind of pointer. However, if you want sizeof *ptr to evaluate to the size of the entire array and want ptr++ to jump over the entire array, then you want the second kind of pointer.
If in doubt, I recommend that you chose the first kind of pointer, because that kind of pointer is easier to handle and more common.
Once you have decided which kind of pointer you want, you can then create an array of these pointers.
If you want an array of the first kind of pointer, then you can define that array like this:
int *ptrs[2];
ptrs[0] = n1;
ptrs[1] = n2;
If you instead want an array of the second kind of pointer, then you can define that array like this:
int (*ptrs[2])[5];
ptrs[0] = &n1;
ptrs[1] = &n2;
I got this code:
#include <stdio.h>
#include <string.h>
int main(void)
{
int a[3]={1,2,3},
b[3];
int (*p)[3]= &a;
b = p;
for(int i=0;i<3;i++)
printf("%i",b[i]);
}
-I wanted output to be like "123", but I am having problems assigning the b array to what the p is pointing.
ps -
memcpy( b, p, sizeof(b)); does just what i want but i want to do it without the use of that function.
The line
b = p;
has a couple of problems. First of all, array expressions may not be the target of the = operator; you can't assign an entire array in a single operation like that1.
Secondly, the types don't match; p has type int (*)[3], while b has type int [3]. Arrays are not pointers - array expressions "decay" to pointer expressions under most circumstances, but in this case even the pointers would be of incompatible types (b would decay to an expression of type int *, not int (*)[3]).
No, the only ways to copy the contents of one array to the other are to use library functions like memcpy or to use a loop to assign each element individually:
for ( size_t i = 0; i < 3; i++ )
b[i] = (*p)[i]; // or b[i] = a[i]
That's it.
Initialization is different from assignment.
Arrays do not have the assignment operator. You need somehow to copy elements of one array to another array.
Without using the standard function memcpy you can use an ordinary loop as for example
for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
{
b[i] = a[i];
}
Or if to use intermediate pointers you can write
for ( int *p = a, *q = b; p != a + sizeof( a ) / sizeof( *a ); ++p )
{
*q++ = *p;
}
You have a small fixed size array, perfectly suitable for wrapping inside a struct, so you can do this:
#include <stdio.h>
#include <string.h>
struct ia3 {
int data[3];
}
int main(void)
{
struct ia3 a = {{1,2,3}};
struct ia3 b;
struct ia3 *p = &a;
b = *p; // struct assignment
for(int i=0;i<3;i++) {
printf("%i",b.data[i]);
}
}
"...but i want to do it without the use of [memcpy(,,)]."
It is unclear why using memcpy() is not agreeable in this exercise, but it does do the task more efficiently then loop for large array sizes.
If you just want a pointer to the array...
int a[3] = {1,2,3};
//create pointer
int *b = a;//does not copy array a, just points to it
//If an additional array is needed, do this...
int b[3] = {0};
int i = 0;
//to copy, without memcpy(), use this alternative.
for(i=0; i<3; i++) b[i] = a[i];//makes copy of array a
for(i=0;i<3;i++)
printf("%i", b[i]);
I am exploring pointer "mechanics" in C/C++. I try to understand if and how is possible to implement a 2D matrix using two pointers (one for "rows" and one for "columns") instead of a single double pointer. I am aware that a matrix with rows*columns number of values could be stored in memory sequentially, but i am looking to comprehend deeper the mechanics of pointers and eventually to implement a function similar to
int value=getValue(vectorNr,vectorValue)
that is able to "simulate" the construct
value=Matrix[vectorNr][vectorValue]
vectorPointer vectorValue
| AddressV1 |------|valAddr11 valAddr12 valAddr13 |
| AddressV2 |------|valAddr21 valAddr22 valAddr23 |
| AddressV3 |------|valAddr31 valAddr32 valAddr33 |
I tried to begin writing a code like this but I quickly get stuck on pointer arithmetic and address offsetting. I also might chose a very dirty approach so any comment is welcome.
CODE TO IMPLEMENT A 2D ARRAY WITH POINTERS (BUT NOT USING DOUBLE POINTERS). To avoid confusion between rows and columns I refer to "Vectors as rows" and "Columns as vector values"
int vectorsNumber = 3; //Number of Vectors
int valuesNumber = 3; //Number of values stored in one Vector
//Addresses of Vectors. Since Vectors holds a reference to set of values, vectorPointer will hold an address for every set.
void* vectorPointer = malloc(vectorsNumber *sizeof(void*));
//Populating the vectorPointer with the address generated by allocating memory for every set of values
for (int i = 0; i < vectorsNumber; i++)
{
vectorPointer = (int*)malloc(valuesNumber * sizeof(int)); //Values shall be of int types
vectorPointer++; //ILLEGAL since cannot perform arithmetic on pointers of type void. What do do??
}
//Restore the initial address. In any case...ILLEGAL arithmetic. What do do??
for (int i = 0; i < vectorsNumber; i++)
{
vectorPointer--; //Restore the initial address. In any case...ILLEGAL arithmetic.
}
//Declaring the pointer to hold the address of one value. Memory was already allocated before
int* valueAddress;
for (int j = 0; j < vectorsNumber; j++)
{
//Getting the address of the first value of the first Vector
valueAddress = (int*)vectorPointer; //Is this casting valid in C language?
//Populating the value with whatever operation
for (int k = 0; k < valuesNumber; k++)
{
*valueAddress = (k + 1)*(j + 1); //populate the Vector with int values
}
vectorPointer++; //Switch to next Vector.ILLEGAL arithmetic
}
Actually, you only need one pointer. One way of doing it is by allocating enough memory to hold all the values, and then have functions that map the x/y values in the array to the respective memory location. Assume we want those to be the dimensions and our array variable:
int dimX = 10, dimY = 5;
int *array;
You can set a value this way:
void arraySet(int value, int x, int y) {
array[x + dimX * y] = value;
}
And get a value this way:
int arrayGet(int x, int y) {
return array[x + dimX * y];
}
Allocate the memory beforehand such as in the main function:
array = malloc(sizeof(int)*dimX*dimY);
Use it like this:
arraySet(123, 9, 3); // sets the value of [9, 3] to 123
printf("Memory at 9, 3 is %d\n", arrayGet(9, 3));
This "two pointers" idea doesn't make any sense and the code you posted cannot be salvaged. What you should do instead is to use a pointer to a 2D array:
int (*ptr)[x][y] = malloc(sizeof *ptr);
...
free(ptr);
That's it. However, a pointer to a 2D array is cumbersome, since we have to de-reference it before accessing the actual array. That is, we'd end up writing (*ptr)[i][j] = ...; which is ugly.
To dodge this, we can instead still allocate a 2D array, but instead of pointing at "the whole array", we point at the first element, which is a 1D array:
int (*ptr)[y] = malloc( sizeof(int[x][y]) );
...
ptr[i][j] = ... ; // more convenient syntax for access
...
free(ptr);
More info: Correctly allocating multi-dimensional arrays
You can simulate int a[2][3]; with
one dimensional array and index computing:
int* matrix = (int*) malloc(6 * sizeof(int));
int get_matrix_2_3(int* matrix, int i, int j) { return matrix[3 * i + j]; }
2-dimensional array:
int** matrix = (int**) malloc(2 * sizeof(int*));
for (int i = 0; i != 2; ++i) {
matrix[i] = (int*) malloc(3 * sizeof(int));
}
matrix[1][2] = 42;
Currently, I'm using the iterative method of swapping element by element which seems to be very inefficient. Is it possible to swap two 2D arrays in constant time?
int a[20][100];
int b[20][100];
I want to swap a & b in O(1).
Also, can the same solution be applied if I want to just override b to a?
Below is the code I used to iteratively override 'a' with 'b'.
Below code is used to override a with b:
for(x = 0;x<row;x++){
for(y=0;y<col;y++){
a[x][y] = b[x][y];
}
}
Below is the code I used to swap a and b:
for(x = 0;x<row;x++){
for(y=0;y<col;y++){
temp = a[x][y];
a[x][y] = b[x][y];
b[x][y] = temp;
}
}
You'll need to store them as pointers. For example:
int a_store[20][100];
int b_store[20][100];
int (*a)[20][100] = &a_store;
int (*b)[20][100] = &b_store;
Now it's easy to swap them. You could also allocate them on the heap, or use std::vector in C++.
Is it possible to swap two 2D arrays in constant time?
To swap 2 2D arrays A[N][M],B[N][M] takes O(N*M) time. This is constant time only if N and M are constant.
The alternative strategy is for code to swap pointers to the arrays.
int main(void) {
size_t N = 3, M = 4;
// ...
int A[N][M];
memset(A, 1, sizeof A);
int B[N][M];
memset(B, 2, sizeof B);
int (*Ap)[N][M] = &A;
int (*Bp)[N][M] = &B;
printf("A:%x %x B:%x %x \n", (*Ap)[0][0], (*Ap)[N-1][M-1], (*Bp)[0][0], (*Bp)[N-1][M-1]);
// Swap pointers in O(1)
int (*t)[N][M] = Ap;
Ap = Bp;
Bp = t;
printf("A:%x %x B:%x %x \n", (*Ap)[0][0], (*Ap)[N-1][M-1], (*Bp)[0][0], (*Bp)[N-1][M-1]);
return 0;
}
Output
A:1010101 1010101 B:2020202 2020202
A:2020202 2020202 B:1010101 1010101
I'm coming from c#, and this is causing me more issues than I would've expected. I've not seen a straight forward solution to this. I'm brand new to C, just playing with it, and all of the various implementation I've tried, from using structs, to passing pointers around isn't getting the job done. (local values aren't changing). Can someone give me a cut and dry example?
Here's a sample of my code
#include <stdio.h>
//alter values based on input
int * doStuff(int a, int b){
int input;
int arr[2]
scanf("%d", &option);
switch(option);
case 1:
arr[0] = a-2;
arr[1] = b;
return arr;
break;
case 2:
arr[0] = a;
arr[1] = b-2;
return arr;
break;
default:
return a, b;
}
main(){
int a = 20;
int b = 20;
int returnedObject[2];
//what i need is like in c# how I can do this
returnedObject = doStuff(a, b);
a = returnedObject[0];
b= returnedObject[1];
}
I need to pass values, alter them, return them, and set the local variables. I'm completely lost with some of the more complex examples. Coming from c# pointers, arrays, how they work is losing me, and it isn't as simple as I had expected.
Functions in C cannot return array types, nor can arrays be the target of an assignment. So code like
int returnedObject[2];
returnedObject = doStuff( a, b );
cannot work. C functions can return pointers to arrays, but I don't think you want to get into that.
C functions cannot return multiple objects, nor is multiple assignment supported.
If your two values are logically attributes of some larger, aggregate type, you can use a struct type to return a single object with multiple attributes, such as
struct result { int x, int y };
struct result doStuff( int a, int b )
{
struct result ret = {a, b}; // initialize struct with inputs
...
case 1:
ret.x = a-2;
break; // y remains unchanged
case 2:
ret.y = b-2;
break; // x remains unchanged
...
return ret;
}
which you would call as
struct result stuff;
stuff = doStuff( a, b );
Alternately, you can pass pointers to your values and update them as necessary:
void doStuff( int *a, int *b )
{
...
case 1:
*a = *a - 2;
break;
case 2:
*b = *b - 2;
break;
}
which you would call as
doStuff( &a, &b );
In this case you don't actually return anything to the caller.
You can pass an array as an argument to the function, like so:
void doStuff( int a, int b, int *result )
{
result[0] = a;
result[1] = b;
...
case 1:
result[0] = a - 2;
break;
case 2:
result[1] = b - 2;
break;
...
}
which you would call as
int results[2];
int a;
int b;
...
doStuff( a, b, results );
Note that when we pass the array expression to the function, its type is changed from int [2] to int *. Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize another array, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. Array expressions in C lose their "array-ness" in most circumstances1. You can use the subscript operator [] on a pointer expression as you would an array expression (the array index operation a[i] is defined as *(a + i)), but pointers are not arrays and vice versa.
1. Note that I'm talking about the expression, not the object. The array object always stays an array object.
Simple solution (Passing by reference/pointer allows to change the value stored)
#include <stdio.h>
//alter values based on input
void doStuff(int *a, int *b, int option)
{
switch(option)
{
case 1:
// a decremented by 2, b is unchanged
*a = *a - 2;
break;
case 2:
// b decremented by 2, a is unchanged
*b = *b - 2;
break;
default:
// a and b are unchanged
break;
}
}
int main()
{
int a = 20;
int b = 20;
int option;
printf("Enter option (1 or 2):\n");
scanf("%d", &option);
printf("BEFORE doStuff() :: a = %d, b = %d\n", a, b);
doStuff(&a, &b, option);
printf("AFTER doStuff() :: a = %d, b = %d\n", a, b);
return 0;
}
You can wrap the array with a struct to return it directly.
#include <stdio.h>
struct doStuffRet {
int arr[2];
};
//alter values based on input
struct doStuffRet doStuff(int a, int b){
int option;
struct doStuffRet r = {{a, b}};
scanf("%d", &option);
switch(option) {
case 1:
r.arr[0] = a-2;
r.arr[1] = b;
return r;
break;
case 2:
r.arr[0] = a;
r.arr[1] = b-2;
return r;
break;
default:
return r;
}
}
int main(void){
int a = 20;
int b = 20;
struct doStuffRet returnedObject;
//what i need is like in c# how I can do this
returnedObject = doStuff(a, b);
a = returnedObject.arr[0];
b = returnedObject.arr[1];
printf("%d %d\n", a, b);
return 0;
}
Make the return type int *.
Create a local variable int *result = malloc(sizeof(int) * 2); and put your a and b or whatever you need to return in result.
When you call the function, assign the result to an int *.
int *res;
res = doStuff(a, b);
a = res[0];
b = res[1];
malloc allocates space for result on the heap. Its input is the number of bytes you need.
2 ints, 4 bytes per int -> 8 bytes == 2*sizeof(int)
The problem is that every time you call your function, you will keep allocating more and more space. C doesn't do garbage collection for you, so when you're done using your int *res, you should free that space by calling free(res).
Further Details:
In C#, you would initialize an array like this: int[] result = new result[2];
Have you every tried printing an array like this Console.WriteLine(myarray);. It doesn't work does it? C# I believe prints something like System.Int32[]. If you did this in Java (System.out.println(myarray);), it would print some weird number.
That number is actually the address of the array.
When you reference your array myarray, you are actually referencing the address of the array. When you do something like myarray[1], you are getting the address of myarray, adding to it 1*sizeof(int) and fetching that value.
In C, you can define arrays in the typical way: int arr[2]; which allocates space for 2 ints.
Alternatively, you can do: int *arr; which defines a pointer (or address). However, you need to tell it to allocate space for integers. As it is now, arr doesn't really point to anything. You allocate space by calling malloc: arr = malloc(2*sizeof(int)); which dynamically allocates space for 2 integers.
Now you can put stuff in your array. arr[0] = 1.
The [] is effectively doing pointer arithmetic.
arr[1] is the same as *(arr + 1)
arr + 1 is getting the address of the array and adding 1 to it. C sees that you're adding to an int * so it interprets 1 to mean 1 int (4 bytes). The * operator dereferences the address, which means it follows the pointer and gets the value stored at that address.
If printing arr gives you 0x1000, arr+1 gives you 0x1004 and * will return the int stored at 0x1004.
On to returning arrays in functions.
In C, you can't return an array like in C# (int[] function(...)), but you can return a pointer (int *function(...)), which you can use like an array (see above example).
The reason you want to use malloc is because malloc allocates space on the heap, so you can use that array after the function returns. If you defined an array like int arr[2];, the space would be allocated on the stack, and the array wouldn't persist after the function returns.
Perhaps you should look at a tutorial to learn more about pointers. I think my answer is too lengthy and not totally relevant to the question.