How to advance the array base address using a function? - c

i am trying writing a function that forwards the pointer by a specified size in bytes.
void
increment_ptr(void **_ptr, int size){
*_ptr = (char *)(*_ptr) + size;
}
int
main(int argc, char **argv){
int arr[] = {11,20};
printf("%d\n", arr[0]);
increment_ptr((void **)&arr, sizeof(int));
printf("%d\n", arr[0]);
return 0;
}
output i am getting is :
vm#vm:~$ ./a.out
11
15
I am expecting the output to be 11, and 20.
Can anybody pls help ?

arr is not an ordinary variable that you can change. It is not a pointer - its type is int[2].
Try this code:
#include <stdio.h>
void
increment_ptr(void **_ptr, int size){
*_ptr = (char *)(*_ptr) + size;
}
int
main(int argc, char **argv){
int arr[] = {11,20};
int* arr1 = arr;
printf("arr is %p\n", (void*)arr);
printf("arr1 is %p\n", (void*)arr1);
printf("arr gives %d\n", arr[0]);
printf("arr1 gives %d\n", arr1[0]);
increment_ptr((void **)&arr, sizeof(int));
increment_ptr((void **)&arr1, sizeof(int));
printf("arr is %p\n", (void*)arr);
printf("arr1 is %p\n", (void*)arr1);
printf("arr gives %d\n", arr[0]);
printf("arr1 gives %d\n", arr1[0]);
return 0;
}
Possible output:
arr is 0xfff1d1b8
arr1 is 0xfff1d1b8
arr gives 11
arr1 gives 11
arr is 0xfff1d1b8 // Notice arr isn't changed
arr1 is 0xfff1d1bc // arr1 works as expected
arr gives 15
arr1 gives 20
In other words: You can't advance the base address of such an array
You might also find this code interesting:
#include <stdio.h>
int main(int argc, char **argv){
int arr[2] = {11,20};
printf("arr is %p\n", (void*)arr);
printf("arr is %p\n", (void*)&arr);
return 0;
}
Possible output:
arr is 0061FED8
&arr is 0061FED8
Notice how printing arr as a pointer gives the same as printing &arr
So what happens in your code is that the number 11 (aka arr[0]) is read as a pointer (casted to char*), then add 4 (so you have 15) which overwrites the current 11. Note: This result indicates the pointers and ints are both 4 bytes on your system.

The code
int arr[2];
declares a memory space. So, when you acquire its address it returns you the base address of this memory space, which is identical to arr.
This is different to the case when you declare a pointer. A pointer is a variable that saves an address, but an array is just the memory space.

When you declare a variable (array or not), it has an address that is unchanged for the rest of that variable's lifetime. It is not possible to move a variable to a new address.
Your code just causes undefined behaviour (strict aliasing violation - *_ptr uses an lvalue of type void * to access memory declared as int).

Related

Why does my A[] function argument have size 8 bytes instead of 4?

I'm learning about C Pointer from freeCodeCamp.org and I'm getting stuck at the Array pointer as the function arguments follow by this.
In the instructor code was like this
int SumOfElement(int A[]) {
int i, sum = 0;
int size = sizeof(A)/sizeof(A[0]);
printf("SOE - Size of A = %d, size of A[0] = %d", sizeof(A), sizeof(A[0]));
for(i = 0; i<size; i++)
{ sum += A[i];}
return sum;
}
int main() {
int A[]= {1,2,3,4,5};
int total = SumOfElements(A);
printf("Sum of elements %d\n",total);
printf("Main - Size of A = %d, size of A[0] %d",sizeof(A),sizeof(A[0]));
}
And his result (from interested part) is :
SOE - Size of A = 4
Main - Size of A = 20
I understood why's that. But in my code when I try to run similar code I got 8 from printing sizeof(A) inside function
int myFunc(int a[]) {
printf("Size of a[] inside function is %d\n", sizeof(a));
return a;
}
int main(){
int a[] = {1, 2, 3, 4, 5};
myFunc(a); // Result is 8
printf("Size of a[] in main function is %d\n", sizeof(a)); // Result is 20
return 0;
}
int A[] is an array declaration, but since it is part of a function parameter list, it gets implicitly adjusted into a pointer to the first element of that array.
int SumOfElement(int A[]) is 100% equivalent to int SumOfElement(int* A).
Therefore it is senseless to do sizeof A inside that function, because doing so will always give you the size of the pointer. Which is typically 4 bytes on a 32 bit system but 8 bytes on a 64 bit system.
For the same reason, int size = sizeof(A)/sizeof(A[0]); is nonsense. You can't calculate an array size like that when A is an array which has decayed into a pointer. This gives you the size of a pointer divided with the size of an int.
For this function to make sense, it should probably have a separate size parameter.

Why I cannot use int arr[2][2] as a parameter?

void setArr(int x[2][2], int a, int b)
{
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
x[i][j] = 0;
}
int main(void)
{
int *arr[2];
for (int i = 0; i < 2; i++) {
arr[i] = malloc(sizeof(int) * 2);
}
setArr(arr, 2, 2);
}
I know this code will not work, but I do not know the reason behind it. Can any one explain to my why, in this case, I cannot use x[2][2] as a parameter to receive arr.
Thanks
I put the code into a visualizer, and the setArr function sets the element of arr into NULL. I know that NULL is 0 in C. But I cannot connect why and how element of arr can be set to NULL.
Can any one explain to my why, in this case, I cannot use x[2][2] as a parameter to receive arr.
Because you are using wildly different types. int *arr[2]; is an array of 2 int*, each of them assigned to an allocated chunk of memory. That's a lookup table or "jagged array" if you will, not a proper 2D array. See Correctly allocating multi-dimensional arrays for details.
Correct code for allocating a 2D array is this:
#include <stdlib.h>
void setArr(int a, int b, int x[a][b])
{
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
x[i][j] = 0;
}
int main(void)
{
int (*arr)[2] = malloc(sizeof(int[2][2]));
setArr(2, 2, arr);
free(arr);
}
Here arr in main is a pointer to the first element of an int[2][2]. The first element of that 2D array is int[2], and a pointer to such an element is int(*)[2].
Function declaration void setArr(int x[2][2], int a, int b) declares setArr as a function that takes as a first parameter an array of 2 arrays each holding 2 integers. Whereas in the main you declare arr (the variable you pass to setArr) as int *arr[2], that is as a pointer to an array of 2 integers.
The solution is to either change your code in main, for example by declaring arr as int arr[2][2] and remove the for loop, or change the setArr so that it takes a pointer to an array of two integers void setArr(int *x[2], int a, int b).
I'm not sure if the latter could cause any problems (gcc -Wall compiles without warnings), but one thing to notice is the difference in memory layout when declaring arr as a pointer to an array of size 2 or declaring it as an array of 2 arrays of size 2. Compiling and executing the following should show you the difference:
int main(void) {
int *arr[2];
for (int i = 0; i < 2; i++) {
arr[i] = malloc(sizeof(int) * 2);
}
printf("The address of arr[0] is %p\n", &arr[0]);
printf("The address of arr[1] is %p\n\n", &arr[1]);
printf("The address of arr[0][0] is %p\n", &arr[0][0]);
printf("The address of arr[0][1] is %p\n", &arr[0][1]);
printf("The address of arr[1][0] is %p\n", &arr[1][0]);
printf("The address of arr[1][1] is %p\n\n", &arr[1][1]);
int arr2[2][2];
printf("The address of arr2[0] is %p\n", &arr2[0]);
printf("The address of arr2[1] is %p\n\n", &arr2[1]);
printf("The address of arr2[0][0] is %p\n", &arr2[0][0]);
printf("The address of arr2[0][1] is %p\n", &arr2[0][1]);
printf("The address of arr2[1][0] is %p\n", &arr2[1][0]);
printf("The address of arr2[1][1] is %p\n", &arr2[1][1]);
// setArr(arr, 2, 2);
}
Running the executable once on my machine I got the following:
The address of arr[0] is 0x7ffe43d226b0
The address of arr[1] is 0x7ffe43d226b8
The address of arr[0][0] is 0xb62010
The address of arr[0][1] is 0xb62014
The address of arr[1][0] is 0xb62030
The address of arr[1][1] is 0xb62034
The address of arr2[0] is 0x7ffe43d226c0
The address of arr2[1] is 0x7ffe43d226c8
The address of arr2[0][0] is 0x7ffe43d226c0
The address of arr2[0][1] is 0x7ffe43d226c4
The address of arr2[1][0] is 0x7ffe43d226c8
The address of arr2[1][1] is 0x7ffe43d226cc
You can see that the when declaring arr as an pointer to an array, the two arrays of two integers are not contiguous, whereas when declaring it as an array of arrays, they are. Moreover, when declaring it as an array of arrays there is no need to dynamically allocate memory (e.g., using malloc).
x[2][2] is just a declaration of a variable; there is no need to declare a var in input of a function; you must declare it before and just use its address:
void setArr(int** x, int a, int b)

Printing what is stored in pointer prints what is stored in that memory adress

When I try to print this
#include <stdio.h>
int main(){
int x = 3;
int *ptr = &x;
//printf("Address is : %d\n",&ptr);
ptr++;
*ptr = 1;
printf("%d %d",x,ptr);
return 0;
}
The code outputs 3 1, shouldn't it be 3 (then address of ptr?). Then, when I uncomment first printf it prints out:
Address is : 6356744
3 6356752
Does anyone know what is going on?
You have several serious problems in your code.
1) You print a pointer value or an address of a variable using %d but should not. That is undefined behavior so we can't know what will happen. To print a pointer value or an address of a variable use %p and cast to a void pointer like:
printf("Address is : %p\n",(void*)&ptr);
2) You write to memory that is not allocated to your program. These lines:
ptr++;
*ptr = 1;
make you write the value "1" one step past x. So this is also undefined behavior.
Correction the above could give you this program:
#include <stdio.h>
int main(){
int x = 3;
int *ptr = &x;
printf("Address is : %p\n",(void*)&ptr);
ptr++;
// *ptr = 1;
printf("%d %p\n",x,(void*)ptr);
return 0;
}
With the possible output:
Address is : 0x7ffc5b0923c8
3 0x7ffc5b0923c8
but the output may change from run-to-run and system-to-system

Manipulate variable length two dimensional array through a function

I am trying to write data into a variable length two dimensional array and my program keeps seg-faulting when I call myfunc but it works fine when I try to perform the same manipulation outside of a function. I can tell that the issues is that the address pointed to at array[0] doesn't equal the address pointed to at data[0]. Can someone advise me as to the root cause of this issue and proper way to rewrite myfun.
void myfun(unsigned char **array){
printf("array = %p, array[0] = %p\n", array, array[0]);
//This line below causes a segfault
strcpy(array[0], "Position0");
}
int main(void) {
int row = rand() % 5 + 1; // random number between 1-5
int col = rand() % 10 + 20; // random number between 20-29
unsigned char data[row][col];
printf("data = %p, data[0] = %p\n", data, data[0]);
//This function call causes a segfault
myfun(data);
printf("%s\n", data[0]);
//This works
strcpy(data[1], "Position1");
printf("%s\n", data[1]);
return 0;
}
Since you are clearly using C99 or later and a compiler with VLA (variable length array) support, you can write the function correctly quite easily:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void myfun(int rows, int cols, char array[rows][cols])
{
printf("array = %p, array[0] = %p\n", array, array[0]);
strcpy(array[0], "Position0");
printf("a[0] = [%s]\n", array[0]);
}
int main(void)
{
int row = rand() % 5 + 1; // random number between 1-5
int col = rand() % 10 + 20; // random number between 20-29
unsigned char data[row][col];
printf("data = %p, data[0] = %p\n", data, data[0]);
myfun(row, col, data);
printf("%s\n", data[0]);
strcpy(data[1], "Position1");
printf("%s\n", data[1]);
return 0;
}
The problem is the function definition. If you want to pass a matrix the way you did, you have to allocate it dynamically, but that's another story. I'll explain the error.
The C language actually implement the static matrices as a single array of size row*col. That is for efficiency.
When you pass the static matrix to that function, you got a problem: it expects a double pointer, but what you pass is actually a single pointer requiring the number of columns. You have to write like this:
void myfun(unsigned char array[][col]){ ...
That's how you should define it, where col is the number of columns.
The problem's that you don't know the number of columns, it's variable, so I suggest you use malloc or calloc to alocate a dynamic matrix.
Editing: look at this link posted as comment by n.m. for details on the static matrix that C implements: Is 2d array a double pointer?

Why can't arrays of same type and size be assigned?

If I declare two arrays - arr1 and arr2 - of, say, type int of size 10 each, and initialize first array, and I wish to create a copy of arr1 in arr2; why can't I just give the instruction arr2 = arr1 ?
I know two structures of same type can be assigned. Why is that not the case with arrays?
The problem with arrays is that in all expressions (except when passed to the sizeof and the unary & operators) they convert to a pointer to their first element.
So, supposing you have:
int arr1[10];
int arr2[10];
...
Then if you write something like
arr1 = arr2;
you are actually attempting to do this:
arr1 = &arr2[0];
or this:
&arr1[0] = &arr2[0];
In both cases you have a problem preventing your code from compiling. In the former case you're attempting to assign between two incompatible types (array vs pointer), while in the latter case you're attempting to modify a constant pointer (&arr1[0]).
Actually they can, but in indirect way:
#include <stdio.h>
int main(){
int arr1[3] = {0};
int arr2[3] = {1, 2, 3};
struct tmp{
int arr[3];
};
printf("%d %d %d\n", arr1[0], arr1[1], arr1[2]);
// casting array to address of struct
// before dereferencing & asigning to it
*(struct tmp*)arr1 = *(struct tmp*)arr2;
printf("%d %d %d\n", arr1[0], arr1[1], arr1[2]);
return 0;
}
You can even make it in a little-bit more generic way:
#include <stdio.h>
#define STRUCT_TO(type, size) struct temp##__LINE__{type arr[size];}; *(struct temp##__LINE__*)
#define STRUCT_FROM *(struct temp##__LINE__*)
int main(){
int arr1[3] = {0};
int arr2[3] = {1, 2, 3};
printf("%d %d %d\n", arr1[0], arr1[1], arr1[2]);
STRUCT_TO(int,3) arr1 = STRUCT_FROM arr2;
printf("%d %d %d\n", arr1[0], arr1[1], arr1[2]);
return 0;
}
Or ... if we can sacrifice some portability, then we can make syntax a little-bit
more symmetrical:
#include <stdio.h>
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(arr[0]))
#define TEMP_STRUCT struct temp##__LINE__
#define AS_STRUCT_DESTINATION(arr) TEMP_STRUCT{typeof(arr[0]) arrTmp[ARRAY_LENGTH(arr)];}; *(TEMP_STRUCT*) arr
#define AS_STRUCT_SOURCE(arr) *(TEMP_STRUCT*) arr
int main(){
int arr1[3] = {0};
int arr2[3] = {1, 2, 3};
printf("%d %d %d\n", arr1[0], arr1[1], arr1[2]);
AS_STRUCT_DESTINATION(arr1) = AS_STRUCT_SOURCE(arr2);
printf("%d %d %d\n", arr1[0], arr1[1], arr1[2]);
return 0;
}
You cannot assign an array into another as you would do if your variables were pointers to an array. Even in this case, you would not create a copy, but only another pointer to the same array.
To copy an array, you should copy the whole content using memcpy():
int a[3] = {1,2,3};
int b[3];
memcpy(b, a, sizeof(a));
In C, array type does not hold size, so if a has type int[] and b has type int[] than to calculate a == b we need to know actual sizes of a and b which are not known neither in compile time nor in run time.

Resources