C语言复杂表达式与指针应用

基础知识

(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语言核心课程)