How does sizeof operator behaves in below code snippet? - c

Please explain the OP for below code snippet :
int *a="";
char *b=NULL;
float *c='\0' ;
printf(" %d",sizeof(a[1])); // prints 4
printf(" %d",sizeof(b[1])); // prints 1
printf(" %d",sizeof(c[1])); // prints 4
Compiler interprets a[1] as *(a+1) , so a has some address , now it steps 4 bytes ahead , then it will have some garbage value there so how is the OP 4 bytes , even if I do a[0] , still it prints 4 , although it is an empty string , so how come its size is 4 bytes ?
Here we are finding out the size of the variable the pointer is pointing to , so if I say size of a[1] , it means size of *(a+1), Now a has the address of a string constant which is an empty string , after I do +1 to that address it moves 4 bytes ahead , now its at some new address , now how do we know the size of this value , it can be an integer , a character or a float , anything , so how to reach to a conclusion for this ?

The sizeof operator does not evaluate its operand except one case.
From the C Standard (6.5.3.4 The sizeof and alignof operators)
2 The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand. The result is an integer.
If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the
result is an integer constant.
In this code snippet
int *a="";
char *b=NULL;
float *c='\0' ;
printf(" %d",sizeof(a[1])); // prints 4
printf(" %d",sizeof(b[1])); // prints 1
printf(" %d",sizeof(c[1])); // prints 4
the type of the expression a[1] is int, the type of the expression b[1] is char and the type of the expression c[1] is float.
So the printf calls output correspondingly 4, 1, 4.
However the format specifiers in the calls are specified incorrectly. Instead of "%d" there must be "%zu" because the type of the value returned by the sizeof operator is size_t.
From the same section of the C Standard
5 The value of the result of both operators is implementation-defined,
and its type (an unsigned integer type) is size_t, defined in
<stddef.h> (and other headers).

This is all done statically, i.e. no dereferencing is happening at runtime. This is how the sizeof operator works, unless you use variable-length arrays (VLAs), then it must do work at runtime.
Which is why you can get away with sizeof:ing through a NULL pointer, and other things.
You should still be getting trouble for
int *a = "";
which makes no sense. I really dislike the c initializer too, but at least that makes sense.

sizeof operator happens at compilation (except for VLA's). It is looking at the type of an expression, not the actual data so even something like this will work:
sizeof(((float *)NULL)[1])
and give you the size of a float. Which on your system is 4 bytes.
Live example
Even though this looks super bad, it is all well defined, since no dereference ever actually occurs. This is all operations on type information at compile time.

sizeof() is based on the data type, so whilst it's getting the sizes outside the bounds of memory allocated to your variables, it doesn't matter as it's worked out at compile time rather than run time.

Related

Explanation of output of program

Can anyone explain why this program prints 4 1 instead of 4 2?
Shouldn't pre increment operator which has higher precedence get executed first and print 4 2?
#include <stdio.h>
int main() {
int a=1;
printf ("%ld %d",sizeof(++a),a);
return 0;
}
Although you've already gotten several answers, I want to provide one more, because your question actually contained three separate misunderstandings, and I want to touch on all of them.
First of all, sizeof is a special operator which, by definition, does not evaluate its argument (that is, whatever subexpression it's taking the size of). So sizeof(++a) does not increment a. And sizeof(x = 5) would not assign 5 to x. And sizeof(printf("Hello!")) would not print "Hello".
Second, if we got rid of the sizeof, and simply wrote
printf("%d %d", ++a, a);
we would not be able to use precedence to figure out the behavior. Precedence is an important concept, but in general it does not help you figure out the behavior of confusing operations involving ++.
Finally, the perhaps surprising answer is that if you write
printf("%d %d", ++a, a);
it is not possible to figure out what it will do at all. It's basically undefined. (Specifically: in any function call like printf("%d %d", x, y) it's unspecified which order the arguments get evaluated in, so you don't know whether x or y gets evaluated first -- although there is an order. But then, when one of them is a and one of them is ++a, you have a situation where a is both being modified and having its value used, so there's no way to know whether the old or the new value gets used, and this makes the expression undefined. See this question for more on this issue.)
P.S. One more issue I forgot to mention, as noted by #Vlad from Moscow: %ld is not a reliable way to print the result of sizeof, which is a value of type size_t. You should use %zu if you can, or %u after casting to (unsigned) if you can't.
From the C Standard *6.5.3.4 The sizeof and alignof operators)
2 The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand. The result is an integer. If
the type of the operand is a variable length array type, the operand
is evaluated; otherwise, the operand is not evaluated and the result
is an integer constant.
So the task of the sizeof operator is to determine the type of the expression used as an operand and then knowing the type of its operand to return the size of an object of the type. If the operand is not a variable length array then the expression used as an operand is not evaluated and the value returned by the sizeof operator is calculated at compile-time.
Thus this call
printf ("%ld %d",sizeof(++a),a);
is equivalent to the call
printf ("%ld %d",sizeof( int ),a);
and in your system sizeof( int ) is equal to 4.
So it does not matter what expression is used (except using a variable length array the size of which is calculated at run time) as an operand. It is the type of the expression that is important. For example you could even write
printf ( "%zu %d\n", sizeof( ( ++a, ++a, ++a, ++a, ++a ) ), a );
and got the same result.
Pay attention to that you should use the conversion specifier zu used for values of the type size_t instead of ld used for signed values. That is you need to write
printf ("%zu %d",sizeof(++a),a);
According to c99 standard,
the sizeof() operator only takes into account the type of the operand, which may be an expression or the name of a type (i.e int, double, float etc) and not the value obtained on evaluating the expression.
Hence, the operand inside the sizeof() operator is not evaluate.

Meaning of &st[3]-st in printf("%ld", &st[3]-st)

I'm new to C and in an exercise, I have to write the output of the following portion of code, which is 3. But I couldn't understand why it is that.
int main() {
char st[100]="efgh";
printf ("\n%ld\n",&st[3]-st);
return 0;
}
When you use an array in an expression, unless it is the argument of & or sizeof, it evaluates to the address of its first element.
Thus &st[3] - st evaluates as &st[3] - &st[0], which is just pointer arithmetic: The difference between the addresses of two array elements is just the difference between their indices, i.e. 3 - 0, which gives 3.
The only problem is that the result is of type ptrdiff_t, but printf %ld expects a long int. If those types are different on your machine, it won't work. In a printf() format string, the correct length modifier for ptrdiff_t is t — use "\n%td\n".
By definition, &st[3] is the same as st+3. st+3-st is 3. (st in that expression decays from array to a pointer. For portability, the printf format string should technically have %td instead of %ld.)

the size of dynamically allocated array in C [duplicate]

This question already has answers here:
Behavior of sizeof on variable length arrays (C only)
(2 answers)
Closed 5 years ago.
I know that this question has been asked before, but my question is more specific,
here is the code:
#include <stdio.h>
#include <time.h> /* must be included for the time function */
main()
{
time_t t = time(NULL);
srand((unsigned) t);
int i = rand();
int a[i];
printf("%d\n", i); /* ouptut: 18659 */
printf("%d\n", sizeof a); /* output: 74636 */
}
I compiled this code using gcc and -ansi option to restrict it to recognize the ANSI C only.
I know that there is no way that the compiler could know at compile-time the size of the array because it's determined randomly at run-time.
Now my question is is the value returned by sizeof is just a random value, or it has a meaning?
The sizeof operator is evaluated at compile time for most operands. In the case of a VLA, it is evaluated at runtime.
From section 6.5.3.4 of the C standard:
2 The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The
size is determined from the type of the operand. The result is an
integer. If the type of the operand is a variable length array type,
the operand is evaluated; otherwise, the operand is not evaluated and
the result is an integer constant
So the size returned by sizeof is the size in bytes of the VLA. In your example, that would be i * sizeof(int)
The value returned by sizeof is a pseudo-random value that has a meaning:
The value represents the size of VLA a, in bytes
It is random only in the sense that the number of array elements is determined by a call to rand.
It appears that sizeof(int) on your system is 4, because the number returned by sizeof is four times the number of elements in the array.
Note: One of the consequences of allowing VLAs in C99 is that sizeof is no longer a purely compile-time expression. When the argument of sizeof operator is a VLA, the result is computed at run-time.
From the gcc manual
The -ansi option does not cause non-ISO programs to be rejected gratuitously. For that, -Wpedantic is required in addition to -ansi.
is the value returned by sizeof is just a random value, or it has a meaning?
It does have a meaning, as 74636 / 18659 = 4, which apparently is the size of int on your machine.
So sizeof (which will be computed at run-time instead of compile-time since the argument is a VLA), will return the size of array a in bytes, which is the number of ints it contains (in other words i or 18659) multiplied by the size of int, which is 4 on your machine.
As i (the result of rand) is random, you can consider that the value of sizeof will be random too in that sense.

Storage of variables and dereferencing them

Based on the following snippet in C
int c1,c2;
printf("%d ",&c1-&c2);
Output : -1
Why does this code not return a warning saying the format %d expects of type int but it's getting a (void *) instead.
Why does it return -1 as an answer(and not 1)? Even if it's subtracting addresses it should be -4 and not -1. When I change the printf statement to printf("%d ",&c2 - &c1) I get 1 and not any random value! Why?
If I change the printf statement as printf("%d ",(int)&c1 - (int)&c2) am I typecasting an address to an integer value? Does that mean the value of the address stored as hexadecimal is now converted to int and then subtracted?
1) It's getting an int. Pointer-to-something minus pointer-to-something is an integer value (type ptrdiff_t). It tells you how many elements away are two pointers pointing into the same array.
2) As the two pointer do not point into the same array, the difference is undefined. Any value can be obtained.
3) Yes. But the "hexadecimal" part is incorrect. Addresses are stored in bits/binary (as are integers). What changes is the interpretation by your program. This is independent of the representation (hex/dec/oct/...).
There are multiple cases of undefined behavior here.
If we go to the draft C99 standard section 6.5.6 Additive operators it says (emphasis mine):
When two pointers are subtracted, both shall point to elements of the
same array object, or one past the last element of the array object;
the result is the difference of the subscripts of the two array
elements. The size of the result is implementation-defined, and its
type (a signed integer type) is ptrdiff_t defined in the
header. If the result is not representable in an object of that type,
the behavior is undefined.
Although, what you have is undefined behavior since the pointers do not point to elements of the same array.
The correct format specifier when using printf for ptrdiff_t would be %td which gives us a second case of undefined behavior since you are specifying the incorrect format specifier.
1) A void* is nothing but an adress. An adress is an number (a long). There, the adress is implicitly cast to an int.
2) In memory, your variable aren't store in the same order than in
your code ;). Furthemore, for the same reason :
int a[2];
a[0] = 3;
*(a + 1) = 5; // same that "a[1] = 5;"
This code will put a "5" in the second case. Cause it will actually do :
*(a + 1 *sizeof(*a)) = 5;
3) Hexadecimal is a number representation. It can be store in a int ! Example :
int a = 0xFF;
printf("%d\n", a); // print 255
I hope that i have answered your questions.
1) Some compilers do issue warnings for malformed printf arguments, but as a variadic function, the run-time has no way of checking that the arguments are of the type specified by the format string. Any mismatch will issue undefined behaviour as the function attempts to cast such an argument to an incorrect type.
2) You say the result should be -4 but that's not correct. Only arrays are guaranteed to have their pointers aligned contiguously. You cannot assume that c2 is at (&c1 + 1).
3) (int)&c1 is converting the address of c1 to an int. That's again, in general, undefined behaviour since you don't know that int is big enough to hold the pointer address value. (int might be 32 bits on a 64 bit chipset). You should use intptr_t in place of the int.

why sizeof unsigned char array[10] is 10

The size of char is 1 byte, and wikipedia says:
sizeof is used to calculate the size of any datatype, measured in the
number of bytes required to represent the type.
However, i can store 11 bytes in unsigned char array[10] 0..10 but when i do sizeof(array) i get 10 bytes. can someone explain explain this behavior?
note: i have tried this on int datatype, the sizeof(array) was 40, where i expect it to be 44.
However, i can store 11 bytes in unsigned char array[10]
No, you cannot: 10 is not a valid index of array[10]. Arrays are indexed from zero to size minus one.
According to C99 Standard
6.5.3.4.3 When [sizeof operator is] applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1.
That is why the result is going to be ten on all standard-compliant platform.
No, the valid indices will be 0-9 not 0-10, it will store 10 elements not 11, so the result of sizeof is correct. Accessing beyond index 9 will be out of bounds and undefined behavior, the relevant section of the C99 draft standard is 6.5.6/8, which covers pointer arithmetic:
[...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
Unlike the C++ standard which explicitly states an array has N elements numbered 0 to N-1 it looks like you need to dig into the examples for a similar statement in the C standard. In the C99 draft standard section 6.5.2.1/4, the example is:
int x[3][5];
and it goes on to state:
Here x is a 3 x 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints.
unsigned char array[10];/*Array of 10 elements*/
which means
array[0],array[1],array[2],array[3].......array[9]
so sizeof(array)=10 is correct.

Resources