QQ said:
Hello I am running this code
int main(void)
{
char A[3],B[3];
printf("Please input A: \n");
scanf("%2s",A);
printf("Please input B: \n");
scanf("%2s",B);
printf("A is %s,B is %s\n",A,B);
}
I get output if I type A more than 2 chars.
./a.out
Please input A:
asdgc
Please input B:
A is as,B is dg
I know the way to avoid this to use
scanf("%s",A);
However, people ususally don't use in this way
so is it a better way to avoid it?
Thanks a lot!
The approach I've adopted over the years, especially with interactive
input, is to read the whole line into memory as a single
dynamically-sized buffer, and then tokenize and parse that buffer.
This has the advantage of consuming all the characters in the input
stream so that you don't have garbage lying around, and it allows you
to verify your input before assigning it. Here's an example:
/*
** Retrieve the next input line from the specified stream,
** stripping off the trailing newline
*/
char *getNextLine(FILE *stream)
{
/*
** Internal line buffer. Dynamically allocated so
** it can deal with lines of arbitrary length. Declared
** static so that only this function has to deal with
** memory management. Pros: memory management is
** encapsulated in this one function, so no memory
*/ leakage. Cons: not re-entrant or thread safe.
static char *buffer = NULL;
static size_t bufsiz = 0;
/*
** Temporary input buffer; reads 512 bytes at a time
** which are then appended to the permanent buffer
*/
char inbuf[512] = {0};
char *tmp = NULL;
/*
** Clear the buffer for each new line.
*/
if (buffer)
{
free(buffer);
buffer = NULL;
bufsiz = 0;
}
/*
** Keep reading input until we hit a newline or EOF, or
** an error occurs (for this example, no distinction is
** made between EOF or error; we just return the buffer or
** NULL in either case.
*/
while (fgets(inbuf, sizeof inbuf, stream))
{
/*
** Extend the buffer as necessary.
*/
tmp = realloc(buffer, strlen(inbuf) + bufsiz + 1);
if (tmp)
{
buffer = tmp;
buffer[bufsiz] = 0;
bufsiz += (strlen(inbuf) + 1);
}
else
{
fprintf(stderr, "Could not extend input buffer past %lu
bytes!\n", (unsigned long) bufsiz);
free(buffer);
buffer = NULL;
bufsiz = 0;
return NULL;
}
/*
** Append the input buffer to the permanent buffer.
*/
strcat(buffer, inbuf);
/*
** Search for the newline. If it's present, replace
** it with the 0 terminator and exit the loop.
*/
if (strchr(buffer, '\n'))
{
*strchr(buffer, '\n') = 0;
break;
}
}
return buffer;
}
int main(void)
{
char A[3],B[3],*line;
for(;
{
printf("Please input A: \n");
line = getNextLine(stdin);
if (strlen(line) > 2)
{
printf("Input too long -- try again\n");
}
else
{
strcpy(A, line);
break;
}
}
/*
** Repeat for B
*/
printf("A is %s,B is %s\n",A,B);
}
Yeah, it's ugly. It can be prettied up a bit (unfortunately I can't
spend a ton of time on it right now). But this is the reality of
interactive input in C -- you have to build your own blade guards.