Dave Schwartz 关于调用 getchar() 两次是对的。您的代码片段中还有一两个粗糙的边缘;让我们谈谈这些,同时我对 Dave 的回答进行一些扩展。
C 语言可以非常密集;在一行代码中可以进行多件事情。对于刚起步的人,我鼓励你写长篇文章,即使你认为你不需要……然后随着你对 C 正在做什么的心智模型变得更丰富而巩固。
例如...让我们修改您的代码片段,使其看起来像这样:
int count = 0;
p = (char*)malloc(32*sizeof(char));
char c = getchar(); /* first call to getchar() */
while( c != '\n') {
p[count] = c; /* easier to read than *p=getchar() */
count++; /* could be combined... see below for a more C-like version. */
/* question: what would happen if we increment count BEFORE we store in p's memory? */
/* Also... your initial code was this: */
/* *p = getchar(); */
/* which is always assigning getchar to p[0]. */
/* see below for more "idiomatic" way to do that. */
/* see below for more "idiomatic" way to do that. */
/* Get the next char, then let while() condition decide if */
/* we come back into the loop body or proceed after it. */
/* It is a common tactic to put an input value in a scratch variable */
/* like 'c' and use it at different points in your loop. */
c = getchar(); /* all additional calls to getchar. */
/* note that we already declared c above the while-loop, so ok to re-use. */
}
/* dont want to call getchar() again here... this is the problem dave called out. */
/* while( getchar() != '\n' ); */
/* ...do some stuff here */
free(p); /* your logic does free the malloc at some point, yes? :-) */
现在您可以尝试将尽可能多的代码折叠成一个表达式。
但是请不要那样做——至少在你能够轻松编写1)易于阅读的代码,2)易于预测它会做什么之前不要这样做。
您最终会发现编写代码并不是最难的部分。
阅读 2 周(或 2 多年前)编写的代码很难。
接下来让我们谈谈循环:使用 while()、for() 和 do/while()。
while() 和 for() 为您提供跳过循环体的选项... do/while() 将始终执行循环体,这可能不是您在您的情况下想要的,因为他们用户可以直接按 Enter给你第一个字符'\n'。
for 循环版本
考虑一下你的逻辑在使用 for() 循环时的样子:
int count = 0;
p = (char*)malloc(32*sizeof(char));
for( char c = getchar(); c != '\n'; c = getchar() ) {
p[count] = c;
count++;
}
do/while 版本
我发现用 do/while() 循环写这个更困难:
并不是说代码很难编写,而是我发现很难让代码可读,所以意图很清楚。
int count = 0;
p = (char*)malloc(32*sizeof(char));
char c;
do {
if( count >= 1 ) {
/* ugly... check count >= 1 so we don't save an uninitialized 'c' */
p[count] = c;
}
count++;
} while( (c = getchar() );
count--; /* adjust because we counted our '\n'. */
再次添加一些额外的 C 习语
这个很难读,因为要理解它,你必须能够
解开 while() 表达式,它执行以下操作:
1) 调用 getchar() 函数并将结果分配给我们的 temp var 'c'
2) 将该赋值的结果与 '\n' 进行比较
3) while() 计算比较的结果,并且只有在 temp char var 'c' 中除了 '\n' 之外还有其他内容时才进入循环体。
在您问“这是真的吗?”之前,您需要考虑很多事情。
仅供参考 - 这是我实际尝试运行的唯一示例...
#include <stdio.h>
#include <malloc.h>
void main( char **argv ) {
printf("Please type some stuff:\n");
int count = 0;
char *p = (char*)malloc(32*sizeof(char));
char c;
while( (c = getchar() ) != '\n') {
p[count++] = c;
/* So... could we just saying the following instead?
* *p++ = c;
*/
}
p[count] = '\0'; /* this would turn our malloced buffer into a C-style string */
printf("found %d chars = '%s'\n", count, p);
free(p);
}
最后一点要思考,请考虑以下几点:
1) 我们的用户在按下回车键之前可以输入多少个字符?
2) 假设 #1 确实有一个限制,它是什么以及为什么?
3) 您可以做些什么来添加检查以确保我们不会让我们的用户尝试输入太多字符?