Art
Art

Reputation: 13

Buffer overflow in scanf()

I was looking online for solution for this problem with no result. I'm trying to do while loop to read only characters using scanf(). If user type more than 3 characters than it will display error.

However, my code works partially if I type 3 characters and press enter it works without executing loop this is what I want. If I type 4 characters and press enter also works it executes loop and says "too long" same for 5 char + enter also what I want.

However, if I type 7 characters and enter it executes loop and exits program right away. Any advice?

Ps. I apologize for any grammar error but English is my second language.

#include<stdio.h>
int main(){
char alo;
char alo1; 
char alo2; 
char alo3;

printf("enter 3 characters: ");
scanf(" %c %c %c%c", &alo, &alo1, &alo2, &alo3); 

while(alo3!='\r' && alo3!='\n'){
    printf("too long \n");
    printf("enter ");       
    scanf(" %c %c %c%c", &alo, &alo1, &alo2, &alo3); 
}   
return 0;
}

Upvotes: 0

Views: 5043

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 753900

Using scanf() only

Using just scanf() to achieve this requires a certain amount of jiggery-pokery. It isn't the best way to code it, but…

#include <stdio.h>

int main(void)
{
    char alo0;
    char alo1;
    char alo2;
    char alo3;

    printf("enter 3 characters: ");

    while (scanf(" %c %c %c%c", &alo0, &alo1, &alo2, &alo3) == 4 &&
           alo3 != '\r' && alo3 != '\n')
    {
        char buffer[4096];
        if (scanf("%4095[^\n]", buffer) == EOF)
            break;
        printf("too long\n");
        printf("enter 3 characters: ");
    }

    printf("Got [%c][%c][%c]\n", alo0, alo1, alo2);
    return 0;
}

The while() condition uses scanf() to read four characters, skipping white space before the first three. Note that it is OK to put newlines in between characters; scanf() doesn't care. If you want line-based input, scanf() is simply the wrong tool for the job! However, assuming that 4 characters are read and the fourth is neither carriage return nor newline, then the code uses:

        char buffer[4096];
        if (scanf("%4095[^\n]", buffer) == EOF)
            break;

to read any characters up to, but not including, a newline. It doesn't mind if there are no such characters so scanf() returns 0. The code then prompts you to enter the correct data and goes around to the main scanf(). This skips the newline that was left behind and then looks for three characters again.

When the while loop exits, it could be because it got three characters and a newline, or because it got fewer characters and EOF, or because the clean-up scanf() detected EOF. The code doesn't attempt to distinguish between these (but it should) and simply prints out three values. Fixing that is not dreadfully hard; simply assign the return from each scanf() to a variable and then test that after the loop:

int rc;
while ((rc = scanf(…)) == 4 && …)
{
    …
    if ((rc = scanf(…)) == EOF) 
        break;
    …
}

if (rc == 4)
    printf(…);
else
    printf("Didn't get 3 characters as requested\n");

Using fgets() for line input

Personally, I think it is easier/better to use fgets() and sscanf() like this:

#include <stdio.h>

int main(void)
{
    char alo0;
    char alo1;
    char alo2;
    char alo3;
    char buffer[4096];
    int rc = 0;

    printf("enter 3 characters: ");

    while (fgets(buffer, sizeof(buffer), stdin) != 0 &&
           (rc = sscanf(buffer, " %c %c %c%c", &alo0, &alo1, &alo2, &alo3)) == 4 &&
           alo3 != '\r' && alo3 != '\n')
    {
        printf("too long\n");
        printf("enter 3 characters: ");
        // In case you get 4 characters but the 4th was not a newline
        // and then you get EOF
        rc = 0;
    }

    if (rc == 4)
        printf("Got [%c][%c][%c]\n", alo0, alo1, alo2);
    else
        printf("Didn't get 3 characters as requested\n");
    return 0;
}

This could report the string that was too long, or otherwise incorrect.

Upvotes: 2

Related Questions