24

I am trying to run a simple C program, but I am getting this error:

warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’

I am running Mac OS X v10.8 (Mountain Lion) and am compiling in the terminal using GCC 4.2.1.

#include <stdio.h>

int main() {
    char me[20];

    printf("What is your name?");
    scanf("%s", &me);
    printf("Darn glad to meet you, %s!\n", me);

    return (0);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
l00kitsjake
  • 955
  • 3
  • 11
  • 24

3 Answers3

49
scanf("%s", &me);

should be

scanf("%s", me);

Explanation:

"%s" means that scanf is expecting a pointer to the first element of a char array.

me is an array object. Array objects are said to decay as a pointer to their first element when passed to a function or used in most expressions except as an argument to sizeof and _Alignof. So passing me or &me[0] is equivalent and the preferred way is to simply pass the destination as me.

Adding & to me creates a pointer to arrays of 20 chars, with type char (*)[20], which is different from the type scanf expects for %s. The compiler reports the type mismatch but the program probably behaves as you expect because both &me[0] and &me refer to the same memory location so scanf() really receives the correct address, albeit with an incorrect type.

Code critic:

Using "%s" could cause a buffer overflow if the user inputs a word longer than 19 bytes, so tell scanf() to limit the input to 19 bytes by specifying "%19s":

scanf("%19s", me);

Note also that the return value of scanf() is the number of successful conversions, so 1 if input was processed successfully for %s, and 0 or EOF otherwise. It is always best to test for scanf() failure to read all inputs and only use the destination variables in case of success:

#include <stdio.h>

int main(void) {
    char me[20];

    printf("What is your name?");
    if (scanf("%19s", me) == 1)
        printf("Darn glad to meet you, %s!\n", me);
    else
        printf("Sorry you had to leave!\n");
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
  • 4
    It would be nice if you explained *why* too – Mike May 15 '13 at 16:50
  • 5
    Or `..., &me[0])`, if you really want to use the `&` operator. – alk May 15 '13 at 16:50
  • 4
    @Mike Because... Wait, the compiler warning clearly tells you why. –  May 15 '13 at 16:50
  • 3
    @H2CO3 - ah, but if it was clear to Jake, he wouldn't have asked the question. ;) – Mike May 15 '13 at 16:52
  • I could have improved this further, but was hesitant to because I'm not certain if you'd approve: Basically, an array expression is converted to a pointer expression when a pointer expression is expected, eg. passing to a function. – autistic May 15 '13 at 17:09
  • @undefinedbehaviour the "array object iis evaluated as pointer" could have the same meaning isn't? – MOHAMED May 15 '13 at 17:14
  • @MOHAMED: *the "array object is evaluated as pointer" could have the same meaning isn't?* not really. The confusion between arrays and pointers is so widespread and problematic one should be more precise regarding how arrays *decay* into pointers to their first element instead of invoking some *evaluation* side-effect. I took the liberty to amend your answer but feel free to revert this change if you disapprove. – chqrlie Aug 02 '23 at 10:51
4

Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize an array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and it will evaluate to the address of the first element in the array.

The array me is declared as a 20-element array of char; normally, when the expression me appears in your code, it will be treated as an expression of type "pointer to char". If you had written

scanf("%s", me);

then you wouldn't have gotten the error; the expression me would have been converted to an expression of the correct type.

By using the & operator, however, you've bypassed that rule; instead of a pointer to char, you're passing a pointer to an array of char (char (*)[20]), which is not what scanf expects for the %s conversion specifier, hence the diagnostic.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • s/bypassed/taken a different avenue/, or something along those lines, perhaps. Because of the rule, the outcome is different. +1 for the quote, regardless. – autistic May 15 '13 at 17:12
  • Note: the `_Alignof` was a mistake in N1570, been removed in the standard. That makes sense, because the operand of `_Alignof` is a type, `_Alignof ( type-name )`, not an arbitrary expression. – Daniel Fischer May 15 '13 at 18:05
  • @DanielFischer Can you please look into this one.The "anomaly" I have point to is pretty clear.It's about the last token, which is between the last delimiter & the NULL character,rather than 2 delimiters as is required for a string token--http://stackoverflow.com/questions/16571060/strtok-issue-if-tokens-are-delimited-by-delimiters-why-is-last-token-between – Rüppell's Vulture May 15 '13 at 19:30
  • @DanielFischer I regret I have to message you this way,I checked your activity and it says you were last seen a minute back and this question was the latest C related activity of yours. – Rüppell's Vulture May 15 '13 at 19:31
2

Another way you could fix this issue is by doing this:

scanf("%s",&me[0]);

You actually have to give the array's starting point (which in most languages is 0).

Matthew
  • 1,905
  • 3
  • 19
  • 26
Ravi Arora
  • 76
  • 6