2013-07-16 21 views
0

全部,调整,报如何在C中分析输入?

末码如果我要问用户进行输入和抢用,比如说,scanf函数的它(),请问如何处理工作(具体关于缓冲液等)?

什么意思是当人们引用'冲洗'的缓冲区?我也听说,刷新输入(或者,而不是定义?)是不好的做法,但刷新输出流是fflush()创建的功能。 - 在上文中,'stream'的含义是什么?

因此,在程序上,如果我要问像输入:

printf("Enter a string: "); 
    scanf("%s", string); 

发生了什么输入;字符串在哪里被scanf函数'抓住'?

输入缓冲区中出现“空白”是什么? (空格字符,NULL,等等?)


在我的脑海里,虽然文学我读从来没有专门针对这些问题,我想象中的来自用户的输入,或者从文件,存储在一些临时字符数组中被访问,并使用适当的指针进行打印/存储。

我之所以提这件事是因为我有一个相关的问题,下面的代码:

int main(){ 
    char string[20]; 
    char string2[20]; 

//strlen test 
    printf("Enter a string: "); 
     scanf("%s", string); 
    printf("\t length: %d\n", strlen(string)); 

//strcat test 
    printf("Enter two strings to concatentate: "); 
     scanf("%s %s", string, string2); 
    strcat(string2, string); 
    printf("\nConcatenated: %s\n\n\n", string); 

return 0; 

}

顺便说一句:)strlen的(和strcat的()以上功能均在本地定义,因此参数可能与您从C库中熟悉的参数不匹配。

产生以下输出:

img

我假定,一旦scanf函数遇到空白它假定字符串的末尾。尽管如此,剩余的输入仍然存在于缓冲区中。然后,当我要求更多的输入时,输入的数据被放置在缓冲区的末尾。因此,这次scanf()被调用时,'andothernonsensehere'被作为下一个输入,因为它在缓冲区中较早存在。

虽然,如果我上面说的是真的,不应该第二个'andothernonsensehere'字符串和在第二个调用'sherrell'输入的第一个字符串连接在一起吗?


TL;博士verison 如何刷新缓冲区,以确保输入的下一个事件将被scanf函数被捕获()?


完整,编辑,代码:

#include <stdio.h> 

int main(){ 
    char string[20]; 
    char string2[20]; 

//strlen test 
    printf("Enter a string: "); 
     scanf("%s", string); 
    printf("\t length: %d\n", strlen(string)); 
    clear(); //make sure buffer is empty 

//strcat test 
    printf("Enter two strings to concatentate: "); 
     scanf("%s %s", string, string2); 

    strcat(string2, string); 
    printf("\nConcatenated: %s\n\n\n", string); 

    return 0; 
} 

void strcat(char *toCopy, char *org){ 
    while(*org != NULL) org++; //find end of characters 
    while((*org++ = *toCopy++) != NULL); //copy 
} 

int strlen(char *a){ 
    char *b = a; 
    while(*b++ != NULL); 
    return b-a; 
} 


void clear(){ 
    while(getchar() != '\n'); 
} 

回答

1

你基本上已经明白了,虽然缓冲可能不是你认为的地方。

scanf不保存缓冲区。从概念上讲,它每次只读取一个字符,直到格式或输入被耗尽。

但是,终端输入通常由终端驱动程序缓冲。或者,为了更加准确,如果没有等待读取的字符,则即使程序仅读取一个字符,直到按下键输入,终端输入的请求也不会返回任何内容。未读字符保留在内核中,在那里它们将按照请求提供给用户程序。 (终端驱动程序还可以处理在输入字符时回显字符,处理退格和其他许多事情)。但是,所有这些行为都可以改变。有关详细信息,请参阅man sttyman termios(可能还有man tty_ioctl)。许多。因此scanf完全不知道会发生什么。它只会消耗字符,直到满足为止,并在必要时调用ungetc以返回它读取的最后一个字符,但不需要。

现在,你的问题:

不应该第二个“andothernonsensehere”字符串,并在第二个呼叫进入第一个字符串,“sherrell,”级联?

答:是的,他们应该。他们将与标准库函数strcat,只要你把它的参数以正确的顺序,并确保string有足够的空间来保存拼接加上终止NUL字符。如你所说,我不能对你的strcat做任何假设,所以我不知道它的参数与标准库版本的顺序相同。但是,如果确实如此,那么您看到的行为是预期的:strcat将追加stringstring2(覆盖随机内存,因为string2不足以容纳级联)的结尾,但不会更改string(除非string是被覆盖的随机存储器)。因此,当您打印出string时,您会看到它原来的内容,即20个字符的字符串,其末尾的NUL字节也会覆盖其他随机存储位置。

由于所有这些未定义的行为正在进行,您的程序可能产生几乎任何输出,或者它可能已经分段或触发nasal demons。我认为你的C编译器可能会在双字边界上对齐字符串,因为我预计string2会立即跟随string,因此在将20个字符放入string后尾随NUL将成为string2的第一个字节,当scanf填入string2时被覆盖。在这一点上追加stringstring2的后果将是,嗯,有趣。

+0

谢谢,这个概念现在更有意义了,我在OP的最后加上了完整的代码,包括我的strcat版本()。任何建议? – sherrellbc

+1

@sherrellbc:我的建议:使用'-Wall'(至少),并使'string'和'string2'变大(或使用更短的输入)。 (NULL是一个指针);把strlen,strcat并在开始时清楚,并更改名称以避免与gcc内建相撞;并将这两个缓冲区更改为40个字符。它运行良好。 (gcc仍然正确地提醒忽略scanf的返回值,你应该总是检查scanf的返回值。) – rici

+0

功能配置是一个值得关注的问题吗? (即在主之前/之后)。我总是以这样一种方式进行编程,使得我包含了习惯中的函数原型(尽管不在这里)。我知道,如果你有一个函数调用另一个函数,它定义在它自己下面,那么调用函数将不会“看到”定义的函数,程序将不会编译。我惊讶地发现,我编写的代码是由于缺少函数原型以及main调用定义后定义的函数而编译的。 – sherrellbc

0
String2 

是未声明的,其输入是 “” 空字符串。因此,您输入第一个并与空字符串连接产生与原始输入相同的字符串 %s是“输入”,其中s代表字符串,并将其存储在字符串内。哪里是你从哪里获得输入。

+0

我没有发布整个代码。这是上面列出的问题很明显的一个例子。 – sherrellbc

+0

这个答案根本与我的问题无关。我知道scanf()函数是如何工作的。 – sherrellbc

+0

scanf(“%s%s”,string,string2); 这条线是它给你的问题 – Shang