首页 百科知识 指针作为函数的参数

指针作为函数的参数

时间:2022-09-22 百科知识 版权反馈
【摘要】:程序中,array为实参数组名,arr为形参数组名。实际上,C语言程序在编译时,都是将形参数组名作为指针变量来处理的。在调用该函数时,系统会建立一个指针变量arr,用来存放从主调函数传递过来的实参数组首元素的地址。表7-1列出了用变量名作函数参数和用数组名作函数参数的对比情况。例7.21的程序可以改写为例7.23中的程序。因此,当使用指针变量作函数的实参时,必须先使该指针变量有一个确定值,明确指向一个已定义的内存单元。

7.4.2 指针作为函数的参数

1.用数组名作函数参数

在前面章节中介绍过可以用数组名作函数的参数。

例如:

img527

img528

程序中,array为实参数组名,arr为形参数组名。当用数组名作参数时,如果形参数组中各元素的值发生变化,则实参数组元素的值随之变化。

前已介绍,实参数组名代表该数组的首地址。形参是用来接收从实参传递过来的数组首地址的,因此,形参可以是一个指针变量(指针变量能存放地址)。实际上,C语言程序在编译时,都是将形参数组名作为指针变量来处理的。

例如:

img529

编译时,将arr按指针变量处理,相当于:

img530

以上两种写法是等价的。在调用该函数时,系统会建立一个指针变量arr,用来存放从主调函数传递过来的实参数组首元素的地址。在arr接收了实参数组的首元素地址后,arr就指向实参数组。因此,*arr就是array[0]的值,*(arr+1)、*(arr+2)、*(arr+3)分别是array[1],array[2],array[3]的值。表7-1列出了用变量名作函数参数和用数组名作函数参数的对比情况。

表7-1 用变量名作函数参数和用数组名作函数参数对比

img531

C语言调用函数时,如果用变量名作为函数参数,则传递的是变量的值;如果用数组名作为函数参数,则传递的是数组的地址值,因此,形参应为指针变量或数组名。

实参数组名代表一个固定的地址值,是指针型常量,而形参数组并不是一个固定的地址值。在函数调用开始时,实参数组起始地址赋值给形参数组,但在函数执行期间,实参数组可以被再次赋值。

例如:

img532

例7.21 将数组a中n个整数按相反顺序存放,如图7-8所示。

算法分析:先将a[0]与a[n-1]对换,再将a[l]与a[n-2]对换……直到将a[int(n-1)/2]与a[n-int((n-1)/2)-1]对换。

具体做法:设两个“位置指示变量”i和j,i的初值为0,j的初值为n-1。将a[i]与a[j]交换,然后使i的值加1,j的值减1,再将a[i]与a[j]对换,直到i=(n-1)/2为止。

img533

图7-8

程序如下:

img534

运行结果如下:

img535

上述程序还可以写成下面的形式(用指针变量作函数的形参)。

程序如下:

img536

运行结果如下:

img537

例7.22 从10个数中找出其中最大值和最小值。

分析:本题不要求改变数组元素的值,只要求得到最大值和最小值。但是调用一个函数只能得到一个返回值,为了能得到两个结果值,今用全局变量在函数之间“传递”数据。程序如下:

img538

img539

运行结果如下:

img540

上述程序还可以写成下面的形式(用指针变量作函数的形参)。

程序如下:

img541

img542

运行结果如下:

img543

归纳起来:有一个实参数组,如果想要在被调函数中改变此数组元素的值,函数调用时实参与形参的对应关系有以下4种情况:

(1)形参和实参都用数组名。

例如:

img544

由于形参数组名接收了实参数组的地址,在函数调用期间,与实参数组共用一段内存单元,改变形参数组元素的值就是改变实参数组元素的值。例7.21的第一个程序就属于这种情况。

(2)实参用数组名,形参用指针变量。

例如:

img545

img546

实参a为数组名,形参x为指向整型变量的指针变量,函数开始执行时,x指向a[0],即x=&a[0],通过x值的改变,可以指向a数组的任何一个元素,改变x 所指向的数据值等同于改变a数组的元素值。例7.21的第二个程序就属于这种情况。

(3)实参形参都用指针变量。

例如:

img547

实参p和形参x都是指针变量。先使实参指针变量p指向数组a,则p的值是&a[0]。函数调用时,将p的值传给形参指针变量x,此时x的初始值也是&a[0],即p和x共同指向同一段内存单元。通过x值的改变可以使x指向数组a的任何一个元素,改变x 所指向的数据值等同于改变a数组的元素值。例7.22的第二个程序就属于这种情况。

(4)实参为指针变量,形参为数组名。

例如:

img548

实参p为指针变量,先使指针变量p指向a[0],即p=a或p=&a[0]。形参为数组名x,从前面的介绍可以知道,程序在编译时,将数组名x作为指针变量处理,函数调用时,将a[0]的地址传给形参x,使指针变量x指向a[0]。可以理解为形参数组x和a数组共用同一段内存单元。在函数执行过程中改变x[i]的值,就是改变a[i] 的值。例7.21的程序可以改写为例7.23中的程序。

例7.23 用实参指针变量改写例7.21。

程序如下:

img549

运行结果如下:

img550

注意:

上面的main函数中的指针变量p是有确定值的。如果在main函数中不设数组,只设指针变量,就会出错。

假如将程序中的main函数修改如下:

img551

img552

main函数在编译运行时将会出错,原因是指针变量arr没有确定值,没有指向一个确定的内存单元,无法进行正确的数据存取。因此,当使用指针变量作函数的实参时,必须先使该指针变量有一个确定值,明确指向一个已定义的内存单元。

以上四种方法,实质上都是地址的传递。其中(3)、(4)两种只是形式上不同,实际上都是使用指针变量。

2.用字符串指针作函数参数

将一个字符串从一个函数传递到另一个函数,可以用地址传递的方法,即用字符数组名作参数或用指向字符的指针变量作参数。如果在被调函数中改变字符串的内容,在主调函数中可以得到改变了的字符串。

(1)用字符数组作参数。

例7.24 用函数调用实现字符串的复制。

程序如下:

img553

程序运行结果如下:

img554

img555

上面程序中,a和b都是字符数组。初值如图7-9(a)所示。copy_string函数的作用是将from[i]赋给to[i],直到from[i]的值等于'\0'为止。在调用copy_string函数时,将a和b第1个字符的地址分别传递给形参数组from和to。因此from[i]和a[i]是同一个单元,to[i]和b [i]是同一个单元。程序执行完以后,b数组的内容如图7-9(b)所示。可以看出,由于b数组原来的长度大于a数组,因此在将a数组复制到b数组后,未能全部覆盖b数组原有内容。b数组最后3个元素仍保留原状。在输出b时由于按%s(字符串)输出,遇'\0'表示输出结束,因此,第一个'\0'后的字符不输出。如果不采取%s格式输出而用%c逐个输出字符是可以输出后面这些字符的。

img556

图7-9

在main函数中也可以不定义字符数组,而用字符型指针变量。main函数可改写如下:

img557

程序的运行结果不变。

(2)形参用字符指针变量。

例7.24的程序中,可以使用指针变量作为被调函数的形参。

程序如下:

img558

img559

上面的程序中,形参from和to是字符指针变量。在调用copy_string时,将数组a首元素的地址传给from,把数组b首元素的地址传给to 。在函数copy_string中的for循环中,每次将*from赋给*to,第1次就是将a数组中第1个字符赋给b数组的第1个字符。在执行from++和to++以后,from和to。就分别指向a[1]和b[1]。再执行*to=*from,就将a[l]赋给b[1],依次类推,最后将'\0'赋给*to。

注意:

上面被调函数的形式可以写成多种形式。

①将copy_string函数改写为:

img560

上述代码将"*to=*from"的操作放在while语句的表达式中,并且将赋值运算与判断是否为'\0'的运算放在一个表达式中,先赋值后判断。在循环体中使to和from每次增1,指向下一个元素,直到*from的值为'\0'为止。

②copy_string函数还可改写为:

img561

上面程序是将to++和from++运算与*to=*from合并,它的执行过程是,先将*from赋给*to,然后使to和from增值。这样,程序显得更加简洁。

③函数还可改写成

img562

上面的程序代码中,当*from不为'\0'时,将*from赋给*to,然后使to和from增值。

④字符可以用其ASCII码来代替。例如,ch='a'可以用ch=97代替,while(ch!='a')可以用while(ch!=97)代替。因此,while(*from!='\0')可以用while(*from!=0)代替(因为'\0'的ASCII代码为0)。另外,关系表达式*from!=0还可简化为*from,这是因为如果*form的值不等于0,则表达式*from为真,同时*from!=0也为真。因此while(*from!=0)和while(*from)是等价的。所以,copy_string函数体可简化为:

img563

⑤如果使用指针变量,函数copy_string还可改写为:

img564

以上程序代码写法多样,使用十分灵活、方便,初看起来不太习惯,含义也不直观。初学者要全面掌握可能有些困难,也容易出错。但对C程序熟练之后,就比较容易理解了。在C语言程序设计中,以上多种形式的代码使用是比较常见的,希望读者逐渐熟悉它,掌握它。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈