c语言函数范文

时间:2023-03-03 07:55:13

c语言函数

c语言函数范文第1篇

关键词:C语言 函数调用 间接访问

中图分类号:TP312 文献标识码:A 文章编号:1007-9416(2015)12-0000-00

C语言程序设计是结构化程序设计,函数是C语言的基本模块,函数调用是C语言运行的重要机制,在C语言中除了提供大量的库函数外,要实现具体的功能必须自己定义函数,定义出函数要实现的功能,使用函数的过程就是调用函数的过程,即函数间的接口,接口的实现是通过参数传递方式实现,函数调用的关键是正确传递实参值,用正确的形参变量来接收。

1 函数的定义

所谓函数定义,即定义函数功能,如求和,求最值,排序功能,用C语言提供的选择结构、循环结构写出具体的代码实现。如果函数只是完成某项特定的处理任务可以定义无返回值的函数,如果函数最后要返回结果,可以定义的返回值的函数,如下两段代码左边有返回值,右边没有返回值。

int sum1(int m)//函数头部

{ int i,sum=0;

for(i=1;i

sum=sum+i;

return sum; }

void sum2(int m)//函数头部

{ int i,sum=0;

for(i=1;i

sum=sum+i;

}

s=sum;

}

2 函数的调用

函数调用的一般形式为:

函数名(实参列表);

实参可以是常数、变量、表达式等,多个实参用逗号,分隔。

在C语言中,函数调用的方式有多种,例如:

01.// 函数作为表达式中的一项出现在表达式中

02.z = max(x, y);

03.m = n + max(x, y);

04.// 函数作为一个单独的语句

05.printf("%d", a);

06.scanf("%d", &b);

07.// 函数作为调用另一个函数时的实参

08.printf( "%d", max(x, y) );

09.total( max(x, y), min(m, n) );

在函数调用中还应该注意的一个问题是求值顺序的问题。所谓求值顺序是指对实参列表中各个参数是自左向右使用呢,还是自右向左使用。对此,各系统的规定不一定相同。

3 实际参数和形式参数

在函数定义时出现函数名后边括号里的变量就是形参,形参必须是变量,因为在函数调用时形参是被赋值对象,形参只在定义它的函数内部被访问,是局部变量。

在函数调用时出现在函数名后边括号里的常量、变量、表达式、函数等是实参,实参当前值是确定的,因为它在赋号右侧。

实参出现在主调函数中,形参出现在被调函数中。

4 传值调用和传址调用

4.1两个数对调的函数实现

#include

int a=3,b=4;

void swap1(int a,int b){//值传递,也称为单向传递

int t;

t=a;a=b;b=t;

}

void swap2(int *a,int *b){//地址传递,也称为“双向传递”,实质还是单向传递

int t;

t=*a;*a=*b;*b=t;

}

main(){

swap1(a,b);

printf("a=%d,b=%d\n",a,b);

swap2(&a,&b);

printf("a=%d,b=%d\n",a,b);

}

第一个输出结果为3,4,第二个输出结果为4,3,在这里传值调用和传址调用正确,多数教材和资料中谈到传址调用时介绍是双向传递,应该是不正确的,以下面例子为例:

4.2有下列程序

# include

void fun1(int x,int y)

{ int z;

z=x; x=y; y=z;

}

void fun2(int *x,int *y)

{ int z;

z=*x; *x=*y; *y=z;

(*x)++; (*y)++;

}

void fun3(int *x,int *y)

{ int z;

z=*x; *x=*y; *y=z;

(*x)++; (*y)++;

}

void main()

{ int a=5,b=9;

fun1(a,b);

printf("a=%d,b=%d\n",a,b);

fun2(&a,&b);

printf("a=%d,b=%d\n",a,b);

fun3(&a,&b);

printf("a=%d,b=%d\n",a,b);

}

在这个程序中有三次函数调用,第一次调用结果还第三次调用都没有改变主调函数中变量的值第二次改变了,第一次是传值调用,第二、三次是传址调用,第二次改变的实质不是因为是传址调用,而是因为使用了间接访问。

5 C语言程序设计函数使用方法

5.1函数是C模块语言的模块

C语言的基本框架是函数,函数是C语言的基本模块,在理解中列举生活中的例子,例如一个部门一开始很小,只有一个人,相当只有一个主函数,慢慢的部门壮大起来,需要的人数增多,这时候部门就可以再进一个人,那必然有一个领导另一个,领导者就是先来的人,也就是主函数,被领导者是后来的人,即被调用函数,主函数安排任务给被调函数,要把任务内容告诉被调用函数,这变是参数传递。

5.2函数代码定义过程

定义时先定义被调用函数,然后再定义主函数,这样在主函数中就不用做函数声明了。

定义被调用函数时,先把函数名字及圆括号和大括号写,里面的代码先不写。然后写主函数定义,主函数在这里没有返回值也无参,主函数的头部定义没有问题,然后先写主函数体代码,通常主函数分三部分, 输入、调用和输出,这三部分相对比较难的是调用,调用时要分析有没有返回值,有没有参数,如果有参数,有几个并且参数的类型要确定,调用时的参数是实际参数,根据实参和形参的一一对应关系,实参确定好了,形参的类型和个数自然也就确定了,这样被调用函数的头部就定义好了。

主函数定义后,被调用函数的头部也定义好了,这时候开始写被调用函数的函数体,也是编写程序最难的一部分,涉及具体的算法。

把主函数和被调用函数定义好后,在具体开发环境下编译、链接、执行,找出程序有没有语法错误和逻辑错误,最后程序得出正确的结果。

6 结语

C语言程序设计函数部分是学习难点,它把以前学的一个函数能实现的功能分在两个或多个函数中实现,并且多个函数这间有接口,接口就是函数调用时的参数传递,参数传递时又涉及到变量的作用域和生存期,函数部分把C语言的各个知识点都联接起来了,是C语言的集成和综合,所以学好函数是学好C语言的关键。

参考文献

[1] 谭浩强.C程序设计(第三版)[M].清华大学出版社,2005年.

[2] 郭继展.新编C语言程序设计[M].机械工业出版社,2003年6月.

c语言函数范文第2篇

一、函数的概念函数是一组语句,这组语句可以完成一个独立的操作,这组语句有一个简短的名字,程序员可以仅仅利用这个名字完成某个操作。函数的使用,使复杂的程序变得简单化、条理化、清晰化。在C语言中函数分为两大类:库函数、用户自定义函数。

1、库函数在编写程序的过程中往往有一些操作需要频繁的使用,并且这些操作的代码实现又有一定的难度。比如数据的输入、输出。在C语言中是没有输入输出语句的,由于输入输出涉及到多计算机硬件的直接操作,对用户来说较困难。这些操作往往由编译系统的开发商提供给用户。它们都是以独立程序块的模式出现,并且存在于编译系统的某个文件中,这就是库函数。比如printf(),scanf()。它们是由编译程序根据一般用户的需要编制并提供给用户使用的一组程序代码。C语言的库函数极大地方便了用户,同时也补充了C语言本身的不足。事实上,在编写C语言程序时,应当尽可能多地使用库函数,这样既可以提高程序的运行效率,又可以提高编程的质量。

2、用户自定义函数用户自定义函数顾名思义就是用户自己定义的函数。程序的编写过程其实就是一个个函数的定义过程。很多情况下,C语言的编译系统提供给我们的函数并不能满足用户的要求,这就要求用户自己编写函数。函数是由一组语句组成,并给定一个名字。相应的函数的定义一般可分为两大部分:函数头部的定义、函数体的定义。形式如下:函数的类型函数名(函数的参数){函数体;}上面大括号上边的一行成为函数的头部(首部),它给出了函数的表面信息:函数返回值的类型,函数的名字,函数要处理的数据;大括号内的语句描述了函数的内在构造,这组语句完成一个独立的操作,是对函数能够完成功能的具体描述。

3、函数的调用函数是由一组语句组成,并给定一个名字。执行与函数相关的一组语句的行为称为函数的调用。应该说函数定义好之后调用之前是没有什么意义的。函数就像某个具有特殊功能的机器工具。这些机器只有在开关打开之后才能发挥作用。在程序编写过程中,完成“开关机器”这个操作的就是函数调用。函数调用的一般形式:函数名(实际参数);

二、函数的教学C语言函数的教学主要是学习自定义函数以及库函数的使用。

1、库函数的教学库函数的教学主要是引导学生主动积极地去使用库函数。由于大多数课本中库函数仅仅是提及,学生大多只会简单输入输出函数及一些字符串处理函数的使用。其实库函数还有大量的函数提供给我们。但很多学生不会主动去了解,去使用,原因主要是学生不了解库函数有哪些,能干什么。针对这种情况,我们可以在教学中找一些用法简单有趣的库函数来激发学生的学习兴趣。比如可以把图形函数库中的一些函数做一简单介绍,在屏幕上输出一些带有色彩的简单的图案。事实证明色彩的引入能引起很多学生主动使用库函数的兴趣。

c语言函数范文第3篇

关键词:传值; 传址; C语言函数; 地址共享

中图分类号:TN91134; TP311文献标识码:A文章编号:1004373X(2012)04005502

Parameter delivery law of C language function

ZHAO Juan1, FAN Chao2

(1. North Institute of Information Engineering, Xi’an Technological University, Xi’an 710025, China;

2. Shaanxi Youth Vocational College, Xi’an 710068, China)

Abstract: C language module design is implemented mainly through the function. The information between the functions is delivered by parameters. The parameter delivery of the function includes the delivery value and delivery address. In order to distinguish the difference of the two modes, two methods of examples and illustrations are adopted. The instances which takes variable, array name and pointer as parameters are listed. By comparing the variation of formal parameter and actual parameter after function call, two laws of the parameter delivery, while the function was called, were summed up: the base type variable, array element and structure variables as parameters are passed by value, that is, they deliver information in one way; the array name and pointer as parameters are passed by address, that is, they share the same address.

Keywords: delivery value; delivery address; C language function; address sharing

收稿日期:20110926在程序设计中常采用模块设计方法,实际上所谓模块设计的思想是一种“分而治之”的思想,把一个大任务分为若干个子任务,这样每一个子任务就相对简单了。程序中的子任务在C语言中通常是用函数来实现的。通过函数间的相互调用来完成程序的主要任务。参数是实现函数间信息传递的主要通道,因此掌握参数的传递方式,把握函数间的传递规律是学习C语言的关键。

1参数的传递方式

C语言函数的参数传递可以归纳为两种方式:传值和传址。下面用实例和图示两种方式进行描述。

1.1传值

传值传递方式主要出现在实参和形参都是变量的时候,如基类型变量、数组元素、结构体变量作参数时,进行的就是值传递,程序如下:

在上述的例子中,函数调用时如图1(a)所示。实参将值传给形参,形参在子函数里发生互换,但不能将互换的值传回给实参,结果如图1(b)所示。因此实参在整个过程中没有发生变化,由此可以总结当用普通变量作参数时,进行的是单向的值传递,只能实参传形参,形参无法传实参。

图1变量作参数的调用过程1.2传址

该方法中函数调用时参数间传递的地址有以下3种情况:变量的地址作参数、数组名作参数以及指针作参数。由于变量的地址作参数与指针作参数类似,这里就不再举例,主要针对数组名作参数和指针作参数进行探讨。

1.2.1数组名作参数

数组名作参数的程序如下:

void f(int t[],int n)

{int i; for(i=0;i

void main()

{ int a[4]={1,2,3,4},i; f(a,4); for(i=0;i

数组名作参数时,传递的是数组的首地址,即实参数组和形参数组共用一段内存空间,如图2(a)所示。在子函数中对数组t的所有元素进行赋值,其实也就是对数组a的所有元素进行赋值,如图2(b)所示。所以当用数组名作参数时,实参和形参共享一个数组,形参数组的改变也就是实参数组的改变,其程序如下:

void swap(int *a, int *b)

{int temp; temp=*a;*a=*b;*b=temp;}

main()

{int x=3, y=5, *p=&x, *q=&y;

swap(p,q); printf("%d,%d",*p,*q);}

图2数组名作参数的调用过程1.2.2指针作参数

指针作参数与数组名作参数类似,传递的也是地址,但此时不是共享一个数组,而是共享一个变量的地址,即实参指针和形参指针共同指向同一个变量,共享同一个变量地址如图3所示。这时有2种情况:改变形参的指向;改变形参所指向的变量。上面的例子属于第二种情况,形参指向的变量值发生变化,也就是实参指向的变量值发生变化。把此例稍做修改得如下程序:

void swap(int *a,int *b)

{int *temp; temp=a; a=b; b=temp;}

将函数稍做改动后,子函数的功能只是改变了形参指针的指向,如图4(c)所示。对实参并无影响,从而也不会影响实参所指向的变量值。

2结语

调用函数时,从参数的传递情况来看,其实质就是传值和传址,传值是变量作参数,实参只负责给形参赋初值,形参在整个过程中的改变都不影响实参,所以是单向的值传递。传址是数组名和指针作参数,此时体现的就是共享,数组名作参数,实参和形参共享一个数组,形参数组的改变就是实参数组的改变;指针作参数共享的是同一个变量的地址,即实参和形参共同指向同一个变量,当改变形参所指向的变量值时,实参所指向的变量值也一同改变,因为它们指向的是同一个变量。如果改变的是形参的指向,则不影响实参指针的改变。

图3指针作参数的调用过程1图4指针作参数的调过过程2参考文献

[1]谭浩强.C程序设计[M].北京:清华大学出版社,2005.

[2]杨战海,薛苏秦,张晓光.基于C语言函数参数传递规律的探讨[J].现代电子技术,2008,31(16):8991.

[3]马新.C语言函数间参数传递机制的探讨[J].白城师范学院学报,2008(6):2627.

[4]王英存.C语言教学中函数参数传递难点探讨[J].中国商界,2010(9):258259.

[5]李寅杰.C语言函数中的三类形参[J].辽宁师专学报:自然科学版,2007(3):5254.

[6]张艳华.C语言函数形参与实参之间的数据传递[J].内江科技,2007(9):80.

[7]张筱红,李军宇,高喜民.C语言函数形参与实参之间的数据传递[J].平顶山工学院学报,2002(3):5152.

[8]王晓青.C语言函数调用时的参数变化[J].青海大学学报:自然科学版,1998(1):5558.

[9]古丽孜拉・安尼瓦尔.C语言函数参数传递的几个问题[J]. 伊犁师范学院学报,2004(3):7374.

c语言函数范文第4篇

关键词:C语言 图形函数 应用

引言

C语言是国际上广泛流行的很有发展前途的计算机高级语言。它既具有一般计算机高级语言的可读性、可移植性的特点,又具有低级语言能够对计算机硬件进行操作的特性,因此,它适合用于操作系统的描述语言,用C语言开发系统软件和应用软件。但在87ANSIC中并没有规定C语言的图形功能,许多C语言教材没有介绍C语言的图形功能,这给许多需要用C语言设计完美、漂亮的用户界面的初学者带来了困难[1-2]。本文旨在通过介绍Turbo C 2.0的主要图形函数及一个具体的实例简介这些函数的用法。

1 与图形绘制有关的系统硬件[2-3]

要使计算机能够绘制图形,必须有一定的硬件基础作为保障。图形绘制的硬件基础主要是显示器和显示卡。显示器的工作方式一般有文本方式和图形方式。要在屏幕上显示图形,必须将其设置成图形方式。衡量显示器的主要性能指标是点距和分辨率。目前显示器常用的点距有0.39mm、0.31mm和0.28mm三种。高档微机配置的彩色显示器目前流行的是VGA档次,它最低的分辨率为640×480,中档的是800×600,高档的是1024×768。显示器必须与显示卡配套使用才能发挥其图形功能。显示卡所能支持的不同分辨率的显卡类型称为显示模式。下表给出Turbo C中常用的几种显示卡的图形模式:

2 Turbo C 2.0中与绘图有关的常用图形函数

2.1 设置图形工作方式的函数:initgraph()。

Turbo C绘图,首先必须设置显示器为图形方式。该函数通过选定参数可确定显卡的类型及图形模式。

如:

int driver,mode;

driver=IBM8514;

mode=IBM8514HI;

initgraph(&driver,& mode,“c:\temp”);

将图形方式设置为IBM8514类型,IBM8514HI图形模式,1024×768的分辨率,搜索路径temp为C盘一级子目录。

2.2 颜色控制函数setbkcolor(int color)及setcolor(int color)。

其中setbkcolor( )设置背景颜色,setcolor( )设置划线颜色。

2.3 基本绘图函数

A. line(int x1,int y1,int x2,int y2)

功能:从点(x1,y1)到点(x2,y2)画一直线。

B. arc(int x,int y,int stange,int endangle,int r)

功能:以(x,y)为圆弧的中心,以stange为起始角度,以endangle为终止角度,以r为半径作一圆弧。

C. setfillstyle(int pattern,int color)

功能:用参数pattern所确定的填充模式,用参数color确定的颜色进行填充。

D. floodfill(int x,int y,int color)

功能:填充一个含有点(x,y)在内的有界封闭区域,这个有界封闭区域的边界由参数color确定,填充模式与填充颜色由函数setfillstyle设定。

2.4 字符输出函数

A. settextstyle(int font,int direction,int size)

功能:在图形方式下设置字符的字体,式样和放大因子。

B. outtextxy(int x,int y,char &str)

功能:在窗口(x,y)的位置输出字符或字符串。

C. getch( )

功能:从控制台取得一字符且不输出,用来使程序暂停,按任意键后使程序继续运行。

3. 绘制一个圆饼型统计图的程序如下

#include

main( )

{ int driver,mode;

driver=VGA;

mode=VGAHI;

initgraph(&driver,&mode,“ ”);

setbkcolor(0);

setcolor(15);

arc(320,240,0,360,180);

line(320,240,500,240);

line(320,240,443,112);

line(320,240,266,70);

line(320,240,200,374);

setfillstyle(4,2);

floodfill(340,230,15);

setfillstyle(5,9);

floodfill(340,180,15);

setfillstyle(7,4);

floodfill(300,240,15);

setfillstyle(8,3);

floodfill(340,280,15);

setcolor(14);

settextstyle(1,0,4);

outtextxy(410,180,“14%”);

settextstyle(1,0,4);

outtextxy(330,110,“16%”);

settextstyle(1,0,4);

outtextxy(200,200,“34%”);

settextstyle(1,0,4);

outtextxy(340,310,“36%”);}

上述程序在Turbo C 2.0中上机通过编译、连接、运行,可得到精美的圆饼型图。读者通过阅读并上机调试运行该程序可以对C语言的图形设置、绘制;颜色的控制、填充等函数的应用有一个感性的认识,对复杂枯燥的C函数提高学习兴趣。

结语

目前许多C语言教材很少介绍C语言的图形功能,而许多C语言学习者对C语言的图形功能很感兴趣,为帮助初学者学习C语言绘图函数并提高学习兴趣,本文简单介绍了C语言一些常用的绘图函数及其应用,权当抛砖引玉!还有一些图形函数没有列出,读者若有兴趣可参阅《C语言函数大全》。

参考文献:

[1]徐士良.PC机C图形编程手册.北京:清华大学出版社,1994.2.

[2]谭浩强.C程序设计(第二版)[M].北京:清华大学出版社,1999.

[3]MarkFinlay.C和C++图形程序设计基础.北京:龙门书局,1997.4.

c语言函数范文第5篇

一、格式说明符和输入项的三对应(类型、个数、顺序)scanf函数格式中的格式说明(“%格式字符”)应与输入项数据类型一致,个数相等、顺序对应(除格式说明中出现“*”附加格式说明字符外)。示例一:inta,b;scanf("%d%d%d",&a,&b);printf("%d,%d",a,b);输入“345”时,输出“3,4”,没有错误提示信息,但是第三个数没有接收的变量,也就没有输出。再如inta,b;scanf("%d",&a,&b);printf("%d,%d",a,b);输入“34”时,输出“3,-858993460”,a得到3,但b是一个随机数,都是因为格式说明(“%格式字符”)与输入项个数不一致造成的。再如structst{intnum;charname[10];intage;floatscore;}student;scanf("%d,%s,%d,%f",&student);输入“10001,"zhang",23,68”,运行程序时,无出错信息,但student不能正确接收输入数据。

应该写成:scanf("%d,%s,%d,%f",&student.num,student.name,&student.age,&stu-dent.score);保证格式说明与输入项个数相等、一一对应,才能使student正确接收输入数据。示例二:chara,b;scanf("%d%d",&a,&b);printf("%d,%d",a,b);输入“34”时,输出“3,4”,输入整型数据,是字符型数据接收,但是结果正确,因为字符型数据在内存中的存放形式是整型数据。再如floata,b;scanf("%d%d",&a,&b);printf("%d,%d",a,b);输入“34”时,输出“0,918028288”,即a和b的结果都是随机数,这就是输入格式和接收的数据类型不一样造成的。又如:inta,b;scanf("%f%f",&a,&b);printf("%d,%d",a,b);输入“1.23.4”时,输出“1067030938,1079613850”,即a和b的结果都是随机数,这也是输入格式和接收的数据类型不一样造成的。

二、非格式说明符的输入非格式说明符要求用户原样照写输入,既不能更改,又不能漏写。示例一:inta,b;scanf("a=%d,b=%d",&a,&b);printf("%d,%d",a,b);输入“12”(即1、2间用空格隔开),输出“-858993460,-858993460”,无错误提示,但结果与输入数据不一致,输出a、b的值是随机数。这就是因为scanf函数中设定的格式(“a=%d,b=%d”)(其中a=,b=均为普通字符)与输入数据的格式(1、2间用空格间隔)不一致造成的,正确的输入形式应为“a=1,b=2”(“,”也绝不能漏掉)。所以,为了保证正确输入数据,输入数据前首先看好程序中scanf函数设定的格式,再按照设定的格式正确输入数据。示例二:scanf("%d,%d",&a,&b);输入时应用以下形式:3,4注意3后面应是逗号,它与scanf函数中的“格式控制”中的逗号对应。如果输入时不用逗号而用空格或其他字符是不对的。34(不对)3:4(不对)如果是scanf("%d%d",&a,&b);则输入时两个数据间应空两个或更多个空格字符。如:34或34

三、附加格式说明符的说明示例一:inta,b;scanf("%2d%2d",&a,&b);printf("%d,%d",a,b);输入“1234”,输出“12,34”输入“123”,输出“12,3”输入“123456”,输出“12,34”因为格式中“d”格式字符表示输入整型数据,“2”附加格式说明字符表示输入数据所占宽度为2,因此,无论用户输入什么,系统都将自动截取两位赋给a,再截取两位赋给b。也就是说可以用附加格式说明符指定输入数据所占列数,系统将自动按它截取所需数据。

再如scanf("%3c",&ch);如果从键盘上连续输入3个字符abc,由于ch只能容纳一个字符,系统就把第一个字符‘a’赋给ch。示例二:floata;scanf("%5.1f",&a);输入“1234”,无错误提示,但a并不能接收输入数据,输出a的值为随机数,再尝试输入别的数据,结果都为随机数。用户本意想用这样的scanf格式输入宽度为5位,小数部分为1位的小数,但得不到预想结果。因为,scanf函数中只有“域宽”(此处为5)附加格式说明字符(指定输入数据所占列数),而没有在“小数位数”附加格式说明字符(只有printf函数有),应该去掉“.1”,即scanf("%5f",&a);或scanf("%f",&a);均可,此时输入“123.4”即可接收。所以,应根据scanf函数中规定的格式字符及其附加格式说明字符使用,不能滥用,输入数据时不能规定精度。示例三:doublex;scanf("%f",&x);输入“123.4”,输出x的值为随机数,没有接收输入的数据,再输入别的数据,结果都为随机数。这是因为用户定义x为双精度型数据,而用“%f”格式输入数据时,不能接收,应该使用“%lf”或“%le”,即scanf("%lf",&x);此时输入“123.4”即可接收。

因此长整型数据和双精度型数据必须使用附加格式说明字符l,短整型数据必须使用附加格式说明字符h。示例四:inta,b;scanf("%2d,%*3d,%2d",&a,&b);输入“12,345,67”,此时,12赋给a,67赋给b。注意:原则上“,%格式字符”应与“输入项”(&a,&b)个数相等,一一对应,此处则出现了个数不等的情况(“%格式字符”项数为3,而输入项数为2)。因为scanf函数中有附加格式说明字符“*”,加“*”项表示输入的数据不赋给相应变量,因此输入的“345”被跳过,接收下一个数据(“67”),致使“%格式字符”与“输入项”个数可以不等的情况出现。在利用现成的一批数据时,有时不需要其中某些数据,可用此法跳过它们。例如scanf("%c%c",&a,&b);printf("%c%c",a,b);输入AB,输出A‘,A’给了字符变量a‘,’作为合法字符给了字符变量b。这时我们改用scanf("%c%*c%c",&a,&b);输入AB,输出AB,‘A’给了字符变量a‘,’被%*c跳过‘,B’就给了字符变量b。可见,使用scanf函数时,要在scanf规定的格式字符及其附加格式说明字符下使用。既不能不用,又不能滥用。

四、注意输入结束标志①遇到空格,或者回车键,或者Tab键。如果相邻两个格式指示符之间,不指定数据分隔符(如逗号、冒号等),则相应的两个输入数据之间,至少用一个空格分开,或者用Tab键分开,或者输入一个数据后,按回车,然后再输入下一个数据。在用“%c”格式输入字符时,空格字符和“转义字符”都作为有效字符输入。示例一:scanf("%d%d",&num1,&num2);假设给num1输入12,给num2输入36,则正确的输入操作为:1236或者:1236示例二:scanf("%c%c%c",&c1,&c2,&c3);如果从键盘输入abc则字符‘a’赋给c1,字符‘’赋给c2,字符‘b’赋给c3。因为%c只要求读入一个字符,后面不需要用空格作为两个字符的间隔空格,因此空格作为下一个字符赋给c2。

故应该从键盘输入abc②遇到输入域宽度结束。例如“%3d”,只取3列。示例一:scanf("%3d",&num1);如果从键盘输入12345,则num1的值为123。③遇到非法输入。例如,在输入数值数据时,遇到字母等非数值符号(数值符号仅由数字字符0-9、小数点和正负号构成)。示例一:scanf("%d%c%f",&a,&b,&c);若输入1234a1230.26第一个数据对应%d格式在输入1234之后遇到的字母a,因此认为1234之后已没有数字了,第一个数据到此结束,把1234送给变量a。字符‘a’送给变量b,由于%c只要求输入一个字符,因此输入字符a后不需要加空格,后面的数值应送给变量c。如果由于疏忽把本来应为1230.26错打成123o.26,由于123后面出现字母‘o’,就认为该数值数据到此结束,把123送给c。

c语言函数范文第6篇

关键词:Java;JNT;C++;DLL

在现今的软件开发领域中,Java以其跨平台的优势得到大量的应用,其代码可以一次编译多处执行。但这种特性给Java带来了一定的局限性,幸好Java提供了完备的C/C++语言接口,这样我们可以利用C语言的强大功能实现Java难以实现的功能,在一定程序上消除Java的局限性和低效率。

JNI是Java Native Interface的英文缩写,中文翻译为本地调用,自从Java 1.1开始就成为了Java标准的一部分。

C/C++是系统级的编程语言,可以用来开发任何和系统相关的程序和类库, 但是Java本身编写底层的应用比较难实现,使用JNI可以调用现有的本地库,极大地灵活了Java的开发。

C/C++的效率是目前最好的语言,可以使用C/C++来实现一些实时性非常高的部分。 C/C++和Java本身都是非常流行的编程语言,一些大型软件中经常使用语言之间的混合编程。

一、创建DLL文件

使用某一种C/C++开发工具创建Dll文件,实现某一功能,供JAVA调用,例如本文在此使用Visual studio 2005创建一个名为testdll的动态库文件。

二、使用JNI

JNI是Java Native Interface的缩写,中文为JAVA本地调用。它允许Java代码和其他语言写的代码进行交互。

1.JAVA类

在JAVA程序中,首先需要在类中声明所调用的库名称,如下:

static {

System.loadLibrary(“testdll”); //加载动态库,testdll为DLL文件名称

}

还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:

public native static void set(int i);

public native static int get();

然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。

例如程序testdll.java,内容为:

public class testdll { static { System.loadLibrary(“testdll”); } public native static int get(); public native static void set(int i); public static void main(String[] args) { testdll test = new testdll(); test.set(10); System.out.println(test.get()); } }

用javac testdll.java编译它,会生成testdll.class。

再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。

2.C/C++

创建C/C++项目需要增加的头文件有jni.h、jni_md.h这两个文件是JNI中必须的;还有就是增加testdll.h。

对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。

接上例子。我们先看一下testdll.h文件的内容:

#include #ifndef _Included_testdll #define _Included_testdll #ifdef __cplusplus extern "C" { #endif JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv * jclass); JNIEXPORT void JNICALL Java_testdll_set (JNIEnv * jclass jint); #ifdef __cplusplus } #endif #endif

在具体实现的时候,我们只关心两个函数原型 JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv * jclass);和 JNIEXPORT void JNICALL Java_testdll_set (JNIEnv * jclass jint);这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。

下面我们用testdll.cpp文件具体实现这两个函数:#include "testdll.h" int i = 0; JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv * jclass) { return i; } JNIEXPORT void JNICALL Java_testdll_set (JNIEnv * jclass jint j) { i = j+5; }

编译连接成库文件,这里就是testdll.dll。把testdll.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。

三、总结

使用JNI可以在JAVA中调用其它语言编写的代码,在一定程度上消除JAVA的局限性和低效率。

参考文献:

[1]高晶,王建华.JNI技术在嵌入式软件开发中的应用[J].哈尔滨师范大学自然科学学报,2007,(06) .

c语言函数范文第7篇

关键词:函数;C语言;程序

中图分类号:TP312.1 文献标识码:A文章编号:1007-9599 (2011) 12-0000-02

Study on the C Language Function Parameters Application

Lin Lifen

(Fujian Polytechnic of Information Technology,Fuzhou350003,China)

Abstract:The function is the core of C language program design,function of the parameters of the status is more important,this article from the C language using the parameters of grammar,pointer parameters,the array parameter and return value of function of several methods discussed in the C language function parameter of the use of technology,for the C language teaching and C language program design reference.

Keywords:Function;C Language;Program

C语言是一门应用范围很广的学科。它与PASCAL语言本质的区别在于它来源于应用,由此决定了它的实用性很强,语言非常灵活,在教学实践中采取不断地将C语言课程所涉及的内容前后进行比较,更好地领会和吸收所学的知识。下面就以C语言中的难点之一:函数返回值和函数参数返回值为例,谈谈二者之间的区别和函数间参数传递几种常用的方法。

C语言的核心是函数,是以函数为基本模块而构架成的。函数的大量使用,必然要涉及到函数间参数的传递。众所周知,函数间参数的传递是值的传递,其函数参数在被另一函数调用后参加运算时,若其值发生改变,在返回调用函数时,是不会将改变后的值带回调用函数的。

例如,我们设计一个函数,求两个整数之和,函数及调用函数如下:

sum(int a,int b,int s){s=a+b;}

main()

{int x=5,y=7,z=0;

sum(x,y,z);printf("%d+%d=%d\n",x,y,z); }

则程序运行结果并不是5+7=12,而是5+7=0。这是因为函数main中的实际参数x、y、z在传递过程中仅将数值5、7、0单向传递给函数sum中的形式参数a、b、c,并未接受函数sum在运行过程中改变后的值,而造成z值不正确。其解决办法有

(1)将变量z设为外部变量,程序如下

int z=0;

sum(int a,int b) {z=a+b;}

main()

{int x=5,y=7;sum(x,y);printf("%d+%d=%d\n",x,y,z);}

程序运行结果:5+7=12

这种方法能正确解决将函数sum的运算结果返回到调用函数main中,但其缺点是因为选择了外部变量,将使得函数的独立性受到外部变量的限制与约束,与模块化程序设计思想相悖。

(2)将变量z设为函数的返回值,程序如下

int sum(int a,int b){int s;s=a+b;return(s);} }

main()

{int x=5,y=7,z=0;z=sum(x,y);printf("%d+%d=%d\n",x,y,z);} }

程序运行结果:5+7=12

这种方法也能很好的解决将函数sum的运算结果返回到调用函数main中的问题,并且没有破坏函数的独立性。但函数的返回值只能是一个,若函数中有一个以上的参数被修改且需要返回时,用这种函数返回值的方法就无法实现。如下例是将两个整数值进行交换

main()

{int m,n;

scanf("%d%d",&m,&n);if(m

printf("两数中大者是%d,小者是%d\n",m,n);} }

函数swap要求将实际参数m与n所对应的形式参数的值进行交换后返回调用函数,这时用函数返回值的方法就无法实现两个值的返回,所以函数返回值的使用具有一定的局限性。

(3)为解决多个值返回的问题,可采用将变量z设为指针类型的变量,程序如下

sum(int a,int b,int*s) {*s=a+b;}

main()

{int x=5,y=7,k=0;int*z=&k;

sum(x,y,z);printf("%d+%d=%d\n",x,y,*z);}

程序运行结果:5+7=12

函数的参数传递仍为值传递,但在函数sum中,a+b的和并没有送给形式参数s,而是送给了指针s所对应的整型变量k。在返回调用函数时,形式参数s被释放了,但整型变量k的值却保留住了a与b的和。

这种使用指针变量作为函数形式参数的方法保证了函数中模块的独立性。设若干个指针变量就能使得函数中多个参数值被修正后仍然能准确的带回调用函数,所以不失为一种较好的参数传递的方法。但是,当函数只需要一个返回值时,用函数返回值进行传递更直观,也易于与初等数学的概念接轨,所以第二种方法也常常被应用。

函数参数的传递除以上三种外,还可以用数组名以及指向数组元素的指针变量作为参数进行传递。

上面所提到的函数返回值或函数参数返回值只能返回一个或少数几个值,若函数中有一批数据需要返回,则需要设一批指针,这样使用很不方便,这时我们可选择用数组名或指向数组元素的指针变量作为函数的参数进行传递,举例如下:设函数conver是将10个数逆转,并将逆转后所改变的值返回调用函数。我们可采用下面(4)和(5)两种方法

(4)函数的参数用数组名表示,程序如下:

conver(int a[],int n)

{int i=0,j=n-1;

while(i

main()

{int s[10],i;

for(i=0;i

conver(s,10);for(i=0;i

程序运行结果:9,8,7,6,5,4,3,2,1,0,

这是因为C语言规定,当数组名作为函数的参数时,并不是把实际参数中数组元素s[0]...s[9]的值传递给形式参数中数组元素a[0]...a[9],而是将实际参数的起始地址传递给形式参数,也即数组a并没有在内存中开辟存储单元,而是与实参数组s共享同一段存储单元,数组a在函数conver中的变化实际上也是对数组s的改变,当函数conver结束返回调用函数时,形参数组a被释放,但实参数组s却保留了函数改变后的值,也即将函数运算结果返回了调用函数。

(5)函数的参数用指向数组元素的指针变量表示,程序如下:

conver(int*a,int n)

{int*b;

b=a+n;while(a

调用函数同上,程序运行结果:9,8,7,6,5,4,3,2,1,0,

我们知道,指针变量存放的是另一个存储单元的地址,当用数组名作为参数时,实际上是将数组s的首地址进行传递,形参是指针变量a,接收的是数组s的首地址,则*a与s[0]是同一个存储单元;当执行a++后,*a与s[1]是同一个存储单元。所以在函数conver中,指针所指对象*a与*b的交换实际上就是数组元素s[0]与s[9],s[1]与s[8]...的交换,当函数结束返回调用函数时,形参a,b被释放,但实参中的值已经被改变。

以上5种方法都能将函数中的参数运算结果返回调用函数,方法(1)会破坏模块的独立性,一般使用较少;方法(2)适用于函数仅有一个返回值;方法(3)适用于函数的参数返回值多于一个时的情况;方法(4)或(5)适用于函数参数的批量传递。需要说明的是,方法(3)与(5)中指针传递的含义相同,(3)中的指针变量z指向一个独立的变量k,而(5)中的指针变量a是指向一个数组s的起始单元的。

c语言函数范文第8篇

关键词:值传递;地址传递;局部变量;图示法

中图分类号:TP311 文献标识码:B 文章编号:1004373X(2008)1608903

Discussion of Parameter Delivery Law Based on C Language Function

YANG Zhanhai,XUE Suqin,ZHANG Xiaoguang

(Computer Center,Yan′an Unversity,Yan′an,716000,China)

Abstract:The function is basical unit of C language,the function parameter delivery adopts transfer way of oneway value.While guiding principle is the function parameter,being in progress is address delivery,as before,address delivery is oneway value transfer way,is really not twoway delivery way.Using relevant part variable knowledge,the various parameter using diagrammatic representation is discussed.By discussion,parameter′s dilivery law of the function is proposed.Graphic analysis method in culture is a kind of brandnew analysis implement,has certain extension value.

Keywords:value delivery;address delivery;part variable;diagrammatic representation metrod

学习和使用C语言,都会遇到函数的参数传递问题,在编写的一些程序里,主调函数调用了被调用函数后,主调函数中的有些变量发生了变化,尤其是在使用指针的情况下更是如此,基于此点,有人误以为,指针作为函数参数时的地址传递是双向的传递方式。

本文以局部变量的概念为基石,采用一种内存图示分析方法。使用该方法,探讨了函数的各种参数传递形式,对参数的传递规律进行深刻的总结。

1 自动局部变量

自动局部变量是函数内部或复合语句内部定义的auto类别的变量,该变量在内存的动态区中开辟,作用范围仅限于函数内部或复合语句内部,只有函数或复合语句能够识别自己的自动局部变量,即自动局部变量对于其他函数而言是不可知的、不可见的。

另外,自动局部变量的生存期也是非常短暂的,当其所在函数被调用时,分配内存单元,调用结束后,释放变量。在下次调用函数时,重新分配内存单元。

形式参数属于局部变量,作用范围仅在所定义的函数中,形参的变化不能被别的函数可见,包括主调函数也不可见。若形式参数为自动局部变量,调用结束后根本就不存在了,更不会被主调函数可见。

按照上面的分析,形参绝不可能把自己调用到主调函数里的,所以,函数的参数的传递应该是单向的。

既然局部变量互不干扰,为简单起见,可以把主调函数和被调用函数的变量画在不同的区域以示区别。为此,特约定,画内存图时以水平线为分界,水平线以下为主调函数的局部变量,水平线以上为被调用函数的局部变量。

下面,便应用以上理论和画图的方法分析几个典型的程序,用以研究函数的参数传递规律。

2 不涉及指针的参数传递

有如下程序,用于交换2个变量的值。交换的思想是把实参变量传递给形参变量后,交换形参变量的值,希望带动2个实参变量的值的改变。

void fun(int a,int b)

{ int t; t = a; a = b; b = t;}

void main(viod)

{ int a = 6,b = 9; fun(a,b); printf ("%d,%d\\n",a,b);}

但程序的执行结果并未实现实参变量值的交换,这说明形参的变化不能影响实参的值,传递是单向值传递的。

下面,便用图示法进行分析探讨。

主程序执行后,变量及其值如图1(a)所示。调用函数fun后,分配的变量及其值如图1(b)所示,此时形参从实参处获得了对应的值。

函数fun中的变量交换,是局部变量的交换,交换结果如图2(a)所示。函数fun调用结束后,释放其所申请的局部变量,结果如图2(b)所示。

显而易见,形参的变化是被调用函数内部的变化,根本不涉及实参的变化,值的单向传递得到肯定。

3 涉及指针的参数传递

3.1 指针形参的改变

下面的程序采用指针参数,函数fun进行2个指针参数变量的值的交换。

void fun(int *p,int *q)

{ int *t; t=p; p=q; q=t;}

void main(void)

{ int a=6,b=9,*p=&a,*q=&b;

fun(p,q); printf ("%d,%d\\n",a,b);}

主程序执行后,变量及其值如图3(a)所示,实参指针p的值为&a,表示指向变量a,实参指针q的值为&b,表示指向变量b。调用函数fun后,分配的变量及其值如图3(b)所示,此时形参从实参处获得了对应的值,其中形参指针p的值为&a,表示指向主调函数中的变量a,实参指针q的值为&b,表示指向主调函数中的变量b。

函数fun中的p和q交换,是局部变量的交换,交换结果如图4(a)所示,p指向了b,q指向了a。函数fun调用结束后,释放其所申请的局部变量,结果如图4(b)所示。

主函数中p和q是实参,而调用函数fun后,p和q没有发生改变,这说明形参的变化没有改变实参的指向,即没有改变实参的值,指针作参数时,值的单向传递得到了肯定。另外,形参指针p和q曾分别指向主函数中a和b,而主函数中a和b也没有发生改变,这说明,仅改变形参指针的值,不会影响主调函数中其他变量的值,不能改变其指向变量的值。

3.2 指针形参指向变量的改变

下面的程序采用指针参数,函数fun进行2个指针参数指向变量的值的交换。

void fun(int *p,int *q)

{ int t; t=*p; *p=*q; *q=t;}

void main(void)

{ int a=6,b=9,*p=&a,*q=&b;

fun(p,q); printf ("%d,%d\\n",a,b);}

主程序执行后,变量及其值如图5(a)所示,实参指针p指向变量a,实参指针q指向变量b。调用函数fun后,分配的变量及其值如图5(b)所示,此时形参从实参处获得对应的值,其中形参指针p指向主调函数中的变量a,实参指针q指向主调函数中的变量b。

函数fun中的*p和*q交换,就是主调函数中的变量a和b的交换,交换结果如图6(a)所示,主调函数中的变量a和b完成了交换。函数fun调用结束后,释放其所申请的局部变量,结果如图6(b)所示。

通过指针形参可以改变其指向变量的值,变量可以是主调函数中变量,但这些变量并不是实参指针变量,实参的值没有发生改变。所以通过指针形参可以改变其指向变量的值并不违背参数的单向传递规律。

3.3 数组名作为函数的参数

数组名是地址常量,代表函数的起始地址,即数组名是指针类型常量,指向了数组的起始位置。按照参数的类型一致原则,形参就应该为指针类型变量,该变量得到实参的传递后,指针指向数组的起始位置。

故数组名作为函数的参数本质是指针作参数的情形,实际上就是图5(a),(b)描述的情形。形参指针的变化不会改变数组的初始位置,不会改变数组名地址常量,指针参数之间的传递遵循单向的值传递规律。形参指针指向的变量就是数组的内存单元,通过形参指针指向的变量的改变可以达到改变数组元素值的目标。

4 结 语

C语言函数参数的传递规律是单向的传递规律,不论参数是否是指针,主调函数的实参是不会改变的。能够改变的只能是指针指向的变量的改变,在数组中把这种指针指向的变量的特性称为共享内存单元。指针指向的变量并不是作为实数的变量,而是其他的变量,实参也指向该变量,指向变量的改变并等价于实参的改变,地址传递并不违背“值传递”规律。

以局部变量的概念为基石,采用内存图示分析方法,是分析和研究参数传递问题的一种新思路、新方法。

参 考 文 献

[1]古丽孜拉・安尼瓦尔.C语言函数参数传递的几个问题[J].伊犁师范学院学报,2004(3):7374.

[2]吴丽贤.C语言中多维数组指针和递归的教学实践[J].电脑知识与技术:学术交流,2007(2):462,464.

[3]张艳华.C语言函数形参与实参之间的数据传递[J].内江科技,2007(9):80.

[4][美] Herbert Schildt.最新C语言精华\.3版.王子恢,译.北京:电子工业出版社,1997.

[5]谭浩强.C程序设计\.3版.北京:清华大学出版社,2005.

[6]杨战海,郭协潮.基于C语言函数调用获得结果的分析研究\.现代电子技术,2007,30(4):102103.

c语言函数范文第9篇

关键词:函数调用 实际参数 形式参数 参数传递

中图分类号:TP312.1 文献标识码:A 文章编号:1007-9416(2012)02-0144-02

函数是C语言中的基本组成单位,一个较大的C程序一般可分为若干个程序模块,实现某一特定功能的模块主要由函数来完成。所以,学习C语言程序设计要善于利用函数,一来可以减少重复编写程序段的工作量,二来可以方便的实现模块化程序设计。但是笔者在实际的教学过程中发现,学生在学习函数这部分知识时显的比较吃力。因为在具体使用函数时,要涉及到函数参数传递问题,而参数类型多种多样,使学生对函数问题产生了很多疑惑,根据教学实际,笔者对函数调用与参数传递问题进行了总结,以便大家对函数问题的理解。

1、主调函数与被调函数

计算机在执行C程序时总是从main函数开始,如果遇到要调用某个函数,则主函数称为主调函数,被调用者称为被调函数。一个C程序可由一个main函数和若干个其他函数构成,main函数用来解决整个问题,它调用解决小问题的其他函数,其他函数也可以相互调用。调用者就是主调函数,被调者就是被调函数,应当注意,main函数只能由系统调用。

2、实际参数与形式参数

在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中进行函数调用时,函数名后面括弧中的参数称为实际参数,简称实参。在定义函数时函数名后面括弧中的变量名就是形式参数,简称形参。即实参出现在函数调用中,形参出现在函数定义中。主调函数通过函数调用将实参中的数据传递给被调函数的形参,从而实现函数间的数据传递。另外实参与形参进行数据传递时,系统要求实参与形参在数量、类型、顺序应严格保持一致,这一点在使用上要特别注意。

3、变量存储类型与作用域

主调函数和被调函数数据传递往往要通过变量进行,不同的变量类型影响数据的处理结果。C语言中变量按存储时分配的空间不同可以分为自动变量,寄存器变量,静态变量和外部变量。按变量的生命周期可以分为局部变量和全局变量,局部变量是在一个函数内部定义的变量,在存储器的动态存储区进行分配空间,作用域只在本函数内部有效,比如在主函数里定义的自动变量,寄存器变量,函数中的形式参数等都属于局部变量,在函数调用时,系统才为其分配存储空间,函数调用结束后,空间释放。而对于静态型局部变量是程序编译时由系统在存储器的静态存储区为其分配存储空间,函数调用结束后,空间不释放,其值要保留到程序退出。全局变量是在程序整个运行期间都要占用内存,所以它是全程有效,贯穿于主调函数与被调函数全过程,其值也要保留到程序退出为止。

4、参数传递的本质与属性

函数参数传递的过程,本质上是一种赋值过程即值传递过程,在调用函数之前,函数的每个实际参数将被复制,复制的值代替对应的形式参数。所以形参实际上得到的不是实参本身,而是实参的值或者实参所代表的值。因此,如果一个变量传递给一个函数,这个变量在调用环境中所存储的值并不会被函数修改,所以形参的值不会反过来影响实参,即实参与形参值传递是单向性的。这两个问题是学习和理解函数参数传递的根本,很多学习C语言的人对这两个问题不是很理解,下面举例说明函数调用时参数传递过程。

4.1 数值传递

当变量为普通变量时,函数实参可以是自动局部变量,静态局部变量,数组元素,寄存器变量,结构体变量,结构体变量成员,常量等形式,函数形参为对应类型的变量,调用函数时,由系统给形参分配存储单元,存放从实参复制过来的数值。函数调用结束后,形参存储单元释放。

例题1:

#include

void func1(int x)

{++x;

printf (“%d”,x);

int main()

{int n=10;

func1(n);

printf (“%d”,n);

return 0 ;

例题1中main函数调用func1函数时,把实参n的值10(注意不是n)传给了形参x,x在func1函数中进行增1运算, 这时x的值发生了改变,但该值不能返回到实参n中,因为x是func1函数内部定义的变量,属于局部变量,调用函数时,系统为x变量在存储器的动态存储区分配存储空间,函数调用结束后,x变量被释放,数值被清,故n值不变,体现了传值的单向性。

4.2 地址值传递

地址值传递是指实参与形参之间传递的数据是地址,与数值传递不同的是,地址值传递的是形参接收实参地址的复制值,而不是实参值本身。另外,地址值传递方式中系统不为形式参数变量分配存储空间,这一点也与数值传递方式不同。因为函数调用完成数据传递后,实参与形参拥有相同的变量地址,它们指向同一变量单元,该变量在主调函数定义时已经分配了存储空间,形参只是接收了它的一个地址值,并没有接收变量本身。根据参数类型的不同,地址值传递方式常见的有如下几种情况。

4.2.1 实参为变量地址,形参为指针

例题2:

#include

void func2( int *x,int *y)

{

x=y;

}

int main()

{ int a=2,b=3;

func2(&a,&b);

printf ("%d,%d",a,b);

return 0;

}

例题2中在主调函数中将a,b的地址值传给了形参指针x和y,在被调函数中将y值赋给了x,这时x的值发生了改变,x存放的是y的存储地址,即x指向3,但是这个指向并不能返回到主调函数。因为这个地址值在函数调用结束后被释放,其值消失。当然,如果想在被调函数中修改主调函数中实参变量的值,需要修改指针变量x和y所指向的地址中的内容。比如将x=y改为*x=*y,即可达到修改实参变量的目的,但是必须清楚,虽然被调函数通过指针可以修改主调函数中的值,但这只是一种间接访问数据的形式而已,实参向形参传递数据的单向性是不变的。

4.2.2 实参为数组名,形参为指针

在C语言中,数组名是一个地址,而且是一个地址常量,它代表的是该数组元素的首地址,不是一个变量。当使用数组名作为实参时,实参的值就是数组的首地址,形参指针接收的也是该数组的首地址,被调函数通过形参指针的变化来访问主调函数中数据。

例题3:

#include

void func3( int *x,int y)

{ int i;

for(i=0;i

printf("%4d",*x++);

}

int main()

{ int a[5]={1,2,3,4,5},b=5;

func3(a,b);

return 0;

}

例题3中形参有两个,第一个表示形参接收一个整型类型的地址,第二个表示接收一个整型类型的数据,至于实参是不是一个指针,是不是一个整型变量,形式参数并不理会,只管数据的类型是否匹配。而从主调函数中可以看出,实参为数组名(地址)和整型数据(整型类型),符合参数传递规则。这样发生函数调用时,形参指针指向了数组a的第一个元素,通过循环程序,输出了数组a的所有元素。

这里还有一个问题,形参指针x在被调函数中的值发生了变化,这个值是不会返回给实参的,很明显,实参中的第一个参数a是数组名,代表一个地址常量,肯定不能对它进行赋值操作,这里进一步验证了实参与形参值传递是单向性的。

4.2.3 实参为数组名,形参为数组名

当实参与形参均为数组名时,这种方式跟其他的地址值传递方式是一样的,系统也是不给形参数组分配内存空间,而是将形参数组名处理成一个指针,因此形参数组并不存在。当发生函数调用时,实参数组只是把首地址赋给形参数组名。这样形参数组名也指向实参数组,两个数组共同占有一段内存空间。因此通过改变形参数组元素的值来达到改变实参数组元素的目的。

例题4:

#include

void func4(int b[5])

{

b[0]=5;

b[1]=4;

b[2]=3;

b[3]=2;

b[4]=1;

}

int main( )

{int i;

int a[5]={1,2,3,4,5};

func4(a);

for(i=0;i

printf("%4d",a[i]);

return 0;

}

例题中实参与形参均为数组名,调用函数时,实参数组的首地址复制后给了形参数组,使形参数组名指向了实参数组,当改变形参数组元素值时,实参元素值必然改变,因为实参数组和形参数组是同一块存储单元。

4.2.4 实参为指针,形参为数组名

4.2.5 实参为指针,形参为指针

对于(1),(5)这两种情况比较好理解,实参为指针,其值为地址,所以形参接收的也是地址,实参与形参类型匹配,可以进行数据传递,在此不一一介绍。

参考文献

[1]梁宏涛,姚立新.C语言程序设计与应用[M].北京:北京邮电大学出版社,2011.

[2]王慧,马茵.C语言中函数参数传递问题探讨[J].技术与市场,2011,8.

[3]谭浩强.C程序设计与应用[M].北京:清华大学出版社,2010.

作者简介

c语言函数范文第10篇

关键词:函数;形参;实参;数据传递

中图分类号:TP312文献标识码:A 文章编号:1009-3044(2007)17-31457-01

Analysis of Data Transferring from Actual Argument to Formal Argument in C Language Function Calling

LU Xiang-ning, LI Xiao-mei

(Hainan Software Professional Institute, Qionghai 571400,China)

Abstract: C's design philosophy is to use functions as building blocks. When a function is called, value of the actual argument is assigned to the variable known as the formal argument. This paper presents that the essence of data transferring from actual argument to formal parameter is value delivery and one-way.

Key words: functions; formal parameters; actual arguments; data transferring

1 引言

在C语言教学过程中,我发现有很多初学者对函数调用过程中实参和形参之间的数据传递问题理解不够透彻,尤其是指针做函数参数时,常常有许多误解。有这样一个程序:

#include

main()

{

void swap(int *p1,int *p2);

int a,b;

int *point1,*point2;

clrscr();

scanf("%d,%d",&a,&b);

point1=&a;point2=&b;

if(a

printf("a=%d,b=%d\n ",a,b);

printf("max=%d,min=%d\n ",*point1,*point2);

}

void swap(int *p1,int *p2)

{

int *temp;

temp=p1;

p1=p2;

p2=temp;

}

编程者的目的很明显,即编写用户自定义函数void swap(int *p1,int *p2),并以整型指针作为参数,在main()函数中调用这一函数来实现两个整型数据a和b的值的互换。但这个函数能否实现两个数值的交换呢?下面我们对其进行分析。

2 函数调用过程分析

在前面这一程序的main()函数中,整型指针变量point1、point2分别指向整型变量a、b,即point1 和point2的值分别为变量a和b的地址。在调用函数swap()时实参(point1,point2)将各自的“值”传递给形参(p1,p2) 。如图1所示(图中虚线箭头表示数据的传递方向,实线箭头表示指向),由于point1 和point2的值分别为变量a和b的地址,所以p1和p2也分别得到变量a和b的地址,即p1和p2也分别指向变量a和b。

图1 实参向形参进行“值”的传递

实参向形参进行“值”的传递之后,执行swap()函数的函数体部分,当执行语句“temp=p1;” 后,将p1的值(主函数中整形变量a的地址)赋给指针变量temp,这时temp也指向了变量a,如图2所示。

图2 执行赋值语句temp=p1;后

执行赋值语句“p1=p2;”,将p2的值(主函数中整形变量b的地址)赋给p1,这时p1不再指向变量a,而指向了变量b,如图3所示,temp和p2的指向不变。

图3 执行赋值语句p1=p2,后

最后执行赋值语句“p2=temp;”,将temp的值(主函数中整形变量a的地址)赋给p2,这时p2的值发生改变,不再指向变量b,而指向变量a。如图4所示。

由上述讨论可以看出,编程者调用swap()函数,仅仅改变了形参变量p1和p2的值,即改变了p1和p2的指向,而这一过程中实参变量point1 和point2并没有指向。swap()函数调用结束后,形参所占内存单元被释放,形参变量p1和p2以及局部指针变量temp消亡。因此,该程序调用swap()函数的执行结果就是改变了通过中间指针变量temp交换了两个形参变量p1和p2的指向,对main()函数没有起到任何作用。

3 函数的改正及问题分析

前例中,调用swap()函数虽然不能改变实参指针变量point1 和point2的值(即它们的指向),但是我们可以改变point1 和point2所指向的内存单元当中的值,即改变整型变量a、b的值。对swap()函数做如下修改:

void swap1(int *p1,int *p2)

{ int temp;

temp=*p1;

*p1=*p2;

*p2=tem}

分析修改后的函数swap1()可知,在函数swap1()调用执行过程中,不仅没能改变实参指针变量point1 和point2的指向,形参指针变量p1和p2的指向也一直没有改变,只是交换了是p1和p2指向的内存单元中的值,即使a、b值互换。

这样以来,就实现了函数调用的功能,达到了编程者的目的。

然而,也有很多人将swap()函数修改为如下形式:

void swap2(int *p1,int *p2)

{ int * temp;

*temp=*p1;

*p1=*p2;

*p2=*tem}

函数swap2()中,编程者以整型指针变量temp为中间变量,交换p1和p2所指向的内存单元中的值,是否能达到这个目的呢?

启动TUBOR C编译环境中,如前例在主函数中对swap2()函数进行调用,编译时 “*temp=*p1;” 语句出现警告,忽略这个警告,运行程序,并输入5,9按回车键,运行结果如图5。

显然,编程者的目的没有达到,执行swap2()函数的过程中,指针变量temp和p1指向了同一个内存单元,并将p2所指向的内存单元中的值赋给p1所指向的内存单元,即将main()函数中变量b的值赋给变量a,因而出现了图示结果。

函数swap2()中问题出现在语句“*temp=*p1;”,对指针变量temp的这种使用方式存在很大的冒险性。由于指针变量temp并没有确定的地址值,所以temp的指向是不可预测的,对*temp赋值可能会造成重要数据的丢失,应避免指针变量的这种使用方式。

4 结论

通过这个例子,本文浅析了函数调用过程中实参与形参之间数据传递的实质,即“值传递”,就好像是实参把自身的数值拷贝了一份给形参,这种“值传递”是单向的,即由实参传递给形参,形参无法改变实参的值。笔者认为这种提法不仅有失准确性,还给初学者造成了概念上的混淆,误认为传递的是实参变量的地址。初学者在学习C语言过程中,往往“谈指针色变”,理解指针做函数参数的情况更是难于上青天,本文结合实例,阐述了函数调用过程中实参对形参的“单向值传递”性,希望对广大初学者有所帮助。

参考文献:

[1]谭浩强.C程序设计[M] .北京:清华大学出版社,2000.186-189.

[2]陈家骏.程序设计教程用C++语言编程[M]. 北京:机械工业出版社,2004.155-160.

[3]Herbert Schildt,著.戴健鹏,译.C语言大全(第2版)[M]. 北京:电子工业出版社,1994.120-125.

注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。

上一篇:监控软件范文 下一篇:语言艺术范文

友情链接