内容正文:
第9章 指针
第9章 指针
指针变量
野指针与空指针
指针变量作形参
指针作函数的返回值
地址参与运算
指针与一维数组
一维数组作形参
指针与二维数组++
指向指针类型的指针
main函数和命令行参数
指向函数的指针变量
使用堆空间
典型命题
一维数组作形参
在第7章函数中提及了一维数组作形参,这节课我们讨论一维数组作形参。
3
例9-13 分析例7-18。
数组间不能相互赋值,实参如何给形参赋值?
由例7-10可知,数组作形参有两个特点,一是数组的长度可以忽略,二是改变形参的数组元素的值,就是改变实参的数组元素的值。
但有个问题,数组间不能相互赋值,函数执行时,实参如何给形参赋值?
4
与数组兼容的指针类型
C语言规定,形参的类型为数组时,数组类型会转化为与之“兼容”的指针类型。
若数组名可以赋值给某指针变量,则该类型的指针变量与此数组“兼容”。如int a[3]; int *p;,由于p = a;,故一维整型数组与整型指针变量兼容。
兼容即可以赋值,swap函数的形参为一维整型数组,数组a的值为其首元素地址,即整型地址,因此,与之兼容的指针变量为整型指针变量,swap函数的形参实为int *a,首部实为void swap(int *a)。
C语言规定,形参的类型为数组时,数组类型会转化为与之“兼容”的指针类型。
若数组名可以赋值给某指针变量,则该类型的指针变量与此数组“兼容”。如int a[3]; int *p;,由于p = a;,
故一维整型数组与整型指针变量兼容。
兼容即可以赋值,swap函数的形参为一维整型数组,数组a的值为其首元素地址,即整型地址,
因此,与之兼容的指针变量为整型指针变量,swap函数的形参实为int *a,首部实为void swap(int *a)。
5
分析下面的程序。
修改后实际的swap函数如图所示。实参赋值给形参(a = b)后,整型指针变量a指向了b[0]。
在swap函数中a[0]为*(a+0)即*a,也就是b[0]的存储单元
a[1]即*(a+1),a指向b[0],a+1指向b[1],因此,*(a+1)就是b[1]的存储单元。
交换a[0]与a[1]就是交换b[0]和b[1]。
最后程序的输出结果如图所示。
6
数组作形参时会转化为兼容的指针类型,当实为整型指针的形参a指向实参数组b的首元素后,
改变形参的“数组元素”的值,就是改变实参的数组元素的值。
7
注意一致性
尽管形参为数组时,也会转换为字符型指针,但函数定义中的代码最好保持一致性,
即数组用下标,指针用间接引用。
这样有更好的可读性。
8
例9-14 编写一个输出字符数组中字符串的函数。
形参的类型可以是字符数组,也可以是字符型指针。
编写一个输出字符数组中字符串的函数时,形参的类型可以是字符数组,也可以是字符型指针。
形参的类型为字符数组时,函数输出字符数组中的字符串。
形参的类型是字符型指针时,函数输出从字符型地址标识的存储单元开始的字符串。
从可读性的角度分析,形参为指针时,函数也可以用于输出字符数组中的字符串。
尽管形参为数组时,也会转换为字符型指针,但函数定义中的代码最好保持一致性,
即数组用下标,指针用间接引用。
9
思考题
用指针作形参实现库函数strncpy。
编程时应直接使用库函数,这里重新定义库函数仅仅是为了更好地了解库函数。
使用库函数strncpy需包含头文件string.h。
10
二维数组与指针
这节课我们讨论二维数组与指针。
11
例9-15 分析二维数组int a[3][2] = {{11, 12}, {21, 22}, {31, 32}} ,设它的内存状态如图所示。
二维数组a的值也是其首元素a[0]的地址,即&a[0]。
如图,a[0]是一个长度为2的一维整型数组,它的类型为int [2],&a[0]是一个int [2]型地址。
数组a的值是&a[0],一维数组a[0]的值
是&a[0][0]。
二维数组a的值也是其首元素a[0]的地址,即&a[0]。
如图,a[0]是一个长度为2的一维整型数组,它的类型为int[2],&a[0]是一个int [2]型地址。
数组a的值是&a[0],一维数组a[0]的值是&a[0][0]。
二维数组a和一维数组a[0]都是一个虚拟的变量,数组a指向a[0],a[0]指向a[0][0]。
它们之间的关系如图所示。
12
分析表达式a + 1
二维数组a的值是&a[0],一个int [2]存储单元的地址,
a + 1的值是一个与a[0]相邻的下一个同类型(即int [2]型)存储单元的地址
与a[0]相邻的下一个同类型存储单元是a[1],
a + 1的值是&a[1],一个int [2]型地址
a指向了a[0],a + 1指向了a[1]。
*a就是a[0]