I couldn't understand how array name, which points to the first address of the array, can represent a value if used with %s in printf. When used with %p, array name would represent the address, which is what I predicted. However, when used with %s, the array name would represent the value. I thought I would have to dereference the array name using * to refer to the value in that address?
// How can an array name represent different values when we just change the argument from %s to %d?
//====== array =======
char name1[10] = "name1";
printf("%s \n", name1); // prints a
printf("%p \n", name1); // prints address
//====== malloc =======
char* name2 = (char*)malloc(10);
strcpy(name2, "name2");
printf("%s \n", name2); // prints a
printf("%p", name2); // prints address
CodePudding user response:
In both cases, the array address1 is passed to printf
.
%s
tells printf
to read the memory at that address and print the characters it finds there until it finds a null character.
%p
tells printf
to print the address in some human-readable way. (The specific format used is implementation-defined; it may vary across different C implementations.)
(Properly, when using %p
, the address ought to be converted to void *
: printf("%p \n", (void *) name1);
. Although the behavior is not defined by the C standard if this is not done, it will work in most C implementations.)
Footnote
1 In printf("%s \n", name1);
, the array name1
is automatically converted to a pointer to its first element. This automatic conversion occurs whenever an array is used in an expression except as the operand of sizeof
, as the operand of unary &
, or as a string literal used to initialize an array.
CodePudding user response:
Both specifiers, %p
and %s
, expect a pointer value.
I thought I would have to dereference the array name using * to refer to the value in that address?
That is what printf
is doing for you, when using the %s
specifier.
printf
reads the specifier %s
, and gets the associated variadic argument as a char *
. Using this pointer value, it performs indirection - printing the character value pointed at, and incrementing the pointer until said character value is equal to the null terminating character.
Very crudely, this looks like:
#include <stdarg.h>
#include <stdio.h>
void print_a_string(const char *str)
{
while (*str)
putchar(*str );
}
void print(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
while (*fmt) {
if ('%' == *fmt) {
fmt ;
if (!*fmt)
break;
if ('s' == *fmt)
print_a_string(va_arg(args, char *));
} else
putchar(*fmt);
fmt ;
}
va_end(args);
}
int main(void)
{
const char *string = "Hello world!";
print("%s\n", string);
}
The %p
specifier produces an implementation defined character sequence that represents a pointer value.
Also note that an argument associated with the %p
specifier should be cast to a void *
.
printf("%p\n", (void *) name1);
CodePudding user response:
I thought I would have to dereference the array name using * to refer to the value in that address?
The printf
function does that, internally.
printf("%s\n", "hello");
is similar to
puts("hello");
In neither case do you see the *
operator: just the address of the first character is passed into the function. The puts
function could look like:
int puts(const char *str)
{
while (*str) {
if (putchar(*str ) == EOF) // The * operator is here!
return EOF;
}
if (putchar('\n') == EOF)
return EOF;
return 0;
}
A function which receives a pointer to an object may use the *
operator to retrieve value(s) from that object, so the value extraction isn't visible in the function call.