对于C语言中的scanf函数的使用问题总结

时间:2019-05-13 19:44:59下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《对于C语言中的scanf函数的使用问题总结》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《对于C语言中的scanf函数的使用问题总结》。

第一篇:对于C语言中的scanf函数的使用问题总结

Scanf函数总结

对于C语言中的scanf函数的小结

对于scanf函数的作用大家应该都知道吧。在任何一本C语言的教材中都有过介绍,它的一般形式是(格式控制,地址表列)

我今天想说说使用这个scanf函数的时候,应该注意哪些问题吧。

1.scanf函数中的格式控制应该是变量名的地址,而不是变量名,例如a和b为整形变量,如果写成scanf(“%d%d”,a,b);就会出错的,应该将这个,a,b改成&a,&b;(表示地址)2我们都知道C语言中的字符串是存放到字符数组中的,如果我们定义了一个字符数组,如char a[20];我们想把字符串输入到这个字符数组中通常有两种方式,第一种.逐个字符输入,采用for循环的形式。第二种,直接输入字符串的形式,用格式控制符%s.第一种我们这样输入,for(i=0;i<=19;i++){ } 第二种我们用这种方式输入 Scanf(“%s”,a);注意第二种这种形式,我们没有加&,这是为什么呢,这是 Scanf(“%c”,&a[i]);

Scanf函数总结

因为,C语言中把这个数组名当做该数组的起始地址。但是这种数组仅限于字符数组,不要企图,利用数值型数组的名。来整体输入,一个数值型的数组,这就是大错误了,比如这样写是不正确的 Int a[10];Scanf(“%d”,a);数值型数组的输入只能采用上面的第一种方法。3对于指针问题,大家需要注意一点,指针就是地址,这是在任何条件下都成立的,(请允许我极端一点),比方看下面的例子。Char *p;Char a[20];P=a;For(i=0;i<20;i++,p++){ } 这是一个采用指针变量输入数据的例子,这里的指针变量p在for循环之前就指向了这个数组a,也就是指向了数组的首元素,也就是是说指针变量p里存放的是,数组首元素的地址,所以在用这个scanf函数进行输出时,指针变量的前方就不用再加取地址符号了。Scanf(“%c”,p);

Scanf函数总结

4.这个问题是整个scanf函数使用过程中最容易出错的一个地方。就是关于用scanf函数在用“%c”格式声明输入字符的时候,是最容易出错的一个地方。一点一点进行,下面请看一个简单的例子: 看下面的一个程序,(1)

#include int main(){

} 我们想要输入三个整数,输入的时候我们要注意了,这里的scanf函数中的格式控制是三个连续的%d,除了格式声明以外中间没有任何其他的字符,这个时候我们输入数据应该加入空格,否则执行不了。1 2 3(1,2之间有空格,2,3之间有空格,(具体原因会在例题2中阐明)加入其他符号也是不可以的)

(2)经过第一道的例题,似乎让我明白了这样的一个规律,如果中间都是除了格式声明以外中间没有任何其他的字符,int a,b,c;scanf(“%d%d%d”,&a,&b,&c);printf(“%d%d%dn”,a,b,c);return 0;

Scanf函数总结

那我就可以用空格,来隔开我的数据了。看看下面的例题 #include int main(){

} 我的输入还是仿照上面,进行截图如下所示 char a,b,c;scanf(“%c%c%c”,&a,&b,&c);printf(“%c%c%cn”,a,b,c);return 0;

我们发现输出并不是我们想象的那样,而是出现了错误,下面我们来解释一下原因,因为我们原来输入的位数值型的数据,所以我们要区分数值的个数,以及位数,比方我想输入

Scanf函数总结 234 456这三个数,我要是连续的把这8个数输入进去,计算机也无法区分,这到底是几个数,所以我们用空格加以区分,这样计算机遇到空格就知道这个数值型的数已经输入完毕了(这是例题1中我们为什么加空格的原因),但是为什么在例题2中我还是这样做,就不可以了呢,这是因为我们现在输入的是字符型数据,而且字符型数据不是像数值型数据那样,有几位数字,字符型的数据只有一位,所以你输入一位数据他就给一个变量,所以不需要像数值型的数据那样隔开了,所以我们直接输入三个连续的字母asd就可以了,就不用空格分开了,如果我们输入a空格s空格d,那么他就会默认的把前三个字符送给三个变量了,也就是a空格s(因为空格也是一个字符)。(3)下面大家看一下这道例题。

//下面程序很简单,就是输入两个数和一个运算符号,#include“stdio.h” void main(){

int;float z,x,y;char cc;printf(“please enter date:n”);scanf(“%f%c%f”,&x,&cc,&y);

Scanf函数总结

} if(cc=='+')z=x+y;if(cc=='-')z=x-y;if(cc=='*')z=x*y;if(cc=='/')z=x/y;printf(“%fn”,z);我们连续输入三个1+2 结果输出3,截图如下

这里要注意的是,输入1之后不能有空格,因为下面是一个字符型数据,输入字符型数据之后,就可以有空格了,因为

Scanf函数总结

后面是一个数值型数据。(所以按照这种方式输入也可以 1+ 2)(4),如果在“格式控制字符串中”除了格式声明还有其它字符,则在输入数据的时候,在对应的位置上应该输入与这些字符相同的字符。#include int main(){

} 我们在输入数据的时候应该这样输入,1,2,3 我要讲的内容就要讲完了,下面和大家说说在输入这个数据的时候,尽量加入,分隔,scanf(“%d,%d,%d”,&a,&b,&c);这样不容易出错,如果什么符号也不用直接这样的话scanf(“%d%d%d”,&a,&b,&c);大家一定要注意我上面说的三个例子。int a,b,c;scanf(“%d,%d,%d”,&a,&b,&c);printf(“%d%d%dn”,a,b,c);return 0;7

第二篇:C语言中的输入输出函数总结

putchar():把变量中的一个字符常量输出到显示器屏幕上;getchar();从键盘上输入一个字符常量,此常量就是该函数的值;printf();把键盘中的各类数据,加以格式控制输出到显示器屏幕上;scanf();从键盘上输入各类数据,并存放到程序变量中;puts():把数组变量中的一个字符串常量输出到显示器屏幕上;gets():从键盘上输入一个字符串常量并放到程序的数组中.sscanf();从一个字符串中提取各类数据。putchar()输出一个字符

getchar()输入流中获取一个字符 例如:

char c = getchar();putchar(c);格式化输入输出scanf()和printf()是最有用的,所以重点讲一下。printf(): 一般形式: printf(“格式控制”.输出列表);eg : printf(“a=%d,b=%f,c=%cn”,a,b,c);1;格式控制.格式控制是用双引号括起来的字符串,也称“转换控制字符串”,它包含以下两部分信息.格式说明:由“%”和格式字符组成,如%d,%f,%c,他的作用是把输出数据转换为指定格式输出,格式的说明总是由“%”字符开始的.普通字符:需要原样输出的字符,或者是一些有特殊含义的字符,如n,t。2;输出列表

就是需要输出的一些数据,也可以是表达式,如果在函数中需要输出多个变量或表达式,则要用逗号隔开.一些特殊字符的输出:

单引号,双引号,和反斜杠的输出在前面加转义字符”” 如:”’” , “”” , “”

%的输出用两个连在一起的%%,即printf(“%%”);

常用的格式说明如下: 格式字符

d 以十进制形式输出带符号整数(正数不输出符号)o 以八进制形式输出无符号整数(不输出前缀O)x 以十六进制形式输出无符号整数(不输出前缀OX)u 以十进制形式输出无符号整数 f 以小数形式输出单精度实数 lf 以小数形式输出双精度实数

e 以指数形式输出单、双精度实数

g 以%f%e中较短的输出宽度输出单、双精度实数 c 输出单个字符 s 输出字符串

这里强调一下:网上很多文章都说f 和lf是一样的,即不管单精度,双精度浮点数,都可以用f, 但我在POJ上做过测试,输出Double时用f确实也可以,但读入时,用f就报WA,所以大家如果对Double进行读写的话,都用lf吧。

说到Double,再啰嗦一句,建议大家要用到浮点数时都用Double,不要用float,因为在很多情况下,float精度不够会导致WA。

特殊:

对64位整数的输入输出,在POJ上的C++环境下(即VC),64位整数是: __int64(注意int前面是两个下划线)输入输出格式为”%I64d”.在G++环境下(即Dev C++)64位整数是 long long 输入输出格式为”%lld”.输出宽度

用十进制整数来表示输出的最少位数。注意若实际位数多于定义的宽度,则按实际位数输出,若实际位数少于定义的宽度则补以空格或0。

精度

精度格式符以“.”开头,后跟十进制整数。意义是:如果输出数字,则表示小数的位数;如果输出的是字符,则表示输出字符的个数;若实际位数大于所定义的精度数,则截去超过的部分。

标志格式字符

-结果左对齐,右边填空格

+ 输出符号(正号或负号)空格输出值为正时冠以空格,为负时冠以负号 例如:

double c=24212345.24232;printf(“%020.4”);表示输出精确到小数点后4位,输出占20位,若有空余的位补0.scanf:

scanf的很多用法都是和printf对应的,故不再赘述。

说一下scanf一个特别好用的地方,就是可以滤去一些不想要的东西。举例说明如下:

比如输入为日期 yyyy-mm-dd,就可以这样写: int year,moth,day;scanf(“%d-%d-%d”,&year,&moth,&day);再比如:

scanf(“%3d %*3d %2d”,&m,&n);输入113 118 69回车(系统将113赋予m,将69赋予n,因为*号表示跳过它相应的数据所以118不赋予任何变量)puts()用的不多,且基本都能用printf()代替,故不再多说。gets()是从输入流中获取一行字符串放入字符数组中: char in[100];gets(in);大家可能最容易出错的地方就是字符串的输入,所以强调一下: 能进行字符,字符串输入的有:

getchar(), scanf(“%c”);scanf(“%s”), gets()

其中getchar()和 scanf(“%c”)的功能是一样的。

需要注意的是,这两个函数读入的是输入流中当前位置的字符,比如:

scanf(“%d”,&n);c = getchar();假设输入 67/(假设“/”代表回车),则第一个scanf读入一个整数67后,当前输入流的位置是67之后,即指向回车符,所以第二个getchar()读入的就是一个回车符了,即 c = ‘n’。

同样,gets()也是从当前位置读入一行字符串。比如:

scanf(“%d”,&n);gets(str);此时读入字符数组中的字符串就是“n” 了

所以通常在用scanf读入一个非字符串的类型之后,如果要读入字符,或字符数组,都用一个额外的getchar()把回车符读掉,若后面跟的不止一个回车符,可能还有多余的空格的话,就用gets()读掉。

和以上不同的是,scanf(“%s”)读入的时候是会忽略掉空格,回车和制表符的。并且以空格,回车和制表符作为字符串结束的标志。

经常会有这样的题,输入第一行是一个整数,接下来每行的第一个是一个字符,用来表示某种操作,后面再跟一些数据,比如: 4 A 100 2 B 23 A 23 89 B 34

像这种输入就需要小心,读入字符时不要读成回车符。为了防止意外,我一般是这样处理这类输入的: char model[2];Scanf(“%d”,&n);for(„,„,„){

scanf(“%s”,model);

if(model[0] == ‘A’){ } else{ } } sscanf(): sscanf()经常用来分解字符串,功能非常强大,但很多功能都需要正则表达式的知识,所以就介绍一下最简单的几种用法,大家如果想了解更多的话,自己去网上找吧。1.char str[100],str1[100],str2[100];gets(str);sscanf(str,”%s%s”,str1,str2);

将读入的一整行字符串按空格,制表符或回车符分割成两个字符串。2 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。

sscanf(“123456 ”, “%4s”, str);

对于C++的输入输出就不再详细的讲了,因为cin,cout的速度实在太慢,不推荐使用,我一般都是到万不得已时才用。

比如当你要读入字符串到string 对象中时,就只能用cin了,这时候还有一个常见的问题,就是如何将一整行字符串读入一个string 中,这就要用到getline函数了。用法为: getline(cin, str);第一个参数就是标准输入流cin,第二个参数是接收读入数据的string对象,本来还有第三个参数,是结束符的标志,但通常用它默认的就可以了,所以不用管。

注意区分这个getline和cin.getline的区别: cin.getline的用法如下: char str[20];cin.getline(str,20);表示从读入的一行字符串中,取最多20各字符放入字符数组str中,注意此处的str是字符数组,而上面的str是string对象。

另外需要注意的是,千万不要把cout和printf混用,因为cout是带缓冲的而printf不带,所以会使得输出的数据顺序混乱。

第三篇:c语言中swap问题小结

#include #include void swap1(int x,int y){ int temp;temp=x;x=y;y=temp;} void swap2(int *x,int *y){ int *temp;temp=x;x=y;y=temp;} void swap3(int *x,int *y){ int temp;temp=*x;*x=*y;*y=temp;} void swap4(int a[],int b[]){ int temp;temp=a[0];a[0]=b[0];b[0]=temp;} void swap5(int a[],int b[]){ int temp;temp=*a;*a=*b;*b=temp;} int main(){ int x,y;x=4;y=3;swap1(x,y);

printf(“swap1: x:%d,y:%dn”,x,y);//形参传值,不能交换,实际传过去是拷贝的一份,没改变主函数中x,y swap2(&x,&y);

printf(“swap2: x:%d,y:%dn”,x,y);//不能交换,函数中只是地址交换了下,地址指向的内容没有交换 swap3(&x,&y);

printf(“swap3: x:%d,y:%dn”,x,y);//能交换,地址指向的内容进行了交换 swap4(&x,&y);

printf(“swap4: x:%d,y:%dn”,x,y);//能交换,地址指向的内容进行交换 swap5(&x,&y);

printf(“swap5: x:%d,y:%dn”,x,y);//能交换,地址指向的内容进行交换 return 0;} swap1: x:4,y:3 swap2: x:4,y:3 swap3: x:3,y:4 swap4: x:4,y:3 swap5: x:3,y:4

第四篇:C语言中结构体的使用

脚踏实地,心无旁骛,珍惜分分秒秒。紧跟老师,夯实基础。什么是结构体?

简单的来说

结构体就是一个可以包含不同数据类型的一个结构 它是一种可以自己定义的数据类型 它的特点和数组主要有两点不同

首先结构体可以在一个结构中声明不同的数据类型 第二相同结构的结构体变量是可以相互赋值的 而数组是做不到的

因为数组是单一数据类型的数据集合 它本身不是数据类型(而结构体是)数组名称是常量指针

所以不可以做为左值进行运算

所以数组之间就不能通过数组名称相互复制了 即使数据类型和数组大小完全相同

定义结构体使用struct修饰符 例如:

struct test { float a;int b;};

上面的代码就定义了一个名为test的结构体 它的数据类型就是test 它包含两个成员a和b 成员a的数据类型为浮点型 成员b的数据类型为整型

由于结构体本身就是自定义的数据类型

定义结构体变量的方法和定义普通变量的方法一样

test pn1;

这样就定义了一test结构体数据类型的结构体变量pn1 结构体成员的访问通过点操作符进行

pn1.a=10 就对结构体变量pn1的成员a进行了赋值操作

注意:结构体生命的时候本身不占用任何内存空间

只有当你用你定义的结构体类型定义结构体变量的时候计算机才会分配内存

结构体

同样是可以定义指针的

那么结构体指针就叫做结构指针

结构指针通过->符号来访问成员

下面我们就以上所说的看一个完整的例子: #include #include using namespace std;

struct test//定义一个名为test的结构体 { int a;//定义结构体成员a int b;//定义结构体成员b };

void main(){ test pn1;//定义结构体变量pn1 test pn2;//定义结构体变量pn2

pn2.a=10;//通过成员操作符.给结构体变量pn2中的成员a赋值 pn2.b=3;//通过成员操作符.给结构体变量pn2中的成员b赋值

pn1=pn2;//把pn2中所有的成员值复制给具有相同结构的结构体变量pn1 cout<

test *point;//定义结构指针

point=&pn2;//指针指向结构体变量pn2的内存地址 cout<

a=99;//通过结构指针修改结构体变量pn2成员a的值 cout<

a<<“|”<

b<

总之

结构体可以描述数组不能够清晰描述的结构 它具有数组所不具备的一些功能特性

下面我们来看一下 结构体变量是如何作为函数参数进行传递的

#include #include using namespace std;

struct test { char name[10];float socre;};

void print_score(test pn)//以结构变量进行传递 { cout<

void print_score(test *pn)//一结构指针作为形参 { cout<

name<<“|”<

socre<

void main(){ test a[2]={{“marry” 88.5} {“jarck” 98.5}};int num = sizeof(a)/sizeof(test);for(int i=0;i

void print_score(test *pn)的效率是要高过void print_score(test pn)的 因为直接内存操作避免了栈空间开辟结构变量空间需求 节省内存

下面我们再说一下 传递结构引用的例子

利用引用传递的好处很多 它的效率和指针相差无几

但引用的操作方式和值传递几乎一样

种种优势都说明善用引用可以做到程序的易读和易操作 它的优势尤其在结构和大的时候 避免传递结构变量很大的值 节省内存 提高效率

#include #include using namespace std;

struct test { char name[10];float socre;};

void print_score(test &pn)//以结构变量进行传递 { cout<

void main(){ test a[2]={{“marry” 88.5} {“jarck” 98.5}};int num = sizeof(a)/sizeof(test);for(int i=0;i

#include #include using namespace std;

struct test { char name[10];float socre;};

void print_score(test &pn){ cout<

test get_score(){ test pn;cin>>pn.name>>pn.socre;return pn;} void main(){ test a[2];int num = sizeof(a)/sizeof(test);for(int i=0;i

//------例程2--

#include #include using namespace std;

struct test { char name[10];float socre;};

void print_score(test &pn){ cout<

void get_score(test &pn){ cin>>pn.name>>pn.socre;} void main(){ test a[2];int num = sizeof(a)/sizeof(test);for(int i=0;i

第一:

例程1中的 test get_score(){ test pn;cin>>pn.name>>pn.socre;return pn;}

调用的时候在内部要在栈空间开辟一个名为pn的结构体变量 程序pn的时候又再次在栈内存空间内自动生成了一个临时结构体变量temp 在前面的教程中我们已经说过 它是一个copy 而例程2中的:

void get_score(test &pn){ cin>>pn.name>>pn.socre;}

却没有这一过程 不开辟任何新的内存空间 也没有任何临时变量的生成第二:

例程1在mian()中

必须对返回的结构体变量进行一次结构体变量与结构体变量直接的相互赋值操作

for(int i=0;i

而例程2中由于是通过内存地址直接操作 所以完全没有这一过程 提高了效率

for(int i=0;i

函数也是可以返回结构体应用的 例子如下:

#include #include using namespace std;

struct test { char name[10];float socre;};

test a;

test &get_score(test &pn){ cin>>pn.name>>pn.socre;return pn;}

void print_score(test &pn){ cout<

void main(){ test &sp=get_score(a);cin.get();cout<

调用get_score(a);结束并返回的时候 函数内部没有临时变量的产生

返回直接吧全局结构变量a的内存地址赋予结构引用sp

最后提一下指针的引用

定义指针的引用方法如下: void main(){ int a=0;int b=10;int *p1=&a;int *p2=&b;int *&pn=p1;cout <

pn就是一个指向指针的引用 它也可以看做是指针别名

总之使用引用要特别注意它的特性 它的操作是和普通指针一样的

在函数中对全局指针的引用操作要十分小心 避免破坏全局指针!

第五篇:c语言中可变参数函数设计方案

c语言中可变参数函数的设计

c语言中可变参数函数的设计

c语言中可变参数函数的设计

-----最近想好好学学这个, 先把网上搜集得资料贴上.========================

参数可变函数的实现(上)CSDN Blog推出文章指数概念,文章指数是对Blog文章综合评分后推算出的,综合评分项分别是该文章的点击量,回复次数,被网摘收录数量,文章长度和文章类型;满分100,每月更新一次。

此文献给如我一般还在探索C语言之路的朋友们。

注:本文中测试程序的编译环境为win2000和VC6.0 缘起:

作为一个程序员,我没有写过参数可变的函数,我相信大部分朋友也没有涉及过,或者我的境界层次太低了。那么缘何我要去揭这一层面纱呢?因为好奇!

我是个思维具有极大惰性的人,曾经识得参数可变函数,也懒得去深究,但是它的三点(函数声明时参数列表中的“…”)却深刻的映入/ 20 了我的记忆里,而且是带着若干个闪耀的问号。可是就在昨天,在拜读某君的高论时,它再一次出现了。我的资质真的是不太够,因为某君在谈到它时只是给出了中关于它的宏定义,我想大概在高手眼里,点这一下就神会了吧。可是他这么轻轻一点却使留在记忆里曾经的那几个问号无限的膨胀,以至于我这个又菜又懒的所谓程序员也萌生了莫大的好奇。

破题:

但凡所谓“实现”都是从没有到有的过程,但是我只是想去解惑它的实现,因为它原本就是好端端的正为成千上万的程序员们服务。

还是从我们熟悉的printf说起:

如果你是个C语言的程序员,无论你是初学者还是高高手,对于printf都不会陌生,甚至你已经用了无数次了。我已经说过我是个有极大惰性的人,所以每次用printf都是照本宣科,规规矩矩的按教科书上说的做,从来没有问过一个为什么,这就是所谓的“熟视无睹”吧。

其实,printf函数是一个典型的参数可变的函数。在保证它的第一个参数是字符串的条件下,你可以输任意数量任意合法类型的参数。只要你在第一个字符串参数中使用了对应的格式化字符串,你就可以输出正确的值。这难道不是件很有趣的事吗?那它是怎么做到的?

1,首先,怎么得到参数的值。对于一般的函数,我们可以通过参数对应在参数列表里的标识符来得到。但是参数可变函数那些可变的参数是没有参数标识符的,它只有“…”,所以通过标识符来得到是不可能的,我们只有另辟途径。/ 20

我们知道函数调用时都会分配栈空间,而函数调用机制中的栈结构如下图所示:

|......|

------------------

| 参数2 |

------------------

| 参数1 |

------------------

| 返回地址 |

------------------

|调用函数运行状态|

------------------

可见,参数是连续存储在栈里面的,那么也就是说,我们只要得到可变参数的前一个参数的地址,就可以通过指针访问到那些可变参数。但是怎么样得到可变参数的前一个参数的地址呢?不知道你注意到没有,参数可变函数在可变参数之前必有一个参数是固定的,并使用标识符,而且通常被声明为char*类型,printf函数也不例外。这样的话,我们就可以通过这个参数对应的标识符来得到地址,从而访问其他参数变得可能。我们可以写一个测试程序来试一下: / 20

#include

void va_test(char* fmt,...);//参数可变的函数声明

void main(){

int a=1,c=55;

char b='b';

va_test(“",a,b,c);//用四个参数做测试

}

void va_test(char* fmt,...)//参数可变的函数定义,注意第一个参数为char* fmt {

char *p=NULL;/ 20

p=(char *)&fmt;//注意不是指向fmt,而是指向&fmt,并且强制转化为char *,以便一个一个字节访问

for(int i = 0;i<16;i++)//16是通过计算的值(参数个数*4个字节),只是为了测试,暂且将就一下

{

printf(”%.4d “,*p);//输出p指针指向地址的值

p++;} }

编译运行的结果为

0056 0000 0066 0000 | 0001 0000 0000 0000 | 0098 0000 0000 0000 | 0055 0000 0000 0000

由运行结果可见,通过这样方式可以逐一获得可变参数的值。

至于为什么通常被声明为char*类型,我们慢慢看来。

2,怎样确定参数类型和数量 / 20

通过上述的方式,我们首先解决了取得可变参数值的问题,但是对于一个参数,值很重要,其类型同样举足轻重,而对于一个函数来讲参数个数也非常重要,否则就会产生了一系列的麻烦来。通过访问存储参数的栈空间,我们并不能得到关于类型的任何信息和参数个数的任何信息。我想你应该想到了——使用char *参数。Printf函数就是这样实现的,它把后面的可变参数类型都放到了char *指向的字符数组里,并通过%来标识以便与其它的字符相区别,从而确定了参数类型也确定了参数个数。其实,用何种方式来到达这样的效果取决于函数的实现。比如说,定义一个函数,预知它的可变参数类型都是int,那么固定参数完全可以用int类型来替换char*类型,因为只要得到参数个数就可以了。

3,言归正传

我想到了这里,大概的轮廓已经呈现出来了。本来想就此作罢的(我的惰性使然),但是一想到如果不具实用性便可能是一堆废物,枉费我打了这么些字,决定还是继续下去。

我是比较抵制用那些不明所以的宏定义的,所以在上面的阐述里一点都没有涉及定义在的va(variable-argument)宏。事实上,当时让我产生极大疑惑和好奇的正是这几个宏定义。但是现在我们不得不要去和这些宏定义打打交道,毕竟我们在讨生计的时候还得用上他们,这也是我曰之为“言归正传”的理由。

好了,我们来看一下那些宏定义。

打开文件,找一下va_*的宏定义,发现不单单只有一组,但是在各组定义前都会有宏编译。宏编译指示的是不同硬件平台和编译器下用怎样的va宏定义。比较一下,不同之处主要在偏移量的计算上。我们还是拿个典型又熟悉的——X86的相关宏定义: / 20

1)typedef char * va_list;

2)#define _INTSIZEOF(n)((sizeof(n)+ sizeof(int)1))

3)#define va_start(ap,v)(ap =(va_list)&v + _INTSIZEOF(v))

4)#define va_arg(ap,t)(*(t *)((ap += _INTSIZEOF(t))sizeof(type)))

其中,argp的类型是char *。

如果你想用va_arg从可变参数列表中提取出函数指针类型的参数,例如

int(*)(),则va_arg(argp, int(*)())被扩展为:

(*(int(*)()*)(((argp)+= sizeof(int(*)()))-sizeof(int(*)())))

显然,(int(*)()*)是无意义的。

解决这个问题的办法是将函数指针用typedef定义成一个独立的数据类型,例如:

typedef int(*funcptr)(); / 20

这时候再调用va_arg(argp, funcptr)将被扩展为:

(*(funcptr *)(((argp)+= sizeof(funcptr))-sizeof(funcptr)))

这样就可以通过编译检查了。

问题:可变长参数的获取

有这样一个具有可变长参数的函数,其中有下列代码用来获取类型为float的实参:

va_arg(argp, float);

这样做可以吗?

答案与分析:

不可以。在可变长参数中,应用的是”加宽“原则。也就是float类型被扩展成double;char, short被扩展成int。因此,如果你要去可变长参数列表中原来为float类型的参数,需要用va_arg(argp, double)。对char和short类型的则用va_arg(argp, int)。

问题:定义可变长参数的一个限制

为什么我的编译器不允许我定义如下的函数,也就是可变长参数,但是没有任何的固定参数?

int f(...)

{ / 20

...}

答案与分析:

不可以。这是ANSI C 所要求的,你至少得定义一个固定参数。

这个参数将被传递给va_start(),然后用va_arg()和va_end()来确定所有实际调用时可变长参数的类型和值。

第一篇

C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为:

int printf(const char* format,...);

它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的(用三个点“…”做参数占位符),实际调用时可以有以下的形式:

printf(”%d“,i);printf(”%s“,s);printf(”the number is %d ,string is:%s“, i, s);

一个简单的可变参数的C函数

先看例子程序。该函数至少有一个整数参数,其后占位符…,表示后面参数的个数不定。在这个例子里,所有的输入参数必须都是整/ 20 数,函数的功能只是打印所有参数的值。函数代码如下:

//示例代码1:可变参数函数的使用 #include ”stdio.h“ #include ”stdarg.h“ void simple_va_fun(int start,...){ va_list arg_ptr;int nArgValue =start;int nArgCout=”0“;//可变参数的数目

va_start(arg_ptr,start);//以固定参数的地址为起点确定变参的内存起始地址。do { ++nArgCout;printf(”the %d th arg: %d",nArgCout,nArgValue);//输出各参数的值

nArgValue = va_arg(arg_ptr,int);//得到下一个可变参数的值

} while(nArgValue!=-1);return;} int main(int argc, char* argv[]){ simple_va_fun(100,-1);simple_va_fun(100,200,-1);return 0;}

下面解释一下这些代码。从这个函数的实现可以看到,我们使用可变参数应该有以下步骤: / 20

⑴由于在程序中将用到以下这些宏: 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 / 20

下载对于C语言中的scanf函数的使用问题总结word格式文档
下载对于C语言中的scanf函数的使用问题总结.doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    C语言中union应用总结

    C语言中union应用总结 定义共用体的类型变量的一般形式为: union 共用体名 { 成员列表; }变量列表; 例如: union data { int i; unsigned char c; float f; }; union da......

    C语言中的文本Txt操作

    对于文件使用方式有以下几点说明: 1)文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是: r(read): 读 w(write): 写 +: 读和写 a(append): 追加 t(text): 文本文件,可......

    C语言中的EOF(精选5篇)

    C语言中的EOF EOF是指文件的结束符,是一个宏定义. 对于键盘输入来说,getchar只有在遇到文本结束标记(ASCII编码为26)时才会返回EOF,其它情况都会返回一个输入符号值。所以对于......

    c语言中的正则表达式regex.h

    c语言中的正则表达式regex.h 如果用户熟悉Linux下的sed、awk、grep或vi,那么对正则表达式这一概念肯定不会陌生。由于它可以极大地简化处理字符串时的复杂度,因此现在已经在许......

    C语言中extern关键字详解大全

    C语言中extern关键字详解作者:华清远见武汉华嵌 技术支持 曹伟东内容清单:1. 用extern声明外部变量在一个文件内声明的外部变量在多个文件中声明外部变量在多个文件......

    c语言中if语句知识点总结(5篇范例)

    If语句知识点总结 一. if语句的三种基本形式 if (表达式)语句; 例: if(x>y) printf(“%d”,x); if(表达式) 语句1; else语句2; 例:if (x>y) printf(“%d”,x); else p......

    C语言中的逻辑运算符和位运算符总结

    老分不清一个&号和俩的用法,今天专门拿出来整理整理: 一、逻辑运算符: 包括:1。&&逻辑与 2。||逻辑或 3。!逻辑非 逻辑运算符用于对包含关系运算符的表达式进行合并或取非 对......

    C语言中变量的存储类别

    一.C语言中,从变量的作用域角度来分,可以分为全局变量和局部变量。 二.变量值存在的时间角度来分,可以分为静态存储方式和动态存储方式。所谓静态存储方式是指在程序运行期间有......