-1

Trying to understand pointer.

Below, I just want to prove to myself the below

address of str ( &str) = address of where str2 is pointed to(str2) actual memory of address for str2 is something different(&str2)

However, when I compile below I get seg fault saying "morePointers.c:6:56: warning: format specifies type 'int' but the argument has type 'char *' [-Wformat]"

How can I correct this while proving this in the code?

int main(int argc, char** argv) {
    char str = "goodbye";
    char *str2 = str;

    printf("%d %d %s %d %d\n", &str2, str2, str2, str, &str);
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
user3502374
  • 781
  • 1
  • 4
  • 12

2 Answers2

2

In this declaration

char str = "goodbye";

you are trying to initialize an object of the type char with a string literal that in the initialization expression has the type char *.

You have to write

char *str = "goodbye"; 

Instead of this declaration

char *str2 = str;

it seems you mean

char **str2 = &str;

that is you are creating a pointer that points to the pointer str.

Thus dereferencing the pointer str2 you will get the value stored in the pointer str that is the address of the first character of the string literal "goodbye".

Here is a demonstrative program

#include <stdio.h>

int main(void) 
{
    char *str = "goodbye";
    char **str2 = &str;

    printf( "str = %p is the same as *str2 = %p\n", ( void * )str, ( void * )*str2 );
    printf( "str2 = %p contains the address of str (&str) = %p\n", ( void *)str2, ( void *)&str );

    printf( "The string literal pointed to by str = %s\n"
            "is the same as pointed to by *str2 = %s\n",
            str, *str2 );

    return 0;
}

The program output might look like

str = 0x561655562008 is the same as *str2 = 0x561655562008
str2 = 0x7ffdb7fc57a8 contains the address of str (&str) = 0x7ffdb7fc57a8
The string literal pointed to by str = goodbye
is the same as pointed to by *str2 = goodbye

Pay attention to that using the conversion specifier %d with pointers results in undefined behavior.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

This would be the correct code:

#include <stdio.h>

int main(int argc, char** argv) {
  char *str = "goodbye";  // a '*' was missing in your code
  char* str2 = str;

  // you need to use %p for pointer values
  // and for each argument for a %p you need to cast to (void*)

  printf("%p %p %s %p %p\n", (void*)&str2, (void*)str2, str2, (void*)str, (void*)&str);
}

Typical possible output for this code on a 32 bit system

00FFF710 00996B30 goodbye 00996B30 00FFF71C

Typical possible output for this code on a 64 bit system

0x7ffc8f58ada0 0x555ba93f6004 goodbye 0x555ba93f6004 0x7ffc8f58ad98
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • "*for each argument for a `%p` you need to cast to `(void*)`*" - Why? `printf("%p %p %s %p %p\n", &str2, str2, str2, str, &str);` works too with `-Wall` and `-Werror` flag enabled. – RobertS supports Monica Cellio Feb 27 '20 at 15:15
  • 1
    @RobertSsupportsMonicaCellio Because `%p` expects a `void *` argument and anything else is undefined behavior (C11 7.1.4): *"If an argument to a function has [...] a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined."* and (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."* – S.S. Anne Feb 27 '20 at 15:19
  • @RobertSsupportsMonicaCellio usually it works without the `(void*)` cast, but the standard says it needs to be `void*`, see this: https://stackoverflow.com/a/24867850/898348. But to be honest I don't really understand _why_ passing a pointer without the cast could cause UB. – Jabberwocky Feb 27 '20 at 15:23
  • @Jabberwocky Some systems might have "fat pointers" of different sizes that contain information about the type. None that I know of have this, but it's possible. – S.S. Anne Feb 27 '20 at 15:24
  • @S.S.Anne good point – Jabberwocky Feb 27 '20 at 15:25
  • I downvoted because there's many easily-accessible duplicates and if not then this qualifies as a typo. Posting answers to low-quality questions like this to get reputation (which works) is low. Feel free to revenge-downvote me if you wish but it's my choice. – S.S. Anne Feb 27 '20 at 15:26
  • 1
    @S.S.Anne that's OK – Jabberwocky Feb 27 '20 at 15:27
  • @S.S.Anne So I need to do this also when printing the address of a non-pointer variable, like `int i = 25; printf("%p",(void*)&i);` – RobertS supports Monica Cellio Feb 27 '20 at 15:32
  • 1
    @RobertSsupportsMonicaCellio Yeah. I hope the C committee changes that in C20. – S.S. Anne Feb 27 '20 at 15:32
  • @RobertSsupportsMonicaCellio yes, but `&i` _is_ a pointer. – Jabberwocky Feb 27 '20 at 15:33
  • @Jabberwocky Yes, but I meant not a "*real*" lvalue pointer variable. – RobertS supports Monica Cellio Feb 27 '20 at 15:36
  • @S.S.Anne Would be definitely worth an update. – RobertS supports Monica Cellio Feb 27 '20 at 15:37
  • @RobertSsupportsMonicaCellio Redirecting to [`printf("%p")` and casting to `(void *)`](https://stackoverflow.com/questions/24867814/printfp-and-casting-to-void)... – S.S. Anne Feb 27 '20 at 15:38