欢迎访问文稿网!

指针作为函数的参数

范文之家 分享 时间: 加入收藏 我要投稿 点赞

指针作为函数的参数

    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语言程序设计中,以上多种形式的代码使用是比较常见的,希望读者逐渐熟悉它,掌握它。

221381
领取福利

微信扫码领取福利

微信扫码分享