user-0 提问: 求各位大佬帮我解惑while和scanf()的逻辑!!!!!!!!!!!!!!!!!!!!!!!!!

回复:
user: user-1
content: 引用 3 楼 lihaicg 的回复:解决的方法： 可以在使用过scanf之后用一个ffush(stdin),或者使用getchar(),把多余的字符吸收掉。 fflush(stdin)是未定义的操作；fflush(stdout);是可以的。 建议用getchar()试试；但是如果一次输入多个字符，一样会循环多次如上的打印； 建议改成这样试试 #include <stdio.h>  int main(void) {     int choice;      while (scanf("%d", &choice) != 1 || (choice < 1 || choice > 5)) {         printf("Input error, please input again!\n");         while (getchar() != '\n')             ;     }     return 0; } 即使输入多个字母也不会出现多次的上述打印（只出现一次）；

user: user-2
content: 解决的方法： 可以在使用过scanf之后用一个ffush(stdin),或者使用getchar(),把多余的字符吸收掉。

user: user-0
content: 看了各位大佬的解释,一个算是搞懂了一些;感谢几位大佬的指教; 自己去修改代码了.. 再次感谢........

user: user-2
content: 逻辑是没有问题的，问题就是出在scanf这个函数上，这个函数在处理%d 整数输入的时候，处理方式是按顺序检查每一个字符，看是否是数字（0-9），如果不是（0-9），则返回，本次scanf调用结束，然后你再次调用scanf的时候上次输入缓冲区里面剩余的内容会被继续处理。 举个例子：你输入 a 然后回车，此时缓冲区中的内容是“a\n”,是两个字符，注意这边用双引号只是特别显示，不是把他们看作字符串。 那么scanf("%d", &choice) 的处理过程是：遇到 a,判断是否（0-9），不是，则返回，同时注意一点此时指向缓冲区的指针并没有向后移位，所以下次调用scanf的时候还是从‘a’开始判断。下面用Bionic版本的C库详细的分析一下这个scanf（“%d”, &n）的具体流程，重点关注注释的两个地方。  		case CT_INT: 			/* scan an integer as if by strtoimax/strtoumax */ #ifdef hardway 			if (width == 0 || width > sizeof(buf) - 1) 				width = sizeof(buf) - 1; #else 			/* size_t is unsigned, hence this optimisation */ 			if (--width > sizeof(buf) - 2) 				width = sizeof(buf) - 2; 			width++; #endif 			flags |= SIGNOK | NDIGITS | NZDIGITS; 			for (p = buf; width; width--) { 				c = *fp->_p; 				/* 				 * Switch on the character; `goto ok' 				 * if we accept it as a part of number. 				 */ 				switch (c) {  				/* 				 * The digit 0 is always legal, but is 				 * special.  For %i conversions, if no 				 * digits (zero or nonzero) have been 				 * scanned (only signs), we will have 				 * base==0.  In that case, we should set 				 * it to 8 and enable 0x prefixing. 				 * Also, if we have not scanned zero digits 				 * before this, do not turn off prefixing 				 * (someone else will turn it off if we 				 * have scanned any nonzero digits). 				 */ 				case '0': 					if (base == 0) { 						base = 8; 						flags |= PFXOK; 					} 					if (flags & NZDIGITS) 					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 					else 					    flags &= ~(SIGNOK|PFXOK|NDIGITS); 					goto ok;  				/* 1 through 7 always legal */ 				case '1': case '2': case '3': 				case '4': case '5': case '6': case '7': 					base = basefix[base]; 					flags &= ~(SIGNOK | PFXOK | NDIGITS); 					goto ok;  				/* digits 8 and 9 ok iff decimal or hex */ 				case '8': case '9': 					base = basefix[base]; 					if (base <= 8) 						break;	/* not legal here */ 					flags &= ~(SIGNOK | PFXOK | NDIGITS); 					goto ok;  				/* letters ok iff hex */ 				case 'A': case 'B': case 'C': 				case 'D': case 'E': case 'F': 				case 'a': case 'b': case 'c': 				case 'd': case 'e': case 'f': 					/* no need to fix base here */ 					if (base <= 10) 						break;	/* not legal here */ 					flags &= ~(SIGNOK | PFXOK | NDIGITS); 					goto ok;  				/* sign ok only as first character */ 				case '+': case '-': 					if (flags & SIGNOK) { 						flags &= ~SIGNOK; 						flags |= HAVESIGN; 						goto ok; 					} 					break;  				/* 				 * x ok iff flag still set and 2nd char (or 				 * 3rd char if we have a sign). 				 */ 				case 'x': case 'X': 					if ((flags & PFXOK) && p == 					    buf + 1 + !!(flags & HAVESIGN)) { 						base = 16;	/* if %i */ 						flags &= ~PFXOK; 						goto ok; 					} 					break; 				}  				/* 				 * If we got here, c is not a legal character 				 * for a number.  Stop accumulating digits. 				 */                      /******这边如果这个字符不符合要求则break，                               下面的fp->_p++ 不会执行********************/ 				break; 		/********注意这边，如果这个字符是符合要求的（0-9），                              则跳转到ok这边，否则不会执行下面这一段代码，                              重点fp->_p++;***************/               ok: 				/* 				 * c is legal: store it and look at the next. 				 */ 				*p++ = c; 				if (--fp->_r > 0) 					fp->_p++; 				else if (__srefill(fp)) 					break;		/* EOF */ 			} 			/* 			 * If we had only a sign, it is no good; push 			 * back the sign.  If the number ends in `x', 			 * it was [sign] '0' 'x', so push back the x 			 * and treat it as [sign] '0'. 			 */ 			if (flags & NDIGITS) { 				if (p > buf) 					(void) ungetc(*(u_char *)--p, fp); 				goto match_failure; 			} 			c = ((u_char *)p)[-1]; 			if (c == 'x' || c == 'X') { 				--p; 				(void) ungetc(c, fp); 			} 			if ((flags & SUPPRESS) == 0) { 				uintmax_t res;  				*p = '\0'; 				if (flags & UNSIGNED) 					res = strtoumax(buf, NULL, base); 				else 					res = strtoimax(buf, NULL, base); 				if (flags & POINTER) 					*va_arg(ap, void **) = 					    (void *)(uintptr_t)res; 				else if (flags & MAXINT) 					*va_arg(ap, intmax_t *) = res; 				else if (flags & LLONG) 					*va_arg(ap, long long *) = res; 				else if (flags & SIZEINT) 					*va_arg(ap, ssize_t *) = res; 				else if (flags & PTRINT) 					*va_arg(ap, ptrdiff_t *) = res; 				else if (flags & LONG) 					*va_arg(ap, long *) = res; 				else if (flags & SHORT) 					*va_arg(ap, short *) = res; 				else if (flags & SHORTSHORT) 					*va_arg(ap, signed char *) = res; 				else 					*va_arg(ap, int *) = res; 				nassigned++; 			} 			nread += p - buf; 			break;

user: user-3
content: 因为scanf函数遇到不符合的参数回把数值重新返回输入流  下次的scanf函数读入时 还是那个错误的参数 你应该在循环里面用getchar函数 把错误的参数弄掉。。。