scanf("%3s", str) with only 1 input character in c

71 Views Asked by At
#include<stdio.h>

int main(void) {
   char str[3];
   scanf("%3s", str);
   return 0;
}

What is the content of str[2] if I enter only one character? Is this undefined behaviour or will all remaining characters be fillt with '\0'? I do only care about the first three charaters. Even the \0 terminator is irrelivant to me because I do not want to use this array as a String.

I tried this and the remaining characters were all '\0' but this could be compiler specific.

4

There are 4 best solutions below

2
Lundin On BEST ANSWER

What is the content of str[2] if I enter only one character?

The content would be indeterminate, since this is is a local array which was never initialized. scanf (family) used with %3s only guarantees that up to 3 characters are read - but if the user types for example a letter then a whitespace character, scanf will stop there and only read the one character entered.

It is also appending a null terminator character after the input, so in case the user types exactly 3 characters and then hit enter, scanf will write the null terminator out of bounds.

You can try this yourself with this little program that prints the binary contents of the buffer:

#include <stdio.h>

int main(void) 
{
  char str[4]={1,2,3,4};
  scanf("%3s", str);
  printf("%.2X %.2X %.2X %.2X", str[0], str[1], str[2], str[3]);
}

Here I changed the size to 4 and initialized the array for illustration purposes.

  • Input: A <enter>
    Output: 41 00 03 04

    41 being the ASCII value of 'A', 00 being the null terminator appended and 03 04 being the contents that happened to be in the memory since before. If this would have been an uninitialized local array, those values could have been "garbage". As we can see, scanf does not "zero pad" the remaining parts of the array (like strncpy would do, for example).

  • Input: ABC <enter>
    Output: 41 42 43 00

    41 42 43 are the letters and 00 is the appended null terminator. Had this been an array with size 3, it would have been out of bounds. scanf has no clue how big the array is, so I would have lied to scanf if I used %3s and passed it a char [3] array, saying "hey you can store 3 characters + null termination here", even though there wouldn't be any room left.

0
gulpr On

C strings are char arrays. The string is terminated with the null terminating character.

To store 3 characters + null terminating character you need 4 elements char array.

Your scanf will invoke undefined behaviour if the user enters 3 or more chars.

What is the content of str[2] if I enter only one character? Is this undefined behaviour or will all remaining characters be fillt with '\0'?

As your variable has automatic storage duration the value str[2] is not determinable (it can be anything).

If str array has static storage duration (ie is defined inside the function with the static attribute or is global) then it will have value of 0 (as not initialized static storage duration objects are zeroed before call to the main functions is done.

0
Eric Postpischil On

The rule for processing an s conversion, in C 2018 7.21.6.2, says:

… the corresponding argument shall be a pointer to the initial element of a character array large enough to accept the sequence and a terminating null character, which will be added automatically…

This tells us that, if you enter one (non-white-space) character (and presumably follow it with a white-space character or some end-of-input indication), that the character will be put into str (at str[0]) and a null character will be put into str after it.

The standard does not say anything is written to any elements of str after those.

Note that %3s allows up to three characters to be read, in which case you need four elements in str so that it can hold the three characters and the terminating null character.

0
chux - Reinstate Monica On

What is the content of str[2] if I enter only one character?

The content of str[2] is indeterminant.


Also a potential bug

The width in "%3s" is 1 too high.

char str[3];
scanf("%3s", str);

Tip, avoid coding the wrong width with %s.

#define GET_WORD_N 256
#define str(token) #token
#define xstr(token) str(token)

char* get_word(void) {
  static char buf[GET_WORD_N + 1];
  if (scanf("%" xstr(GET_WORD_N) "%s", buf) == 1) {
    return buf;
  }
  return NULL;
}