数组对象类型
Array of Type,它是多个相同对象类型的一维派生类型,包含两要素:元素个数,元素的对象类型
所谓多维数组,不过是元素的迭代衍生,本质还是一维的
声明 | 对象标识的名称 | 对象类型 | 对象存储元素类型 | 解释 |
---|---|---|---|---|
int b[3] |
b |
int[3] |
int |
int[3] 类型包含3个元素,每个元素对象类型为int |
int a[2][3] |
a |
int[2][3] |
int[3] |
int[2][3] 类型包含2个元素,每个元素对象类型为int[3] |
sizeof用法
当其后跟对象类型时,必须加括号
sizeof(3); // √
sizeof 3 ; // √
sizeof(int[3]); // √
sizeof int[3] ; // ×
不完全对象类型
对象类型的其中一种分类:完全对象类型,不完全对象类型。
不完全对象类型,指缺少“能确定对象大小”信息的类型,包括:
- 缺少元素个数的数组:
extern int a[]
- 变长数组VLA
- 包含不完全对象类型的struct/union
- void类型
指针对象类型
Pointer to Type,任何一种对象类型,都有对应的指针对象类型
原类型 | 对应指针类型 | 解释 |
---|---|---|
int[2][3] |
int(*)[2][3] |
数组指针的语法比较怪 |
int(*)[2][3] |
int(**)[2][3] |
指针类型也是类型,也就有对应的指针类型 |
int*[2][3] |
int*(*)[2][3] |
元素为int* 的[2][3] 形数组,其指针类型就如第一行 |
举一反三,int(*[2])[3]
类型应该如下解构(结合上表规则):
它是一个2元素数组,数组中的元素类型是指针,该指针指向int[3]
(即类型为int(*)[3]
)
int(*ppa[2])[3]; // 此时ppa[1]没有指向具体内存,所以不能直接解引用寻找对应内存地址
int a[3] = {1,2,3};
ppa[1] = &a;
printf("%d\n", (*ppa[1])[2]); // 输出3
(*ppa[1])[2] = 10;
printf("%d\n", (*ppa[1])[2]); // 输出10
typedef使用
C提供typedef为对象类型提供别名。
对于数组、指针相关的typedef,稍显不同寻常
原始类型 | 目标类型(别名) | 声明语法 | 描述 |
---|---|---|---|
int(*)[2] |
PAINT |
typedef int (*PAINT)[2]; |
倒像是声明变量了 |
int[2] |
AINT |
typedef int AINT[2]; |
|
int[2][3] |
AAINT |
typedef int AAINT[2][3]; |
由于将对象类型包装,所以指针语义将被延续:
typedef int* PINT;
int* p,q; // p是int*, q是int
PINT r,s; // r和s均为int*
内存对象的属性:值
每个内存对象的值包含两层语义:值,值的类型。可表示为二元组<Value, ValueType>
- 对于非数组对象类型:ValueType = ObjectType,对象按规则转换成Value (左值转换);
- 对于数组对象类型: Value = 第一个元素的首地址,ValueType = 元素类型对应的Pointer Type
- e.g.
int a[2]
,其对象类型为int[2]
,则a
的值为<a代表的内存的首地址, int*>
(可以从编译器报错中确认)
- e.g.
对内存对象的抽象:内存六元组
Object = <Addrress, ObjectType, Name, Size, Value, ValueType>
名称 | 含义 | 说明 |
---|---|---|
Address | 系统给对象分配内存的首地址编号 | 系统分配,不再改变 |
ObjectType | 对象的类型 | 即声明变量时的变量类型 |
Name | 对象标识符 | 即声明变量时的变量名,在符号表中,代表这块内存 |
Size | 内存的大小 | 内存的字节数量,sizeof可得 |
Value | 这段内存的表示值 | 根据ObjectType确定 |
ValueType | 这段内存的表示值类型 | 根据ObjectType确定 |