Related
I am currently doing pointers. I have been programming for a long time, but not in C/C++. With that being said, my pointer knowledge is abysmal.
Currently, I am following a guide on YouTube and he prints the code below.
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", p);
}
This prints successfully for him, and he sees a memory location. For me, I see the error
warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *'
From this, I expect I need to put an & in front of the p to make it print the value. But then I receive this error,
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", &p);
}
'int', but argument 2 has type 'int **'
Where is the hole in my knowledge? Any key tips or strategies when working with this, I don't know why I find this so abstract.
Thanks,
I was expecting the value to print as expected, but instead am greeted with the error.
%d is the wrong format specifier for pointers. That may work on a more lenient or noncompliant implementation, but you should use %p to print pointer values.
Warnings are not errors. You're receiving a warning, which is not stopping your program from working, because the print specifier %d (ie printf("%d")) is for displaying integers, and you're giving it a non-integer argument of type int*.
The problem here is not with the argument, it's with the print specifier. Your attempt at a fix just changes the int* to an int**, which still does not match the format specifier %d. Use %p instead, which is the specifier for pointers, and will fix the warning, and print the address in hexadecimal notation.
You could also suppress the warning with a series of explicit casts from int* to int, but integer representations of memory addresses are generally much less used than hexadecimal representations in the first place.
Note that using wrong format specifier in printf() lead to undefined behaviour1).
The correct format specifier to print a pointer is %p format specifier.
Remember, format specifier %p expect that the argument shall be a pointer to void, so you should type cast pointer argument to void *. The correct statement to print pointer p would be:
printf("%p\n", (void *)p);
C11#7.21.6.1p9 [emphasis added]
9 If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
I'm a beginner in C, today I'm studying the pointer part, I found that I can print an address directly, when using the right type escaper, I can even print the intended value stored in that memory address.
Later, I did some experiments:
##### CODE PART ######
#include <stdio.h> // Define several variable types, macros, and functions about standard input/output.
int main () {
char my_string[] = "address test";
printf("%s\n", &my_string);
printf("%p\n", &my_string);
printf("%d\n", &my_string);
printf("%x\n", &my_string);
printf("\n");
char *p = "pointer string test";
printf("%s\n", p);
printf("%p\n", p);
printf("%d\n", p);
printf("\n");
char *p2 = 'p';
printf("%c\n", p2);
printf("%p\n", p2);
printf("%d\n", p2);
return 0;
}
##### OUTPUT #####
address test
0x7fff58778a7b
1484229243
58778a7b
pointer string test
0x107487f87
122191751
p
0x70
112
I'm not quite understand the behavior of %d format output at first, But after more observations and experiments. I found that %d is converting part of the hex value of the memory address.
But for address of my_string it omitted the 0x7fff part, for address of p it omitted 0x10 part, for p2 it omitted the 0x part. In my cognition, 0x is the head sign of a hex value.
But how should I know how much digits will be omitted by C when converting a memory address to int, as it does in the sample of my_string and p?
PS: My system version is OSX10.10
The C standard (ISO/IEC 9899:2011) has this to say about converting between pointers and integers:
6.3 Conversions
6.3.2.3 Pointers
¶5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.67)
¶6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
67) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to
be consistent with the addressing structure of the execution environment.
Note that the behaviour of converting between pointers and integers is implementation defined, not undefined. However, unless the integer type used is uintptr_t or intptr_t (from <stdint.h> — or <inttypes.h>), you are likely to see truncation effects if the sizes of the pointer and the integer types do not match. If you move your code between 32-bit and 64-bit systems, you will run into problems somewhere.
In your code, you have 64-bit pointers (because you're on Mac OS X 10.10 and you need to specify explicitly -m32 to get a 32-bit build, but your results are consistent with a 64-bit build anyway). When you pass those pointers to printf() with the %d and %x conversion specifications, you are requesting printf() to print a 32-bit quantity, so it formats 32 of the 64 bits you passed. The behaviour is ill-defined; you aren't getting a conversion, per se, but the calling code (in main()) pushes a 64-bit pointer onto the stack and the called code (printf()) reads a 32-bit quantity off the stack. If you requested that a single call to printf() should print several values (e.g. printf("%d %x\n", p, p);), you'd get more surprising results.
You should compile with options like:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror …
With those options, your code would not compile; the compiler would complain about mismatches between the format strings and the values passed. When I saved your code into a file noise.c and compiled it with clang (from XCode 7.2, running on Mac OS X 10.10.5), I got:
$ /usr/bin/clang -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror noise.c -o noise
noise.c:5:20: error: format specifies type 'char *' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%s\n", &my_string);
~~ ^~~~~~~~~~
noise.c:7:20: error: format specifies type 'int' but the argument has type 'char (*)[13]' [-Werror,-Wformat]
printf("%d\n", &my_string);
~~ ^~~~~~~~~~
noise.c:8:20: error: format specifies type 'unsigned int' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%x\n", &my_string);
~~ ^~~~~~~~~~
noise.c:14:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p);
~~ ^
%s
noise.c:17:11: error: incompatible integer to pointer conversion initializing 'char *' with an expression of
type 'int' [-Werror,-Wint-conversion]
char *p2 = 'p';
^ ~~~
noise.c:18:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%c\n", p2);
~~ ^~
%s
noise.c:20:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p2);
~~ ^~
%s
7 errors generated.
$
Compile with stringent warnings, and pay heed to those warnings.
There is no such thing like "hex value". A number is an amount. Decimal and hex are just representations of the number using different conventions. One can, as well, represent the number using roman numerals and its value still remains the same.
The address of a variable is a concept, not a physical thing. It usually happens to be a (large) number on the current OSes and CPU architectures but this is not set in stone.
Depending on the compiler and the code it compiles, a variable can be stored in memory (it has an address that looks like a large integral number) or not. The compiler can optimize the code and store a temporary variable in a CPU register; in this case it doesn't have an address.
Back to your code. &my_string is the address of variable my_string. It looks like a number. You probably run the code on a 64-bit processor. Memory addresses in this situation are 64-bit unsigned numbers.
printf("%p\n", &my_string); - prints a 64-bit unsigned number (the most appropriate representation of a pointer on the hardware architecture you are using).
printf("%d\n", &my_string); - you pass a 64-bit number to printf() but because of the %d specifier it thinks the value is 32-bit. It grabs only half of the passed value (4 out of the 8 bytes) and represents it as a signed integer. But which half? It depends on the architecture where the code runs. The behaviour of this code is undefined.
printf("%x\n", &my_string); - similar with %d, it prints only (the same) half of the passed value using the hexadecimal notation. The behaviour of this code is, again, undefined.
The 0x prefix is not part of the hex representation; it is just a marker that signals to the C compiler that a number in the hexadecimal representation follows. While the hex representation is universal, different languages use different ways to encode them. Even the C language uses two different markers for them; 0x is used to prefix the numbers and \x is used to prefix the hex representation of a character.
There's no rule. This is not covered by the C standard. Your code causes undefined behaviour. Any results you observe for this entire program are meaningless.
With printf you must convert the arguments to the right type yourself.
printf("%d\n", &my_string);
printf("%x\n", &my_string);
is cause for undefined behavior. The format specifier and the argument type must match for printf to work correctly. For a list of valid format specifiers and data types to which they apply, take a look at http://en.cppreference.com/w/c/io/fprintf.
The following lines suffer from the same problem.
printf("%d\n", p);
printf("%c\n", p2);
printf("%d\n", p2);
The line
char *p2 = 'p';
assigns the integer value that represents the character 'p' to p2. However, that is not a valid address.
The integral types that can be used to hold a pointer are intptr_t and uintptr_t. Hence, you can use:
char my_string[] = "address test";
intptr_t ptr = &my_string;
However, you cannot use %d format specifier to print that value. You will need to use:
printf("%" SCNdPTR "\n", ptr);
to print that.
Take a look at http://en.cppreference.com/w/c/types/integer for more details.
I wrote this simple program
#include <stdio.h>
int main(void)
{
int array[10];
printf("sizeof(array): %lu\n", sizeof(array));
printf("sizeof(&array): %lu\n", sizeof(&array));
printf("array: %p\n", array);
printf("&array: %p\n", &array);
printf("value: ");
scanf("%d", array); // 1
//scanf("%d, &array"); // 2
}
Output:
sizeof(array): 40
sizeof(&array): 8
array: 0x7fffaab6f480
&array: 0x7fffaab6f480
value: 10
It compiles when I use 1. However, it doesn't when I use 2!
I get this compilation warning
warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type
‘int (*)[10]’ [-Wformat=]
scanf("%d", &array);
^
although array and &array have the same value, they have different sizes (40 and 8 respectively) on my system.
On the other hand, this code
int array[10];
fread(&array, x, y, z);
compiles and works perfectly as
int array[10];
fread(array, x, y, z);
I noticed in the warning message that &array has the type int (*)[10]. Now what does that mean?
I also believe I have no troubles with fread() because it accepts a void *, but what about scanf()? How does it differentiate between pointer types?
And why doesn't it treat array as &array even though they're practically have the same value?
Arrays decays to pointers, so using the array as argument is the same as passing a pointer to the first element.
When you're doing &array, you get a pointer to the array (the int (*)[10] thing), and not a pointer to an integer.
With the scanf and printf family, you must pass the exact type that they expect (after the default argument promotions are applied - but that is not relevant in this example).
This is because the arguments correspond to a ... in the prototype, meaning that the compiler does not attempt to convert your argument to the expected type. If you use the wrong type you just get undefined behaviour.
This happens in the second case, scanf("%d", &array). As your examples show &array does not have type int *, therefore the behaviour is undefined.
In practice, it is likely to work anyway if your compiler uses the same representation for int * as it does for int (*)[10], which all modern compilers do AFAIK. But , of course, you should not rely on undefined behaviour, especially when there is an easy fix available.
In the fread example, it matches the prototype parameter void *. Therefore the compiler converts your argument to void *. Since the first element of an array is at the same memory address as the array itself, (void *)&array == (void *)array, even though array and &array have different types (and possibly even different representations), they both point to the same memory address.
First, your program was compiled very well - warning is not an error.
The warning message tells you that there's mismatch between format and type: "%d" format requires int *, but you sent &array, whose type is int (*)[10].
array is 10-length array of int. Its type is int [10]. However, array can be converted to pointer, that is, &array[0].
When you try to pass array to function, you actually pass a pointer, &array[0]. So both this code
printf("%d", array);
scanf("%d", array);
and this another code
printf("%d", &array[0]);
scanf("%d", &array[0]);
are the same.
Now let's look at another thing, &array. Its type is int (*)[10], that is, pointer to array.
Of course, the actual values of both &array[0] and &array are the same, but they have different types. So they're diferent things, as 'A' and 65 are different.
Altough it looks okay since the values are the same, I don't think it is such a good practice - Use array or &array[0].
Both are syntactically correct C, and do exactly the same thing, as you suggest. However, one is more correct than the other. That said, neither is perfect.
To be properly pedantic, you should have this:
scanf("%d", &array[0]);
.. because that's a pointer to an integer, array[0], and what you really want.
In fact, you can pass anything to scanf (if you ignore the documentation), and the compiler is expected to accept it (misuse of the standard library does not trigger an error, traditionally). If you pass something invalid then your program is expected to fail at runtime (or not, if you're lucky -- undefined behaviour is like that).
However, your compiler is trying to be helpful and interpret the scanf format string for you to make sure you did the right thing, but if you look carefully, it's not an error, its a warning. You're free to ignore it, if you choose.
The reason you don't get an error with fread is because that function does not take an integer, it takes void *, and both forms can be converted to that type just as easily.
When I try to compile this code:
void main()
{
float x;
x=6.5;
printf("Value of x is %f, address of x %ld\n", x, &x);
}
it gives me this error:
pruebaso.c: In function ‘main’:
pruebaso.c:5:9: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
printf("Value of x is %f, address of x %ld\n", x, &x);
^
pruebaso.c:5:9: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 3 has type ‘float *’ [-Wformat=]
I've seen in another forum the solution is to make a cast to a void pointer first:
http://www.linuxquestions.org/questions/programming-9/beginning-c-programming-how-to-print-memory-locations-printf-conversion-number-927305/
But making this change,
printf("Value of x is %f, address of x %ld\n", (double)x, (void *)&x);
now gives me a warning:
pruebaso.c: In function ‘main’:
pruebaso.c:5:9: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
printf("Value of x is %f, address of x %ld\n", (double)x, (void *)&x);
^
pruebaso.c:5:9: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 3 has type ‘void *’ [-Wformat=]
Could someone explain me how could I solve it without getting a warning?
Thank you
You need to include <stdio.h> to suppress the first warning and use a cast to void * and use %p to suppress the second warning.
In C90, using printf() without <stdio.h> invokes undefined behavior because the implicit declaration will not match the actual declaration, since printf() is variadic. (Using fputs() would be okay, by comparison.) In C99, implicit declarations are not allowed but GCC allows you to compile such code anyway.
#include <stdio.h>
int main(void)
{
float x = 6.5;
printf("Value of x is %f, address of x %p\n", x, (void *) &x);
}
The %p format specifier is used for printing pointers. Technically, it must be used with a char * or void * pointer. On modern systems, this will not affect the result; but passing other pointer types to %p will technically invoke undefined behavior (which is bad).
The %ld format in your code is wrong, even though it will work on most systems. First, it takes a long argument, which requires a cast (even though the cast will only make a difference on a few systems). Second, even if you add the cast, not all information in the pointer is guaranteed to remain (it might chop off bits or do something else). In practice, 64-bit Windows systems are the only systems where a cast to long chops of bits and the cast works fine everywhere else.
So use %p and cast to void *.
void main()
{
float x;
x=6.5;
printf("Value of x is %f, address of x %ld\n", x, &x);
}
The immediate problem is that you're missing the required #include <stdio.h>, but that's not the only problem with your code. Some of these things are errors that you can probably get away with (compilers may not complain, and may generate code that does what you expect), but there's no reason not to do it right.
#include <stdio.h>
int main(void)
{
float x;
x = 6.5;
printf("Value of x is %f, address of x %p\n", x, (void*)&x);
}
To explain the changes I made:
#include <stdio.h> is required for any program that calls printf. More precisely, a declaration of printf is required, and <stdio.h> provides it. (In principle you could write your own declaration instead, but there's no good reason to do so.)
The correct definition of main is int main(void). void main() may be accepted by some compilers, but it's useful mostly as a way to detect bad books. If you're using a book that tells you to use void main(), its author does not know the language very well, and may have given you other misinformation. Find a better book. (Caveat: void main(), or more likely void main(void) might actually be the preferred implementation-defined form for some embedded systems. but you're probably not using such a system.)
The "%ld" format requires an argument of type long int. The only correct format for printing a pointer value is "%p". Since "%p" requires an argument of type void*, you should explicitly cast your pointer value to void*. Omitting the cast is likely to "work", but float* and void* are distinct types, and are not guaranteed to have the same representation or to be passed to functions in the same way.
C implicitly declares functions if you use them before defining it, which caused the error " incompatible implicit declaration of built-in function ‘printf’".
To fix this, add #include <stdio.h> at the top of the file (this copies over the header file that includes a declaration for printf.
The second thing issue is that you should use %p to print pointers.
The resulting code is
#include <stdio.h>
int main(void)
{
float x;
x=6.5;
printf("Value of x is %f, address of x %p\n", x, (void *) &x);
return 0;
}
I've below piece of code :
float i=85.00;
printf("%f %p",i,i);
which prints o/p:
85.00000 (nil)
But when I change the order like below:
float i=85.00;
printf("%p %f",i,i);
the o/p is :
(nil) 0.00000
While I expect that similar o/p should be printed as earlier, in mentioned order.
What is the behaviour going on can anyone please explain?
What you're doing is undefined behavior. The %p format specifier promises that you're passing in a pointer (specifically a void* pointer), and you're passing in a double instead (float values get promoted to double when passed to variadic functions such as printf). So as soon as you fail to satisfy the requirements, the compiler and implementation are free to do whatever they want, and printing out 0 instead of 85 in the second case is perfectly legal.
What's likely happening is that the compiler is using a calling convention which places floating-point values in separate registers (e.g. the x87 floating-point stack, or the SSE2 SIMD registers) instead of on the stack, whereas integer values like pointers get passed on the stack. So when the implementation sees a %p format specifier, it tries to read the argument off of the stack, when in fact the argument is actually elsewhere.
As others have mentioned, you should really be compiling with the -Wall option (assuming GCC or a GCC-compatible compiler). It will help you catch these kinds of errors.
printf() expects a pointer for the format specifier %p whereas you are passing the value of a float. This is undefined behaviour.
If you want to print the address, then pass the address:
printf("%f %p",i, &i);
If you turn on the warnings, you'll see the problem:
warning: format ‘%p’ expects argument of type ‘void *’, but argument 3
has type ‘double’ [-Wformat]
You are probably hitting some undefined behavior; printing a float as a pointer has absolutely no sense.
And GCC 4.8 invoked as gcc -Wall rightly warns you:
dwakar.c:5:3: warning: format '%p' expects argument of type 'void *',
but argument 3 has type 'double' [-Wformat=]
printf("%f %p",i,i);
^
So please use gcc -Wall to compile your code and correct it till no warnings are given.
Notice that at the ABI level floating point and pointers arguments are passed thru different registers. So the implementation probably prints as pointer the (uninitialized, or old) content of whatever register is involved.