getchar()函数的奇怪行为

时间:2015-12-23 23:35:10

标签: c getchar

我尝试编写一个函数,将数据存储在文本文件中,使用fopen("filename","w")其中" filename"是用户输入的字符串。我通过getchar()函数选择这样做,我需要一个计数器变量,每次击键都会增加。事情变得令人费解和困惑。

   char *p;
   int count = 0; 
   p = (char*)malloc(32*sizeof(char));
   do 
   {
       *p = getchar();
       count++;
   }
   while(getchar() != '\n');

输入最多3个字符,只需按1次Enter键,计数器就准确到2个字符后,它会跟随一个奇怪的模式。

--------------------Input------------------------Count--------------------
-------------------- t --------------------------  1  --------------------
-------------------- te -------------------------  2  --------------------
-------------------- tes  -----------------------  2  --------------------
-------------------- test ------------------------ 3 ---------------------
-------------------- test1 ----------------------- 3 ---------------------
-------------------- test12 ---------------------- 4 ---------------------
-------------------- test123 --------------------- 4 ---------------------
-------------------- test1234 -------------------- 5 ---------------------

基本上,每增加2个字符,计数就会增加1。

该功能如何在此上下文中工作,为什么需要2次击键?

2 个答案:

答案 0 :(得分:6)

您每次在循环中调用getchar两次。你在字符的末尾按下enter(换行符)。并且在第二个getchar之前计算计数。因此,计数将被(n + 1) / 2四舍五入,其中n是字符数。

另外一个用于换行。除以2,因为每个增量读取两个字符。并且向上舍入,因为增量发生在第二次读取之前。

答案 1 :(得分:0)

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? :-) */

现在你可以尝试将尽可能多的代码折叠到单个表达式中。 但不要这样做 - 至少在你能轻松编写易于阅读的代码之前,以及2)易于预测它会做什么。

你最终会发现编写代码并不是困难的部分。

阅读代码是在2周(或2年以前)写的,这很难。

让我们谈谈下一个循环:while(),for()和do / while()。 while()和for()为您提供跳过循环体的选项... do / while()将始终执行循环体,这可能不是您想要的情况,因为用户可能只需按Enter键给你第一个字符' \ n'。

for loop version 考虑一下你的逻辑如何看待for()循环:

int count = 0; 
p = (char*)malloc(32*sizeof(char));
for( char c = getchar(); c != '\n'; c = getchar() ) {
   p[count] = c;
   count++;
}

do / while version 我发现使用do / while()循环编写它更加困难: 并非难以编写代码,但我发现很难使代码可读,因此 intent 是明确的。

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()评估比较的结果,如果除了' \ n'之外还有其他内容,则只进入循环体。在临时char var' c'。

在您提出问题之前,请大家好好解决这个问题"是真的吗?"。 fyi - 这是我实际尝试过的唯一样本...

#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)您可以做些什么来添加支票以确保我们的用户不会尝试输入太多字符?