Experimenting with Pointers and Arrays in C - c

Can someone explain to me the difference between:
int *arr[5] vs. int (*arr)[5] vs. int *(*arr)[5]
I'm trying to wrap my mind around how pointers/arrays are actually represented in C...

I would suggest using http://cdecl.org.
int *arr[5] "declare arr as array 5 of pointer to int"
int (*arr)[5] "declare arr as pointer to array 5 of int"
int *(*arr)[5] "declare arr as pointer to array 5 of pointer to int"
plus a visit to this page from MSDN: Interpreting more complex declarators.

The first makes a variable named arr that is of an array length 5 of type int*, so it is an array length 5 of int pointers.
The second declares a variable named arr that is a pointer to an array length 5 of type int. So it is a pointer to an array of ints length 5.
The third is a variable named arr that is a pointer to an array of length 5 of type int pointer. So it is a pointer to an array length 5 of int pointers. Or, a pointer to the type of the first case!
To think of how to analyze things like this in the future, realize that parenthesis have the highest priority here so by having (*arr) it is first, and foremost, a pointer. Then the array notation has second highest priority, so (*arr)[5] is a pointer to an array of length 5...but what type of array? Well the type is the lowest priority, so that comes last. If we have int (*arr)[5], then it is a pointer (1st) to an array length 5 (2) of type int (3).
With that we can look at something like: int** (*arr)[7] It is a pointer named arr (1) to an array length 7 (2) of type int**, or pointers to pointers of ints (3).
As far as wondering how pointers/arrays are represented in C...
pointers and arrays are both 32 bit variables (like ints on most systems) that contain a 32 bit address to a memory location (where they point). Arrays obviously point to the beginning of an array, so *arr == arr[0]. While pointers can point to anything. When you declare an array (arr[5], arr[1000], etc.) it makes a pointer named arr as well as reserves whatever space is in between the brackets (5 or 1000). But when you declare a pointer (*arr), it does not reserve any space. Otherwise, the variable arr in both cases is simply a pointer. Also, if you want to be confusing, you could even dereference your pointers like so: pointer[0], instead of *pointer.
As a final note example, we can look at something like: int * (*arr)[5][7] and analyze both what it is and what the compiler is doing:
First, it is a pointer named arr (1), to an array length 5 (2) each to an array length 7 (3) but because an array length n is just a pointer to a reserved location in memory, so really (2) is an array length 5 to a pointer (pointing to memory blocks of size 7). Finally, each of the memory blocks of size 7 (3) is of type int * (4).
So, it is a pointer to an array length 5 of pointers to arrays of length 7 of type int *!
I hope this helps! I know I had a lot of fun playing with C and seeing what was possible and what different things did =)

A pointer is the address of another object. An array is a contiguous block of objects. So:
int *a[5];
a is an array of 5 pointers to int. This means that a represents a block of 5 contiguous address values, where each of those values can hold the address of an int.
int (*b)[5];
b is a pointer to an array of 5 ints. This means that b is a single address value, where that value can hold the address of an array of 5 ints.
int *(*c)[5];
c is a pointer to an array of 5 pointers to int. This means that c is a single address value, where that value can hold the address of an array of 5 pointers to int. This could hold the address of the first object a, so c = &a; would be valid.

int *arr[5] is an array of five int*s.
int (*arr)[5] is a pointer to an array of five ints.
int *(*arr)[5] is a pointer to an array of int*
Generally, one makes a typedef:
typedef int fiveintarray[5];
typedef int* intptr;
typedef intptr fiveintptrarray[5];
And then uses it:
fiveintarray array; //array of five integers
fiveintarray* pointer_to_array; // pointer to array of five integers
fiveintptrarray array; //array of five pointers to integers
fiveintptrarray* pointer_to_array; //pointer to array of five pointers to integers

int *arr[5] -> an array, of length 5, of pointers to int
int (*arr)[5] -> a pointer to int arrays of length 5
int *(*arr)[5] -> a pointer to a pointer to int arrays of length 5

Related

C: size of *array[x]?

I have a question that should be fairly straightforward (I hope).
In c, the size of an array delcared as int array[10][10];,
for example, I understand as having 10 spots in which to store 10 integers. However, what's the size of an array declared as int *array[10];? I know that *array has 10 elements, but how many elements does array have?
This is a hole in my understanding I would really like to clear up. Thanks for any help!
int *array[10]; is an array of 10 int *s, so the number of elements is 10.
To elaborate, for int *array[10];, ty type of array variable is int * [10], an array of 10 elements of type pointer to integers.
The array size would be 10 * sizeof pointer-to-integer-in-your-platform.
You have to understand the declaration in C.
Start dividing it in parts:
int array[10][10];
array is the name of the variable, the part [10] means that it is an array of 10 arrays of int, each array holding 10 elements (the second [10]).
Now:
int * array[10];
array is the name of the variable, the part [10] means that it is an array of 10 elements of type int * (integer pointers not integers as before).
The sizes in the firs case will be 10 times the size of an array of 10 integers = the space required for 100 integers.
In the second case will be the size to hold 10 pointers to integer.
As side note maybe your confusion comes from the fact that C allows access to elements of both declaration in the same way. I.e. the following will get the 5th integer of the second array:
int b = array[2][5];
But the difference remains substantial because in the first declaration the compiler will allocate contiguous space to hold all 100 integers (organized, as per C allocating method, as 10 arrays of 10 integers each in succession), in the second case will be allocated only an array of 10 pointers each pointing to the location of an array of 10 integers. And the 10 arrays will not be allocated, nor the pointers initialized.
In that case it is programmer responsibility to allocate 10 arrays of int and assign the address of each one to the array of pointers.
Another point to clarify (thanks to alk to have pointed it out) is that in the case of the array of pointers the second dimension is undefined, meaning that each array of int pointed can be of 1, 10, 1000 or whatever elements.
how many elements does array have?
int *array[10];
array is array of 10 pointers to int, the same as int* array[10] - so array has 10 elements (each element being a pointer).

C - Pass variable length array of strings to function and modify strings inside function [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 6 years ago.
int main()
{
matrix[2][4] = {{11,22,33,99},{44,55,66,110}};
int **ptr = (int**)matrix;
printf("%d%d",**matrix,*ptr);
}
But when a 2-d array is passed as a parameter it is typecasted into (*matrix)[2] ..
what type does the compiler store this array as... is it storing as a 2-d array or a double pointer or an pointer to an array .. If it is storing as an array how does it interprets differently at different situations like above. Please help me understand.
Is 2d array a double pointer?
No. This line of your program is incorrect:
int **ptr = (int**)matrix;
This answer deals with the same topic
If you want concrete image how multidimensional arrays are implemented:
The rules for multidimensional arrays are not different from those for ordinary arrays, just substitute the "inner" array type as element type. The array items are stored in memory directly after each other:
matrix: 11 22 33 99 44 55 66 110
----------- the first element of matrix
------------ the second element of matrix
Therefore, to address element matrix[x][y], you take the base address of matrix + x*4 + y (4 is the inner array size).
When arrays are passed to functions, they decay to pointers to their first element. As you noticed, this would be int (*)[4]. The 4 in the type would then tell the compiler the size of the inner type, which is why it works. When doing pointer arithmetic on a similar pointer, the compiler adds multiples of the element size, so for matrix_ptr[x][y], you get matrix_ptr + x*4 + y, which is exactly the same as above.
The cast ptr=(int**)matrix is therefore incorrect. For once, *ptr would mean a pointer value stored at address of matrix, but there isn't any. Secondly, There isn't a pointer to matrix[1] anywhere in the memory of the program.
Note: the calculations in this post assume sizeof(int)==1, to avoid unnecessary complexity.
No. A multidimensional array is a single block of memory. The size of the block is the product of the dimensions multiplied by the size of the type of the elements, and indexing in each pair of brackets offsets into the array by the product of the dimensions for the remaining dimensions. So..
int arr[5][3][2];
is an array that holds 30 ints. arr[0][0][0] gives the first, arr[1][0][0] gives the seventh (offsets by 3 * 2). arr[0][1][0] gives the third (offsets by 2).
The pointers the array decays to will depend on the level; arr decays to a pointer to a 3x2 int array, arr[0] decays to a pointer to a 2 element int array, and arr[0][0] decays to a pointer to int.
However, you can also have an array of pointers, and treat it as a multidimensional array -- but it requires some extra setup, because you have to set each pointer to its array. Additionally, you lose the information about the sizes of the arrays within the array (sizeof would give the size of the pointer). On the other hand, you gain the ability to have differently sized sub-arrays and to change where the pointers point, which is useful if they need to be resized or rearranged. An array of pointers like this can be indexed like a multidimensional array, even though it's allocated and arranged differently and sizeof won't always behave the same way with it. A statically allocated example of this setup would be:
int *arr[3];
int aa[2] = { 10, 11 },
ab[2] = { 12, 13 },
ac[2] = { 14, 15 };
arr[0] = aa;
arr[1] = ab;
arr[2] = ac;
After the above, arr[1][0] is 12. But instead of giving the int found at 1 * 2 * sizeof(int) bytes past the start address of the array arr, it gives the int found at 0 * sizeof(int) bytes past the address pointed to by arr[1]. Also, sizeof(arr[0]) is equivalent to sizeof(int *) instead of sizeof(int) * 2.
In C, there's nothing special you need to know to understand multi-dimensional arrays. They work exactly the same way as if they were never specifically mentioned. All you need to know is that you can create an array of any type, including an array.
So when you see:
int matrix[2][4];
Just think, "matrix is an array of 2 things -- those things are arrays of 4 integers". All the normal rules for arrays apply. For example, matrix can easily decay into a pointer to its first member, just like any other array, which in this case is an array of four integers. (Which can, of course, itself decay.)
If you can use the stack for that data (small volume) then you usually define the matrix:
int matrix[X][Y]
When you want to allocate it in the heap (large volume), the you usually define a:
int** matrix = NULL;
and then allocate the two dimensions with malloc/calloc.
You can treat the 2d array as int** but that is not a good practice since it makes the code less readable. Other then that
**matrix == matrix[0][0] is true

Can't use fixed array in 'dynamic array' in struct [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 6 years ago.
int main()
{
matrix[2][4] = {{11,22,33,99},{44,55,66,110}};
int **ptr = (int**)matrix;
printf("%d%d",**matrix,*ptr);
}
But when a 2-d array is passed as a parameter it is typecasted into (*matrix)[2] ..
what type does the compiler store this array as... is it storing as a 2-d array or a double pointer or an pointer to an array .. If it is storing as an array how does it interprets differently at different situations like above. Please help me understand.
Is 2d array a double pointer?
No. This line of your program is incorrect:
int **ptr = (int**)matrix;
This answer deals with the same topic
If you want concrete image how multidimensional arrays are implemented:
The rules for multidimensional arrays are not different from those for ordinary arrays, just substitute the "inner" array type as element type. The array items are stored in memory directly after each other:
matrix: 11 22 33 99 44 55 66 110
----------- the first element of matrix
------------ the second element of matrix
Therefore, to address element matrix[x][y], you take the base address of matrix + x*4 + y (4 is the inner array size).
When arrays are passed to functions, they decay to pointers to their first element. As you noticed, this would be int (*)[4]. The 4 in the type would then tell the compiler the size of the inner type, which is why it works. When doing pointer arithmetic on a similar pointer, the compiler adds multiples of the element size, so for matrix_ptr[x][y], you get matrix_ptr + x*4 + y, which is exactly the same as above.
The cast ptr=(int**)matrix is therefore incorrect. For once, *ptr would mean a pointer value stored at address of matrix, but there isn't any. Secondly, There isn't a pointer to matrix[1] anywhere in the memory of the program.
Note: the calculations in this post assume sizeof(int)==1, to avoid unnecessary complexity.
No. A multidimensional array is a single block of memory. The size of the block is the product of the dimensions multiplied by the size of the type of the elements, and indexing in each pair of brackets offsets into the array by the product of the dimensions for the remaining dimensions. So..
int arr[5][3][2];
is an array that holds 30 ints. arr[0][0][0] gives the first, arr[1][0][0] gives the seventh (offsets by 3 * 2). arr[0][1][0] gives the third (offsets by 2).
The pointers the array decays to will depend on the level; arr decays to a pointer to a 3x2 int array, arr[0] decays to a pointer to a 2 element int array, and arr[0][0] decays to a pointer to int.
However, you can also have an array of pointers, and treat it as a multidimensional array -- but it requires some extra setup, because you have to set each pointer to its array. Additionally, you lose the information about the sizes of the arrays within the array (sizeof would give the size of the pointer). On the other hand, you gain the ability to have differently sized sub-arrays and to change where the pointers point, which is useful if they need to be resized or rearranged. An array of pointers like this can be indexed like a multidimensional array, even though it's allocated and arranged differently and sizeof won't always behave the same way with it. A statically allocated example of this setup would be:
int *arr[3];
int aa[2] = { 10, 11 },
ab[2] = { 12, 13 },
ac[2] = { 14, 15 };
arr[0] = aa;
arr[1] = ab;
arr[2] = ac;
After the above, arr[1][0] is 12. But instead of giving the int found at 1 * 2 * sizeof(int) bytes past the start address of the array arr, it gives the int found at 0 * sizeof(int) bytes past the address pointed to by arr[1]. Also, sizeof(arr[0]) is equivalent to sizeof(int *) instead of sizeof(int) * 2.
In C, there's nothing special you need to know to understand multi-dimensional arrays. They work exactly the same way as if they were never specifically mentioned. All you need to know is that you can create an array of any type, including an array.
So when you see:
int matrix[2][4];
Just think, "matrix is an array of 2 things -- those things are arrays of 4 integers". All the normal rules for arrays apply. For example, matrix can easily decay into a pointer to its first member, just like any other array, which in this case is an array of four integers. (Which can, of course, itself decay.)
If you can use the stack for that data (small volume) then you usually define the matrix:
int matrix[X][Y]
When you want to allocate it in the heap (large volume), the you usually define a:
int** matrix = NULL;
and then allocate the two dimensions with malloc/calloc.
You can treat the 2d array as int** but that is not a good practice since it makes the code less readable. Other then that
**matrix == matrix[0][0] is true

What is pointer to array of integers

In this example, what it means? In my opinion in this, to all the address of array b[] ,array a[] will point correspondingly to all its location ? So do we write it in the following way?
int (*a)[10];
int b[10];
a = &b;
a is a pointer to an array of 10 ints. a=&b; means that a is pointing to array b, i.e, It contains the address of the first byte of b which is the address of array b.
It means a is a pointer to an array of 10 ints. The declaration like this where number of elements is specified is used to make pointers to two-dimensional arrays. Like
int (*a)[10];
int b[][10];
a=b;
If you are creating a pointer to one dimensional array, declaration like this is not necessary. If you have b an array of 10 ints and you want to make a pointer to it simply do this
int *a;
int b[10];
a=b;
Also & is not necessary on arrays because b is already the address of first element in the array. & is only necessary when you want an address of specific member of the array like int *a=&b[5];
a is a pointer to an array of 10 integers.
So, for example, a++ will increase a
by the size of int(ie = 4 bytes)

What is the size of pointer to an array of type int?

I have the following code
#include <stdio.h>
int main(void) {
int arr[] = {10,20,30,40};
int* ptr = arr;
printf("%d\n",sizeof(arr));
printf("%d",sizeof(ptr));
return 0;
}
The output is
16
4
size of pointer in C is 4. 'arr' is also a pointer to an integer but its size comes out to be 16, which is product of size of one element and number of elements.
On the other hand if I store the same pointer into another pointer variable then its size becomes 4. This is very confusing. The same thing happens if I try to send arr as an argument to a function and then print the size of arr in that function. How does C handle a pointer to an array?
'arr' is also a pointer to integer
No, it's not. arr is an array. The size of an array is the size of an element times the number of elements. If it were a pointer, it's size would be the same as any other pointer.
How does C handles pointer of array?
C handles pointers to arrays the same way it handles all other pointers. However there are no pointers to arrays in your code, only a pointer to int (ptr).
A pointer is just a memory address, therefore on 32-bit systems it is always 4 bytes. Depending on the environment it is 4 or 8 bytes on 64-bit systems.
There is no real confusion in your example. arr is an array of 4 32-bit integers, therefore 16 bytes. It is 'handled', or 'passed around', as a pointer to the first int, an int*, which is why you can copy it to other variables of that type, either explicitly or as a parameter. At which time there is no longer a relationship to the original array, and it is just a pointer - 4 bytes on your system.
The best way to look at it is that there is an implicit conversion possible from int[] to int*, like there is from char to int.
When you do sizeof(arr) you will get the size of array which is number of elements * size of int.
When you do sizeof(ptr) you will get the size of pointer which is size of int.
This is very confusing. The same thing happens if I try to send arr as an argument to a function and then print the size of arr in that function.
When you send the array like this foo(arr), you are actually sending the base address of arr. And when we pass address of a variable to a function, it will store the address in a pointer. So again if you try to get the size of arr you'll get the size of pointer.
sizeof only works to find the length of the array if you apply it to the original array.
int a[5]; //real array. NOT a pointer
sizeof(a); // :)
However, by the time the array decays into a pointer, sizeof will give the size of the pointer and not of the array.
int a[5];
int * p = a; // assigning address of the array to pointer
sizeof(p); // :(
It will return always 4 bytes on 32-bit system and 8 bytes on 64-bit system!
Arrays decaying into pointers when they are passed to a function and continuing to keep the array length in the type system.
When you pass an array to a function it decays to pointer. So the sizeof function will return the size of int *
So when you pass the array to the function you need to pass the Number of elements also-
void function (size_t sz, int *arr) { ... }
:
{
int x[20];
function (sizeof(x)/sizeof(*x), x);
}

Resources