"我试图通过从stdin输入的字符串计算长度"……"我知道在最后添加n-=2可以实现我的目的,但我真的想了解在这里发生了什么。"
fgets() 的文档包括以下内容:
"……从指定的流中读取一行并将其存储到由str指向的字符串中。当读取(n-1)个字符,读取换行符或到达文件结尾时停止,以先到者为准。 "
如果没有检查函数返回值,并传递一个错误的字符串长度值,就会限制检测错误的可能性,并引入未定义行为的可能性。为了解决这些问题,请更改以下内容:
fgets(str,99,stdin)
比如说这个:
if( fgets (str, sizeof str, stdin) != NULL )
{
...
剖析以下内容:给定用户输入值:"glacious"
,在内存中str
的样子是这样的:
|g|l|a|c|i|o|u|s|\n|\0|?|...|?|
0 1 2 3 4 5 6 7 8 9 10 99
int n = 0;
while(str[n++] != '\0');
迭代次数:
n at start n at finish
- 第1项: 当
n==0
且 str[0]
(g
) 不是 \0
时,n++
并且 n==1
- 第2项: 当
n==1
且 str[1]
(l
) 不是 \0
时,n++
并且 n==2
- 第3项: 当
n==2
且 str[2]
(a
) 不是 \0
时,n++
并且 n==3
- 第4项: 当
n==3
且 str[3]
(c
) 不是 \0
时,n++
并且 n==4
- 第5项: 当
n==4
且 str[4]
(i
) 不是 \0
时,n++
并且 n==5
- 第6项: 当
n==5
且 str[5]
(o
) 不是 \0
时,n++
并且 n==6
- 第7项: 当
n==6
且 str[6]
(u
) 不是 \0
时,n++
并且 n==7
- 第8项: 当
n==7
且 str[7]
(s
) 不是 \0
时,n++
并且 n==8
- 第9项: 当
n==8
且 str[8]
(\n
) 不是 \0
时,n++
并且 n==9
- 第10项: 当
n==9
且 str[9]
(\0
) 等于 \0
时,n++
并且 n==10
清晰地说明了所有迭代的状态,包括对n
的最终后置增量操作,使其总数达到用户输入假定为只有8个字符的10
。 \n
和最终的后置增量(对于\0
)解释了对n
的附加值。总之,问题在于要调整您的期望,以考虑缓冲区中的所有字符,包括您无法看到的字符。
有趣的是,计算n
的值并不等同于测量str
的字符串长度,其中习惯用法方法(strlen())将产生9个字符的长度。鉴于C字符串的定义,以下显示了对于每种相应的查看str
的方法,假设已初始化,则会产生不同的结果:
char str[100] = {0}
而 str
的内容是:"glacious\n"//隐含了 null 终止符
//method to calculate n in discussion above
// //yields n == 10
int len = strlen(str); //yields n == 9
//after using strcspn()
str[strcspn(str, "\n")] = 0;
len = strlen(str); //yields n == 8
size_t size = sizeof str; //yields size == 100
作为附言,如果目标是计算条目数量,并且如果可以接受替代方法,请考虑简化该方法...
替换此部分:
char str[100];
printf("文字列を入力してください:");
fgets(str,99,stdin);
int n = 0;
while(str[n++] != '\0');
printf("文字列の長さは%dです\n", n);
return 0;
使用以下代码,当遇到\n
(换行符)或EOF
(-1
)(stdio.h
中的#define
)时会中断循环,从而正确计算用户输入的数量(减去换行符):
int count = 0;
printf("Please enter a string:");
int c = fgetc(stdin);
while(( c != '\n') && (c != EOF))
{
count++;
fputc(c, stdout);
c = fgetc(stdin);
}
printf("\n\nThe length of the string is: %d\n", count);
return 0;
glacious\n\0
=> 10。 - ggorlennul
字符,n
也会增加。此外,请记住,如果有空间,fgets
返回输入包括“信号”换行符。 - Adrian Molefgets
,它会从长度中减去一来为 EOS 字符腾出空间。因此,您可以提供缓冲区的完整大小(例如100
而不是99
)。更习惯用法:fgets(str,sizeof(str),stdin);
- Craig Estey'\n'
,你可以使用:n = 0; while (str[n] != '\n' && str[n] != '\0') n++;
在这种情况下,为了去除'\n'
,你可以在退出循环后简单地使用str[n] = 0;
。 - David C. Rankin