1

suppose i have the code:

1a.

char str1[50];
scanf("%s",&str1);

this works fine.

1b.

char str1[50];
scanf("%s",str1);

this also works fine.

however, the following code cant take input from user.

1c.

char str1[50];
scanf("%c",str1[0]);

I know that & is required to take input from user and store it in an address, but what is happening in first case ?

guitar_geek
  • 498
  • 2
  • 9
  • 19

4 Answers4

3

The correct way to read in a string is either of these:

scanf("%s", &str1[0]);    // Correct
scanf("%s", str1);        // Also correct

The first one is explicitly correct--you want to pass the address of the first char. The second, it turns out, is equivalent. When you pass an array to a function, it silently "decays" to a pointer. The compiler converts arguments like array into &array[0].

scanf("%c",str1[0]);      // Incorrect

Passing the first character instead of the address of the first character is flat out wrong. This will either fail to compile, or will very likely crash when you run the program. A character is very different from an address.

scanf("%s", &str1);       // Undefined behavior

This is wrong, but not "flat out" wrong, if I may be allowed to make such a distinction.

Passing &str1 is a common error. The reason is subtle indeed. &str[0] is the address of the first character of the string. &str is the address of the entire 50-character array. The subtlety here is that these will in fact be the same address in memory--an array starts at its first character.

So why is this wrong?

The answer is in typing.

  • The type of &str[0] is char * -- pointer to character. That's the expected type when you use %s.

  • The type of &str is char (*)[50] -- pointer to a 50-character array. This is not the same thing as char *. For further explanation, see: How come an array's address is equal to its value in C?.

The values of &str and &str[0] are equal, but the types are different. This type mismatch is, pedantically speaking, an error. It causes undefined behavior.

I know what you're thinking. "Okay, smart guy--if this is an error, then why does it work, huh?" Well, C is a funny language. It's really trusting. Overly trusting, really. If you tell it to jump off a cliff, it'll jump off that cliff. It doesn't go out of its way to verify that you're doing absolutely correct and sensible things.

There are lots of times when you can ask it to do something that's technically invalid. Compilers aren't required to diagnose and prevent undefined behavior. In the name of efficiency, it's permissible for them to do anything they want: crash, or print an error message... or, commonly, appear to actually work. This is one of those cases. The values of &str and &str[0] are the same, and because scanf() is a varargs function, not all compilers will catch the type mismatch.

The morale is: don't rely on the compiler to tell you every time you make a mistake. If you mess up and invoke undefined behavior, you may get away with it for a while. Your code may appear to work. But you're sitting on a ticking time bomb. One day it will blow up in your face.

Community
  • 1
  • 1
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • isnt &str is the address of the variable that stores the address of the 50-char array? – tomer.z Sep 09 '14 at 19:58
  • `str1` is that very array. It doesn't hold the array's address, it **is** the array. `str1` is the array and `&str` is the address of the array. – John Kugelman Sep 09 '14 at 20:04
1

Let's take it all one-by-one:

I know that & is required to take input from user and store it in an address, but what is happening in first case ?

Actually, that's wrong. You cannot store things in an address, as addresses are not modifiable.
What you probably wanted to say is, that you know C is strictly pass-by-value, and thus to let a function modify an object you need to pass a pointer to it (which neccessitates using &).

Now, let's look at your code:

char str1[50];
scanf("%s",&str1);

This is Undefined Behavior, because scanf expects a pointer to character-type (char* unsigned char* signed char* and const-qualified versions).
Passing a value of type char(*)[50] is not ok. Why does it still work?
Because the address of an array and its first element are guaranteed to be identical, your implementation has only one data-pointer-type, and you had the luck (which will bite you later).

This one is ok, if one disregards the buffer-overflow waiting to happen. Always pass a proper limit:

char str1[50];
scanf("%s",str1);

Should be:

char str1[50];
scanf("%49s",str1);

Your next example does something completely different, reading the single next char from the input-stream into *str1:

char str1[50];
scanf("%c",str1[0]);

That's probably not what you wanted.

Additional note: Always check how many fields where assigned, that's the return-value of scanf.

Community
  • 1
  • 1
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
0

When you declare an array such as char str1[50], memory for the array is allocated on the stack and looks like:

str1
+----+----+----+----+----+----+----+
| 0  | 1  |   ........   | 48 | 49 |
+----+----+----+----+----+----+----+

Now, if you take the elements of the array, they are:

str1[0]
+----+----+----+----+----+----+----+
| 0  | 1  |   ........   | 48 | 49 |
+----+----+----+----+----+----+----+

     str1[1]
+----+----+----+----+----+----+----+
| 0  | 1  |   ........   | 48 | 49 |
+----+----+----+----+----+----+----+

etc.

For arrays like that, it so happens that the address of str1 is the same as the address of str1[0].

Synantically, the correct way of using using scanf is:

scanf("%s", str1);

or

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

It works with

scanf("%s", &str1);

since &str1 and &str1[0] are the same.

They won't work if you use a dynamically allocated array.

char* str2 = malloc(50);

Let's say the value returned by malloc is AAA

The memory layout for str2 looks like:

str2
+-----+
| AAA |
+-----+

The memory at address AAA looks like:

+----+----+----+----+----+----+----+
| 0  | 1  |   ........   | 48 | 49 |
+----+----+----+----+----+----+----+

The elements of the array are located starting at AAA.

str2[0]
+----+----+----+----+----+----+----+
| 0  | 1  |   ........   | 48 | 49 |
+----+----+----+----+----+----+----+

     str2[1]
+----+----+----+----+----+----+----+
| 0  | 1  |   ........   | 48 | 49 |
+----+----+----+----+----+----+----+

For this case, &str2 is not the same as &str2[0]. If you use:

scanf("%s", &str2);

you will experience undefined behavior.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

In my opinion, the real issue here is that C / C++ treats array names as references rather than values, combined with the fact that some C / C++ compilers will treat an explicit reference to an array name, such as &str, the same as str. For example with the following code, some 32 bit compilers (Visual C/C++ 4.0) will output 32 for sizeof str1 and 32 for size of &str1, while others (Visual Studio 2005 or later) will output 32 for sizeof str1 and 4 for sizeof &str1

#include <stdio.h>
main()
{
char str1[32];
    printf("%d %d\n", sizeof(str1), sizeof(&str1));
    return (0);
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61