【时时三省】(C语言基础)字符指针作函数参数
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省
如果想把一个字符串从一个函数“传递”到另一个函数,可以用地址传递的办法,即用字符数组名作参数,也可以用字符指针变量作参数。在被调用的函数中可以改变字符串的内容,在主调函数中可以引用改变后的字符串。
例题1
用函数调用实现字符串的复制。
解题思路:
定义一个函数copy_string用来实现字符串复制的功能,在主函数中调用此函数,函数的形参和实参可以分别用字符数组名或字符指针变量。分别编程,以供分析比较。
编写程序:
( 1 )用字符数组名作为函数参数
运行结果:
程序分析:
a和b是字符数组。copy string函数的作用是将from [ i ]赋给to [ i ],直到from [ i ]的值等于' \0 '为将from [ i ]赋给to [ i ],直到from [ i ]的值等于' \0 '为止。在调用copy string函数时,将a和b第1个字符的地址分别传递给形参数组名from和to。因此from [ i ]和a [ i ]是同一个单元,to[ i ]和b [ i ]是同一个单元。由于b数组原来的长度大于a数组,因此在将a数组复制到b数组后,未能全部覆盖b数组原有内容。b数组最后3个元素仍保留原状。在输出b时由于按%s(字符串)输出,遇' \0’即告结束,因此第一个' \0 '后的字符不输出。如果不采取% s格式输出而用% c逐个字符输出是可以输出后面这些字符的。
( 2 )用字符型指针变量作实参copy_string函数不变,在main函数中定义字符指针变量from和to,分别指向两个字符数组a,b。
运行结果与程序(1)相同。
程序分析:
指针变量from的值是a数组首元素的地址,指针变量to的值是b数组首元素的地址。它们作为实参,把a数组首元素的地址和b数组首元素的地址传递给形参数组名from和to(它们实质上也是指针变量)。其他与程序(1)相同。
( 3 )用字符指针变量作形参和实参
运行结果同上。
程序分析
形参改用char*型变量(即字符指针变量)。在程序(1)和( 2 )中copy_string函数的形参用字符数组名,其实编译系统是把字符数组名按指针变量处理的,只是表示形式不同。copy_string函数中不是用下标法引用数组元素,而是通过移动指针变量的指向,找到并引用数组元素。
main函数中的a是字符指针变量,指向字符串“I am a teacher .”的首字符。b是字符数组,在其中存放了字符串“You are a student .”。p是字符指针变量,它的值是b数组第一个元素的地址,因此也指向字符串" You are a student .”的首字符。copy string函数的形参from和to是字符指针变量。在调用copy string时,将数组a首元素的地址传给from,把指针变量p的值(即数组b首元素的地址)传给to。因此from指向a串的第一个字符a[0],to指向b [ 0 ]。在for循环中,先检查from当前所指向的字符是否为' \0 ',如果不是,表示需要复制此字符,就执行“* to = *from”,每次将* from的值赋给* to,第1次就是将a串中第1个字符赋给b数组的第1个字符。每次循环中都执行“from ++”和“to ++”,使from和to分别指向a串和b数组的下一个元素。下次再执行“* to = * from”时,就将a串中第2个字符赋给b [ 1 ]…最后将' \0 '赋给* to,注意此时to指向哪个单元。
程序改进:
对copy_string函数还可以改写得更精练一些,可以作以下一些改动:
( 1 )将copy_string函数改写为
void copy string ( char * from , char * to )
{while ( (*to = *from ) ! =' \0 ' )
{ to + +;from + +;}
}
请与上面程序对比。在本程序中将“* to = * from”的操作放在while语句括号内的表达式中,而且把赋值运算和判断是否为' \0 '的运算放在一个表达式中,先赋值后判断。在循环体中使to和form增值,指向下一个元素……直到*from的值为' \0 '为止。
( 2 ) copy_string函数的函数体还可改为
{while ( ( * to + + = * from++ ) ! =' \0 ');}
把上面程序的to + +和from++运算与* to = *from合并,它的执行过程是,先将* from赋给* to,然后使to和from增值。显然这又简化了。
( 3 ) copy_string函数的函数体还可写成
{ while ( * from ! = \0 ' )
*to++ = *from++;
*to='\0';
}
当* from不等于0时,将* from赋给xto,然后使to和from增值。
( 4 )由于字符可以用其ASCII码来代替(例如,“ch = ' a '”可用“ch = 97”代替,“while ( ch ! = ' a ' )”可以用“while ( ch ! = 97 )”代替)。因此,“while ( * from ! = ' \0 ' )”可以用“while ( * from ! = 0 )”代替( ' \0 '的ASCII代码为0 )。而关系表达式“* from ! = 0”又可简化为“* from”,这是因为若* from的值不等于0,则表达式“* from”为真,同时“* from ! = 0”也为真。因此“while ( * from ! = 0 )”和“while ( * from )”是等价的。所以函数体可简化为
{while ( * from )
to + + = * from + +;
* to =' \0 ' ;
}
( 5 )上面的while语句还可以进一步简化为下面的while语句:
while ( * to + + = * from++ );
它与下面语句等价:
while ( ( * to + + = * from++ ) ! =' \0 ' );
将* from赋给*to,如果赋值后的*to值等于'\0 ',则循环终止( '\0 '已赋给* to )。
( 6 )函数体中也可以改为只用一个for语句:
for (;( * to + + = * from++ ) ! = 0;););
或
for (;*to + + = * from++;);
( 7 )也可以用字符数组名作函数形参,在函数中另定义两个指针变量pl,p2。函数copy_string可写为
void copy_string ( char from[] , char to [] )
{char * pl , * p2 ;
pl = from ; p2 = to ;
while ( ( * p2 + + = *p1++ ) ! =' \0 ');
}