3

Look at the following code:

#include <stdio.h>

int main()
{
    char str[80];
    int n;
    scanf("%s%n",str,&n);
    printf("%s\t%d",str,n);
    putchar('\n');
    getchar(); //to remove '\n'
    scanf("%s%n",&str,&n);
    printf("%s\t%d",str,n);
    return 0;
}

Here is the input and output:

abc
abc     3
123
123     3

As we know, scanf is a variable parametric function, so its parameters will not be cast when it's called. As a result, parameters must be passed in the type exactly what them should be. However, the type of str is char * (decayed from char (*)[80]), while &str has the type of char (*)[80], although they have the same value, namely &str[0].

So why can scanf("%s",&str); work properly without causing segfault due to pointer arithmetic?

nalzok
  • 11,870
  • 17
  • 57
  • 105

1 Answers1

10

The two pointer values (str and &str) have the same binary value, namely the address of str. They do, however, have different types: When passed as an argument, str is converted to type char *, while &str has type char (*)[80]. The former is correct, while the latter is incorrect. It works, but you are using an incorrect pointer type, and in fact gcc warns about the incorrect argument type to scanf.

Tom Karzes
  • 17,131
  • 2
  • 14
  • 32
  • 6
    str has type char[80], but it decays to char*. – 2501 Jan 10 '16 at 10:30
  • Yes, that's true. When passed as an argument, it becomes `char *`. – Tom Karzes Jan 10 '16 at 10:33
  • 3
    It's nothing to do with being passed as an argument. An array decays to a pointer in many usages. It is however wrong to refer to `str` as a _pointer_, as you do in the first sentence of your answer. – davmac Jan 10 '16 at 10:39
  • I reworded it slightly to avoid confusion. My statement about `str` being converted to `char *` when passed as an argument was entirely correct. I never said that was the *only* situation in which that conversion took place, and of course it isn't. – Tom Karzes Jan 10 '16 at 11:00
  • It's still wrong: "str has type char * (when passed as an argument)" - no, `str` is of type "80 element array of `char`", it doesn't have any other type no matter how it is used. The process of decay is a _conversion_, the value is no longer the original value (i.e. it is not `str` anymore). So you could say for instance : "The value of `str` decays to a value of type `char *` (when passed as an argument)" and this would be correct. Even "`str` decays to a value of type `char *` ..." would be better IMO. – davmac Jan 10 '16 at 11:07
  • @davmac I see your point. I reworded it slightly. – Tom Karzes Jan 10 '16 at 11:18
  • @TomKarzes it's better now, thanks (upvoted). – davmac Jan 10 '16 at 11:35