自己写的printf()和scanf()函数
scanf用法
scanf()函数是所有C语言学习者在学习C语言过程中所遇到的第二个函数(第一个函数是printf(),Brian W.Kerninghan & Dennis M.Ritchie的“hello,world”程序基本上是所有的C语言学习者第一个范例),所以scanf()函数应当是C学习者能熟练运用的一个函数,但有很多初学者对此函数不能很好的运用,在实际编程中错误使用scanf()函数,导至程序产生某种错误不能正常运行,以至产生“scanf()函数有BUG”,“scanf()函数无用论”等等错误观点。
本文结合笔者在编程实践中及论坛上网友所遇到的问题作一释疑,但笔者水平有限(菜鸟级),难免有谬误之处,还望达人指点一二。
(Email:knocker.k@) 本文分上,下两篇讲述了C语言中的scanf()函数的用法,重点阐述使用scanf()函数过程中出现的常见错误及对策。
当然,文中某些解决方法,均可以采用其他函数和方法来更好地解决,但本文仅限讨论scanf()函数本身。
上篇,详细介绍了scanf()函数控制串的构成。
下篇,用实际例程介绍scanf()函数控制串运用出现的常见错误及对策技巧。
二、scanf()函数的控制串函数名: scanf功能: 执行格式化输入用法: int scanf(char *format[,argument,...]);scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息。
可以读入任何固有类型的数据并自动把数值变换成适当的机内格式。
其调用格式为: scanf("<格式化字符串>",<地址表>);scanf()函数返回成功赋值的数据项数,出错时则返回EOF。
其控制串由三类字符构成:1。
格式化说明符;2。
空白符;3。
非空白符;(A)格式化说明符格式字符说明%a 读入一个浮点值(仅C99有效)%A 同上%c 读入一个字符%d 读入十进制整数%i 读入十进制,八进制,十六进制整数%o 读入八进制整数%x 读入十六进制整数%X 同上%c 读入一个字符%s 读入一个字符串%f 读入一个浮点数%F 同上%e 同上%E 同上%g 同上%G 同上%p 读入一个指针%u 读入一个无符号十进制整数%n 至此已读入值的等价字符数%[] 扫描字符集合%% 读%符号附加格式说明字符表修饰符说明L/l 长度修饰符输入"长"数据h 长度修饰符输入"短"数据W 整型常数指定输入数据所占宽度* 星号空读一个数据hh,ll同上h,l但仅对C99有效。
c语言函数名前后双下划线
c语言函数名前后双下划线__C语言函数名前后双下划线__C语言是一种广泛应用于软件开发的编程语言,它提供了丰富的函数库以及灵活的语法结构,使得开发者能够快速高效地编写出高质量的程序。
在C语言中,函数名前后双下划线是一种常见的命名规范,用于区分系统函数和用户自定义函数,以避免冲突和命名混乱。
在C语言中,函数是一段完成特定任务的程序代码,它接受输入参数并返回输出结果。
函数名前后双下划线的命名规范,可以使函数名更加明确和易于理解,提高代码的可读性和可维护性。
下面将介绍几个常见的带有双下划线的函数名,并解释其用途和作用。
1. __printf__函数:这是C语言中最常用的函数之一,用于向标准输出设备(通常是屏幕)打印输出信息。
它可以接受多个参数,包括格式控制字符串和要输出的数据,然后按照格式字符串的要求进行格式化输出。
例如,`printf("Hello, World!\n");`会在屏幕上输出"Hello, World!"。
2. __scanf__函数:与printf函数相反,scanf函数用于从标准输入设备(通常是键盘)读取输入数据。
它也可以接受多个参数,包括格式控制字符串和要读取的变量地址,然后根据格式字符串的要求从输入设备中读取数据并存储到相应的变量中。
例如,`scanf("%d", &num);`会从键盘上读取一个整数,并将其存储到变量num中。
3. __malloc__函数:在C语言中,动态内存分配是一种重要的技术,可以在程序运行时动态地分配和释放内存空间。
malloc函数就是用于分配内存空间的函数,它接受一个参数,即所需的内存空间大小(以字节为单位),然后返回一个指向分配的内存空间的指针。
例如,`int *ptr = (int *)malloc(sizeof(int));`会分配一个整数大小的内存空间,并将其地址存储到指针ptr中。
c语言中的几种输入方式
c语言中的几种输入方式
在C语言中,有几种常见的输入方式,包括:
1. scanf():这是最常用的输入函数,用于从标准输入(通常是键盘)读取
数据。
它的一般形式是 `scanf("%格式说明符", &变量)`。
例如,
`scanf("%d", &num)` 用于读取一个整数。
2. getchar():这个函数用于从标准输入读取一个字符。
3. gets():这个函数用于从标准输入读取一个字符串,直到遇到换行符或EOF。
但是,这个函数不检查输入长度,可能会导致缓冲区溢出,因此不推荐使用。
4. fgets():这个函数用于从指定的流中读取一行数据到缓冲区。
它的一般形式是 `fgets(buffer, size, stream)`,其中 `buffer` 是存储读取数据的缓冲区,`size` 是缓冲区的大小,`stream` 是要读取的流。
5. getline():这个函数用于从标准输入读取一行数据,包括换行符。
它的一般形式是 `getline(char lineptr, size_t n, FILE stream)`,其中 `lineptr` 是
一个指向字符指针的指针,用于存储读取的行的地址,`n` 是缓冲区的大小,`stream` 是要读取的流。
以上就是C语言中的几种常见输入方式。
C语言 中scanf详解
C 中scanf ( ) 函数用法心得我觉得,在输入输出函数中,scanf()函数,应该是最麻烦的,有时它给我们的结果很可笑,但是一定是一原因的....首先声明一下,这篇日志不是介绍scanf()中各种格式符用法的文章(没有这个必要,但是大家一定要会用).我尝试了很多种输入,包括一些错误的练习,曾经对scanf()由迷茫转向清醒,又由清醒再次转向迷茫......不知道何时是个尽头,谁让C如此高深呢?在这里贴出来,也是想让自己时而不时能看到,也想知道自己的理解是否有错,错在哪里(所以我就厚着脸皮,放在上面了).注意, 键盘缓冲区与输入有着密切的关系,并且, 类型匹配对输入也极为重要!!下面进入主题:scanf对流的操作遵从类型匹配操作原则,如果类型不匹配,它将不读取输入流。
因此输入流将滞留,如果输入流不空,scanf不会等待用户输入,直接从缓冲区中输入. 但是,scanf() 怎样匹配? stdin又是什么?在网上搜到的关于匹配的非常少,有些细节原因还是找不到.所以,我自作主张的下了点结论:例: scanf("%d,%d",&i,&j); 输入:12 ,13回车但是,j!=13. //注意,12后有一个空格,why?原因:我解释为,在scanf()中,格式字符串中普通字符(不包括空白字符)实行的是严格匹配,因为格式串中%d后面是一个 ',' ,因此输入中数字12后必须为一个','.scanf("1123%s",&str); 输入:1123aaabb 时str为aaabb,但是,输入24aabbdd时, 会出错,因为1123必须进行严格匹配.另外: scanf("%d\n",&i); printf("i=%d",i); 要怎么输入才能输出:i=12 ? 它不是你想像中的那样,有机会尝试一下吧!一些样例:scanf()是一个有返回值的函数,它的返回值是什么?怎么样利用这个特性?scanf()中的匹配原则: 在本文第五点具体说明...scanf()中各种数据格式匹配的开始条件,结束条件 .如: %d ,\n等类型输入结束条件.scanf("%d\n",&i);printf("%d",i); 输入 12回车,并无输出,why? scanf()函数的结束条件: 当各个格式符匹配完毕,且最后有一个回车时,函数结束. scanf("%s",str)连续输入127个就不能继续输入了. //TC中,VC好像是4000多..//说明键盘缓冲区长度为一个字节吗?但是 stdin->bsize(缓冲区大小)事实上为512,这又是为什么?stdin缓冲区中的数据残留 : scanf("%3s",str); c= getchar(); 输入: aaabbccc回车, 此时str="aaa",c='b'; //缓冲区中数据残留!getch()不经过缓冲区,直接接收键盘上输入的字符.//在上例中,加上一个 ch=getch(); 但是getch()并不能读取bbccc中的任何一个,说明getch()与getchar()并不一样,并且它们对Enter读取的值也不同! 一个不常用的格式符: %[] ,如 scanf("%[a-z]",str);输入: abcdefdsaABCDEF 输出:str="abcdefdsa" ;怎么用scanf()来输入一个有空格的字符串?scanf()处理时,一个Enter送到缓冲区中有两个值 : 一个回车(10) ,一个换行(13). 可以用getchar()来接收(但是,在只能接收到\n,即13).在一个scanf()函数之后加个fflush(stdin)可以清除输入数据残留?scanf("%3s",str); fflush(stdin); c=getchar();直接输入aaabbbddd回车, c还能取得值吗?下面是详细解释:scanf()函数执行成功时的返回值是成功读取的变量数 , 也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,它就返回几。
c2-简单输入输出和数制
一个完整的程序,常常要求具备输入输出功能。
C语言程序的输入输出功能是通过调用系统提供的标准函数(库函数)实现的。
格式化输入输出函数格式化输入输出函数按指定的格式完成输入输出过程。
1.输出函数printfprintf(格式控制串,输出表) 按照给定的输出格式、向标准输出设备输出信息输出项如printf("v=%f\n",a);其中"v=%f \n"是给定的格式控制串,而a是输出项,它们之间用逗号分隔。
格式控制串中用%打头后面跟一个字母的部分称为格式说明符,它规定了输出项的输出格式。
常用的格式说明符及其意义如下所示:%d 十进制整数(正数不输出符号)%f 浮点小数(实数)%x 十六进制整数%c 单一字符%s 字符串格式控制串:包含两种信息格式说明符:%格式字符,用于指定输出项输出格式,而是用一个具体的值代替输出普通字符或转义字符:原样输出上述的printf(),是把输出项a的值按%f规定的浮点小数形式显示出来,格式控制串中除转换说明符以外的其它字符都原封不动地输出到标准输出设备使用printf()函数可以有一个以上的输出项,这时格式控制串中的格式说明符与输出项的个数必须相同。
它们按各自的先后顺序一一对应例1 printf函数举例void main(){int a, b; //int是整型数据类型名定义2个整型变量a=10;b=25;printf("a=%d b=%d\n", a, b);printf("a+b=%d\n a-b=%d\n", a+b,a-b);}从上例中可以看出格式说明符不仅规定了输出格式,而且也决定了输出项的值在整个输出信息中的位置。
例如输出项a的输出位置就是格式控制串中与它对应的格式说明符的位置,即a=后面的%d的位置。
此外,从上面也可以看出,输出项可以是运算表达式,这时输出的是它的运算结果值2、输入函数scanfscanf(“格式控制串”,输入表) 从标准输入设备输入数据例如scanf("%d%d", &r,&h); //&取地址操作符格式控制串中一般只使用格式说明符,常用的格式说明符与前面printf函数中介绍的相同。
DSP 调用 C 输入输出函数 scanf() printf() gets() puts() zz
DSP 调用C 输入输出函数scanf() printf() gets() puts() zz1.1 标准输入输出函数1.1.1 格式化输入输出函数Turbo C2.0 标准库提供了两个控制台格式化输入、输出函数printf( ) 和scanf(), 这两个函数可以在标准输入输出设备上以各种不同的格式读写数据。
printf()函数用来向标准输出设备(屏幕)写数据; scanf() 函数用来从标准输入设备(键盘)上读数据。
下面详细介绍这两个函数的用法。
一、printf()函数printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。
在编写程序时经常会用到此函数。
printf()函数的调用格式为:printf("<格式化字符串>", <参量表>);其中格式化字符串包括两部分内容: 一部分是正常字符, 这些字符将按原样输出; 另一部分是格式化规定字符, 以"%"开始, 后跟一个或几个规定字符,用来确定输出内容格式。
参量表是需要输出的一系列参数, 其个数必须与格式化字符串所说明的输出参数个数一样多, 各参数之间用","分开, 且顺序一一对应, 否则将会出现意想不到的错误。
1. 格式化规定符Turbo C2.0提供的格式化规定符如下:━━━━━━━━━━━━━━━━━━━━━━━━━━符号作用——————————————————————————%d 十进制有符号整数%u 十进制无符号整数%f 浮点数%s 字符串%c 单个字符%p 指针的值%e 指数形式的浮点数%x, %X 无符号以十六进制表示的整数%0 无符号以八进制表示的整数%g 自动选择合适的表示法━━━━━━━━━━━━━━━━━━━━━━━━━━说明:(1). 可以在"%"和字母之间插进数字表示最大场宽。
c语言程序设计教程第二版课后习题答案
c语言程序设计教程第二版课后习题答案【篇一:c语言程序设计教程_李含光_郑关胜_清华大学出版社习题答案习题答案[完美打印版]】1.单项选择题(1)a (2)c(3)d (4)c (5)b 2.填空题(1)函数(2)主函数(main)(3)printf() , scanf()第2章习题参考答案1.单项选择题1-5 cbccc 6-10 cdcdc 11-13 dbb 2.填空题(1)1(2)26 (3)6 , 4 , 2 (4)10 , 6(5)3.000000 (6)双精度(double)(7)9 (8)字母,数字,下划线(9)13.700000 (10)11(11)((m/10)%10)*100+(m/100)*10+m%10(12)0 (13)10 ,9 ,11(15)(x0y0)||(x0z0)||(y0||z0)(16)double (17)x==0(18)sqrt(fabs(a-b))/(3*(a+b))(19)sqrt((x*x+y*y)/(a+b))第3章习题参考答案1.单项选择题1-5 cccdd 6-10 bcdbc11-15 bcbbb16 a 2.填空题(1)用;表示结束(2){ }(3)y=x0?1:x==0?0:-1(4)y%4==0y%100!=0||y%400==0(5)上面未配对(6)default 标号(7)while , do while , for(8)do while(9)本次(10)本层 3.阅读程序,指出结果(1)yes(2)*(3)abother(4)28 70(5)2,0(6)8(7)36 (8)1(9)3,1,-1,3,1,-1(10)a=12 ,y=12(11)i=6,k=4 (12)1,-2 4.程序填空(1)x:y , u:z(2)m=n , m!=0,m=m/10(3)teps , t*n/(2*n+1) , printf(“%lf\n”,2*s) (4)m%5==0 ,printf(“%d\n”,k) (5)cx=getchar() , cx!=front , cx(6)double s=0, 1.0/k , %lf (7)s=0 , sgmin, 5.编程题(1). #include stdio.h int main() {double x,y; scanf(%lf,x); if(x1) y=x;else if(x=1.0x10) y=2*x-11; elsey=3*x-11;printf(%lf\n,y); return 0; } (2).#include stdio.h int main() {double x,y,z,min;scanf(%lf%lf%lf,x,y,z); if(xy) min=y; else min=x; if(minz)min=z;printf(min=%lf\n,min); return 0; } (3).#include stdio.h int main() {int y,m,d,flag,s=0,w,i;scanf(%d%d%d,y,m,d);flag=(y%4==0y%100!=0||y%400==0);w=((y-1)*365+(y-1)/4-(y-1)/100+(y-1)/400)%7;for(i=1;i=m;i++) {switch(i) {case 1:s=d;break; case 2:s=31+d;break; case 3:s=59+d;break; case 4:s=90+d;break; case 5:s=120+d;break; case6:s=151+d;break; case 7:s=181+d;break; case8:s=212+d;break; case 9:s=243+d;break; case10:s=273+d;break; case 11:s=304+d;break; case12:s=334+d;break;} }s=(w+s)%7; if(s==0)printf(星期日\n); elseprintf(星期%d\n,s); return 0; }(4).#include stdio.h int main() {float p,r;scanf(%f,p); if(p=10) r=p*0.1;else if(p10p=20) r=10*0.1+(p-10)*0.075; else if(p20p=40)r=10*0.1+10*0.075+(p-20)*0.05; else if(p40p=60)r=10*0.1+10*0.075+20*0.05+(p-40)*0.03;else if(p60p=100)r=10*0.1+10*0.075+20*0.05+20*0.03+(p-60)*0.015; else if(p100)r=10*0.1+10*0.075+20*0.05+20*0.03+40*0.015+(p-100)*0.01; printf(%f\n,r); return 0; } (5).#include stdio.h int main() {char c;while((c=getchar())!=\n) {if(c=ac=z) c=c-32; putchar(c);}return 0; } (6).#includestdio.h int main() {int m,k=2;printf(输入一个正整数:\n); scanf(%d,m); while(km) if(m%k==0) {printf(%4d,k); m=m/k; } else k++;printf(%4d\n,m); return 0; } (7).#includestdio.h int main() {int a,n,s=0,p=0,i;scanf(%d %d,n,a); for(i=1;i=n;i++) {p=p*10+a; s=s+p; }printf(%d\n,s); return 0; } (8).#includestdio.h int main(){int i,j,k;for(i=1;i=9;i++) for(j=0;j=9;j++) for(k=0;k=9;k++)printf(%5d,100*i+10*j+k); return 0; }(9).#includestdio.h #includemath.h int main() {float a=-10,b=10,x,f1,f2,f; f1=(((2*a-4)*a+3)*a)-6; f2=(((2*b-4)*b+3)*b)-6; do {x=(a+b)/2;f=(((2*x-4)*x+3)*x)-6; if(f*f10) { b=x; f2=f; } else { a=x;f1=f; }}while(fabs(f)=1e-6); printf(%6.2f\n,x); return 0; }(10).#includestdio.h#includemath.h int main() {int n=2;double eps,t,s=0,x;scanf(%lf %lf,x,eps); t=x; s=t;while(fabs(t)=eps) {t=-t*(2*n-3)*x*x/(2*n-2); s=s+t/(2*n); n++; }printf(%d,%lf\n,n,s); return 0; }(11).#includestdio.h int main() {unsigned long s,t=0,p=1; scanf(%u,s); while(s!=0) {if((s%10)%2!=0) {t=t+(s%10)*p; p=p*10; }s=s/10; }printf(%u\n,t); return 0; }第4章习题参考答案1.单项选择题1-5 dddbd 6-10 badcd 11-14 bdab 2.填空题(1)2(2)嵌套,递归(3)全局变量,局部变量,静态变量,动态变量(4)auto , static , register , extern (5)外部变量(6)编译,运行 3.阅读程序,指出结果(1)15(2)5(3)5,4,3 (4)i=5 i=2 i=2 i=4 i=2(5)求水仙花数(6)-5*5*5(7)30 (8)0 10 1 11 2 124.程序填空(1)float fun(float , float) , x+y,x-y, z+y,z-y (2)x , x*x+1 (3)s=0 , a=a+b 5.编程题(1).while(s!=0) #includestdio.h { unsigned int fun(unsigned int);p=p+s%10; int main() s=s/10; { } unsigned int s; return p; scanf(%u,s); } printf(%u\n,fun(s)); (2). return 0;#includestdio.h } #includestdlib.h unsigned int fun(unsignedint s) #includemath.h { void f1(float,float,float,float); unsigned int p=0; void f2(float,float,float,float);【篇二:《c语言程序设计》课后习题答案(第四版)谭浩强】t>1.1什么是计算机程序11.2什么是计算机语言11.3c语言的发展及其特点31.4最简单的c语言程序51.4.1最简单的c语言程序举例61.4.2c语言程序的结构101.5运行c程序的步骤与方法121.6程序设计的任务141-5 #include stdio.hint main ( ){ printf (**************************\n\n);printf( very good!\n\n);printf (**************************\n);return 0;}1-6#include stdio.hint main(){int a,b,c,max;printf(please input a,b,c:\n);scanf(%d,%d,%d,a,b,c);max=a;if (maxb)max=b;if (maxc)max=c;printf(the largest number is %d\n,max);return 0;}第2章算法——程序的灵魂162.1什么是算法162.2简单的算法举例172.3算法的特性212.4怎样表示一个算法222.4.1用自然语言表示算法222.4.2用流程图表示算法222.4.3三种基本结构和改进的流程图262.4.4用n?s流程图表示算法282.4.5用伪代码表示算法312.4.6用计算机语言表示算法322.5结构化程序设计方法34习题36第章最简单的c程序设计——顺序程序设计37 3.1顺序程序设计举例373.2数据的表现形式及其运算393.2.1常量和变量393.2.2数据类型423.2.3整型数据443.2.4字符型数据473.2.5浮点型数据493.2.6怎样确定常量的类型513.2.7运算符和表达式523.3c语句573.3.1c语句的作用和分类573.3.2最基本的语句——赋值语句593.4数据的输入输出653.4.1输入输出举例653.4.2有关数据输入输出的概念673.4.3用printf函数输出数据683.4.4用scanf函数输入数据753.4.5字符数据的输入输出78习题823-1 #include stdio.h#include math.hint main(){float p,r,n;r=0.1;n=10;p=pow(1+r,n);printf(p=%f\n,p);return 0;}3-2-1#include stdio.h#include math.hint main(){float r5,r3,r2,r1,r0,p,p1,p2,p3,p4,p5;p=1000;r5=0.0585;r3=0.054;r2=0.0468;r1=0.0414;r0=0.0072;p1=p*((1+r5)*5);// 一次存5年期p2=p*(1+2*r2)*(1+3*r3); // 先存2年期,到期后将本息再存3年期 p3=p*(1+3*r3)*(1+2*r2); // 先存3年期,到期后将本息再存2年期p4=p*pow(1+r1,5); // 存1年期,到期后将本息存再存1年期,连续存5次 p5=p*pow(1+r0/4,4*5); // 存活期存款。
printf和scanf的用法(一)
printf和scanf的用法(一)printf和scanf用法说明1. printf函数用法•printf函数是C语言中用于输出字符、字符串、数字等数据的函数。
•基本语法:printf("格式控制字符串", 参数列表);•格式控制字符串中可以包含普通的字符、转义字符和格式转换符。
普通字符输出•普通字符直接按照字符串的形式输出。
•示例:printf("Hello World!");转义字符输出•转义字符用于输出一些特殊字符,比如换行符、制表符等。
•示例:printf("Hello\nWorld!"); // 输出结果为两行printf("Hello\tWorld!"); // 输出结果中间有一个制表符格式转换符输出•格式转换符用于输出各种类型的数据,如整数、浮点数、字符、字符串等。
•常用格式转换符如下:–%d输出整数–%f输出浮点数–%c输出字符–%s输出字符串•示例:int num = 10;float pi = ;char ch = 'A';char str[] = "Hello World!";printf("num = %d\n", num); // 输出整数printf("pi = %.2f\n", pi); // 输出浮点数,保留两位小数printf("ch = %c\n", ch); // 输出字符printf("str = %s\n", str); // 输出字符串2. scanf函数用法•scanf函数是C语言中用于从标准输入读取字符、字符串、数字等数据的函数。
•基本语法:scanf("格式控制字符串", 参数列表);•格式控制字符串中可以包含普通的字符和格式转换符。
c++语言printf()输出格式大全scanf()输入格式大全
c++语⾔printf()输出格式⼤全scanf()输⼊格式⼤全1.转换说明符%a(%A) 浮点数、⼗六进制数字和p-(P-)记数法(C99)%c 字符%d 有符号⼗进制整数%f 浮点数(包括float和doulbe)%e(%E) 浮点数指数输出[e-(E-)记数法] 1.23E+10,即 1.23 乘以 10 的 10 次幂%g(%G) 根据数值不同⾃动选择%f或%e%i 有符号⼗进制整数(与%d相同)%u ⽆符号⼗进制整数%o ⼋进制整数 e.g. 0123%x(%X) ⼗六进制整数<?xml:namespace prefix = st1 />() e.g. 0x1234%p 指针%s 字符串%% "%"2.标志左对齐:"-" e.g. "%-20s"右对齐:"+" e.g. "%+20s"空格:若符号为正,则显⽰空格,负则显⽰"-" e.g. "% "#:对c,s,d,u类⽆影响;对o类,在输出时加前缀o;对x类,在输出时加前缀0x;对e,g,f 类当结果有⼩数时才给出⼩数点。
3.格式字符串(格式)[标志][输出最少宽度][.精度][长度]类型"%-md" :左对齐,若m⽐实际少时,按实际输出。
"%m.ns":输出m位,取字符串(左起)n位,左补空格,当n>m or m省略时m=ne.g. "%7.2s" 输⼊CHINA 输出" CH""%m.nf":输出浮点数,m为宽度,n为⼩数点右边数位e.g. "%" 输⼊3852.99输出3853.0长度:为h短整形量,l为长整形量printf的格式控制的完整格式:% - .n l或h 格式字符下⾯对组成格式说明的各项加以说明:①%:表⽰格式说明的起始符号,不可缺少。
c语言课课程设计题目
c语言课课程设计题目一、教学目标本课程的教学目标是使学生掌握C语言的基本语法、数据类型、运算符、控制结构、函数等基本知识,培养学生编写简单C程序的能力,提高学生运用C语言解决实际问题的能力。
1.掌握C语言的基本语法和规则。
2.理解数据类型、变量和常量的概念及使用。
3.熟悉各种运算符的用法及其优先级。
4.掌握顺序结构、分支结构、循环结构等控制结构的使用。
5.了解函数的定义、声明和调用。
6.能够使用C语言编写简单的程序,进行基本的输入输出操作。
7.能够利用C语言进行基本的数学计算和逻辑判断。
8.能够运用C语言进行数据的排序和查找等操作。
情感态度价值观目标:1.培养学生对计算机编程的兴趣,激发学生主动学习和探究的热情。
2.培养学生解决问题的能力和创新精神,提高学生自信心和自我成就感。
3.培养学生团队协作意识,增强学生沟通能力和合作精神。
二、教学内容教学内容主要包括C语言的基本语法、数据类型、运算符、控制结构、函数等基本知识。
具体安排如下:1.C语言概述:介绍C语言的历史、特点和应用范围。
2.数据类型和变量:讲解整型、浮点型、字符型等数据类型的使用,以及变量的声明和初始化。
3.运算符和表达式:介绍算术运算符、关系运算符、逻辑运算符等,以及表达式的组成和计算。
4.控制结构:讲解顺序结构、分支结构(if-else)、循环结构(for、while)的使用和嵌套。
5.函数:介绍函数的定义、声明和调用,包括主函数、递归函数等。
6.输入输出操作:讲解printf()和scanf()函数的使用,以及文件的读写操作。
7.编程实践:通过实例讲解和练习,使学生掌握C语言编程的基本技巧和方法。
三、教学方法本课程采用多种教学方法相结合的方式,以提高学生的学习兴趣和主动性。
具体方法如下:1.讲授法:教师讲解C语言的基本概念、语法和编程技巧,引导学生掌握知识要点。
2.案例分析法:通过分析典型实例,使学生了解C语言在实际问题中的应用,提高学生的编程能力。
c语言中scanf的用法及规则
题目:C语言中scanf的用法及规则1. 介绍C语言中的scanf函数是用来从标准输入流中读取数据的函数,在程序中非常常见。
它的使用非常灵活,但也有一些需要注意的规则和用法。
2. 基本用法在C语言中,scanf函数的基本用法是通过格式化输入来读取数据,例如:```cint num;printf("请输入一个整数:");scanf("%d", &num);```这段代码中,我们使用了格式化字符串"%d"来告诉scanf函数我们要读取一个整数,并通过"&num"将读取的整数保存到变量num中。
3. 格式化字符串在使用scanf函数时,格式化字符串非常重要。
它告诉scanf函数如何解析输入的数据,并决定了读取的数据类型和格式。
一些常见的格式化字符串包括:- %d 读取十进制整数- %f 读取浮点数- %c 读取单个字符- %s 读取字符串4. 注意事项在使用scanf函数时,需要注意一些规则和问题。
scanf函数会在遇到空格、回车或换行符时停止读取数据,这可能导致意外的结果。
如果用户输入的格式与scanf函数要求的格式不匹配,会导致错误。
需要对输入进行严格的验证和处理。
5. 高级用法除了基本的格式化输入外,scanf函数还支持一些高级的用法,例如:- 可以使用"*"来忽略读取的数据,例如scanf("%*d", &num)表示忽略一个整数。
- 可以使用"[...]"来指定读取的字符范围,例如scanf("%[a-z]", str)表示只读取小写字母。
6. 总结在C语言中,scanf函数是一个非常有用的函数,能够方便地从标准输入流中读取各种类型的数据。
但是在使用时需要注意格式化字符串、输入验证和处理等问题,以确保程序能够正确地读取输入。
C语言程序设计基础单元总结与练习题及答案
《C语言程序设计》单元总结与练习题答案单元一程序设计宏观认识单元总结提升本单元中,核心内容有C语言程序框架结构、程序的构成和程序开发过程。
通过本单元的学习,我们应该知道:1.C语言程序最基本的程序框架由两部分构成,分别是:(1)编译预处理(2)函数组2.C程序最大的特点就是所有的程序都是用函数来装配的,函数是构成C语言程序的函数返回值类型函数名(形式参数)关键字不能作为用户自定义标识符C.用户自定义标识符中不区分大小写字母D.标识符中可以出现下划线,且可以出现在标识符的任意位置5.以下可用作用户自定义标识符的一组是(c )。
A.void、return、if B.printf、include、fabsC.Max、_abc、Main D.2abc、pay$、sum-10二.填空题1.C语言程序一般由若干个函数构成,程序中应至少包含一个_________,其名称只能为_________。
2.C语言程序中每条语句必须以_________结束。
3.C语言程序的注释是以_________开头,以________结束的,在VC++编程环境中,可使用_________作为注释的起始标识,注释对程序的执行不起任何作用。
4.最初编写的C语言程序称为_________,其扩展名为_________,编译后生成的文件为_________,其扩展名是_________,连接后生成的文件是_________,其扩展名是_________。
5.C语言规定,标识符只能由_________、_________和_________三种字符组成,而且,首字符只能是_________或_________。
******************************************************************************* 习题答案:一.选择题1.C 2.B 3.C 4.C 5.C二.填空题1.主函数main2.分号;3./* */ pp或.c 目标文件(或目标程序).obj 可执行文件(或可执行程序).exe5.字母(A~Z,a~z)、数字(0~9)、下划线“_”字母或下划线*******************************************************************************单元二程序设计基础知识单元总结提升本单元中,核心内容有C语言中基本的数据类型、常量和变量、运算符和表达式以及算法的概念。
使用scanf和printf注意的问题
转:scanf(), getchar(), 以及gets()函数注意点----------------------------------------------------| 问题描述一:(分析scanf()和gets()读取字符) |----------------------------------------------------scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。
但是有时候却就是因为使用这些函数出了问题,却找不出其中的原因。
下面先看一个很简单的程序:程序1:程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。
可是执行程序后会发现除了问题:当从键盘输入一个字符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。
例如用户输入字符'a', 打印结果是97,10。
这是为什么呢?【分析】首先我们看一下输入操作的原理,程序的输入都建有一个缓冲区,即输入缓冲区。
一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。
正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因!其实这里的10恰好是回车符!这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。
而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样第二次的读入函数直接从缓冲区中把\n取走了,显然读取成功了,所以不会再从终端读取!这就是为什么这个程序只执行了一次输入操作就结束的原因!这里再插一句:ASCII码中的10是line feed-\n-换行,将当前位置移到下一行开头;13是carriage return-\r-回车,将当前位置移到本行开头。
C语言输入函数专辑
C语⾔输⼊函数专辑 I/O作为编程的基本元素,具有⾮常重要的作⽤,但因为常⽤所以有些细节也常常被我忽略,所以写这样⼀篇专辑来对C语⾔的输⼊输出作总结。
1、scanf()C语⾔中数据的标准输⼊函数功能:执⾏格式化输⼊⽤法:int scanf(char *format[,argument,...]);scanf()函数是通⽤终端格式化输⼊函数,它从标准输⼊设备(键盘) 读取输⼊的信息。
可以读⼊任何固有类型的数据并⾃动把数值变换成适当的机内格式。
其调⽤格式为: scanf("<格式化字符串>",<地址表>);返回值:scanf()函数返回成功赋值的数据项数,出错时或者遇到⽂件结束符则返回EOF(⼀般在stdio.h中被宏定义为-1);除了⽂件结束,做题遇见最多的是标准输⼊,但是标准输⼊与⽂件不⼀样,⽆法事先知道输⼊的长度,必须⼿动输⼊⼀个字符,表⽰到达EOF:Linux中,在新的⼀⾏的开头,按下Ctrl-D,就代表EOF;Windows中,Ctrl-Z表⽰EOF。
其控制串由三类字符构成:1.格式化说明符;2.空⽩符;3.⾮空⽩符;⼀、空⽩符 空格,制表符和换⾏,⼀般scanf函数(格式字符为%c时除外)会在读操作中略去输⼊中⼀个或多个空⽩符,空⽩符可以,直到第⼀个⾮空⽩字符出现为⽌,遇到空⽩字符时读取停⽌,并把空⽩字符留在输⼊队列中。
⼆、⾮空⽩符 ⼀个⾮空⽩字符会使scanf()函数在读⼊时剔除掉与这个⾮空⽩字符相同的字符(⽐如输⼊时我们想在输⼊元素之间输⼊逗号)。
三、特别说明%c和%s %s 是读字符串,读取时开始时忽略空⽩符,从第⼀⾮空⽩符开始读,直到遇到空⽩符停⽌,并且会将空⽩符留在输⼊缓冲区。
%c是读字符,任何字符都可以读取(包括空⽩符)。
测试代码:#include<stdio.h>int main(){char str[10];char ch;scanf("%s", str);scanf("%c", &ch);printf("%s\n", str);printf("%c", ch);return 0;}输⼊1234_123输出1234空格 对于第⼀个%s读⼊时遇到分隔符“空格”就停⽌,但是空格还是保存在缓冲区的。
c语言第4版习题答案
c语言第4版习题答案C语言第4版习题答案C语言是一门广泛应用于计算机科学和软件开发领域的编程语言。
对于学习C语言的人来说,习题是非常重要的一部分,通过解答习题可以巩固所学的知识,并提升编程能力。
本文将为读者提供C语言第4版习题的答案,帮助读者更好地理解和掌握C语言。
第一章:开始1.1 问题一:请写出一个简单的C程序。
答案:以下是一个简单的C程序示例:```c#include <stdio.h>int main() {printf("Hello, World!");return 0;}```1.2 问题二:请解释#include <stdio.h>的作用是什么?答案:#include <stdio.h>是一个预处理指令,它告诉编译器在编译过程中将stdio.h这个头文件包含进来。
这个头文件中包含了一些输入输出函数的声明,如printf和scanf。
第二章:数据类型、运算符和表达式2.1 问题一:请写一个程序,计算两个整数相加的结果。
答案:以下是一个计算两个整数相加的程序示例:```c#include <stdio.h>int main() {int a, b, sum;printf("请输入两个整数:");scanf("%d %d", &a, &b);sum = a + b;printf("两个整数的和为:%d", sum);return 0;}```2.2 问题二:请解释赋值运算符和算术运算符的区别。
答案:赋值运算符(=)用于将一个值赋给一个变量。
例如,a = 5; 将5赋给变量a。
而算术运算符(+、-、*、/等)用于执行算术运算,如加法、减法、乘法和除法。
例如,a + b 将变量a和b的值相加。
第三章:控制流3.1 问题一:请写一个程序,判断一个数是否为正数、负数或零。
《C语言程序设计基础》教材参考答案-20140211
《C语言程序设计基础》教材参考答案包括各单元:一.随堂练习二.单元总结三.单元练习四.实训指导单元一程序设计宏观认识一.随堂练习【随堂练习1-1】1.根据上述示例模仿编程,输入正方形的边长,计算其面积。
#include <stdio.h>void main( ){ int a,s; //数据准备,边长a,面积sprintf("请输入正方形的边长:");scanf("%d",&a); //数据输入s=a*a; //数据计算printf("该正方形的面积为:%d.\n",s);}【随堂练习1-2】1.下面哪些标识符属于合法的用户自定义标识符:Main、void、_num、my$、a*、N4、3m、a-2答:合法的用户自定义标识符是:Main、_num、N42.结合【例1.2】指出程序代码中所用到的标识符哪些是关键字,哪些是预定义标识符,哪些是用户自定义标识符。
答:关键字:void、int预定义标识符:include、main、printf、scanf用户自定义标识符:a、b、c3.分析【例1.2】中函数的结构,包括函数首部(函数返回值类型、函数名、形式参数)、函数体语句(说明语句、可执行语句)。
答:函数首部:void main( ),其中函数返回值类型为void、函数名为main、形式参数无;函数体语句:{}内的语句为函数体,其中:说明语句为int a,b,c;,其余为可执行语句。
【随堂练习1-3】1.在VC++6.0环境中完成【例1.2】程序开发过程。
(略)2.查阅【例1.2】所对应的工程文件夹,了解相关文件的含义。
工程文件夹中:.CPP:用C/C++语言编写的源代码文件。
.DSP:VC开发环境生成的工程文件,VC4及以前版本使用MAK文件来定义工程。
项目文件,文本格式。
.DSW:VC开发环境生成的WorkSpace文件,用来把多个工程组织到一个WorkSpace中。
scanf()的使用及一些注意事项
scanf()的使⽤及⼀些注意事项 相⽐较Java的键盘录⼊,C语⾔的scanf有⼀些需要注意的细节,为了避免使⽤的时候踩坑,我们就来了解⼀下scanf。
scanf()是C语⾔的格式输⼊函数,和printf函数⼀样被声明在stdio.h头⽂件中,它的基本使⽤很简单:1int a;2 scanf("%d",&a);//程序执⾏到这⾥时,就等待⽤户输⼊;它接收的是变量的地址 //所以⼀般情况下除了指针型变量和数组名要给变量加上取地址符&注意事项⼀:内存溢出(输⼊的类型要和占位符⼀致就不拿出来单独啰嗦了)1char s[1];//长度为1,只能存⼀个元素2 printf("请输⼊s的值:");3//因为这⾥使⽤的是数组名,数组名就是地址,所以不⽤加取地址符&4 scanf("%s",s); //输⼊abcd5 printf("s=%s\n",s);诶,照结果来看abcd都被存进字符数组s⾥⾯了,但是我们知道,s是不是只能存⼀个字节的数据,所以bcd已经⾮法占⽤内存了。
虽然有时候程序看起来会正常执⾏,但是它会留下⼀些隐患。
使⽤的时候需要注意这⼀点。
注意事项⼆:录⼊多个变量1double m,n;2 printf("请输⼊m、n:");3//占位符不写东西时,录⼊的时候默认以空格分隔 //如果占位符⽤逗号分隔,录⼊的时候⽤逗号分隔4 scanf("%lf%lf",&m,&n);// scanf("%lf,%lf",&m,&n);5 printf("n=%lf m=%lf\n",m,n);如果我将第四⾏代码换成注释的代码就需要这样⽤:输⼊的时候⽤空格分隔会发⽣什么呢可以看到,n的值没能录⼊。
建议使⽤默认的分隔符,占位符中不要⾃⼰加东西。
c语言 枚举的scanf输入占位符
枚举类型在C语言中是一种自定义的数据类型,它允许程序员定义自己的数据类型,并为该类型赋予一些特定的值。
在C语言中,枚举类型通常被用来定义一组相关的常量,这些常量可以在程序中被直接使用,而不需要记住其具体的数值。
枚举类型在程序中的应用非常广泛,如定义状态、菜单选项、错误码等。
对于枚举类型的输入,通常会使用scanf函数来接收用户输入的值。
但是,由于枚举类型的取值是常量,而scanf函数需要根据不同的变量类型来进行格式化输入,因此我们需要了解枚举类型的scanf输入占位符。
在C语言中,枚举类型的输入占位符为%d。
虽然枚举类型的取值是常量,但是它们在内存中会被存储为整数,因此可以使用%d来接收用户输入的枚举类型的值。
当使用scanf函数接收枚举类型的输入时,只需要使用%d作为输入占位符即可。
举个例子,假设我们有一个枚举类型定义如下:```cenum Weekday{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};```如果我们想要通过用户输入来获取一个星期几的枚举值,可以这样写:```cenum Weekday day;printf("请输入星期几(1-7):");scanf("%d", &day);```在这个例子中,我们定义了一个名为day的枚举类型变量,并通过scanf函数使用%d作为输入占位符来接收用户输入的值。
用户输入的值将被存储在day变量中,并可以直接在程序中使用。
使用枚举类型的scanf输入占位符可以更方便地接收用户输入,并将其赋值给枚举类型变量。
这样不仅可以提高程序的可读性,还可以避免使用过多的魔术数字,使程序更加健壮和易于维护。
枚举类型的scanf输入占位符为%d,可以方便地接收用户输入的枚举值,并将其赋值给枚举类型变量。
在程序设计中,合理利用枚举类型和scanf输入占位符可以使程序更加清晰和易于理解。
Scanf函数的用法[1]
scanf()函数的控制串函数名: scanf功能: 执行格式化输入用法: int scanf(char *format[,argument,...]);scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息。
可以读入任何固有类型的数据并自动把数值变换成适当的机内格式。
其调用格式为: scanf("<格式化字符串>",<地址表>);scanf()函数返回成功赋值的数据项数,出错时则返回EOF。
其控制串由三类字符构成:1。
格式化说明符;2。
空白符;3。
非空白符;(A)格式化说明符格式字符说明%a 读入一个浮点值(仅C99有效)%A 同上%c 读入一个字符%d 读入十进制整数%i 读入十进制,八进制,十六进制整数%o 读入八进制整数%x 读入十六进制整数%X 同上%c 读入一个字符%s 读入一个字符串%f 读入一个浮点数%F 同上%e 同上%E 同上%g 同上%G 同上%p 读入一个指针%u 读入一个无符号十进制整数%n 至此已读入值的等价字符数%[] 扫描字符集合%% 读%符号附加格式说明字符表修饰符说明L/l 长度修饰符输入"长"数据h 长度修饰符输入"短"数据W 整型常数指定输入数据所占宽度* 星号空读一个数据hh,ll同上h,l但仅对C99有效。
(B)空白字符空白字符会使scanf()函数在读操作中略去输入中的一个或多个空白字符,空白符可以是space,tab,newline等等,直到第一个非空白符出现为止。
(C)非空白字符一个非空白字符会使scanf()函数在读入时剔除掉与这个非空白字符相同的字符。
注:scanf()控制串知识就介绍到这里(应该比较齐全了^_^),如有遗漏下次补上。
下面将结合实际例程,一一阐述.三、 scanf()函数的控制串的使用例1.#include "stdio.h"int main(void){int a,b,c;scanf("%d%d%d",&a,&b,&c);printf("%d,%d,%d\n",a,b,c);return 0;}运行时按如下方式输入三个值:3□4□5 ↙(输入a,b,c的值)3,4,5 (printf输出的a,b,c的值)(1) &a、&b、&c中的&是地址运算符,分别获得这三个变量的内存地址。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
自己来写printf()和scanf()函数一、预备知识——C语言中的可变参数函数1.先举一个例子:#define bufsize 80char buffer[bufsize];/**************************************************************** * 这个函数用来格式化带参数的字符串*****************************************************************/ int vspf(char *fmt, ...){va_list argptr; //声明一个转换参数的变量int cnt;va_start(argptr, fmt); //初始化变量//将带参数的字符串按照参数列表格式化到buffer中cnt = vsnprintf(buffer,bufsize ,fmt, argptr);va_end(argptr); //结束变量列表,和va_start成对使用return(cnt);}/**************************************************************** * 主函数*****************************************************************/ int main(int argc, char* argv[]){int inumber = 30;float fnumber = 90.0;char string[4] = "abc";vspf("%d %f %s", inumber, fnumber, string);printf("%s\n", buffer);return 0;}下面我们来探讨如何写一个简单的可变参数的C函数.2.写可变参数的C函数要在程序中用到以下这些宏:void va_start( va_list arg_ptr, prev_param );type va_arg( va_list arg_ptr, type );void va_end( va_list arg_ptr );va在这里是variable-argument(可变参数)的意思。
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件。
下面我们写一个简单的可变参数的函数,该函数至少有一个整数参数,第二个参数也是整数,是可选的。
函数的功能只是打印这两个参数的值。
void simple_va_fun(int i, ...){va_list arg_ptr;int j=0;va_start(arg_ptr, i);j=va_arg(arg_ptr, int);va_end(arg_ptr);printf("%d %d\n", i, j);return;}我们可以在我们的头文件中这样声明我们的函数:extern void simple_va_fun(int i, ...); 我们在程序中可以这样调用:simple_va_fun(100); simple_va_fun(100,200); 从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针.2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数,这里为参数i。
3)然后用va_arg返回可变的参数,并赋值给整数j 。
va_arg的第二个参数是你要返回的参数的类型,这里是int型。
4)最后用va_end宏结束可变参数的获取.然后你就可以在函数里使用第二个参数了。
如果函数有多个可变参数的,依次调用va_arg获取各个参数。
如果我们用下面三种方法调用的话,都是合法的,但结果却不一样:1)simple_va_fun(100); 结果是:100 -123456789(会变的值) 2)simple_va_fun(100,200); 结果是:100 200 3)simple_va_fun(100,200,300); 结果是:100 200 我们看到第一种调用有错误,第二种调用正确,第三种调用尽管结果正确,但和我们函数最初的设计有冲突.下面一节我们探讨出现这些结果的原因和可变参数在编译器中是如何处理的.3.可变参数在编译器中的处理我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的,由于1)硬件平台的不同 2)编译器的不同,所以定义的宏也有所不同,下面以VC++中stdarg.h里x86平台的宏定义摘录如下:typedef char * va_list;#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define va_end(ap) ( ap = (va_list)0 )定义_INTSIZEOF(n)主要是为了某些需要内存的对齐的系统.C语言的函数是从右向左压入堆栈的,图(1)是函数的参数在堆栈中的分布位置.我们看到va_list被定义成char*,有一些平台或操作系统定义为void*.再看va_start的定义,定义为&v+_INTSIZEOF(v),而&v是固定参数在堆栈的地址,所以我们运行va_start(ap, v)以后,ap指向第一个可变参数在堆栈的地址,如图:图( 1 )然后,我们用va_arg()取得类型t的可变参数值,以上例为int型为例,我们看一下va_arg取int型的返回值:j= ( *(int*)((ap += _INTSIZEOF(int))-_INTSIZEOF(int)) ); 首先ap+=sizeof(int),已经指向下一个参数的地址了.然后返回ap-sizeof(int)的int*指针,这正是第一个可变参数在堆栈里的地址(图2).然后用*取得这个地址的内容(参数值)赋给j.图( 2 )最后要说的是va_end宏的意思,x86平台定义为ap=(char*)0;使ap不再指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不会为va_end产生代码,例如gcc在linux的x86平台就是这样定义的。
在这里大家要注意一个问题:由于参数的地址用于va_start宏,所以参数不能声明为寄存器变量或作为函数或数组类型。
关于va_start, va_arg, va_end的描述就是这些了,我们要注意的是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.4.可变参数在编程中要注意的问题因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型.有人会问:那么printf中不是实现了智能识别参数吗?那是因为函数printf 是从固定参数format字符串来分析出参数的类型,再调用va_arg的来获取可变参数的.也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的.另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.如果simple_va_fun()改为:void simple_va_fun(int i, ...){va_list arg_ptr;char *s=NULL;va_start(arg_ptr, i);s=va_arg(arg_ptr, char*);va_end(arg_ptr);printf("%d %s\n", i, s);return;}可变参数为char*型,当我们忘记用两个参数来调用该函数时,就会出现core dump(Unix) 或者页面非法的错误(window平台).但也有可能不出错,但错误却是难以发现,不利于我们写出高质量的程序。
以下提一下va系列宏的兼容性. System V Unix把va_start定义为只有一个参数的宏:va_start(va_list arg_ptr);而ANSI C则定义为:va_start(va_list arg_ptr, prev_param);如果我们要用system V的定义,应该用vararg.h头文件中所定义的宏,ANSI C的宏跟system V的宏是不兼容的,我们一般都用ANSI C,所以用ANSI C的定义就够了,也便于程序的移植。
二、自己写的STM32单片机printf()与scanf()函数include "stdarg.h"/************************************************************void MyPutChar(unsigned char ch)**通过串口输出一个字符**********************************************************/void MyPutChar(unsigned char ch){USART_SendData(USART1,ch);while(!(USART1->SR&USART_FLAG_TXE)); //等待发送完毕}/******************************************************************void my_printf(const char *fmt , ...)**格式化输出函数****************************************************************/void my_printf(const char *fmt /*format*/, ...){va_list arg_ptr; //声明一个转换参数的变量char arry[100]; //临时数组char *str; //临时数组指针va_start(arg_ptr, fmt); //初始化变量while((*fmt)!='\0'){if(*fmt == '\n' ){MyPutChar('\n');MyPutChar('\r');}else if(*fmt=='%'){fmt++;switch(*fmt){case 'd': //以十进制输出{dec2str(va_arg(arg_ptr, int),arry);str=arry;while(*str!='\0'){MyPutChar(*str); //发送一个字符}}break;case 's'://输出一个字符串{str=va_arg(arg_ptr, char*);while(*str!='\0'){MyPutChar(*str); //发送一个字符str++;}}break;default:break;}}else{MyPutChar(*fmt); //输出一个字符}fmt++;}va_end(arg_ptr); //结束变量列表,和va_start成对使用str=(char*)0;}/**************************************************************** **void my_scanf(const char *fmt , ...)**格式化输出函数****************************************************************/ void my_scanf(const char *fmt /*format*/, ...){va_list arg_ptr; //声明一个转换参数的变量int dec;int *d_ptr;char str[50];char *s_ptr;va_start(arg_ptr, fmt); //初始化变量while((*fmt)!='\0'){if(*fmt=='%'){fmt++;switch(*fmt){case 'd': //输入一个十进制数{MyGetStr(str);dec=str2int(str);d_ptr=va_arg(arg_ptr, int*);*d_ptr = dec;}break;case 's': //输入一个字符串{s_ptr=va_arg(arg_ptr, char*);MyGetStr(s_ptr);}break;default:break;}}else //什么也不做{}fmt++;}va_end(arg_ptr); //结束变量列表,和va_start成对使用s_ptr=(char*)0;d_ptr=(int*)0;}/**************************************************************** **int str2int(char *str)**将一个字符串装换为一个数值(十进制整数)**输入:str要转换的字符串,返回十进制数****************************************************************/ int str2int(char *str){int da = 0;if(*str == '-')//是负数{str++;while(*str != '\0'){if(*str>'0' && *str<'9'){da = da*10;da += *str-'0';}str++;}return (0-da);}else{while(*str != '\0'){if(*str>'0' && *str<'9'){da = da*10;da += *str-'0';}str++;}return (da);}}/**************************************************************** **void dec2str(int dec,char *str)**将一个十进制整数转换为一个字符串**dec:十进制数,str要转换的字符串****************************************************************/ void dec2str(int dec,char *str){char c;char *str1;if(dec<0){*(str++)='-';dec= - dec;//取正}str1=str;do{c = '0'+ dec %10;dec = dec/10;*(str++) = c;}while(dec!=0);*str='\0'; //字符串末尾加入‘\0'作为结束符str--;do{c=*str1;*(str1++)=*str;*(str--)=c;}while(str1<str);}/**************************************************************** **void MyGetStr(char *str)**从串口获得一个字符串****************************************************************/ void MyGetStr(char *str){while((*str=GetChar())!='\0'){str++;}}/**************************************************************** **char GetChar(void)**从串口获得一个字节,由my_scanf()函数调用****************************************************************/ char GetChar(void){while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);return ((char)(USART1->DR&0X1FF));}。