基础知识
(1)指针数组:int *a[10]
理解:a和[]先结合,构成数组a[10](同时说明这变量的本质是数组,所以最终应该叫做**数组),紧接着与*号结合说明这个数组中10个元素都是指针,且指向的是int型变量。因此他是一个指针数组。
(2)数组指针:int (*a)[10]
理解:a首先和*号结合表明变量a是一个指针变量(本质就是个指针,所以最终应该叫**指针),紧接着和[]结合,表明这个指针变量指向一个数组,这个数组由10个int类型元素构成。所以名称为数组指针。
(3)函数指针
譬如函数为 void func(void);那么函数指针为void (*p)(void); 指针变量p 变量p的类型为void (*)(void); 调用方式为(*p)( ); 或者p( );
typedef与结构体
(1)结构体在使用时都是先定义结构体类型,再用结构体类型去定义变量。
(2)C语言语法规定,结构体类型使用时必须是struct 结构体类型名 结构体变量名;这样的方式来定义变量。
(3)使用typedef一次定义2个类型,分别是结构体变量类型,和结构体变量指针类型。
typedef struct teacher
{
char name[20];
int age;
int mager;
}teacher, *pTeacher;
typedef与const
(1)typedef int *PINT; const PINT p2; 相当于是int *const p2;
(2)typedef int *PINT; PINT const p2; 相当于是int *const p2;
(3)如果确实想得到const int *p;这种效果,只能typedef const int *CPINT; CPINT p1;
使用typedef的重要意义(2个:简化类型、创造平台无关类型)
(1)简化类型的描述。
char *(*)(char *, char *); typedef char *(*pFunc)(char *, char *);
(2)很多编程体系下,人们倾向于不使用int、double等C语言内建类型,因为这些类型本身和平台是相关的(譬如int在16位机器上是16位的,在32位机器上就是32位的)。为了解决这个问题,很多程序使用自定义的中间类型来做缓冲。譬如linux内核中大量使用了这种技术.
内核中先定义:typedef int size_t; 然后在特定的编码需要下用size_t来替代int(譬如可能还有typedef int len_t)
(3)STM32的库中全部使用了自定义类型,譬如typedef volatile unsigned int vu32;
二重指针
二重指针用来指向一重指针的地址,所以给二重指针赋值的时候,必须用一重指针的地址来赋值,否则类型检查会出错。
二重指针存放的也是一个地址,因此在内存中也是占用4个字节。
二维数组的内存映像
(1)一维数组在内存中是连续分布的多个内存单元组成的,而二维数组在内存中也是连续分布的多个内存单元组成的。
(1)从内存角度来看,一维数组和二维数组没有本质差别。
(2)二维数组int a[2][5]和一维数组int b[10]其实没有任何本质差别。我们可以把两者的同一单元的对应关系写下来。
a[0][0] a[0][1] a[0][4] a[1][0] a[1][1] a[1][4]
b[0] b[1] b[4] b[5] b[6] b[9]
一维数组和二维数组的比较
一维数组和二维数组在内存访问效率上几乎是一样的。但是在一些特定的情况下用二维数组效果比用一维数组好。
譬如说:有2个班级,每个班级10个人把他们的学号用数组定义出来。
如果用一维数组:int a[20]; 如果用二维数组:int a[2][10];
调用的时候,比如a[1][5]就代表第2个班级的学号为6的学生,而一维数组应该表示为a[15]就不是很直观。
(本文内容参考了朱有鹏C语言核心课程)