4.3 KiB
2.8 高级指针
如果你爱一个人,就让他用指针,因为指针是天堂;如果你恨一个人,也让他用指针,因为指针是地狱。
指针是 C/C++ 语言中功能最强大,最具灵活性的功能之一,用好指针可以使程序更加优美简洁。指针的实质是非常简单的,每个人都很容易学会指针,但每一个 C/C++ 开发者,包括很多高手在内,都必须时刻注意指针的使用,因为一旦违反指针的使用规则,程序便极具破坏性。
2.8.1 指针的使用
void*
2.8.2 指针的实质
2.8.3 指针与数组
我们知道,数组中的元素是何种类型,我们就将这个数组称为 X型数组。例如:
short arry[256];
被称作 short 数组。同样,如果数组中保存的是指针类型,我们则称这个数组为指针数组。
short* parry[256]; // 这是一个 short* 类型的数组, 数组中的每个元素都是一个指向 short 型变量的指针.
请记住,指针数组的实质仍是数组。
通过 ‘&’ 符号,能够获得变量的地址,那么该如何获得数组的地址?
数组中的元素是连续排列的,如果取某个元素的地址来代表整个数组,那显然是数组的首个元素地址最具代表性。数组首个元素的地址被称作数组首地址,数组名就代表了这个地址。我们看以下的程序:
/*
* @brief: Program 2-8-3-1
*/
short* parry[256];
void* tmp = &parry[0];
if(tmp==parry)
{
printf("True\n"); // 这句一定会被打印出来.
}
由于数组的名字代表了数组首地址(也就是指针),那么,我们也可以把一个指向某连续内存区的指针看作数组:
unsigned char* pointer;
pointer = calloc(256); // 分配一片长度为 256 的连续内存区, 并将这片内存区清零.
pointer[15] = 0xAA;
printf("Pointer+15=0x%x.\n", *(pointer+15)) // 输出内容为 “Pointer+15=0xaa.”
数组名这个特殊指针,与其他指针变量最大的差异在于:我们可以对指针变量进行赋值操作,但向数组名赋值是不和法的。这是因为数组是静态分配的,它的首地址是固定的,可以说数组名这个特殊指针是自带 const 属性的。因此,下面的程序将导致编译错误:
short* parry[256];
parry++; // 这里有个错误.
2.8.4 指针与结构体/联合体
结构体名称和首个元素的地址就代表了结构体的地址:
/*
* @brief: Program 2-8-4-1
*/
typedef struct _STA_T
{
int a;
}STA_T;
typedef struct _STB_T
{
STA_T b;
int c;
}STB_T;
void fun(STA_T* st)
{
STB_T* stb = st;
printf("%d", stb->c);
}
int main(void)
{
STB_T stx;
stx.c = 5;
fun(&stx); // 打印内容为 “5”.
}
2.8.5 指针的类型转换
不难注意到,Program 2-8-3-1 中将两种不同类型的指针直接进行了比较,这里会产生一个编译警告。我们该如何消除它?
short* parry[256];
void* tmp = &parry[0];
if(tmp==(void*)parry)
{
printf("True\n");
}
没错,指针也是一个类型,也就是说,类型转换的概念同样适用于指针。我们可以把一种类型的指针转换成另一种类型的指针,也可以把指针转换成整数,甚至可以把整数转换成指针。还记得 2.1.11 中的例子么?
// 假设系统是从低位开始寻址.
unsigned int a = 0x11223344;
char* pa = (char*)&a; // 通过 & 符号取变量 a 的地址. 指针 pa 的值便是变量 a 的首地址.
printf("%d.\n", *pa); // 0x44.
pa++;
printf("%d.\n", *pa); // 0x33.
pa++;
printf("%d.\n", *pa); // 0x22.
pa++;
printf("%d.\n", *pa); // 0x11.
pa++;
这是指针类型转换的一种用法,相当于把变量 a 看作长度为 4 的 char 型数组,然后我们通过 pa 指针一次访问了这个数组中的全部元素。
指针的转换同样会遇到位数问题:
char arry[256];
printf("%d", (short)arry); // 数据将被截断.
2.8.6 指针与函数
2.8.7 多级指针
2.8.8 指针参数
2.8.9 指针与内存泄漏
数组访问的溢出 没有释放的内存 野指针
练习
1、Program 2-8-4-1 中同样有编译警告,你该如何去除这些警告?
函数指针 指针数组 数组名