why the following output? - c

I am using gcc and written a small program as under:
#include<stdio.h>
void doing(){
char buf[4096 + 1];
printf("buf %d\n", buf);
printf("buf %f\n", buf);
printf("buf %d\n", (unsigned) buf);
printf("buf %s\n", buf+2);
printf("buf %d\n", buf+2);
}
int main (void){
char buf[4096 + 1];
printf("(unsigned) buf %d\n", (unsigned) buf);
doing();
printf("(unsigned) buf %d\n", (unsigned) buf);
return 0;
}
The Output of the program is:
(unsigned) buf 2268303
buf 2264159
buf 0.000000
buf 2264159
buf
buf 2264161
(unsigned) buf 2268303
I don't know why printing 2268303 as integer and where from this 2268303 value comes and one function is giving the value as 2268303 and another 2264159

Let's break it down a bit and see what we can say about each line of code, one after the other:
int main (void){
char buf[4096 + 1];
You declare a char[4097], that is typically allocated on the stack by adjusting the stack pointer when main is entered. The contents of the array are indeterminate.
printf("(unsigned) buf %d\n", (unsigned) buf);
An expression of array type, unless it is the operand of the address (&), sizeof or _Alignof operators, or it is a string literal used to initialise a character array, is converted to a pointer to the array's first element (6.3.2.1 p. 3), so that line is equivalent to
printf("(unsigned) buf %d\n", (unsigned) &buf[0]);
takes the address of the first byte in buf, converts it to unsigned and prints the resulting number as a signed integer. Note that the behaviour is undefined if the resulting unsigned value is not representable as an int. The conversion of the pointer &buf[0] to unsigned is implementation-defined, and may invoke undefined behaviour (6.3.2.3 p. 6). Typically, sizeof(unsigned) bytes of the pointer value are interpreted as an unsigned integer (typically includes that the size of a pointer is not smaller than the size of an unsigned). In your case, the result was that
(unsigned) buf 2268303
was printed. Next
doing();
So let's look at doing:
void doing(){
char buf[4096 + 1];
Another char[4097] is declared, typically it is allocated by adjusting the stack pointer when doing is entered. The contents of this array are also indeterminate.
printf("buf %d\n", buf);
Again, the expression buf of type char[4097] is converted to a char*, namely &buf[0], and that is passed to printf which expects an int argument. The type mismatch invokes undefined behaviour, commonly sizeof(int) bytes of the pointer value are interpreted as a signed integer. The result is the ouptut
buf 2264159
which strongly hints that the buf in doing was allocated 4144 bytes away from main's and the stack grows downward.
printf("buf %f\n", buf);
Once again we have the array-to-pointer conversion, and now printf expects a double argument but gets a char*. More undefined behaviour, the manifestation is that
buf 0.000000
is printed. How that comes cannot be answered in general (after all, it's undefined behaviour), on 64-bit systems, a common behaviour is that printf arguments of pointer or integral types are passed in general purpose registers, and floating point arguments in floating point registers, so that printf would read a floating point register - which happens to contain a 0 value.
printf("buf %d\n", (unsigned) buf);
This line has the same semantics as the corresponding line of main, but since it's a different array buf, the (unsigned) integer obtained from the conversion is different.
buf 2264159
it prints the same as the first printf in doing, which is not surprising (but not guaranteed, since undefined behaviour is involved).
printf("buf %s\n", buf+2);
buf is converted to &buf[0], then 2 is added to that, resulting in &buf[2]. That is passed to printf, which, due to the %s conversion expects a pointer to a 0-terminated array of char as argument. This is the only printf call in the entire programme where the type of printf's second argument matches the type expected due to the conversion specifier exactly. But the contents of buf are indeterminate, so if there is no 0 byte in the array, that will cause invalid reads by printf. However, apparently buf[2] was 0, so just
buf
was printed.
printf("buf %d\n", buf+2);
buf + 2 again evaluates to &buf[2], and that is passed where printf expects an int. The type mismatch invokes undefined behaviour, but the output
buf 2264161
suggests that nothing nefarious happened, and since &buf[2] is two bytes behind &buf[0], the number printed is two larger than the number printed in doing's first printf.
}
Back to main:
printf("(unsigned) buf %d\n", (unsigned) buf);
That line is identical to the first printf call in main, so it has the same semantics, that was discussed above,
(unsigned) buf 2268303
and produces the same output.
return 0;
}

Please read C Basics. You will get your answer.
Regarding,
one function is giving the value as 2268303 and another 2264159
Observe that, one char buf[] is declared in main() and another one is in doing(). Both have different storage and both will work in their own scope. [Read Scope of variables in C]

If you use %p you will get hex values.
You also need to brush up on scope as well. Go through these links too.
(unsigned) buf 2268303 // You have defined this in main its a local array so it has
//2268303 as address. And for an array the array name acts as a
//pointer too
buf 2264159 // You have defined this in fn doing, it is local to that function
//and has a different address (it is a different array than the one
//in your main)

Here's the explanation:
This:
printf("buf %d\n", buf);
will print the address(memory position) of the first element on your "buf" array
This:
printf("buf %f\n", buf);
will try to read a float from the address of the first element on your "buf" array, printf probably returns zero because it doesn't know what to do with it.
This:
printf("buf %d\n", (unsigned) buf);
will do the same as the first printf since the address of "buf" is always greater or equal than zero.
This:
printf("buf %s\n", buf+2);
will try to read a float from the address of the first element on your "buf" array, printf probably returns an empty string because it doesn't know what to do with it.
Finally:
printf("buf %d\n", buf+2);
returns the position off the third element in you "buf" array
Important to notice:
the two "buf" arrays you declared (one inside main, the other inside doing()) are two distinct arrays even though you gave them the same name.
Inside doing() "buf" refers to the one you created there, inside main "buf" also refers to the one you created there. Thats the reason why you get two different addresses when printing from inside doing or main

Related

Why does char* of an array point to the entire array instead of the address?

I've seen some similar questions asked on here, but haven't been able to find a concise answer.
In learning pointers, I've come to understand that
in a case of
int test=1; int* p = &test;
printing "p" with printf("%p", p); will give the address of test, while printing *p with printf("%d", *p); will give the actual value of test, which is what ptr p points to.
Now, for doing this with a char, doing
char word[] = "test"; char* ptr = &word[0];
then printing ptr with printf("%s", ptr); gives the output "test", but I expected it to give the address of word[0].
I have figured out that if I do printf("%p", ptr); it does print the address.
So my question is, does this pointer contain both the address and the value of the array test[]? Or does printf just grab what it needs based off of which of %s or %p you use, and in that case, why couldn't you just do printf("%d",test); in my earlier example and get the value of test rather than the address? Is the fact that I'm using %s automatically outputting the entire array since it starts at that address?
%s tells printf to take the pointer it is given and print the first character that is there, then the character after that, then the character after that, and so on until printf finds a null character (a character that has value zero).
So, this not about a pointer pointing to the “entire array.” The pointer just points to one thing. It is about the command given to printf. %p says “print the value of the pointer.” %s says “print the characters at the location pointed to.”
… why couldn't you just do printf("%d",test); in my earlier example and get the value of test rather than the address?
%d is a command to printf to print the value of the int it is passed. You should not pass it a pointer for this because printf is expecting an int. That is just what the command is for.

%p vs %x in format String

Hi im a bit confused in String formats in C.
can someone explains me what is the output of every print of typed here?
printf("%p", pointer);
printf("%x", pointer);
printf("%x", &pointer);
%p means “print a pointer.” You should pass it a pointer that has been converted to void *. %x means “print an unsigned int in hexadecimal.” You should pass it an unsigned int; it is not correct to pass it a pointer.
Suppose we have:
char *pointer = "Hello";
char array[] = "World";
Then, in:
printf("%p", (void *) pointer);
printf("%p", (void *) array);
The value of pointer will be printed in some implementation-defined manner. (It should show you the address that is stored in pointer.)
In the second printf, the array array will be converted to a pointer to its first element, and the value of this pointer will be printed in the implementation-defined manner.
Note that I inserted casts to (void *). This is the proper way to use %p.
In:
printf("%x", (unsigned) pointer);
printf("%x", (unsigned) array);
The value of pointer will be converted to an unsigned int. The result of this conversion is implementation-defined. It should not be surprising, but it may be different from what you see with %p. Additionally, an unsigned int may be too narrow to contain the full value of the pointer, in which case some information will be lost.
After this conversion, the first statement will print the value in hexadecimal (without a leading “0x”, whereas using %p often does include a leading “0x”). The second statement will again convert array to a pointer to its first element, then convert that to unsigned int, and then print that in hexadecimal.
If unsigned int is wide enough, it is possible, even not unlikely, that the values printed by this method will show the same hexadecimal values as shown by the %p method, but you cannot rely on that.
Note that printing these using %x without the cast to unsigned has behavior not defined by the C standard—it is an error to pass a pointer for a %x specification. You must convert it first. Your original code, without the cast, could result in the value being printed coming from some arbitrary data not related to the pointer, or it could have caused your program to abort, or it could have printed the correct address, or it could have done something else—the behavior is not defined.
In:
printf("%x", (unsigned) &pointer);
printf("%x", (unsigned) &array);
The address of pointer, rather than its value, will be converted to an unsigned int and then printed in hexadecimal. This will almost certainly be different than the result of printing pointer.
For &array, the address of the array will be converted to unsigned. Unlike the previous statements, array is not converted to a pointer to its first element. This is because & is a special operator that suppresses this conversion. It returns the address of the array.
The address of the array is the “same” as the address of its first element, because, in memory, the array starts where its first element starts. However, the pointers may have different representations, and it is possible that converting &array to unsigned int may produce a different value than converting array to unsigned int. Nonetheless, in most C implementations, they produce the same value, so you will see the same result for printf("%x", (unsigned) &array); as you did for printf("%x", (unsigned) array);.
first is for pointers and the second one for integers even if the result very often will be the same. And this is explaining everything. If you want to print pointer %p if integer %x.
All other deliberations are wrong as using wrong format specifier invokes the UB.

Why does sizeof(*"327") return 1 instead of 8 on a 64 bit system?

printf("%lu \n", sizeof(*"327"));
I always thought that size of a pointer was 8 bytes on a 64 bit system but this call keeps returning 1. Can someone provide an explanation?
Putting * before a string literal will dereference the literal (as string literal are array of characters and will decay to pointer to its first element in this context). The statement
printf("%zu \n", sizeof(*"327"));
is equivalent to
printf("%zu \n", sizeof("327"[0]));
"327"[0] will give the first element of the string literal "327", which is character '3'. Type of "327", after decay, is of char * and after dereferencing it will give a value of type char and ultimately sizeof(char) is 1.
The statement:
printf("%lu \n", sizeof(*"327"));
actually prints the size of a char, as using * dereferences the first character of string 327. Change it to:
char* str = "327";
printf("%zu \n", sizeof(str));
Note that we need to use %zu here, instead of %lu, because we are printing a size_t value.
The string literal is an anonymous, static array of chars, which decays to a pointer to its first character -- that is, a pointer value of type char *.
As a result expression like *"abc" is equivalent to *someArrayOfCharName, which in turn is equivalent to *&firstCharInArray which results in firstCharInArray. And sizeof(firstCharInArray) is sizeof(char) which is 1.
Good answer by haccks.
Also, the behaviour of your code is undefined, because you have used the wrong format specifier.
So, use %zu instead of %lu because sizeof() returns size_t and size_t is unsigned.
C11 Standard: §7.21.6.1: Paragraph 9:
If a conversion specification is invalid, the behavior is
undefined.225) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.

C compiler relocates pointer that overlaps another variable

I am doing some experiments to see how C allocates variables on the stack. I am getting some odd behavior with the following code. C appears to be growing the stack downward, so in the following example, the char c is allocated in the byte immediately before the short s. I then create an int pointer bigRandP and point it at the same location occupied by c, so the "int" it sees overlaps with the space on the stack occupied by s. I then try to assign something to the location referenced by the int pointer.
unsigned short nameSum = 0;
unsigned char smallRand = 0;
unsigned int* bigRandP;
//The "int" pointed to by iP should overlap s
bigRandP = (unsigned int*)(&smallRand);
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);
*bigRandP = 0;
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);
0028FF1A 0028FF19 0028FF19
0 0 419430400
0028FF1A 0028FF19 0028FF00
0 0 4210788
The printed results are interesting. Not only does the assignment fail (the int pointed to by bigRandP is not set to 0), the int pointer itself is silently relocated to point somewhere else further down the stack. What is going on? Is this the C compiler's way of keeping me from overwriting other variables with overlapping pointers?
bigRandP is a pointer to unsigned int.
You pointed it to an unsigned char object, then you modified the unsigned int object that bigRandP points to.
Apparently smallRand and bigRandP are stored close to each other in memory. By trying to modify sizeof (unsigned int) bytes of a 1-byte object, you clobbered part of the pointer object itself.
Bottom line: Your program's behavior is undefined.
Also, though this probably isn't related to the behavior you're seeing, the %p format requires a void* argument. If you want to print some other type of pointer, you should convert it to void*:
printf("%p %p %p\n", (void*)&nameSum, (void*)&smallRand, (void*)bigRandP);
It's likely to "work" with or without the casts on systems where all pointers have the same representation, but the version with the casts is more correct on all systems.

malloc returns negative value

I am running this piece of code on a hardware.
unsigned char *buf;
buf = malloc(sizeof(int));
printf("Address of buf %d\n" , &buf);
if(!buf)
return MEMORYALLOC_FAILURE;
The malloc is returning negative value. What could be the problem?
Address returned by malloc is not negative or positive, it just address, use %p to print it, not %d:
printf("Address of buf %p\n" , &buf);
And if you want to print the address returned from malloc, remove the ampersand:
printf("Address of buf %p\n" , buf);
You're printing the address of a memory location as a signed integer. If the memory address--for example on a 32bit machine--is more than 2,147,483,647 (0x7FFFFFFF) it will display as a negative number.
In this case you're also printing the address of a local variable on the stack rather than the address returned by malloc.
The error with using %d to print a pointer-sized value is that pointers may vary in size. The correct approach therefore would be to use the printf specifier for pointers, %p:
// nb: we don't take the address of buf,
// buf is already a pointer (thus its *value* is an address)
printf("Address of buf %p\n", buf);
Type mismatch:
you try to print an address with the specifier for an int ("%d"). You should use "%p" and cast the value to void*
printf("Address of buf %p\n" , (void*)&buf);
Also note the above will not tell you where the allocated memory is. For that you'd need
printf("Address of newly allocated memory %p\n" , (void*)buf);
The cast to void* is mandated by the C99 standard (emphasis is mine)
The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.
Also note that pointers to void need not have the same representation as pointers to other types.
malloc returns either NULL (aka 0) or a memory address. Memory addresses cannot be negative. You just converted the pointer itself to a number, resulting in a negative number.
malloc returns a pointer. It never returns a negative value. If you think it is then you probably have a broken everything. On the other hand if you mean it returns a null pointer, then it means you are unable to allocate that memory.

Resources