3

i am new to c and have used python before. This whole buffer overflow stuff is really breaking my mind.

#include <stdio.h>

int main(){

    char str1[3];
    while(true){
        scanf("%2s", str1);
        printf("test\n");
    }
}

This is a little code i've written to test the syntax and the stdio library. I was really suprised when the program outputted "test" multiple times, depending on how many characters i entered. So for example, when I entered two characters, it printed "test" two times. Can anyone please tell me why this is happening and how I can fix it?

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • 2
    Your posted code fails to compile on my compiler, because it is missing `#include `, which is required if you want to use `bool` in C. Are you using a C or a C++ compiler? – Andreas Wenzel Jul 30 '22 at 17:55
  • It's the same thing when I use 1 instead of trrue. I'm using g++. – user15589641 Jul 30 '22 at 17:57
  • What do you mean by "entered 2 characters"? What exactly was the data on the input stream? Did you try outputting what `scanf` assigned to `str1`? – William Pursell Jul 30 '22 at 17:59
  • I removed the c++ tag on the question, but now I am not sure whether this was appropriate, since you are now stating that you are using a C++ compiler. Why are you using a C++ compiler for compiling C-style code? – Andreas Wenzel Jul 30 '22 at 18:02
  • If you are entering data interactively and type `ab`, I would expect it to print once and immediately block. If you type `ab`, I would expect the behavior you describe. – William Pursell Jul 30 '22 at 18:02
  • In your question, you wrote: "So for example, when I entered two characters, it printed "test" two times." -- I am unable to reproduce this. Did you enter both characters on the same line? Please specify the exact input, including when you pressed the ENTER key. – Andreas Wenzel Jul 30 '22 at 18:06
  • Why need to use `%2s` as the format. Instead use `%s`. Or a better function to be used would be `fgets`. – L_R Jul 30 '22 at 18:07
  • @WilliamPursell I entered all characters in the same line. It printed test times every two characters i entered, so for example my input character is f: f test ffff test test ffffff test test test – user15589641 Jul 30 '22 at 18:11
  • @user15589641 Why would you expect any different? The scanf only consumes 2 characters at a time, since you specified `%2s`. As soon as it reads 2 characters, it returns. – William Pursell Jul 30 '22 at 18:15
  • @WilliamPursell but how does that effect the printf? – user15589641 Jul 30 '22 at 18:17
  • If your goal is to learn `C`, stop looking at `scanf`. It is a completely unnecessary function whose only purpose is to confuse people. It has no actual purpose. Time spent learning the foibles of `scanf` is a complete wasted. Just avoid it. – William Pursell Jul 30 '22 at 18:17
  • Every time scanf returns, a `printf` will be executed and you will see "test" in the output. – William Pursell Jul 30 '22 at 18:18
  • But shouldn't the while loop continue from the top again. I would expect the loop to start from the top after every print of "test" because it is the end of the loop. So no mattre how many characters I enter into the scan function, it will always print "test" once – user15589641 Jul 30 '22 at 18:21
  • What would you recommend to use instead of scanf?` – user15589641 Jul 30 '22 at 18:21
  • 1
    If you type `abcdef` into the terminal, scanf will read `ab` and return. The "test" is printed. Then it goes to the top of the loop and scanf reads `cd`. It won't block again until it has exhausted all the available data. – William Pursell Jul 30 '22 at 18:23
  • Now I get it, thank you – user15589641 Jul 30 '22 at 18:25

3 Answers3

1

You can figure out what happens by modifying your code as follows:

#include <stdio.h>

int main(){

    char str1[3];
    while( 1 ){
        scanf("%2s", str1);
        printf("test: %s\n", str1);
    }
}

which simply prints the contents of the str1 alongside of the "test" string. Here is an example output for an input string of 1234567:

1234567
test: 12
test: 34
test: 56
test: 7 

The scanf("%2s", str1); statement reads two characters from the stdin and assings them to the str1. The read characters are "popped" from the input stream, i.e., they are removed. If the stdin happens to contain more characters, the excess ones are left untouched. Therefore, for the given input, when the first scanf is returned, the str1 containes 12\0, and the stdin contains 34567.

Since these are in the infinite loop, the code repeats, scanf gets called again, reading the first two characters from the stdin again, only this time finds 34.

And the process repeats, untill there are no characters left on the stdin, then the scanf waits for the user input, presumably as you would have expected.

Basically, scanf keeps reading instead of waiting for user input, since the stdin already contains something to read.

So for example, when I entered two characters, it printed "test" two times.

This on the other hand, does not make sense, as it should be printing "test" for N/2 times, rounded up, where N is the number of characters you enter.


There is not much that I can suggest for "fixing this", since it is not really clear what you are expecting. But if you want to get rid of the remaining characters in the stdin, you can check this.

aulven
  • 521
  • 3
  • 14
0

You need to clear your input buffer as per this answer

Otherwise, you'll read from the stdin, print it, jump back to the loop head and continue reading, if there is still something in the buffer.

infinitezero
  • 1,610
  • 3
  • 14
  • 29
0

Each time through the loop, scanf("%2s", str1) reads at most 2 non-whitespace characters from the input stream. If there are more than 2 non-whitespace characters available in the stream, the loop will continuously call scanf (and printf) until scanf blocks waiting for data. If the input stream contains ffff\n and has not yet been closed (eg, a user is entering data interactively from a tty), the first 2 calls to scanf will immediately return and printf will be called twice. The 3rd call to scanf will block until more data is available, or the stream is closed, or there is an error.

William Pursell
  • 204,365
  • 48
  • 270
  • 300