#include <stdio.h>
int main(void) {
int a[5] = {0, 1, 2, 3, 4}, *p;
p = a;
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
return 0;
}
When I executed this code, I got a negative value for p. I have studied that address cannot be negative. Then why I have got a negative value
%d is not the correct format specifier to handle a pointer (address). You should be using %p and cast the corresponding argument to void* for printing an address. Using wrong argument type for a particular format specifier invokes undefined behavior.
To quote C11 chapter §7.21.6.1
[...] If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
In this code, *p does not denote an address, anyway.
You cannot print an array by just using the %ds in a single format string. You need to have a loop. In your code,
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
the format string expects 5 ints as argument, while you supply only a pointer and an int. FWIW, supplying insufficient argument for supplied conversion specifiers invoke undefined behavior, too. Quoting the same standard,
[...] If there are insufficient arguments for the format, the behavior is
undefined. [...]
To elaborate, replace
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
by
for (i= 0; i < 5; i++, p++)
printf("%d %p\n", *p, (void *)p);
For pointers, use %p with printf():
int a[5] = {0, 1, 2, 3, 4}, *p;
p = a;
printf("%p\n%d", (void *)p, *p);
Also make sure your comiler warnings are at the highest level. You should get a warning for using %d with a pointer then:
warning <code>: 'printf' : '%d' in format string conflicts with argument 1 of type 'int *'
Mis-matched printf() specifiers and arguments
printf("%d\n%d\n%d\n%d\n%d\n", p, *p); expects 5 int. Code is supplying a int * and int. Result: undefined behavior.
Instead:
printf("Pointer %p\nValue: %d\n", (void *) p, *p);
Related
What is difference between %d and %p when printing?
For example:
int main() {
int a = 9;
printf("%d\n", &a);
printf("%p\n", &a);
return 0;
}
The printf function supports different conversions for different types of arguments: %d produces a decimal representation (d for decimal) for an argument of type int, %p produces a system dependent representation of a void pointer (p for pointer)
There are multiple problems in your code:
you pass the address of an int variable, hence a type int * where printf expects an int for the %d conversion: This has undefined behavior
you pass the address of an int variable, hence a type int * where printf expects an void * for the %p conversion: This has undefined behavior
you did not include <stdio.h> and you call the function printf without a proper prototype: the prototype inferred from the call is incompatible with the actual definition, so the behavior is undefined.
The output you observe is the result of undefined behavior: it is unpredictable and potentially irreproducible: on my system, I get different output every time I run the program, even without recompiling. Undefined behavior means anything can happen.
Here is a modified version:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main() {
int a = 9;
printf("%d\n", a);
printf("%p\n", (void *)&a);
printf("0x%"PRIxPTR"\n", (uintptr_t)&a);
printf("%p\n", (void *)NULL);
printf("0x%"PRIxPTR"\n", (uintptr_t)NULL);
return 0;
}
Output:
9
0x7fff54823844
0x7fff54823844
0x0
0x0
The last conversion takes a uintptr_t, an integer type large enough to store an integer representation of a pointer. On my system, OS/X, the %p conversion produces the same output as 0x%x for the corresponding integer type.
Will output something like:
-1807747332,
00000083943ff6fc
The format specifier converts the value of the corresponding variable to the format data type. %d converted it to a signed integer. If you use %p it simply treats the value as the memory address of a pointer and prints it in hexadecimal.
I'm trying to do the following thing:
#include <stdio.h>
typedef unsigned char Set[128];
Set A; //Global variable
void main()
{
A[0] = 1;
A[1] = 2;
A[2] = 3;
printf("%x, %x, %x\n", A, &A, &A[0]);
printf("%u, %u, %u\n", A[0], A[1], A[2]);
Set *p;
p = A; //Same result with: p = &A;
printf("%x, %x, %x\n", p, &p, &p[0]);
printf("%u, %u, %u\n", p[0], p[1], p[2]);
}
The first and third prints are fine - I get to see the addresses of the two variables, and for 'p' the address it points on.
I want 'p' to point on 'A' so I'll be able to access to the values in the array of 'A' through 'p', but it doesn't work - the values at the fourth print are not as the second, it's not printing the values of the array.
how can I create a pointer to 'Set' variable type?
You're using many wrong / mismatched format specifiers for the supplied argument types. This causes undefined behavior.
Remember, for a pointer type, you must use %p format specifier, and in case the pointer is not a pointer to a char type, you must cast the argument to void *.
Regarding the above statement for the requirement to cast, refer chapter §6.2.5/P28,
A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type. [....]
and footnote 48,
The same representation and alignment requirements are meant to imply interchangeability as
arguments to functions, return values from functions, and members of unions.
That being said, always pay attention to the types!!
In your code,
A is of type unsigned char [128] (array),
and p is of type unsigned char (*) [128].
Thus, p = A; is not a valid statement, as the types are not compatible. You must take the address of A to make the statement valid, something like
p = &A; // now the types are compatible
Well that's because pointer type of p is different that type of a. Here when you try to use p[1] you are basically trying to access some memory which you don't have access to. (You have undefined behavior when you access p[1] etc). And also due to mismatched type you will also run into undefined behavior in printf itself.
Rather you can get what you want by (Now you will get desired array elements).
printf("%u, %u, %u\n", (*p)[0], (*p)[1], (*p)[2]);
Also to type ponters use %p format specifier. (Casting it to void*).
printf("%p, %p, %p\n", (void*)A, (void*)&A, (void*)&A[0]);
How to compile code?
Also try to compiler your code with all warnings enabled. gcc -Wall -Werror progname.c.
Compiler complained!
Also p=A compiler complained about it. Because you are assigning unsigned char* to unsigned char(*)[128].
error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types]
p = A; //Same result with: p = &A;
^
And
error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘unsigned char (*)[128]’ [-Werror=format=]
printf("%x, %x, %x\n", p, &p, &p[0]);
^
How to make these warnings go away?
p=&A;
This will do the correct assignment. And use the correct format specifiers as mentioned in answer.
How did the unsigned char* appear?
Well array decayed into pointer in this case - and it decayed into pointer to the first element. The type of the first element is unsigned char - a pointer to it would be unsigned char*. That's how it came into ...
p is pointer to type unsigned char [128], that means it is of type unsigned char (*)[128] while the type of A, after decay, is unsigned char *. Both are of incompatible type. You need
p = &A;
and
printf("%p, %p, %p\n", (void *)A, (void *)&A, (void *)&A[0]);
printf("%u, %u, %u\n", A[0], A[1], A[2]);
Set *p;
p = &A; // Assign address of A which is of type unsigned char (*)[128]
printf("%p, %p, %p\n", (void *)p[0], (void *)p, (void *)&p[0]);
printf("%u, %u, %u\n", p[0][0], p[0][1], p[0][2]);
int main()
{
int a;
int* b;
a = 40;
b = &a;
printf("the address of a is %p, and the value of a is %d \n",&a, a);
return 0;
}
I find that both (void*)&a and &a print the same thing. So why do people still add (void*)? Is it just a habit?
You use specifier %p to print address stored in pointer, and this format specifier expects type to be void * . And as &a is of type int * , cast void * is used .
The printf() format specifier %p expects a void* type pointer. Since what you are passing might not be a void* type pointer, and the standard does not mandate for all pointers to have the same format, is is important that you cast a pointer to void* before passing it to printf.
For instance:
int* a = malloc(sizeof(int));
printf("a is %p",(void*)a);
Is done as best practice incase int* and void* are not similar
C Standard says that using an incorrect specifier for an argument in printf will result in undefined behavior.
7.21.6.1 The fprintf function
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.
Since pointer to int is not the same type as pointer to void, and %p may only be used for a pointer to void and even if some other rules says that any pointer may be converted to pointer to void and back, that doesn't change the fact that the behavior is undefined, because of the quoted rule.
Firstly, different pointer types are not necessarily interchangable.
Secondly, for varargs no implicit conversion takes place as the compiler does not know the expected type.
I am trying to understand the pointer concepts in-depth.
In the following code,
#include <stdio.h>
int main()
{
int i = 10;
int *iptr = &i;
printf("(float)* : %f\n", (float)*iptr);
printf("(float*) : %f\n", (float*)iptr);
printf("*(float*) : %f\n", *(float*)iptr);
return 0;
}
output:
(float)* : 10.000000
(float*) : 10.000000
*(float*) : 0.000000
I also got a warning for the type-cast (float*).
I find it difficult to even analyse the difference. If anyone can help me to analyse what is the exact usage of all three, it would be helpful.
The difference is
You are dereferencing the int and casting it to float in
printf("(float)* : %f\n", (float)*iptr);
which is fine.
You are casting the int pointer to a float pointer, and printing the float pointer with the "%f" specifier is undefined behavior, the correct specifier for printing pointers is "%p", so
printf("(float*) : %f\n", (float*)iptr);
is wrong, it should be
printf("(float*) : %p\n", (void *) iptr);
casting to float * here is not meaningful, because the void * address is the same as the float * address and also the int * address, the difference would be when you do pointer arithmetic.
You are casting the int pointer to a float and dereferencing the resulting float pointer, although it will violate strict aliasing rules in
printf("(float*) : %f\n", *(float*)iptr);
which is also undefined behavior
The first one is correct.
i is an int variable, and iptr a pointer to that int.
(float)*iptr: *iptr dereferences iptr, which returns an int. Then that int is converted to a temporary float containing the same value. And that float is used by printf.
*(float*)iptr: Attempts to cast a pointer-to-int into a pointer-to-float. This is invalid, and should produce a compiler warning or error. It creates a pointer with the same address, but with the type saying that it points to a float value.
The * operator then dereferences it, so the int is read as if it were a float. So the resulting float would be invalid, and it could result in a segfault because floats are longer than ints, so it reads more memory than there is allocated for the int.
(float*)iptr: Same problem, but it doesn't dereference the (invalid) pointer, and passes a pointer-to-float into printf, instead of a float. But printf expects a float. Some compilers should also produce a warning/error here because the format string indicates what value types are expected.
If the format specifier indicates %p, it expects a pointer (void*, float*, or any other). It will then print out the address, and not the value it points to. This can be useful in debugging for example.
In the C11 specification is said that argument type of %p must be void ** in case of scanf() function but I can't figure how to input an address and store it into a void **.
Infact if I try to make:
void **p;
scanf("%p", p);
I get a segmentation fault.
P.S.
C11 specification:
The corresponding argument shall be a pointer to a pointer to void
void **p;
scanf("%p", p);
doesn't work for the same reason that
int *i;
scanf("%i", i);
doesn't work - you're writing to an uninitialized pointer (or telling scanf to write to one, at least).
This works:
int i;
scanf("%i", &i);
and so does this:
void *p;
scanf("%p", &p);
NOTE: Original post did not have a mention for c11 standard.
Well, as per the c99 specification document, chapter 7.19.6. 1 2, paragraph 8 12,
p
Matches an implementation-defined set of sequences, which should be the
same as the set of sequences that may be produced by the %p conversion of
the fprintf function. The corresponding argument shall be a pointer to a
pointer to void. The input item is converted to a pointer value in an
implementation-defined manner. If the input item is a value converted earlier
during the same program execution, the pointer that results shall compare
equal to that value; otherwise the behavior of the %p conversion is undefined.
So, it is not void **, rather , a void *.
Next, Your reason for a segmentation fault is the use of uninitialized pointer p in scanf(). You did not allocate memory to p before using [passing it to scanf() as argument] it.
As others' suggested, you can nicely use something like
void *p;
scanf("%p", &p);
here, the &p value is actually pointer to a pointer to void and have a defined address.
You didn't initialize p. Try:
void *p;
scanf("%p", &p);
This takes the address of p, which is valid.
Standard says that %p should have void * type argument. You need to declare p as void * and then
scanf("%p", &p);
The reason that you are getting segfault is because in void **p, p is not pointing anywhere.