有人可以帮我解决问题吗?我对%[^\n]
有疑问。当我尝试输入错误输入时程序循环我写的警告,但如果我使用%s
并输入我的字符串,则下一个语句无法正常工作。
#pragma warning (disable:4996)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("input name [1..30 char]: ");
scanf("%[^\n]", name); fflush(stdin);
if ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z')) {
flag = 1;
}
else {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z)\n");
}
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
else {
flag1 = 1;
}
} while (flag == 0 || flag1 == 0);
do {
printf("Input phone number[6..12 digits]: ");
scanf("%s", number); fflush(stdin);
for (i = 0; i < strlen(number); i++) {
if (number[i] >= '0' && number[i] <= '9') {
flag2 = 1;
}
else {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9)\n");
}
if (strlen(number) >= 6 && strlen(number) <= 12) {
flag3 = 1;
}
else {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits\n");
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
getchar();
return 0;
}
答案 0 :(得分:2)
哦顺便说一下,问题可能只是scanf
调用将换行符留在缓冲区中,如果循环再试一次,看到的第一个字符将是换行符,scanf
应该不读任何东西。
您应该做两件事:首先检查scanf
返回的内容,如果它读取字符串,则应返回1
。其次,您应该通过在格式字符串scanf
中首先添加空格来告诉" %[^\n]"
丢弃任何可能的前导空格。
大多数scanf
格式会自动跳过前导空格,但在使用"%["
或"%c"
格式时则不会。
另外,为了不用担心写出数组的界限,你应该添加一个长度修饰符,以确保scanf
没有读取比它可以写的更多的输入:" %29[^\n]"
。如果在此之后字符串的长度为29
,那么您应该阅读,直到您逐字符到达行尾。
答案 1 :(得分:1)
这是你的程序修复:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
// In case you need this -- not needed for this case
void discard_input()
{
char c;
while( ( c = getchar() ) != '\n' && c != EOF );
}
void remove_trailing_newline(char * s)
{
char * ch = s + strlen( s ) - 1;
while( ch != s ) {
if ( *ch == '\n' ) {
*ch = 0;
break;
}
--ch;
}
return;
}
int main(){
char name[30];
char number[12];
int flag, flag1, flag2, flag3;
int i;
printf("Add New Contact\n");
do {
printf("\nInput name [1..30 char]: ");
fgets( name, 30, stdin );
remove_trailing_newline( name );
flag1 = flag = 1;
if ( !isalpha( name[ 0 ] ) ) {
flag = 0;
printf("First letter of name should be an alphabet (A-Z or a-z), found: %s\n", name );
}
// impossible
if (strlen(name) > 30) {
flag1 = 0;
printf("Length of name should be between 1 and 30 characters\n");
}
} while (flag == 0 || flag1 == 0);
do {
printf("\nInput phone number[6..12 digits]: ");
fgets( number, 12, stdin );
remove_trailing_newline( number );
flag2 = flag3 = 1;
int len_phone = strlen( number );
for (i = 0; i < strlen(number); i++) {
if ( !isdigit( number[ i ] ) ) {
flag2 = 0;
}
}
if (flag2 == 0) {
printf("Phone numbers should only contain digits (0-9), found:'%s'\n", number);
}
if ( len_phone < 6 || len_phone > 12) {
flag3 = 0;
printf("Length of phone numbers should be between 6 and 12 digits, found: %d\n", len_phone );
}
} while (flag2 == 0 || flag3 == 0);
printf("\n");
printf( "Name: '%s'\n", name );
printf( "Phone: '%s'\n", number );
printf("New contact successfully added!\n");
printf("Press Enter to continue...");
getchar();
return 0;
}
您可以找到程序here。
这些定价或多或少都很有趣,我在这里列举一下:
起初,我认为问题是尾随的新行被留在输入缓冲区中。 fflush(stdin)
实际上是C中的未定义行为,因为fflush()
函数用于输出流。无论如何,我将代码包含在question 12.26b of the comp.lang.c FAQ中,因为我认为它正在将其作为参考。然后,我决定使用scanf()
更改fgets()
。这是因为scanf()
将空格作为分隔符,因此您无法写出完整的名称,即姓名和姓氏。请记住,gets()
不是一个选项,因为它将输入写入缓冲区的限制。实际上,fgets()
通过让我们定义要读取的字符限制来解决这个问题。问题是fgets()
还包括&#39; \ n&#39;在缓冲区中,这就是我包含remove_trailing_newline()
函数的原因。整蛊,不是吗?
您添加了一个条件来检查名称输入是否超过30个字符。实际上,这是不可能检查你的程序。首先,fgets()
将读取29个字符+最终字符标记(0)。其次,如果你实际上允许输入超过30个字符,那么输入将被写入超过缓冲区的大小,这是未定义的行为(在大多数情况下崩溃)。你必须使用更复杂的东西,比如C ++中的 std :: string ,然后检查它的长度。或者也许可以使用第三方展开式string
代替C.或推出自己的expandable string ...
您可以使用isalpha(c)
和isdigit(c)
函数来判断是否存在字母字符或数字。
当您要多次使用某个值时,例如strlen(name)
,那么您应该预先计算它并将其存储在局部变量中。虽然一个好的编译器(它的优化器)会检测到这种情况并为你解决它,但你永远不知道哪个编译器会编译你的代码,以及它有多高级。此外,优化器更容易使事情变得简单。
如果您在某种情况下设置了用于发出错误信号的信号,则更容易将其设置为&#34;无错误&#34;在检查任何内容之前的值,并且仅在出现错误的情况下,将其设置为&#34;错误&#34;值。这将更容易阅读,因此,要理解。
希望这有帮助。