sizeof-operator reverse behavior - c

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.

Related

Parameters in the sizeof operator in C

I understand that when we use sizeof operator on an array name, it gives the total size of the array in bytes. For example
int main(int argc, const char * argv[]) {
int a[][5] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
int n=sizeof(a);
printf("%d\n",n);
}
It gives 60 as output for 15 elements of the array. But when I write
int n=sizeof(*a);
It gives 20 as the output that is the size of the first row while *a is the base address of the 0th element of the 0th row, and its type is a pointer to an integer. And a points to the first row itself. Why is this happening?
*a is row 0 of a, and that row is an array of five int.
In most expressions, an array is automatically converted to a pointer to its first element. Thus, when you use *a in a statement such as int *x = *a;, *a is converted to a pointer to its first element. That results in a pointer to int, which may be assigned to x.
However, when an array is the operand of a sizeof operator, a unary & operator, or an _Alignof_ operator, it is not converted to a pointer to its first element. Also, an array that is a string literal being used to initialize an array is not converted to a pointer (so, in char foo[] = "abc";, "abc" is used as an array to initialize foo; it is not converted to a pointer).
*a is not a pointer, it's an int[5], which is coherent with your reading of 20 assuming a 4-byte int.
Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, 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.
The expression a has type "3-element array of 5-element array of int"; thus, sizeof a should yield 3 * 5 * sizeof (int).
The expression *a is the same as the expression a[0] (a[i] is defined as *(a + i) - *a is the same as *(a + 0), which is the same as a[0]). Both *a and a[0] have type "5-element array of int"; thus sizeof *a and sizeof a[0] should both yield 5 * sizeof (int).
However...
If you pass a to a function, such as
foo( a );
then a is not the operand of the sizeof or unary & operators, and the expression will be converted from type "3-element array of 5-element array of int" to "pointer to 5-element array of int":
void foo( int (*a)[5] ) { ... }
If you computed sizeof a in function foo, you would not get 5 * sizeof (int), you would get sizeof (int (*)[5]), which, depending on the platform, would be 4 to 8 bytes.
Similarly, if you passed *a or a[i] to a function, what the function actually receives is a pointer to int, not an array of int, and sizeof will reflect that.
In this 2d array *a is a pointer because when you print it, its seems an address (but it is the 1st column address) :
printf("%d\n", *a);
Output : 9435248
So :
for(int i = 0;i < 3;i++)
printf("%d\n", *a[i]);
The output is :
1
10
100
When you use of *a like this : *a[3] its means you are in 3rd row and 1st column by default.
*a is the address of 1st column and we have 5 column, so when you try this :
sizeof(*a);
Output will be 20 => (5 column) * (int pointer which is 4 byte)).
A 2D array is viewed as an array of 1D arrays. That is, each row in a 2D array is a 1D array. For a given 2D array A, int A[m][n]
you can think of
A[0] as the address of row 0
A[1] as the address of row 1 etc & so on.
Dereferencing can be thought of as below,
A[i][j] = *(A[i] + j) = *(*(A+i) + j)
So when you say *A, it means A[0] which gives you the address of 1st row & not the 1st element of the matrix.
Dereference of A or *A gives the address of row 0 or A[0].
Dereference of A[0] gives the first entry of A or A[0][0] that is
**A = A[0][0].
& since you have 5 elements in the 1st row the size if 20 bytes.
Sizeof returns the size of the variable in memory expressed in bytes. This includes padding (unused bytes added by a compiler to a structure to improve performance). Your array has 15 elements of size 4. The sizeof an integer in memory is 4 in you case. You can easily verify this by running:
printf("sizeof an integer: %zu\n", sizeof(int));
It is always a good idea to use standard int types.
#inlcude <stdint.h>
uint32_t a[][5] = {
{1,2,3,4,5},
{10,20,30,40,50},
{100,200,300,400,500}
};
This will produce exactly the same code but wil clearly show the memory size of the (32 bit) integer.
In your case uint8_t (unsigned int of 8 bit) might be more appropriate. You can read more here. To get the number of elements you should devide the total memory of the array by the sizeof an element.
sizeof(a)/sizeof(a[0])
You can also use a macro to do this:
#define ARRAY_LENGTH(array)(sizeof(array)/sizeof(array[0]))
/*ARRAY_LENGTH(a) will return 15 as expected.*/
You can also look for an answer here: How can I find the number of elements in an array?

Pointers to array of pointers in 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.

Does C compiler allocates memory for variable name used for declaring an array?

Let us take an example :--
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = NULL;
For the variable arr, will there be any memory allocation ??
Now, what will happen if =>
p = arr;
p = &arr;
p = &arr[0];
Please help me out to understand this.
This declaration:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
causes 10 * sizeof (int) bytes to be allocated to hold the 10-element array object. (No space for any pointer object is allocated.) The array is initialized as specified.
int *p = NULL;
creates a single pointer object and initializes it to contain a null pointer value.
p = arr;
arr is an expression of array type. In most contexts, its value is implicitly converted to a pointer to its first element. So this assignment causes p to point to the first (0th) element of arr; *p == 1.
p = &arr;
This is invalid. &arr is of type int(*)[10], or pointer to array of 10 ints. p is of type int*. The types are incompatible. Any conforming C compiler must diagnose this error. (The diagnostic may be a non-fatal warning, but don't let that fool you; it's still an error, what the C standard calls a "constraint violation".)
p = &arr[0];
This is identical to p = arr;. arr[0] is the first (0th) element of the array, an int object with the value 1. &arr[0] is the address of that int object, and is of type char*. So this also causes p to point to the initial element of the array arr.
After this assignment, you can use either arr or p as the prefix for an indexing operator. The indexing operator is actually defined to take a pointer, not an array, as its prefix, so arr[0] uses the result of the array-to-pointer conversion, making it identical to p[0].
But arr and p still cannot always be used interchangeably. For example, sizeof arr gives you the size of the array object (10 * sizeof (int)), while sizeof p gives you the size of a pointer (sizeof (int*)).
Suggested reading: Section 6 of the comp.lang.c FAQ.
(To answer the question in your title, the compiler doesn't, or at least isn't required to, allocate memory at run time for the name of an array. It won't allocate 3 bytes of memory at run time because you named your array arr, or 22 bytes because you called it array_with_a_long_name. It might do so for debugging purposes, but then any such allocated space isn't accessible to your program.)
arr[10] creates locations for 10 ints.
p = arr ;
p= &arr[0] ;
are the same thing.
&arr is not something generally useful. It is a int (*)[10] which the compiler should complain about assigning to p.
In fact, if you do a little test and print out the addresses of these three:
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
gcc ends up giving you the same thing for all three cases.
% ./a.out
X: 7fff906b5b20 7fff906b5b20 7fff906b5b20
But where you can really see the difference is if you ask for each item +1 :
printf("X: %lx %lx %lx\n", (long) arr, (long) &arr, (long) &arr[0]) ;
printf("X+1: %lx %lx %lx\n", (long) (arr +1), (long) ( &arr +1) , (long) ( &arr[0] +1 )) ;
% ./a.out
X: 7fff73c105b0 7fff73c105b0 7fff73c105b0
X+1: 7fff73c105b4 7fff73c105d8 7fff73c105b4
arr +1 is four bytes larger than arr (the size of an int), as is &arr[0] +1, but &arr +1 is forty bytes larger, the size of the entire array.
Storage is not set aside for variable names (arrays or otherwise), except to support debuggers.
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize an array in a declaration, 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 this expression will be the address of the first element of the array.
So, taking your three cases:
p = arr;
The expression arr has type "10-element array of int". Since it is not the operand of either the sizeof or unary & operators, it is converted to an expression of type "pointer to int", or int *, and its value is the address of the first element of the array.
p = &arr;
The expression arr has type "10-element array of int". Since arr is the operand of the unary & operator, the conversion above is not performed; instead, the type of the expression &arr is "pointer to 10-element array of arr", or int (*)[10]. The value is the same as the above expression (the address of the array is the same as the address of the first element of the array), but the types of the two expressions are different (int * vs. int (*)[10]), and types matter for things like pointer arithmetic.
p = &arr[0];
Gives the same type and result as p = arr;.
For your array, storage is set aside as follows:
+----+
arr[0]: | |
+----+
arr[1]: | |
+----+
... ...
+----+
arr[9]: | |
+----+
Note that there is no separate storage for a variable named arr that points to the beginning of the array; that pointer value is inferred from the array expression as described above. You can assign to arr[N], but there's no separate arr to assign anything to (part of the reason why array expressions are non-modifiable lvalues).

How does C retrieve the address of a row for a 2d array

Can someone explain to me how C retrieves the correct memory address for a row when you only use one subscript to access a 2d array?
Example -
int array2D[2][2] = {1,2,3,4};
printf ( "starting address of row2 = %p" , array2D[1]);
I understand that when subscripting in C that what is actually going on is pointer addition so for a 1d array the array name points to element 0. In this case if I had wanted element 1 the compiler would take the starting address (say 4000) and add 4 to it (assuming a 4 bit int) so that what is returned is the item at memory address 4004.
My understanding is that when you populate a 2d array, as in my example, they are allocated sequentially so I would have
1 2
3 4
at addresses
4000 4004
4008 4012
So how does C work out that in this case array2D[1] should point to 4008 and not 4004? Does it run a sizeof() operator or have I misunderstood a fundamental here?
Thanks in advance
C knows how long each row is, so it does the multiplication to find the row.
int x[][3] = {{1,2,3},{4,5,6}};
then &x[1][0] is &x[0][0] plus 3 * sizeof(int).
That's why in a multidimensional C array declaration, all but the first dimension must be specified.
Pointer arithmetic depends on the type of the element being pointed to. Given a pointer p to type T, p + 1 points to the next element of type T, not necessarily the next byte following p. If T is char, then p + 1 points to the next char object after p, which starts at the byte immediately following p; if T is char [10], then p + 1 points to the next 10-element array of char after p, which starts at the 10th byte following p.
The type of the expression array2d in is "2-element array of 2-element array of int", which "decays" to type "pointer to 2-element array of int", or int (*)[2]1. Thus the expression array2d[1] is interpreted as *(array2d + 1). Since array2d points to an object of type int [2], array2d + 1 points to the next 2-element array of int following array2d, which is 2 * sizeof int bytes away from array2d.
1. Except when it is the operand of the sizeof 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" will be converted to an expression of type "pointer to T" and its value will be the address of the first element in the array.
This is going to be a bit long-winded, but bear with me still.
Array subscription is just a shorthand: (p[N]) equals (*(p + N)) in all contexts for pointer types (both are invalid expressions for void*, though).
Now, if p is an array type, it would decay to a pointer type in an expression like (*(p + N)); an int[2][2] would decay into a pointer of type (*)[2] (i.e. a pointer to an int[2]).
Pointer arithmetic takes types into account; we need to convert things to char* to visualize what the compiler does to us:
T *p;
p[N] equals *(p + N) equals *(T*)((unsigned char*)p + N * sizeof *p)
Now, if T were an int[2] (to equal the situation we described above), then sizeof *p would be sizeof(int[2]), i.e. 2 * sizeof(int).
This is how subscription works in so-called multidimensional arrays.
sizeof(array2D[1]) == 8;
if array2D address is 4000;
so array2D[1] address is 4000+sizeof(array2D[1]) == 4000+8;

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