4.5 返回指针的函数
函数不但可以具有指针类型的参数,它的返回类型也可以是指针。在下面的程序中,函数swaprp交换两个参数所指向的变量的值,并返回一个指针,该指针指向值较大的那个变量。
/***********c0404.c***********/ char * swaprp(char * a, char * b) { char temp = * a; * a = * b; * b = temp; return * a > * b ? a : b; } int main(void) { char m = 102, n = 103, * pc; pc = swaprp(& m, & n); }
如图4-7所示,因为标识符swaprp看上去既可以与星号“*”进行语法关联,也可以与括号“(”进行语法关联,但括号的优先级比星号高,所以,对函数swaprp的声明应当这样解读:它的类型是函数,第一个参数是char *类型的变量a,第二个参数是char*类型的变量b,该函数返回一个指针,指向char。当然,也可以直接说是返回一个指向char的指针。
图4-7 声明一个函数,该函数的返回类型是指针
在函数swaprp里,变量值的交换和前面相比没有什么不同,唯一的变化是多了一个奇怪的return语句:
return * a > * b ? a : b;
因为函数swaprp的返回类型不是void,所以这里是返回表达式* a>* b ? a :b的值。这是一个我们没见过的表达式,称为条件表达式。条件表达式由三个表达式E1、E2、E3,以及条件运算符?和:按下述方式组合而成:
E1 ? E2 : E3
再来看表达式* a>* b ? a : b,这里涉及三个运算符,其优先级从高到低依次为一元*运算符、关系运算符>和条件运算符?:,所以这是一个条件表达式,等价于((*a)>(* b))? a : b。
条件表达式的求值过程是这样的:先求值E1,如果E1的值不为0,则求值E2,且整个条件表达式的值来自E2;如果E1的值为0,则求值E3,且整个条件表达式的值来自E3。例如,条件表达式5 ? 6 : 7的值是6,而0 ? 8 : 9的值是9。
这样一来,return语句的功能就很清楚了:表达式* a和* b都是左值,先进行左值转换,关系运算符对左值转换后的值进行比较,若结果为1,则整个条件表达式的值是左值a经左值转换后得到的指针;若结果为0,则整个条件表达式的值是左值b经左值转换后得到的指针。最后,return语句返回条件表达式的值(指针)给它的调用者。取决于比较的结果,返回的指针指向main函数内的变量,要么是变量m,要么是变量n。
再来看main函数,我们声明了一个指针类型的变量pc,并用它来接受函数swaprp的返回值。因为pc是指向char的指针,而函数swaprp的返回值也是指向char的指针,类型一致,可以赋值。
练习4.4
1.在程序中添加一个char类型的变量c,并用函数swaprp的返回值所指向的变量的值初始化它。
2.以下,函数cusum用于计算从1加到N的和,N是非负整数。参数sum用于接受一个指针,累加的结果保存在该指针所指向的变量里;参数r也用于接受一个指针,该指针所指向的变量里保存了所要累加的最大值。如果这个值是0或者大于1000000000,则函数返回0,否则返回1。现在请按上述要求将函数体补充完整,并上机验证程序的编写是否正确。
_Bool cusum(unsigned long long int * sum, unsigned long long int * r) { }
3.以下类型中,属于变量类型的是_______;属于函数类型的是_______。
(a)char
(b)main函数
(c)_Bool
(d)signed int
(e)指针
4.若* E是合法的表达式,则该表达式的结果不可能是_______。
(a)值
(b)左值
(c)代表一个变量
(d)代表E(的值)所指向的那个变量
5.在表达式& E中,E必须是_____,如果E的类型是int,则&E的结果类型是_____。
(a)值
(b)左值或者函数指示符
(c)指向int的指针
(d)int