《C Primer Plus》学习笔记(第九章到第十章)
第九章:函数
函数是完成特定任务的独立程序代码单元,使用函数可以省去编写重复代码的苦差。如果程序要多次完成某项任务,用函数会方便很多。函数让程序更加模块化,从而提高了代码的可读性,更方便后期的修改、完善。
描述性的函数名能清楚的表达函数的用途和组织结构。然后单独设计和测试每个函数,直到函数都能正常完成任务。在动手编写代码之前,仔细考虑一下函数应该完成什么任务,以及函数和程序整体的关系。
函数原型告诉编译器函数的类型,函数调用表明在此处执行函数;函数定义明确的指定了函数要做什么,任何程序在使用函数之前都要声明函数的类型,一般而言,函数原型指明了函数的返回值类型和函数接收的参数类型,当执行到函数时,会找到该函数的定义并执行其中的内容,执行完代码后,计算机返回主调函数继续执行下一行。函数中的变量是局部变量,意思是该变量只属于该函数,函数名不会与其他函数中的变量名冲突。
形式参数也是局部变量,属该函数名私有。
在函数调用中,实际参数提供了值,该值在函数运行的过程中可以被调用,但是不会改变提供该值的变量的值(指针可以在函数中改变传入参数的值)。(黑盒视角)
return可以从函数中返回值,返回值不仅可以赋值给变量,也可以被用作表达式的一部分,返回值不一定是变量的值,也可以是任意表达式的值。实际得到的返回值相当于把函数中指定的返回值赋给与函数类型相同的变量所得到的值。return的作用是终止函数并把控制返回主调函数的下一条语句
主调函数把它的参数存储在被称为栈的临时存储区,被调函数从栈中读取这些参数。
递归 就是自己调用自己 递归函数必须包含能让递归调用停止的语句。通常,递归函数都使用if或其他等价的测试条件在函数形参等于某特定值时终止递归。
递归和循环哪个更好? 一般而言,选择循环比较好。首先,每次递归都会创建一组变量,所以递归使用的内存更多,而且每次递归调用都会把创建的一组新变量放在栈中。递归调用的数量受限于内存空间。其次,由于每次函数调用要花费一定的时间,所以递归的执行速度比较慢。递归不方便阅读和维护。在效率优先的程序中要注意使用递归。
linux编译多源代码文件的程序 gcc file1.c file2.c gcc file1.c file2.o
把函数原型放在头文件中,就不用每次使用函数文件时都写出函数的原型
&用于存储变量的地址
声明指针变量时必须指定指针所指向变量的类型,因为不同的变量类型占用不同的存存储空间,一些指针操作要求知道操作对象的大小。另外,程序必须知道存储在指定地址上的数据类型。
形式参数是定义在被调用函数中的变量,实际参数是出现在函数调用中的值
第十章:数组和指针
数组由数据类型相同的一系列元素组成,通常被用来存储程序需要的数据
初始化数组 int number[20]={};可以在括号内自己初始化数组的值,不加值默认全部为0,int number[]={1,2,3};默认该数组的大小为3,注:变长数组不能赋初值,一般通过循环赋值。
只读数组不能改变数组中的值;
编译器不会检查数组下标是否使用得当。在C标准中,使用越界下标的结果是未定义的。
二维数组和多维数组是建立在一维数组上的,二维数组初始化如下:
int a[2][2]={{0,0},{0,0}};
这样一个2*2的数组就可以初始化了,可以不是零,可以赋值为任意你需要的值。
指针的值是它指向的对象的地址
在指针前面使用*运算符可以得到该指针所指向对象的值
指针加1,指针的值递增它所指向类型的大小
因为数组名是该数组首元素的地址,作为实际参数的数组名要求形式参数是一个与之匹配的指针。只有在这种情况下,C才会把int arr[]和int *ar解释成一样。也就是说,ar指向int的指针。
指针变量的基本操作
赋值:可以把地址赋给指针
解引用:*运算符给出指针指向地址上存储的值。
指针与整数相加:可以使用+运算符把指针与整数相加,或整数与指针相加
递增指针:递增指向数组元素的指针可以让该指针移动至数组的下一个元素。
指针减去一个整数:可以使用-运算符从一个指针中减去一个整数
递减指针
指针求差:可以计算两个指针的差值
比较:使用关系运算符可以比较两个指针的值,前提是指向的对象类型相同
切记:创建一个指针时,系统只分配了存储指针本身的内存,并未分配存储数据的内存。因此,在使用指针之前,必须先用已分配的地址初始化它。
地址的地址或指针的指针就是双重间接
变长数组还允许动态内存分配,这说明可以在程序运行时指定数组的大小。普通C数组都是静态内存分配,即在编译时确定数组的大小。
复合字面量是提供临时需要的值的一种手段。复合字面量具有块作用域,这意味着一旦离开定义复合字面量的块,程序将无法保证该字面量是否存在。也就是说,复合字面量的定义在最内层的花括号中。
