Pointers to array of pointers in c - c

Can someone please explain me what is the difference between the two following declarations:
char (*arr_a)[5];
char arr_b[20];
and why:
sizeof (*arr_b) = sizeof (char)
sizeof (*arr_a) = 5*sizeof(char)

char (*arr_a)[5];
declares a pointer to a 5-element array of char.
char arr_b[20];
declares just a 20-element array of char.
So, the output of
sizeof (*arr_a)
should be straight forward -- dereferencing the pointer to an array yields the array and it's size is 5.
The following:
sizeof (*arr_b)
gives 1, because dereferencing the identifier of an array yields the first element of that array, which is of type char.
One thing you need to know to fully understand this is how an array evaluates in an expression:
In most contexts, the array evaluates to a pointer to its first element. This is for example the case when you apply indexing to the array. a[i] is just synonymous to *(a+i). As the array evaluates to a pointer, this works as expected.
There are exceptions, notably sizeof, which gives you the storage size of the array itself. Also, _Alignof and & don't treat the array as a pointer.

arr_a is a pointer to an array of 5 char while arr_b is an array of 20 chars. arr_b is not a pointer unlike arr_a.
sizeof (*arr_b) equals to sizeof (char) because *arr_b is of type char (equivalent to arr_b[0]). For
sizeof (*arr_a) equals to 5*sizeof(char) because *arr_a refers to an array of 5 chars and sizeof returns the size of array which is 5.

Related

sizeof-operator reverse behavior

we know that when we use array it hold address of first element and &array is store whole array address its true when i use in printf but in sizeof operator it is reverse behavior why
i am using code-block with GCC on windows 7
int main(void)
{
int c[5];
printf(" %d %d %d %d\n",c,c+1,&c,&c+1);\\when we add 1 in "c" it add more 4 bytes and when "&c+1" it add 20 byte witch is true
printf(" %u %u ",sizeof(c),sizeof(&c));\\But when we print first element size (with "c") it give 20 byte and when print (With "&c") whole arry size it give 4 byte
return 0;
}
\i cant understand why please explain
I think what you need to know here is, &array is still a pointer, just the type differs.
For an array like int arr[]={4,3,2,1,0}
Most cases, arr is same as &arr[0], i.e., int *, but with sizeof operator, it behaves differently (see note below). When passed to sizeof operator, it gives you the size of the whole array, i.e., sizeof(int [4]) in this case.
&arr is of type int (*)[4], and it's a pointer.
So, to get the number of elements in the array, you should do something like
printf ("Number of elements = %zu", sizeof(arr)/sizeof(arr[0]));
/ *(size of the entire array / size of one element in the array) */
Quoting C11, chapter §6.3.2.1 (emphasis mine)
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
That said,
sizeof yields a result of type size_t, you should use %zu format specifier to print the result.
to print a pointer to an object, you must use %p format specifier and cast the corresponding argument to void *.
First off, if you want to print the result of sizeof, the correct format is %zu. sizeof gives you a size_t, not an int. To print a pointer, use %p and cast the argument to (void *).
Second, to get the number of elements in an array, it's sizeof arr / sizeof arr[0] (size of the whole array divided by the size of a single element, which could also be written sizeof arr / sizeof *arr).
That said, the thing you're asking about has nothing to do with arrays, really. For example, if you do
char c;
then sizeof &c will be 4 (on a 32-bit platform), but &c + 1 will give you a memory address that's 1 byte higher than &c, not 4 bytes.
This is because pointer arithmetic is done in units of the pointed-to type (not the type of the pointer itself). That is, you need to compare ptr + 1 and sizeof *ptr (or &var + 1 and sizeof var).
In your code, three of the four expressions are straightforward:
sizeof &arr is 4 because the type of &arr is "pointer to array of 5 ints" and you are on a 32-bit platform, so pointers are 4 bytes.
sizeof arr is 20 because the type of arr is "array of 5 ints" and int is 4 bytes big on your platform, so the array takes 5 * 4 = 20 bytes.
&arr + 1 gives you the memory address one past arr. It's like asking "if arr were an element of an array, where would the next element start?". Since arr is 20 bytes big, the memory address one past arr is 20 bytes higher.
That leaves the odd one:
arr + 1 compiles because arr decays to a pointer here. That is, because the array is not the operand of sizeof or &, it evaluates to a pointer to its first element, like &arr[0]. And in &arr[0] + 1 the pointed-to type is int, so adding 1 means stepping to the next int in memory, which is 4 bytes away.

Difference between *array and array[0] when calculating number of array elements in C

For the given array:
int array[10];
What is the difference between
sizeof array / sizeof *array
and
sizeof array / sizeof array[0]
when calculating the number of elements in array?
There is none in this case. Both ultimately results in the type int because in the first case array decays into pointer to the first element when used as an operand of *(You are dereferencing a int*).
Note one thing - you might have heard that on sizeof there is no decay of arrays but here the decay happens when array is used as operand to *. The operand for sizeof is simply int. (Discussing about sizeof arr/sizeof *arr)
In case you want to get a clear idea - try this
int a[10][20];
printf("%zu %zu\n",sizeof a/ sizeof *a, sizeof a/ sizeof **a);
Your second case is WYSIWYG type of thing - what I mean by this, it just says total size of the array and divide it with what it contains (the size of it). And yes it would return the size of the array. That is what is being done.
arr[0] is nothing but *(arr+0) means *arr. So that makes sense and they are same.
Few points that will clarify things (If you later use sizeof)
array and &array[0] is same in this context. Their value and type both will be same. But For pointers being the same value is just one thing - their implication on the pointer arithmetic is a whole different story.
int a[10][20]; Here a and &a and a[0] all has same value but their type is different and since pointer arithmetic is closely coupled with what it points to. It matters.
The expression array[n] is by definition the same as *(array + n)
The expression array + 0 is by definition the same as array (unless array is an operand of sizeof).
So yes, array[0] and *array are the same.
This is much more than is needed in this case. For arguments of sizeof only the type matters, and it is certainly the same for both expressions.
For some additional information:
In C the reference to the start address of the array is given by the name without the brackets []:
array
At the array address the first element is listed in memory, so both :
*array and array[0] give the first element of the array.
Moreover, these addresses will also be equal:
array == &array[0]

Why isn't this pointer arithmetic allowed in C? [duplicate]

This question already has answers here:
Is array name a constant pointer in C++?
(2 answers)
Closed 6 years ago.
char arr[] = "Hello";
arr = arr + 1; // error occurs
As far as I know, an expression that has array type is converted to pointer type that points to the initial element of the array. Therefore, I expected arr = arr + 1 (pointer to first element(arr) of the array becomes the pointer to the second element of the array)to work. Why doesn't this work in C?
arr + 1 is indeed a pointer to the second element of the array (i.e. &arr[1]).
However, that does not mean that you can somehow write that pointer value back into arr. You can't do it for at least two reasons.
Firstly, arr is an array of char elements, not a pointer. There's an obvious type mismatch here.
Secondly, being an array, arr a non-modifiable lvalue. You cannot change arr itself, you can only change its elements (this distinction is somewhat hard to grasp, but it is there).
Finally, if we just ignore the deeper intricacies and focus on what formally happens at the top level, due to array type decay your expression is equivalent to
(char *) arr = (char *) arr + 1;
The assignment is impossible since the left-hand side is a result of [implicit] type conversion. In C type conversions always produce rvalues. You cannot assign to rvalues.
In other words, it is not the "pointer arithmetic" that's disallowed here. The pointer arithmetic is fine. It is what you do with the result of that pointer arithmetic that causes the error.
Arrays are non-modifiable lvalues. They can't be the left operand of an assignment operator.
C11-§6.3.2.1:
A modifiable lvalue is an lvalue that
does not have array type, does not have an incomplete type, [...]
§6.5.16/2:
An assignment operator shall have a modifiable lvalue as its left operand.
In the statement
arr = arr + 1;
arr is the left operand of = operator and is of array type. It can't be modified.
So, it's not the pointer arithmetic but the constraint by the language on the assignment operator that is the reason for syntactical error.
Note that in some contexts arrays decay to a pointer to its first element, though pointers and arrays are different types. Arrays are not pointers. It is only the pointer arithmetic and array indexing which are equivalent. For example
char *ptr = &arr[0] + 1 => &(*(arr + 0)) + 1 => &(*arr) + 1 => arr + 1 // * and & nullify each other
This is because arrays are similar to pointers except that they can not be modified. However you can modify a pointer that is pointing to an array. For the above example you can do like this:
char arr[]="Hello";
char *ptr=arr;
ptr=ptr+1;
Initially the pointer ptr will be pointing to the first character of the array i.e. 'H' and after modifying the value it will point to the second character i.e. 'e'. You can also do the following:
char arr[]="Hello";
char *ptr=arr;
ptr=arr+1;
Both produce the same effect which shows that arr+1 is indeed pointer arithmetic. However you can not modify the value of arr because its type is that of a character array and not pointer to a character array.
As far as I know, an expression that has array type is converted to pointer type that points to the inital element of the array.
It is true in most contexts. It is not true in the following contexts:
When using the addressof operator (&arr). The type of &arr is char (*)[6]. It is not char**.
When using the sizeof operator. sizeof(arr) is 6. Had it been a pointer, it would be the size of a pointer (4 or 8 in most common platforms).
When used as the LHS of an assignment operator. A variable of array type is not modifiable.
Therefore, I expected arr = arr + 1 (pointer to first element(arr) of the array becomes the pointer to the second element of the array)to work. Why doens't this work in C?
The RHS of the expression evaluates to a pointer to the second element of arr. However, that line does not work due to (3) above. arr is not a modifiable value. It cannot be used as the LHS of an assignment operator.
char[] is not pointer, while char* is a pointer.
This works, but it is wrong solution:
int main()
{
char *arr = "Hello";
arr = arr + 1; // Wrong!
printf("%s\n", arr); // Output: ello
}
If arr is heap-allocated with malloc you can get memory leak if free memory starting arr+1 not arr.
But you can do something like this:
int main()
{
char arr[] = "Hello";
char *wordFromSecondLetter = &arr[0] + 1;
printf("%s\n", wordFromSecondLetter); // Output: ello
}
Or like this
int main()
{
char arr[] = "Hello";
printf("%s\n", &arr[1]); // Output: ello
}
Because arr is not a pointer but a char array. You can verify this by checking sizeof arr. To get a pointer to char, you should use char *arr = "Hello";.
The biggest difference between a pointer and an array is that you can directly assign a value to a pointer, but you can't do this to an array.
In fact, when you write arr + 1, arr "decays" to the pointer to its first element, that is to say, arr == &arr[0]. So arr + 1 is legal pointer arithmetic, but giving its value to arr, which is an array, is illegal.

how does p become a 2-D array after the call to malloc?

The following snippet declares a 2-D array of 4 X 10 using malloc function
/* Declare a pointer to an array that has 10
ints in each row. */
int (*p)[10];
register int i, j;
/* allocate memory to hold a 4 x 10 array */
p = malloc(40*sizeof(int));
But I do not understand how does p become a 2-D array. Initially p is declared to be an array of pointers that point to int. What happens after the call to malloc ? I am unable understand this.
In C, pointers and arrays are not the same, despite looking very similar. Here p is of type "pointer to array of 10 ints". You're using it as a "pointer to array of 4 arrays of 10 ints", which is a single block of memory (the only pointer is the outermost pointer). It's basically a dynamically allocated int[4][10].
The trick to reading these definitions is to realize that they're written the same way you use the item. If you have:
*x[10];
The array subscript is applied first, then the pointer dereference. So it's an array of pointers if you define int *x[10]. If you use parenthesis to override normal precedence, you can get the pointer dereference to happen first, so you have a pointer to an array.
Confusing? It gets worse. In function arguments, the outermost array of a function parameter is converted into a pointer.
int *p[10]; // array of 10 pointer to int
int (*p)[10]; // pointer to array of 10 ints
void foo(int *p[10] /* pointer to pointer to int */);
void foo(int (*p)[10] /* pointer to array of 10 ints */);
Further, arrays are converted to pointers when you use them.
int x[10]; // array of 10 int
sizeof(x); // 10 * sizeof(int)
int *y = x; // implicitly converts to a pointer to &x[0]!
sizeof(y); // sizeof(int *)
This means that you can allocate memory for an array of arrays, then let that implicitly convert to a pointer to an array, which you in turn use as if it were an array of arrays!
Anyway, this is all very confusing so please do not ever use this in production code - at least, not without a clarifying typedef:
typedef int vector[3];
vector *array_of_vectors; // actually a pointer to a vector,
// but you can use it as an aray to a vector if enough
// memory is allocated
The memory, worth 40 ints, is reserved to the pointer p. p points at his memory block. It so happens that p chooses to organize this memory as 10 equal parts, each of which happen to hold 4 ints' worth.
That's if this code is actually correct. My C is very rusty at this point.
First, some background information:
Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T", and its value is the address of the first element in the array. For example, given the array
int a[10];
anytime the expression a appears in the code, its type will be converted from "10-element array of int" to "pointer to int", or int *, except for cases like sizeof a, _Alignof a, and &a. If we have a 2D array of T, such as
int a[10][10];
the expression a will be converted from type "10-element array of 10-element array of int" to "pointer to 10-element array of int", or int (*)[10] (look familiar? that's the type of your pointer p).
If we want to dynamically allocate an N-element array of type T, we write something like
T *p = malloc(N * sizeof *p);
sizeof *p is equivalent to sizeof (T). In this particular case, type T is "10-element array of int", or int [10]. We want to allocate 4 such arrays, so we can write
int (*p)[10];
p = malloc(4 * sizeof *p);
This allocates space for 4 10-element arrays of int, and assigns the result to p. (sizeof *p == sizeof (int [10])).
So how does this become a 2D array?
Remember that the expression a[i] is equivalent to *(a + i); we find the address of the i'th element of type T following a and dereference the result. In this case p[i] gives us the address of the ith 10-element array of int following p. Since we dereference the pointer as part of the subscript operation, the type of the expression p[i] is "10-element array of int". Thus we can subscript this expression again and get p[i][j].

C pointer : array variable

I read this in my book (and many sources on the internet):
The array variable points to the first element in the array.
If this true, then the array variable and the first element are different. Right?
It means by below code, it will produce two different results:
int main(){
char msg[] = "stack over flow";
printf("the store string is store at :%p\n",&msg);
printf("First element: %p\n",&msg[0]);
}
But I receive the same results for the two cases. So, by this example, I think we should say: the array variable is the first element. (because it has the same address)
I don't know if this true or wrong. Please teach me.
The array variable signifies the entire memory block the array occupies, not only the array's first element. So array is not the same as array[0] (cf. sizeof array / sizeof array[0]). But the array's first element is located at the same memory address as the array itself.
Saying the array points to the first element is also incorrect, in most circumstances, an array expression decays into a pointer to its first element, but they are different things (again cf. sizeof for example).
They point to the same address, i.e. printf will show the same value but they have different types.
The type of &msg is char(*)[16], pointer to array 16 of char
The type of &msg[0] is char *, pointer to char
A cheap way to test this is to do some pointer arithmetic. Try printing &msg + 1.
This C FAQ might prove useful.
The array variable is the whole array. It decays into a pointer to the first element of the array.
If you look at the types:
msg is of type char [16]
&msg is of type char (*)[16]
&msg[0] is of type char *
So in a context where msg can decay into an array, for example when passed as an argument, its value would be equal to &msg[0].
Let me draw this:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|s|t|a|c|k| |o|v|e|r| |f|l|o|w|\0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
Imagine the starting point of this array, where 's' is located is address 0x12345678.
msg itself, refers to the whole 16 bytes of memory. Like when you say int a;, a refers to 4 bytes of memory.
msg[0] is the first byte of that 16 bytes.
&msg is the address where array begins: 0x12345678
&msg[0] is the address of first element of array: 0x12345678
This is why the values of &msg and &msg[0] are the same, but their types are different.
Now the thing is, msg by itself is not a first class citizen. You cannot for example assign arrays. That is why, in most of the cases, the array will decay into its pointer.
If you know function pointers, this is very similar:
int array[10];
int function(int);
In int *var = array, array decays to a pointer (&array)
In void *var = function, function decays to a pointer (&function)
Note that, in case of function pointers, we like to keep the type, so we write:
int (*var)(int) = function;
Similarly, you can do with arrays:
int (*var)[10] = array;
char myChar = 'A'
char msg[] = 'ABCDEFGH'
When you type myChar you get value.
But with msg you get pointer to first char(for values you have to use msg[x])
msg = &msg[0]
This can help you to understand, I think.
Look at it this way:
&msg = 0x0012
&msg[0] = 0x0012
&msg[1] = 0x0013
In this case &msg[1] is pointing to msg+1. When you reference &msg or &msg[0] you are referring to the same address of memory because this is where the pointer starts. Incrementing the array variable will increment the pointer by +1 since a char variable is only 1 byte in size.
If you do the same trick with say an integer you will increment the pointer by +4 bytes since an integer is 4 bytes in size.
When you use an array expression, the compiler converts it to a pointer to the first element. This is an explicit conversion specified by the 1999 C standard, in 6.3.2.1 3. It is a convenience for you, so that you do not have to write &array[0] to get a pointer to the first element.
The conversion happens in all expressions except when an array expression is the operand of sizeof or the unary & or is a string literal used to initialize an array.
You can see that an array and its first element are different by printing sizeof array and sizeof array[0].
In most circumstances, an expression of array type ("N-element array of T") will be replaced with / converted to / "decay" to an expression of pointer type ("pointer to T"), and the value of the expression will be the address of the first element in the array.
So, assuming the declaration
int a[10];
the type of the expression a is "10-element array of int", or int [10]. However, in most contexts, the type of the expression will be converted to "pointer to int", or int *, and the value of the expression will be equivalent to &a[0].
The exceptions to this rule are when the array expression is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration.
So, based on our declaration above, all of the following are true:
Expression Type Decays to Value
---------- ---- --------- -----
a int [10] int * address of the first element of a
&a int (*)[10] n/a address of the array, which is the
same as the address of the first
element
&a[0] int * n/a address of the first element of a
*a int n/a value of a[0]
sizeof a size_t n/a number of bytes in the array
(10 * sizeof (int))
sizeof &a size_t n/a number of bytes in a pointer to
an array of int
sizeof *a size_t n/a number of bytes in an int
sizeof &a[0] size_t n/a number of bytes in a pointer to int
Note that the expressions a, &a, and &a[0] all have the same value (address of the first element of a), but the types are different. Types matter. Assume the following:
int a[10];
int *p = a;
int (*pa)[10] = &a;
Both p and pa point to the first element of a, which we'll assume is at address 0x8000. After executing the lines
p++;
pa++;
however, p points to the next integer (0x8004, assuming 4-byte ints), while pa points to the next 10-element array of integers; that is, the first integer after the last element of a (0x8028).

Resources