0

I am a new learner for c. And I can't see what on earth this difference is. Thank you for your help!

#include<stdio.h>
int main(void)
{
    char a[9];
    scanf("%s",&a);//scanf("%s",a)
    printf("%s",&a);//printf("%s",a)   they all can run correctly!
    for(int i=0;i<9;i++)
    {
        printf("%c;",a[i]);
    }
    return 0;
}
chd_li
  • 13
  • 1
  • Closely related: [How come an array's address is equal to its value in C?](https://stackoverflow.com/q/2528318/10077) – Fred Larson May 06 '20 at 14:31
  • 1
    An array decays to a pointer when passed to a function, so although you would need `scanf("%d", &i)` you only need `scanf("%s", a)` for an array. – Weather Vane May 06 '20 at 14:33
  • 1
    I'd like to add that you'd need to reference (&) `a` if it were simply an integer when passing it to `scanf`, as you need to pass a pointer to `scanf`. `char a[9]` is an array, so `a` is already a pointer to the first element of the array, thus eliminating the need for `&`. – Inobulles May 06 '20 at 14:58
  • Are they have same output and you want to know why? or you just want to know why code doesn't crash anyway? – milad May 06 '20 at 15:19
  • regarding: `char a[9]; scanf("%s",&a);` if the input is more than 8 characters, the result will be a buffer overrun, resulting in undefined behavior. When using the 'input format specifiers" `%s` and/or `%[..]` always include a MAX characters modifier as those specifiers always append a NUL byte to the input. – user3629249 May 08 '20 at 20:36

3 Answers3

6

With &, you are invoking undefined behavior for type mismatch: %s expect char*, but &a here has type char(*)[9] (a pointer to 9-elemnent character array).

In typical environment, pointers are implemented as simple memory addresses. Despite of type mismatch, the address of the array &a and its first element a will be the same (same size and same value), so there are high chance to work well.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
3

Allow a little analogy

Imagine you live in a (semi-)transparent world and you have a few differently colored laser pointers.

You use red lasers to point at people, blue lasers to point at planes, yellow lasers to point at mobile phones, ..., ...

It's illegal to mismatch pointers and objects (undefined behaviour in C slang), so no yellow lasers on planes, no blue lasers on people, ...

Now imagine you are using a yellow laser to point to a mobile phone of someone travelling in a plane, and you ask a color-blind friend (the printf()) what plane the pointer points to. Your friend does not care about the color and, wrongly, says it's whatever plane the yellow laser shines on.

But the responsible person for the error is you. You tricked your friend!

Don't lie to the compiler

pmg
  • 106,608
  • 13
  • 126
  • 198
0

regarding:

#include<stdio.h>
int main(void)
{
    char a[9];
    scanf("%s",&a);//scanf("%s",a)
    printf("%s",&a);//printf("%s",a)   they all can run correctly!
    for(int i=0;i<9;i++)
    {
        printf("%c;",a[i]);
    }
    return 0;
}

When compiling, always enable the warnings, then fix those warnings. ( for gcc, at a minimum use: -Wall -Wextra -Wconversion -pedantic -std=gnu11 ) Note: other compilers use different options to produce the same results.

The posted code results in three(3) warning messages from the compiler

gcc   -O1  -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11  -c "untitled2.c"  

untitled2.c: In function ‘main’:

untitled2.c:5:13: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[9]’ [-Wformat=]
     scanf("%s",&a);//scanf("%s",a)
            ~^  ~~

untitled2.c:6:14: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[9]’ [-Wformat=]
     printf("%s",&a);//printf("%s",a)   they all can run correctly!
             ~^  ~~

untitled2.c:5:5: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Wunused-result]
     scanf("%s",&a);//scanf("%s",a)
     ^~~~~~~~~~~~~~

Compilation finished successfully.

The final statement: "Compilation finished successfully.", when there are warning messages, only means the compiler produced some 'work around' for the problems, That does not mean the compiler produced the code that you wanted.

regarding:

for(int i=0;i<9;i++)
{
    printf("%c;",a[i]);
}

if the input from the user was less than 8 bytes, then some trash/garbage bytes will be output.

Suggest:

for( int i=0; a[i]; i++ )  // stops on NUL byte
{
    printf("%c;",a[i]);
}

so only the user input and not the uninitialized bytes be output.

Even better, since the call to scanf() with %s will have NUL terminated the input is to use the single statement:

printf( "%s\n", a );

OT: When calling any of the scanf() family of functions, always check the returned value (not the parameter values) to assure the operation was successful. Note: those functions return the number of successful 'input format conversion' specifiers (or EOF). Suggest: (after syntax corrections and error checking added)

if( scanf("%8s",a) != 1 )
{  // error occurred
    fprintf( stderr, "scanf for input data failed\n" );
    exit( EXIT_FAILURE );
}
user3629249
  • 16,402
  • 1
  • 16
  • 17