Home > database >  How does array name represent different values when switching %p form %s in printf in C
How does array name represent different values when switching %p form %s in printf in C

Time:12-14

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 name1
    printf("%p \n", name1); // prints address

    //====== malloc =======
    char* name2 = (char*)malloc(10);
    strcpy(name2, "name2"); 
    printf("%s \n", name2); // prints name2
    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.

  • Related