1

I'm trying to test the -> operator, but I can't seem to do that, because when I execute the following program and feed the input with a stream, the program stops working.

Note1: I get a warning before compiling, it says that:

format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat=]

Note2: if I omit the line printf("%s\n", *(&home1)->name ), it works just fine, and actually prints whatever I wrote.

#include <stdio.h>
#include <string.h>

typedef struct home_type {
    char name[30] ;
}home;

int main (void) {
    home home1 ;
    char name[30] ;
    scanf ("%[^\n]%*c", name);
    strcpy( home1.name, name) ;
    printf("%s\n", home1.name ) ;
    printf("%s\n", *(&home1)->name ) ;
    return 0 ;
}
newbie
  • 1,199
  • 1
  • 10
  • 25
  • `printf("%s\n", &(&home1)->name[0]);`........ ;) – LPs Feb 17 '17 at 09:34
  • 2
    note: `scanf ("%[^\n]%*c", name);` fails if they press Enter without anything else beforehand, and you will fall through to `strcpy`ing an uninitialized string – M.M Feb 17 '17 at 09:41
  • 1
    Remember that `->` has the `*` already built in, so you don't need another one. – gbarry Feb 17 '17 at 09:47

4 Answers4

5

Remove * and it works. Your code *(&home1)->name is analogous to *(home1.name) e.g. instead of passing the pointer to the first character, it passes the value of the first char in name; due to default argument promotions, that value is converted into an int.

Thus:

printf("%s\n", (&home1)->name );

should work; however you don't need -> here; -> is now just a shortcut for using a pointer-to-structs more conveniently; i.e. (*ptr).name into a more palatable ptr->name; as home is already a struct and not just a pointer to struct, you should use the . instead.

  • yeah, thanks, I was just trying to see how did the `->` operator works in a trivial example. – newbie Feb 17 '17 at 10:10
4

You just have to drop the * (i.e. not dereference):

printf("%s\n", (&home1)->name );

The member name is an array which gets converted into a pointer (char*) when passing to printf(). However, when you dereference it, it's just a single char that you pass. Obviously, it doesn't match with what printf() expects for the format %s.

See: What is array decaying?

Community
  • 1
  • 1
P.P
  • 117,907
  • 20
  • 175
  • 238
  • The member name name is an array which gets converted into a pointer (char*) what is `char*` ? I only know * as a dereference operator which access to the content of a memory address, and why does the dereference operator convert it to a single char? I mean, I understand the fact that the `*` in `*(&home1)->name` is redundant (thanks)... is it because the actual content I'm accesing is the first element of the vector `name`? – newbie Feb 17 '17 at 10:03
  • 1
    @newbie `char*` the type of the 2nd argument that pass (after *decay* - see the link). `->` is implies the struct is a pointer (`&home`). But the `*`(dereference) is applied to the member `name` which is an array. Dereferencing it gives `name[0]` (the first char in `name`). May be, try the same without using a struct if that makes it easier to understand: `char name[30]; scanf("%s", name);` and then see `printf("%s", name);` vs. `printf("%s", *name);`. – P.P Feb 17 '17 at 10:09
  • thank you so much... I was just checking that link, I haven't seen it till 10 seconds ago. Actually using the * with the `name` and with your and others' help, helped me understand the `->` and the `*` operators a little better, and even what the `printf()` function actually does. – newbie Feb 17 '17 at 10:14
  • OMG... I just realised about the associativity from right to left of the `*`, and that the parenthesis that wrap `&home` make that precedence higher, and `->` has higher precedence than `*`, so the `*` affects the actual char[], which I guess by default is the first ([0]) element. – newbie Feb 17 '17 at 10:23
  • 1
    @newbie or, a value of type `array of N` will in most context (including, if preceded by `*`, or passed as an argument to a function), decay into a *`pointer to N`* that points to the first element of the array. – Antti Haapala -- Слава Україні Feb 17 '17 at 13:12
  • it's more general than I was thinking? so, an array (of a given type), will decay [for historical memory needs] in several contexts into a pointer (of a given type) that points to the first element of that array. what about the rest of the elements of that array? I will play a little, and see how I can access to them, but I'm guessing they're in consecutive positions in memory(?). – newbie Feb 17 '17 at 13:31
4

Operators -> and . are interchangeable:

  • obj.field is the same as (&obj)->field
  • ptr->field is the same as (*ptr).field

Note that you have added an asterisk to the result of (&home1)->name, which produces a char. Since printf is a variable-argument function, char is promoted to int during the call, explaining the warning.

When you pass an int for a parameter expecting a pointer, undefined behavior happens; in your case, the program crashes. Removing the dereference operator * will fix this problem.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

(&home1)->name is the member array. *(&home1)->name is a dereference on the member array which because of array decay is equivalent to (&home1)->name[0]. This has type char. Passing a char through the ... of a variadic function such as printf promotes it to int (... causes default argument promotions to apply).

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142