1、二级指针
什么是二级指针?我们说,指针变量是用于存放变量的地址,而通常意义上,我们说的指针变量其实是指代一级指针。二级指针也是指针变量,只不过它是用于存放一级指针变量的地址。如图所示:
这里*的增加可能会让人头晕,但实际上其背后的含义是很简单的。指针变量的类型有统一的格式:指向的变量类型+*。这也就是说,*代表它是一个指针变量,*之前的内容,则是这个指针变量所指向的数据的类型。正如图中的pi变量,*说明它是一个指针变量,int则是它所指向的数据类型,即整型;同理,对于ppi变量,*说明它是一个指针变量,int*是它所指向的数据类型,即pi的类型int*
对于二级指针,如上图的ppi,可以进行两次解引用。第一次解引用得到的是pi,即变量i的地址;第二次解引用就可以理解为对pi解引用,由此得到变量i。
2、指针数组
什么是指针数组?指针数组就是用于存放指针的数组。
指针数组可以用来模拟实现二维数组:
最后输出的结果是完全一样的
当然,也可以写成解引用的形式,二者本质上是一样的:
输出结果也是一样的
3、结构体
A、结构的定义
想要搞懂结构体之前,我们必须明白什么是结构。
结构是一些数据的集合,与数组不同,数组必须是相同类型元素的集合,而结构可以是不同类型元素的集合。
现实情况是很复杂的,描述一个物体,只用一种类型的数据显然是不够的。比如说,我要描述一个人,名字是字符型的,身高是浮点型的,岁数是整型的,这显然不是一种类型的数据能够描述完的。
C语言为了应对这种情况,引入了结构体。
B、结构体的定义
那么,结构体如何定义呢?
首先,我们要区分结构体类型与结构体变量。同其它变量与类型一样,结构体类型是不占内存空间的,结构体变量需要占内存空间,结构体变量是以结构体为类型所创建的变量。
上图所示的两种结构体变量创建方式,创建出的结构体变量都是全局变量,并不是很推荐。通常,我们都在主函数中创建结构体变量。
C、结构体变量的初始化
结构体变量如何初始化呢?
结构体变量的初始化,本质上就是对结构体中所含各个变量的初始化。具体如图所示:
结构体变量初始化之后,如何输出结构体变量中的各个内容呢?这时我们就要使用到点操作符。
最后输出结果如下所示:
D、结构体的嵌套使用
在定义结构体时可以嵌套使用
相应地,嵌套结构体的初始化亦有所不同,相当于要初始化两个结构体变量。
访问这样的嵌套结构体:
E、结构体传参
函数的传参有两种:传值调用和传址调用。所以结构体传参也有两种方式,传结构体变量以及传结构体变量的地址。
a、传结构体变量
b、传结构体变量的地址
c、如何选择
我们可以看到,两种结构体传参方式,最终输出的结果是完全一样的。既然如此,我们该如何选择结构体的传参方式呢?
我们知道,在函数的传值调用中,形参是实参的一份临时拷贝,这样的临时拷贝要占据内存空间,同时从实参向实参拷贝也需要耗费一定时间,所以如果传结构体变量会造成时间和空间的双重浪费。
而函数的传址调用则没有这样的问题。因为传过去的是结构体变量的地址,所以函数中直接访问的便是该地址所对应的结构体变量,而不是原结构体变量的临时拷贝。
因而,在结构体传参中,我们通常都是传结构体变量的地址。