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.