甘南网站建设,腾讯云 建网站,七牛云wordpress图床,网页制作软件教程参考资料#xff1a;
《C Primer》第5版《C Primer 习题集》第5版
6.1 函数基础#xff08;P182#xff09;
典型的函数定义包括#xff1a;返回类型#xff08; return type #xff09;、函数名字、0 个或多个形参#xff08; parameter #xff09;组成的列表、函…参考资料
《C Primer》第5版《C Primer 习题集》第5版
6.1 函数基础P182
典型的函数定义包括返回类型 return type 、函数名字、0 个或多个形参 parameter 组成的列表、函数体。其中函数体为语句块。
我们通过调用运算符执行函数。调用运算符的形式是一对圆括号作用于函数或指向函数的指针圆括号之内是实参(argument)列表实参用来初始化函数的形参。调用表达式结果的类型就是函数的返回类型。
调用函数
函数调用完成两项工作
用实参初始化函数的形参。将控制权移交到被调用函数。
形参和实参
实参和形参一一对应但没有规定求值顺序。
实参的类型必须与对应的形参匹配实参的数量和形参一致。
函数的形参列表
形参列表可以为空但不能省略
void f1() { /* ... */ }
void f2(void) { /* ... */ }每个形参都是含有一个声明符的声明函数最外层作用域的局部变量不能和函数形参同名。
形参名不是必须的如果某个形参在函数中不会被用到可以不对其命名。
函数的返回类型
函数的返回类型不可以是数组或函数因为这两种类型不支持拷贝操作但可以是指向数组或函数的指针。
6.1.1 局部对象P184
名字的作用域是程序文本的一部分名字在其中可见。对象的生命周期是程序执行过程中该对象存在的一段时间。
形参和函数体内部定义的变量称为局部变量local variable这些变量只在函数内部可见且会隐藏外层作用域中的同名变量。
在所有函数体之外定义的对象在程序启动时被创建直到程序结束才会销毁。
自动对象
我们把只存在于块执行期间的对象称为自动对象automatic object。
局部静态对象
如果想令局部变量的生命周期贯穿函数调用及之后的时间可以使用 static 将其定义成局部静态对象local static object。局部静态对象在程序第一次经过其定义语句时初始化直到程序结束才销毁
int count_calls(){static int cnt 0;return cnt;
}如果局部静态变量没有显式的初始值将执行值初始化。
6.1.2 函数声明P186
函数只能定义一次但可以声明很多次。函数的声明和定义非常相似区别在于无须函数体也无须形参的名字用分号代替即可。
函数最好在头文件中声明在源文件中定义。
6.1.3 分离式编译P186
C 语言支持分离式编译即把程序分隔到多个文件中每个文件独立编译。
编译和链接多个源文件
6.2 参数传递P187
形参的初始化机制和变量初始化一样如果形参是引用类型它将绑定到对应的实参上否则将实参的值拷贝给形参。
6.2.1 传值参数P187
指针形参
指针形参初始化时和其他非引用类型一样执行拷贝操作拷贝之后两个不同的指针指向同一个对象。 在 C 中建议使用引用形参代替指针形参 6.2.2 传引用参数P188
使用引用避免拷贝
当某些对象拷贝效率较低或不支持拷贝时可以使用引用形参访问该类的对象。如果函数无需改变引用形参的值最好将其声明为常量引用。
使用引用形参返回额外信息
6.2.3 const形参和实参P190
当形参具有顶层 const 属性时传入常量还是非常量都是可以的换句话说形参中的顶层 const 属性在初始化时被忽略了。
C 允许我们定义若干相同名字的函数前提是这些函数应有不同的形参列表
void func(const int ci);
void func(int i); // 错误指针或引用形参与const
尽量使用常量引用
把函数不会改变的形参定义成普通引用是一种常见的错误这样做会让人误认为函数可以修改这个对应实参的值同时还会限制能接受的实参类型不能把 const 对象、字面值、需要类型转换的对象传递给普通引用形参上。
6.2.4 数组形参P193
由于数组不支持拷贝所以数组不能作为函数的返回类型由于数组名通常会转换成指针所以我们向函数传递一个数组时实际上传递的是指向首元素的指针。
尽管不能通过值传递的方式传递数组但 C 允许我们把形参写成数组形式
// 下面三个函数是等价的唯一的形参都是const int*
void print(const int*);
void print(const int[]);
void print(const int[10]); // 这里的10其实没啥用无论 print 函数使用上述的哪种方式声明编译器只检查传入的参数是否是 const int* 。也就是说将数组当作实参传递给函数时会自动转化为指向首元素的指针。
使用标记指定数组长度
数组本身包含一个结束标记如 C 风格字符串。
使用标准库规范
利用 begin() 和 end() 传递数组的首元素指针和尾后指针。
显式传递一个表示数组大小的形参
数组形参和const
当不需要改变数组元素时应该将数组形参设为指向 const 的指针。
数组引用形参
当形参为数组的引用时数组的维度就成了类型的一部分
void print(int (arr)[10]); // 限制实参必须为维度为10的数组传递多维数组
由于 C 中多维数组实际上是数组的数组所以多维数组除第一维外均不可以忽略
void print(int (*matrix)[10]);
void print(int matrix[][10]); // 因为编译器会忽略第一个维度所以声明时最好不写6.2.5 main处理命令行选项P196
int main(int argc, char *argv[]) { ... }argc 表示 argv 数组中字符串的数量。当实参传递给 main 函数后argv 的第一个元素指向空串或程序的名字接下来的元素依次为命令行提供的实参最后一个指针的下一个元素为 0 。如命令
prog -d -o ofile data0argv 数组中的内容为
argv[0] prog; // 程序名也可能是空串
argv[1] -d; // 实参实际上argv[1]开始
argv[2] -o;
argv[3] ofile;
argv[4] data0;
argv[5] 0;6.2.6 含有可变形参的函数P197
initializer_list实参
如果所有实参类型相同但数量不固定我们可以使用名为 initializer_list 的标准库类型作为形参。initializer_list 定义在同名头文件中 initializer_list 中的元素永远是常量。
void error_msg(initializer_liststring il){for(auto beg il.begin();beg!il.end();beg){cout *beg ;}cout endl;
}// 调用方式
error_msg({functionX, expected, actual});省略符形参
省略符形参是为了便于 C 程序访问某些 C代码而设置的省略符只能出现在形参列表的最后一个位置
void foo(pram_list, ...);
void foo(...);6.3 返回类型和return语句P199
return;
return expression;6.3.1 无返回值函数P200
没有返回值的语句只能用于返回值为 void 的函数中。返回值为 void 的函数最后一句后面会隐式执行 return 。
返回值为 void 的函数也能返回使用第二种类型的 return 语句但 expression 必须为另一个返回 void 的函数。
6.3.2 有返回值函数P200 在含有 return 语句的循环后面也应该有一条 return 语句。如果没有的话该程序就是错误的而许多编译器无法发现这个错误。 值是如何被返回的
返回的值用于初始化调用点的一个临时量。
返回值也可以是引用类型
const string shorterString(const string s1, const string s2){return s1.size() s2.size() ? s1 : s2;
}不要返回局部对象的引用或指针
函数完成后它所占用的空间也会被释放掉。
返回类类型的函数和调用运算符
调用运算符的优先级和点运算符和箭头运算符相同满足左结合律。
引用返回左值
函数的返回类型决定函数调用是否为左值调用一个返回引用的函数得到左值其他返回类型得到右值。
列表初始化返回值
C11 规定函数可以返回花括号包围的值的列表。如果列表为空临时量执行值初始化。
vectorstring example{return {hello, world};
}主函数main的返回值
main 函数是唯一返回类型不是 void 但可以没有 return 语句的函数编译可以隐式插入一条返回 0 的 return 语句。
main 函数返回 0 表示执行成功其他值表示执行失败。cstdlib 头文件定义了 EXIT_FALLURE 和 EXIT_SUCCESS 两个预处理变量用来表示 main 函数执行的失败与成功。
递归
main 函数不能调用自己。
6.3.3 返回数组指针P205
虽然函数不能返回数组但可以返回数组的指针或引用
typedef int arrT[10]; // arrT是含有是个整数的数组类型
arrT* func(int i); // 使用类型别名可以简化表达式func 函数接受一个 int 实参返回一个指向包含 10 个 int 的数组的指针。
声明一个返回数组指针的函数
如果在声明 func 函数时不想使用类型别名则可以按照如下方式声明
int (*func(int i))[10];数组的维度必须在名字之后而函数的形参列表应该紧跟在函数名字后面所以数组维度要写在形参列表后面(*func(int i)) 外侧的括号不能省略否则函数的返回类型将是指针的数组这显然是不合法的。
使用尾置返回类型
在 C11 新标准中可以使用尾置返回类型简化 func 的声明
auto func(int i) - int(*)[10];任何函数都可以使用尾置返回为了表示函数真正的返回类型在形参列表之后我们在本应出现返回类型的地方放置一个 auto 。
使用decltype
int arr[10] {};decltype(arr) *func(int i);