c语言怎么输入一个字符串跳出循环,关于字符串:键入Quit退出C程序

我在想程序的问题是什么。 键入quit时无法退出程序。

这是我所拥有的:

#include

#include

int main(void) {

char string[200];

printf("Enter a bunch of words:");

do

{

scanf("%[^

]c", string);

}while(strcmp(string,"quit")!=0);

return 0;

}

scanf(" %199[^

]", string);注意%和199之前的空格,以防止写入string的字符过多。不需要尾随c

您是否对使用scanf进行的锻炼有规范要求?如果不是,则ID建议其他方法。

@GovindParmar是的,我必须使用scanf,我们不能使用我们尚未学习的任何东西。

@UnholySheep不,它不是。它是一种字符串的扫描格式,该字符串包含除换行符之外的任何字符,后跟文字c。

为什么使用scanf("%[^

]c", string);而不是fgets (string, sizeof string, stdin)? (然后是strncmp (string,"quit", 4);)

@ DavidC.Rankin这是学校作业的一部分,我不能使用任何尚未教过的东西,所以我必须使用scanf

那scanf(" %[^

]%*c", string);呢? (*是分配抑制运算符,允许在不影响返回的转换计数的情况下读取和忽略下一个字符(例如%c)。(应检查if (scanf(" %[^

]%*c", string) != 1) { * handle error * })

嗨@anon您应该解释您认为"%[^

]c"的含义。

@AnttiHaapala:并不是真的。 %[^

]将留在输入流中。因此,下一个字符不能为文字c。

@ DavidC.Rankin hmmm,非常感谢您提供此修复程序,非常感谢,但是我仍然没有被教过这种技术,因此我必须以一种更简单的方式来做。有没有办法做while(1)然后在循环内做if(strcmp(string," quit")!= 0)break;香港专业教育学院尝试了这么多的排列,我不知道如何使它工作。

@jxh当然不可能匹配整个格式,但这就是什么意思。

@jxh它在单词之间留有空格。我想,如果我没有它,它将停在第一个空间。

@anon:但是,您想用尾随的c完成什么?

您的两个最大问题是使用scanf困扰新C程序员的两个最常见问题:

You are using an incorrect format string; and

You fail to check the return of scanf.

让我们首先解决第一件事:

scanf("%[^

]c", string);

您的格式字符串"%[^

]c"使用字符类格式说明符"%[...]"来读取string的文本。然后是"c" -仅与输入字符串末尾的文字'c'相匹配。那样写不会发生,因为"%[^

]"将读取不是'

'的所有字符,仅保留'

'才能读取-与'c'不匹配。

此外,"%[...]"说明符与"%c"说明符一起不占用前导空格('

'为空格)。因此,在stdin中保留未读取的'

'时,您对下一个scanf的调用将失败,因为"%[^

]"不会读取'

'并且它与'c'不匹配,从而导致匹配失败,即'

'在stdin中仍然未被读取,事情很快就失控了。

要解决所有问题,您需要记住上面的(2.)并使用字段宽度修饰符来保护string的数组边界,然后您应读取并保存提取并放入string的字符后的字符以验证是否已读取完整的输入行-否则,您有责任在尝试下一次读取之前删除stdin中剩余的所有多余字符。

对于初学者,您可以使用格式适当受限的字符串,该字符串开头应包含space,这将导致scanf放弃所有前导空格,例如

" %199[^

]%c"

请注意,上面的最终字符将被保存,将进行两次转换,因此您将需要一个字符变量来处理最终转换说明符的结果,例如

do {

char c;     /* final character read */

int retn;   /* variable to save scanf return */

/* prompt */

fputs ("Enter a bunch of words ('quit' exits):", stdout);

/* read saving scanf return */

retn = scanf (" %199[^

]%c", string, &c);

(注意:提示已在do {...} while (..);循环内移动)

接下来,您将负责每次检查scanf的返回。您必须处理三个条件

(return == EOF)用户通过按Ctrl + d(或在Windows Ctrl + z上)生成手册EOF来取消输入;

(return < expected No. of conversions),必须处理匹配或输入失败,并且必须考虑输入缓冲区中可能剩余的每个字符。 (通常,您将在输入缓冲区中向前扫描,直到找到'

'或EOF并丢弃其余的多余字符,请参见示例中的empty_stdin()函数);和

(return == expected No. of conversions)表示读取成功-然后由您检查输入是否满足任何其他条件(例如正整数,正浮点等)。

综上所述,您可以使用scanf循环阅读并寻找"quit"作为提示退出的关键字,如下所示:

do {

char c;     /* final character read */

int retn;   /* variable to save scanf return */

/* prompt */

fputs ("Enter a bunch of words ('quit' exits):", stdout);

/* read saving scanf return */

retn = scanf (" %199[^

]%c", string, &c);

if (retn == EOF) {      /* check the return against EOF */

fputs ("(user canceled input)

", stderr);

return 0;

}

else if (retn < 2) {    /* checking both string and c read */

fputs ("input failure.

", stderr);

empty_stdin();

}

else if (c != '

') {   /* check c is '

', else string too long */

fprintf (stderr,"warning: input exceeds %d characters.

",

MAXC - 1);

empty_stdin();

}

else    /* good input, output string */

printf ("string: %s

", string);

} while (strcmp (string,"quit") != 0);

最后,请勿在代码中使用幻数(200是幻数)。相反,如果您需要一个常数,则#define一个(或多个)。您必须对数字进行硬编码的唯一地方是例如scanf field-width修饰符-不能使用变量,宏或命名常量。这是该规则的一个例外。同样,请勿对文件名或路径进行硬编码。所有函数都带有参数,甚至main()都将所需的信息传递给程序。

综上所述,您可以执行以下操作:

#include

#include

#define MAXC 200    /* constant - maximum characters in string */

void empty_stdin (void)

{

int c = getchar();

while (c != EOF && c != '

')

c = getchar();

}

int main (void) {

char string[MAXC];    /* use constants for array bounds */

do {

char c;     /* final character read */

int retn;   /* variable to save scanf return */

/* prompt */

fputs ("Enter a bunch of words ('quit' exits):", stdout);

/* read saving scanf return */

retn = scanf (" %199[^

]%c", string, &c);

if (retn == EOF) {      /* check the return against EOF */

fputs ("(user canceled input)

", stderr);

return 0;

}

else if (retn < 2) {    /* checking both string and c read */

fputs ("input failure.

", stderr);

empty_stdin();

}

else if (c != '

') {   /* check c is '

', else string too long */

fprintf (stderr,"warning: input exceeds %d characters.

",

MAXC - 1);

empty_stdin();

}

else    /* good input, output string */

printf ("string: %s

", string);

} while (strcmp (string,"quit") != 0);

return 0;

}

使用/输出示例

$ ./bin/scanf_string_quit

Enter a bunch of words ('quit' exits): Hello

string: Hello

Enter a bunch of words ('quit' exits): My dog has fleas and my cat has none.

string: My dog has fleas and my cat has none.

Enter a bunch of words ('quit' exits): quit

string: quit

使用Ctrl + d(或在windoze上为Ctrl + z)生成手册EOF:

$ ./bin/scanf_string_quit

Enter a bunch of words ('quit' exits): Hello

string: Hello

Enter a bunch of words ('quit' exits): (user canceled input)

将MAXC重置为20并将字段宽度修饰符重置为scanf到19,您可以检查对太长的行的处理,例如第一个输入合适,第二个输入太长:

$ ./bin/scanf_string_quit

Enter a bunch of words ('quit' exits): my dog has fleas and my cat has none.

warning: input exceeds 19 characters.

Enter a bunch of words ('quit' exits): 1234567890123456789

string: 1234567890123456789

Enter a bunch of words ('quit' exits): 12345678901234567890

warning: input exceeds 19 characters.

Enter a bunch of words ('quit' exits): quit

string: quit

仔细检查一下,如果您还有其他问题,请告诉我。

哇!非常感谢,我非常感谢所有细节。 Ive遵循了您和另一个用户的建议,一旦我键入quit,程序就会退出。但是,这导致了一个新问题,因为我没有描述程序的目的,所以你们回答了您认为程序想要的内容,我将发布一个新问题,更全面地解释我拥有程序后想要做什么放弃。

这样的事情可以接受吗?

#include

#include

int main(void) {

char string[200] = {0};

printf("Enter a bunch of words:");

do {

memset(string, 0, 200);

scanf("%s", string);

} while (strcmp(string,"quit") != 0);

return 0;

}

您尚未确切说明要对字符串进行的处理,因此很难给出答案。但是,要注意的一件事是,您必须对string做一些事情(我刚刚在这里将其归零),以便strcmp识别"退出",或者扫描string的子字符串,因为如果所有内容都会附加在后面,然后您的字符串将是"(...)quit",而strcmp不会将其识别为" quit"。

附带说明一下,请始终初始化数组,否则可能会发生不良情况。

我不能使用memset,我还没在课堂上学到:/。但是,我按照您的建议初始化了数组,并且无需memset即可工作。非常感谢!

@anon您也可以使用for循环将string中的每个索引设置为0,但是任务可能不仅仅需要这样做。很高兴这是有用的。

@Joshua我一直都喜欢Integer Overflow Man,他是我最喜欢的超级英雄。确实存在这种危险,但是匿名人士并没有真正指定他所完成任务的界限,所以我只是想提出最简单的建议,以解决他似乎遇到的问题。内存安全似乎并不是其中的一部分。

鉴于您提供的稀疏解释,最直接的更改可能是修改扫描字符串以吞下而不是理论上的c,这实际上是不可能的:

scanf("%[^

]

", string);

为了防止缓冲区溢出,您应该指定缓冲区必须存储多少空间:

scanf("%199[^

]

", string);

只要您知道输入内容永远不会超过199个字符,这是安全的。但这在理论和实践上都是一个很弱的假设。超过199的字符将在下一次迭代中作为下一个单词被扫描,如果输入的是199 .后跟单词quit,则程序将意外退出。您需要一种更可靠的方法来扫描到该行的其余部分并丢弃它,然后再读取下一行。

您可能会想使用另一个%[...]来捕获额外的字符,如下所示:

scanf("%199[^

]%*[^

]

", string);

但是,对于输入少于或等于199个字符的常见情况,这将失败。这是因为如果转换导致输入为空,则scanf将失败。因此,将保留在输入中。

如果限于使用scanf,则需要将扫描分为多个单独的scanf调用,以便将其余行的错误和非错误扫描视为相同的结果,从而导致第二个scanf吞下换行符本身。

scanf("%199[^

]%*[^

]", string);

scanf("

");

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值