Why does reading into a string buffer with scanf work both with and without the ampersand (&)?

CScanf

C Problem Overview


I'm a little bit confused about something. I was under the impression that the correct way of reading a C string with scanf() went along the lines of

(never mind the possible buffer overflow, it's just a simple example)

char string[256];
scanf( "%s" , string );

However, the following seems to work too,

scanf( "%s" , &string );

Is this just my compiler (gcc), pure luck, or something else?

C Solutions


Solution 1 - C

An array "decays" into a pointer to its first element, so scanf("%s", string) is equivalent to scanf("%s", &string[0]). On the other hand, scanf("%s", &string) passes a pointer-to-char[256], but it points to the same place.

Then scanf, when processing the tail of its argument list, will try to pull out a char *. That's the Right Thing when you've passed in string or &string[0], but when you've passed in &string you're depending on something that the language standard doesn't guarantee, namely that the pointers &string and &string[0] -- pointers to objects of different types and sizes that start at the same place -- are represented the same way.

I don't believe I've ever encountered a system on which that doesn't work, and in practice you're probably safe. None the less, it's wrong, and it could fail on some platforms. (Hypothetical example: a "debugging" implementation that includes type information with every pointer. I think the C implementation on the Symbolics "Lisp Machines" did something like this.)

Solution 2 - C

I think that this below is accurate and it may help. Feel free to correct it if you find any errors. I'm new at C.

char str[]  
  1. array of values of type char, with its own address in memory

  2. array of values of type char, with its own address in memory as many consecutive addresses as elements in the array

  3. including termination null character '\0' &str, &str[0] and str, all three represent the same location in memory which is address of the first element of the array str

    char *strPtr = &str[0]; //declaration and initialization

alternatively, you can split this in two:

char *strPtr; strPtr = &str[0];

4. strPtr is a pointer to a char 5. strPtr points at array str

  1. strPtr is a variable with its own address in memory
  2. strPtr is a variable that stores value of address &str[0]
  3. strPtr own address in memory is different from the memory address that it stores (address of array in memory a.k.a &str[0])
  4. &strPtr represents the address of strPtr itself

I think that you could declare a pointer to a pointer as:

char **vPtr = &strPtr;  

declares and initializes with address of strPtr pointer

Alternatively you could split in two:

char **vPtr;
*vPtr = &strPtr

10. *vPtr points at strPtr pointer 11. *vPtr is a variable with its own address in memory

  1. *vPtr is a variable that stores value of address &strPtr
  2. final comment: you can not do str++, str address is a const, but you can do strPtr++

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionabelnView Question on Stackoverflow
Solution 1 - CGareth McCaughanView Answer on Stackoverflow
Solution 2 - CangelitaView Answer on Stackoverflow