Justin Leung
Justin Leung

Reputation: 39

Understanding scanf in C

So I'm fairly new to programming and I started C about 3 days ago. I was creating this short program to test myself. It's just an extremely basic C program asking for your first and last name. Here is the code:

#include <stdio.h>

int main() 
{

    char first[20];

    char last[20];

    printf("Please enter your first name:");
    scanf("%s",&first);
    printf("\nand Please enter your last name:");
    scanf("%s",&last);
    printf("Greetings fellow %s %s!\n",first,last);
    return(0);
}

But when I go to compile I get this error every single time:

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

I know I can use gets() except apparently it's bad and I shouldn't use it. What is wrong with this code? I don't understand what the problem is.

Upvotes: 2

Views: 721

Answers (5)

suspectus
suspectus

Reputation: 17258

Remove the & from the scanf statements.

scanf("%s", first);  // first is pointer to start of first
scanf("%s", last);   // last is pointer to start of last 

In C the name of an array is a pointer to the start of the array.

After the format parameter scanf requires pointer argument or arguments.

scanf(  "%s", first  );
scanf format-arg input-args

For example, if a integer parameter were being used for scanf, the & (take the address of) operator would be required.

int n;
scanf("%d", &n);    // &n is pointer to n

Upvotes: 1

Jerry Coffin
Jerry Coffin

Reputation: 490108

Try changing scanf("%s",&first); to scanf("%s",first); (and similarity for last).

Under normal circumstances (including these) the name of an array evaluates to the address of the first element in the array. In this case, that's a pointer to char, which is the type scanf expects for a %s conversion.

With the & on the beginning, you get the same pointer value (i.e., the same address), but as a pointer to an array instead of a pointer to the element of the array. Since this doesn't match the type expected by %s, the result is undefined behavior (though since it's the right address, this will usually work with most typical compilers/CPUs).

Upvotes: 1

user529758
user529758

Reputation:

I know I can use gets() except apparently it's bad and I shouldn't use it.

Exactly, exactly - it's prone to buffer overflow errors. And scanf() is equally evil (partially for the same reason - it's not trivial to specify the buffer length, and anyways, it's way more complex than necessary, it's hard to get it right, and it's superfluously expensive for simple raw I/O), don't use it either. Use fgets() for acquiring user input, it saves your from being shot in the foot by letting you pass it the length of the buffer to be written to:

char buf[0x40];
fgets(buf, sizeof(buf), stdin);

Now that you know the "how", I'll explain to you the "why".

Arrays, when passed to functions, are said to decay into pointers. If you pass a char [] to a function, it will see that as a char * that points to the first element to the array. That's why you don't have to explicitly use the "addressof" (&) operator for a (char) array (which is conceptually a string in C).

If you use it, you don't get a pointer to the first element of the array, but a pointer to the array itself, and that's not what you want.

(In general, it could work, as it apparently did for you, but in theory it invokes undefined behavior because the actual type of the expression passed in and the type expected by the %s conversion specifier don't match.)

This document is a good read about arrays and pointers, make sure to read and understand it.

Upvotes: 7

aah134
aah134

Reputation: 860

scanf need an address, however a char array [] is already an address and scanf doesnt need the reference sign & because the name itself is an address

Upvotes: 0

Shumail
Shumail

Reputation: 3143

You are using array. Dont use & with scanf while input to array

e.g: scanf("%s",first);

Arrays are already passed by reference. You don't need to put & as array is already passed as a pointer to the first element in C

Upvotes: 2

Related Questions