目录
函数的参数
在函数头中定义的参数称为函数的形式参数,简称形参。
与定义在函数代码块内部的变量一样,形参也是局部变量,属于函数私有。
在其他函数中使用同名变量不会引起冲突,每次调用函数,就会给形参赋值。
调用带实际参数的函数
实际参数简称实参,是主调函数赋值给被调函数的具体值。
实际参数可以是变量、常量或表达式。
无论实际参数时上述哪种形式,都要被求值,将值拷贝给被调函数的形参。
实参与形参的关系
实参是具体的值,形参的值是从实参的计算结果中拷贝而来。
无论被调函数对拷贝数据做什么操作,都不会影响主调函数中的原始数据,除非传址(一种特殊的传值)。
传参
C语言的所有参数都用 “传值调用” 的方式进行传递,被调函数的形参将获得实参的一份拷贝。这样被调函数可以放心的修改这个拷贝值,不用担心会修改到主调函数中的参数。
但是如果传递的参数是一个数组名,在被调函数中使用数组下标对数据元素进行修改,这样主调函数中的参数也会被修改。数组并未被复制到形参中,这种行为被称为“传址调用”,但它在本质上讲并不违背 “传值调用” 的原则。传址也是一种特殊的传值。详细内容见博客《数组名作为函数参数》
数组名或指针作为参数进行传递,它们本身的值实际上都是指针,被调函数的形参获得的是这个指针的一份拷贝。下标引用(即使用中括号[])实际上是间接访问的另一种形式。使用它可以对指针执行间接访问操作,访问指针所指向的内存位置,在这份指针值得拷贝上执行间接访问操作所访问的是原来的数组。
const应用,对函数形参使用const,保护主调函数的实参数据
修饰函数中的形参
指向常量的指针通常用于函数的形参中,表明该函数不会使用指针改变传递来的要处理的数据。被调函数不会通过函数形参修改主调函数中的数据内容。
举例:
float rate_turn_fun(const float* mifer, int num)
{
int i;
float total_fer;
for(i = 0; I <10;i++)
{
total_fer += mifer[i]; 正确
total_fer += *(mifer+i); 正确
}
*mifer = total_fer; 错误,使用mifer只能访问数据,不能修改数据
return total_fer;
}
这样使用const并不是要求主调函数中的原数组是常量,而是在被调函数中,处理该数组时将其视为常量,不可更改。这样使用const可以保护主调函数中的数组数据不被修改。使用const修饰形参,函数不能修改数组名或指针修改数组中元素的值。
不过对于基本类型,这种const是没有意义的,因为此时的实参传递给形参时本身就是一份拷贝,不会改变原实参的值。
主调函数通过实参传给被调函数的形参的值,都是一份拷贝。但是如果这个拷贝是个内存地址,那么直接操作这个内存地址,就可以改变里面的值。
这也是我们常说的若果使用指针传递参数,小心主调函数的数据被修改,除非这是你期望看到的。
这也印证了我们之前博客《什么是机器语言…》中的C语言的第五个优点。
const指针或普通指针的区别
把const数据或非const数据的地址初始化为指向const的指针或为其赋值是合法的。但是,只能把非const的数据的地址赋值给普通指针,将const的数据的地址赋值给普通指针,结果是未定义的,未知的。
举例:
int xuqi[5] = {1,9,8,3,6};
const heli[5] = {1,2,10,5,6};
rate_turn_fun(xuqi,5); 有效
rate_turn_fun(heli,5); 有效
如果有函数
void rate_manage_fun(float* mifer, int num);
则:
rate_manage_fun(xuqi,5); 有效
rate_manage_fun(heli,5); 不能这样传参,会出现未知结果。
函数传参的原则:
函数无法访问其他函数中的变量,这种限制访问保护了数据的完整性。但是,当切实需要在函数中访问另一个函数内的数据时(修改),可以把指针作为函数的参数。
const修饰字符串
const char * pc = "Behold a string literal!";
程序根据该声明把相应的字符串存储在内存中,内含这些字符值的字符串就是一个对象。
由于字符串字面量中的每个字符都能被单独访问,所以每个字符也是一个对象。
该声明还创建了一个标识符为pc的对象,存储着字符串的地址。
由于可以设置pc重新指向其他字符串,所以标识符pc是一个可修改的左值。const只能保证被pc指向的字符串内容不被修改,但是无法保证pc不指向别的字符串。
指针的值可以修改,指向的内容不可修改!!!
见博客《const关键字,常量指针与指针常量》
由于* pc指定了存储 ‘B’ 字符的数据对象,所以 *pc是一个左值,但不是一个可修改的左值。
以此类似,因为字符串字面量本身指定了存储字符串的对象,所以它也是一个左值,但不是可修改的左值。