Accessing memory address using format specifiers [duplicate] - c

I'm trying to print out the value of argv at this point in my code, but when I try to compile it, I get
warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘char **. I'm not sure what this warning means though. Is %p not meant to be used for argv even though it's a pointer?
int main(int argc, char* argv[])
{
printf("%s%p", "argv = ", argv);
}

So why don't you cast it?
printf("argv = %p\n", (void *)argv);`
The %p pointer is specified (POSIX printf(); C11 §7.21.6.1 The fprintf function):
p — 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.
Since char ** is not a void *, you need to do the explicit conversion. The compiler isn't allowed by the standard to do the conversion to void * for you — the ellipsis notation in the declaration of printf() means that default argument promotions occur, but that affects only the float type and integer types smaller than int (short, char, etc).
On most machines these days, that's a no-op. On the (long obsolete) machine where I learned to program in C, there weren't void * yet (too old for the standard), but the equivalent was char *, and the value of a char * address for a given memory location was different from the pointer value for any other type — the casts were not optional.
Note that I'm assuming you intend to print the value of the address. If you intend to print the contents, then there's more work to be done.

Well, not any pointer (type).
According to C11, chapter §7.21.6.1, for the %p conversion specifier,
p
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.
So, the argument must be of type void * (or, a char*, given they have the same alignment requirements). Any other type of pointers, must be converted through an explicit cast, as there is no default argument promotion for pointers.
Something like
printf("%s%p", "argv = ", (void *)argv);
should do.

In order to print argv and it's address you need to do
int main(int argc, char* argv[])
{
int i;
printf("address of argv = %p\n", (void *)argv);
for (i = 0; i < argc; ++i)
{
printf("%s\n", argv[i]);
}
return 0;
}

Related

What is the difference between int (*p)[10]=s and int (*o)[5]=&s?

On basis of the convention int (*o)[5]=&s; is the right way for a pointer o to point an array having 5 elements.
We can also write this s in this statement
int (*p)[10]=s;
but why preferring
&s at int (*o)[5]=&s;
as both of them return the same output.
#include <stdio.h>
int main()
{
int s[5]={10,1,2,3,4};
int (*p)[10]=s;
printf("%d\n",*p);
printf("%d\n",**p);
printf("%d\n",&s);
printf("\n");
int (*o)[5]=&s;
printf("%d\n",*o);
printf("%d\n",**o);
printf("%d",&s);
return 0;
}
Output of this program is:
-593812272
10
-593812272
-593812272
10
-593812272
This is not valid:
int s[5]={10,1,2,3,4};
int (*p)[10]=s;
Because you're initializing a variable of type int (*)[10] (a pointer to an array of int of size 10) with an expression of type int *. These types are not compatible.
While this is fine:
int (*o)[5]=&s;
Because the type of the initializer matches the type of the variable.
Also, when printing pointer values, you should use the %p format specifier and cast the argument to void *. Mismatching format specifiers with their associated arguments triggers undefined behavior.
This line
int (*p)[10]=s;
is incorrect. The initializer has the type int * due to the implicit conversion of the array designator s to a pointer to its first element. And the two pointers in the left hand side and in the right hand are not compatible. So the compiler should issue a message.
This line
int (*o)[5]=&s;
is correct. The initializer has the type int ( * )[5] that is the same type of the initialized pointer o.
Pay attention to that to output a value of a pointer you have to use the conversion specifier %p. Otherwise using the conversion specifier %d to output a pointer invokes undefined behavior.
So for example instead of these calls
printf("%d\n",*o);
//...
printf("%d",&s);
you have to write
printf("%p\n", ( void *)*o);
//...
printf("%p\n", ( void * )&s);
The expression *o yields value of the array s that is in turn is implicitly converted to a pointer to its first element.
The values of the expression *o and of the expression &s are the same because it is the address of the extent of memory occupied by the array. But their types are different. The first expression used as an argument of the call of printf has the type int * while the second expression has the type int ( * )[5].

Formatted printing pointer value

I found that we can print the pointer value with %p format specifier. N1570 7.21.6.1(p8):
p 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
Since the pointer to void can be converted to pointer to any other object type I'm curious would the conversion by hand is necessary. Example:
struct test_t{
int a;
}
void foo(){
struct test_t *test_ptr = malloc(sizeof(*test_ptr));
printf("Pointer test_ptr = %p\n", test_ptr);
}
Here I did not convert it to void * assuming that the compiler does this for me. Is it conforming? Or I should convert such pointers to void * on my own like
printf("Pointer test_ptr = %p\n", (void *) test_ptr);
The Standard specifies that the representation of and alignment of void * is the same as char *. It is not specified if the void * representation/alignement is must be the same as any object type.
The version with (void *) is correct, and your original code causes undefined behaviour. (You already provided the relevant Standard quote so I have no need to add further quotes).
Since the pointer to void can be converted to pointer to any other object type I'm curious would the conversion by hand is necessary
"can be" means there is potential for a conversion to happen. Such a conversion only actually happens when it was requested , with the language standard specifying which constructs request a conversion.
For the arguments to printf, only the default argument promotions are applied. There are not any other conversions.

warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘char **’

I'm trying to print out the value of argv at this point in my code, but when I try to compile it, I get
warning: format ‘%p’ expects argument of type ‘void *’, but argument 3 has type ‘char **. I'm not sure what this warning means though. Is %p not meant to be used for argv even though it's a pointer?
int main(int argc, char* argv[])
{
printf("%s%p", "argv = ", argv);
}
So why don't you cast it?
printf("argv = %p\n", (void *)argv);`
The %p pointer is specified (POSIX printf(); C11 §7.21.6.1 The fprintf function):
p — 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.
Since char ** is not a void *, you need to do the explicit conversion. The compiler isn't allowed by the standard to do the conversion to void * for you — the ellipsis notation in the declaration of printf() means that default argument promotions occur, but that affects only the float type and integer types smaller than int (short, char, etc).
On most machines these days, that's a no-op. On the (long obsolete) machine where I learned to program in C, there weren't void * yet (too old for the standard), but the equivalent was char *, and the value of a char * address for a given memory location was different from the pointer value for any other type — the casts were not optional.
Note that I'm assuming you intend to print the value of the address. If you intend to print the contents, then there's more work to be done.
Well, not any pointer (type).
According to C11, chapter §7.21.6.1, for the %p conversion specifier,
p
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.
So, the argument must be of type void * (or, a char*, given they have the same alignment requirements). Any other type of pointers, must be converted through an explicit cast, as there is no default argument promotion for pointers.
Something like
printf("%s%p", "argv = ", (void *)argv);
should do.
In order to print argv and it's address you need to do
int main(int argc, char* argv[])
{
int i;
printf("address of argv = %p\n", (void *)argv);
for (i = 0; i < argc; ++i)
{
printf("%s\n", argv[i]);
}
return 0;
}

why do we need to use (void*)&a instead of &a

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.

Why use the & sign to retrieve an integer's memory address, but not a function's address?

I'm currently following along with the Big Nerd Ranch's Objective-C guide, and one of the examples is as follows:
int main(int argc, const char * argv[])
{
int i = 17;
printf("i stores its value at %p\n", &i); return 0;
}
// output => i stores its value at 0xbffff738
int main(int argc, const char * argv[])
{
int i = 17;
printf("i stores its value at %p\n", &i);
printf("this function starts at %p\n", main); return 0;
}
// output => i stores its value at 0xbffff738
// this function starts at 0x100000ed0
I tried using the "&" symbol in front of main, and I get the same result- 0x100000ed0. But when I remove the ampersand from in front of "i", I see only 0x11 instead of 0xbffff738.
Question- why the difference? And why does one work with or without an ampersand, while the other seems to require it in order to produce the expected output?
An expression of function type (including a function name) is implicitly converted to a pointer to the function in most contexts. The exceptions are when it's the argument to a unary sizeof or & operator. sizeof function_name is illegal, but in &function_name the subexpression function_name is not converted to a pointer; the & operator then yields the function's address.
So given that foo is the name of a function, these expressions:
foo
&foo
*foo
**foo
***foo
...
all yield the address of the function.
There are similar rules for array expressions, which are usually converted to the address of the array's first element. There's one additional exception (a string literal used in an initializer for an array object), and &array_name is valid (it yields the address of the array object, which refers to the same address but has a different type than the address of the first element).
Incidentally, the %p format expects an argument of type void*. On many systems, all pointers have the same representation, so you can probably get away with passing any pointer value -- but there's no guarantee that it will work. For maximum safety and portability, you should print a pointer value by casting it to void*:
printf("i stores its value at %p\n", (void*)&i);
And there is no standard format for printing a function pointer value. This:
printf("this function starts at %p\n", (void*)main);
is likely to work, but strictly speaking the behavior of the conversion from int (*)(int, char **) (the type of the address of main) to void* is undefined. See this question for more information.
For 100% portability, you can extract the representation of a function pointer by treating it as an array of unsigned char, but it's probably not necessary.
i is not a pointer type but an integer type. You need the & operator to get its address.
main is a function designator and in an expression is converted to a pointer to a function in the usual conversion rules.
printf("this function starts at %p\n", &main); // OK, & yields a pointer to main
printf("this function starts at %p\n", main); // OK also, usual conversion rules
// yields a pointer to main
Note that the printf call is technically undefined behavior as p conversion specifier requires an argument of type void *.
In C, like array names which are converted to pointers to array's first element when passed to a function, function names are converted to the pointer to that function. In case of
printf("i stores its value at %p\n", (void *)&i);
i is not a pointer type and hence you need to pass a pointer type argument and this would be done by placing & before i in the argument.
in C, function name is handled specially. you can see three of these give the same output:
main
*main
&main
http://ideone.com/jMz0W4
unlike data identifiers, which have type tree system, function identifiers have no.

Resources