正如在 cmets 部分中已经指出的那样,问题在于该行
scanf("%s",&k[i]);
错了。当使用scanf 和%s 格式说明符时,它将读取输入的整个单词并将该单词写入字符数组k(在您的情况下导致buffer overflow)。
如果您只想读取单个字符,则应使用%c 格式说明符而不是%s。
但是,使用"%c" 的问题是它总是会读取输入流上的第一个字符,这可能是换行符。如果您不希望 scanf 将换行符写入变量,则可以改用格式字符串 " %c"。这将导致scanf 首先从输入流中提取并丢弃所有空白字符(空格、制表符、换行符等),然后再提取字符并将其写入变量。这样,scanf 将永远不会向您的变量写入换行符。
上述解决方案描述了如何使用scanf 解决您的问题。但是,对于基于行的输入,使用scanf 是generally not recommended。请参阅本指南了解一些替代方案:
A beginners' guide away from scanf()
使用scanf 不好的一个原因例如如下:
假设您想输入用户的两个字符。使用scanf,您的代码可能如下所示:
char first, second;
printf( "Please enter the first character: " );
scanf( " %c", &first );
printf( "Please enter the second character: " );
scanf( " %c", &second );
如果用户在按下 ENTER 之前通过输入多个字符来响应第一个提示,则scanf 将接受此输入为有效并返回用户输入的第一个字符。第二次调用scanf 将返回用户输入的第二个字符。它不会等待用户输入新的输入行。换句话说,scanf 会将用户对第一个提示的响应作为对第二个提示的回答。
这个例子表明scanf 不是为可靠地从用户那里获取基于行的输入而设计的。因此,我建议您改用函数fgets。这样,例如,如果用户在每个响应行中输入了多个字符,您就可以拒绝用户输入。
在您的情况下,我建议创建一个函数get_char_from_user,它使用fgets 而不是scanf,例如:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//this function will continue prompting the user until
//the user enters a valid response of a line consisting
//of exactly one character
char get_char_from_user( const char *prompt )
{
for (;;) //infinite loop
{
char buffer[1024], *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read exactly one line of input
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
printf( "Error reading input from user!\n" );
exit( EXIT_FAILURE );
}
//find the newline character, if it exists
p = strchr( buffer, '\n' );
//make sure that entire line was read into buffer
if ( p == NULL && !feof(stdin) )
{
int c;
printf( "The line was too long to fit buffer.\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
printf( "Unrecoverable error when reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//remove the newline character from string
*p = '\0';
//verify that exactly one character was entered
if ( strlen( buffer ) != 1 )
{
printf( "Error: Please enter exactly one character!\n" );
continue;
}
return buffer[0];
}
}
使用这个函数,上面从用户那里读取两个字符的例子可以改成如下:
char first, second;
first = get_char_from_user( "Please enter the first character: " );
second = get_char_from_user( "Please enter the second character: " );
现在,代码更简单,输入验证更好。
但是,就您的原始代码而言,如果能够以允许您编写提示的方式编写代码,那就太好了
Please enter the first character:
Please enter the second character:
Please enter the third character:
Please enter the fourth character:
Please enter the fifth character:
在一个循环中。这需要将get_char_from_user 的prompt 参数更改为printf 格式字符串。之后,您将能够编写如下代码:
int main()
{
const char * const nth_strings[] =
{ "first", "second", "third", "fourth", "fifth" };
char k[5];
for ( int i = 0; i < 5; i++ )
{
k[i] = get_char_from_user(
"Please enter the %s character: ",
nth_strings[i]
);
}
printf( "You entered the following characters:\n" );
for ( int i = 0; i < 5; i++ )
{
putchar( k[i] );
}
}
这是可能的,通过将函数 get_char_from_user 设为 variadic function,如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
//this function will continue prompting the user until
//the user enters a valid response of a line consisting
//of exactly one character
char get_char_from_user( const char *prompt, ... )
{
for (;;) //infinite loop
{
char buffer[1024], *p;
va_list vl;
//prompt user for input
va_start( vl, prompt );
vprintf( prompt, vl );
va_end( vl );
//attempt to read exactly one line of input
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
printf( "Error reading input from user!\n" );
exit( EXIT_FAILURE );
}
//find the newline character, if it exists
p = strchr( buffer, '\n' );
//make sure that entire line was read into buffer
if ( p == NULL && !feof(stdin) )
{
int c;
printf( "The line was too long to fit buffer.\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
printf( "Unrecoverable error when reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//remove the newline character from string
*p = '\0';
//verify that exactly one character was entered
if ( strlen( buffer ) != 1 )
{
printf( "Error: Please enter exactly one character!\n" );
continue;
}
return buffer[0];
}
}
如果将最后两个代码块(函数main和函数get_char_from_user)合并到一个程序中,您将得到程序与用户之间的以下交互:
Please enter the first character: Hello
Error: Please enter exactly one character!
Please enter the first character: H
Please enter the second character: e
Please enter the third character: l
Please enter the fourth character: l
Please enter the fifth character: o
You entered the following characters:
Hello
如您所见,程序在同一行中同时输入多个字符时拒绝输入,并再次提示用户。