在 C 语言的世界里,指针是一把 “双刃剑”,它有强大的操控能力,同时也让无数初学者望而生畏。但当你真正掌握指针后,就会发现它是编写高效、灵活代码的关键。本文将从指针的基础概念入手,结合丰富的示例,带你逐步揭开 C 语言指针的神秘面纱。
一、指针的本质:内存地址的具象化
指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,在使用指针存储其他变量地址之前,必须对其进行声明。指针变量声明的一般形式为:
type *name;
其中type是指针的基类型,它必须是一个有效的 C 数据类型,例如char、int、float等。而name是指针变量的名称,用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:
int *p; // 定义一个指向int类型的指针变量p
double *q; // 定义一个指向double类型的指针变量q
char *ch;//定义一个指向char类型的指针ch
指针理解要点:
1.指针是内存中一个最小单元的编号,也就是地址,本质上指针就是地址
2.平时所说的指针即指针变量,指针变量就是一个用来存放地址的变量,指针变量里存放的是地址,而通过这个地址就可以找到一个内存单元,地址是唯一标识这个地址空间的。
#include <stdio.h>
int main()
{
int a = 10;//a是整型变量,占4个字节的内存空间
int* pa = &a;//pa是指针变量,用来存放地址
return 0;
}
二、指针的基础操作与内存映射
1. 取地址运算符 &
int a = 10;//向内存申请四个字节来存储10
int *p = &a;//&为取地址操作符 int说明p指向的对象是int类型的 *说明p是指针变量
printf("%p\n",&a);
%p 是以地址的形式打印
2. 解引用运算符 *
int a = 10;
int *p = &a;
*p = 20;
//*是解引用操作符,意思就是通过p中存放的地址,找到P所指向的对象,*p就是p所指向的对象
printf("%d\n",a);
解引用操作符主要是通过指针修改内存中的值,最终a的值被改为20。
3.指针的解引用
int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;
return 0;
}
从调试窗口可以看到,此时a的地址为0X00CFF84C,此时内部存储值为0x11223344
当通过解引用操作符将a的值变为0后,调试窗口也发生了变化,储存值的所有位变为0。
当代码改为如下类型时,
int main()
{
int a = 0x11223344;
char* pc = (char*)&a;
*pc = 0;
return 0;
}
从调试窗口可以看到,此时a的地址为0X0072F858,此时内部存储值为0x11223344
当通过解引用操作符将a的值变为0后,只有储存值的第一位变为0。
结论:指针类型决定了指针在被解引用时访问几个字节,若是int*类型的指针,解引用访问4个字节,如果是char*的指针,解引用访问1个字节,可推广到其他类型 。
三、指针变量的大小
指针变量的大小取决于地址的大小,32位平台下地址是32个bit位,即4个字节,64位平台下地址是64个bit位,即8个字节
x64平台:
x86平台:
四、指针和指针类型
1.指针类型
我们知道变量有不同的类型,因此指针也有不同的类型
当有代码如下时:
int num = 10;
p = #
要将&num的值保存到p中,我们就知道p是一个指针变量,指针变量的类型定义如下:
char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
2.指针+-整数
int main()
{
int a = 0x11223344;
int* pa = &a;
char* pc = (char*)&a;
printf("pa = %p\n",pa);
printf("pa + 1 = %p\n",pa + 1);
printf("pc = %p\n",pc );
printf("pc + 1 = %p\n",pc + 1);
return 0;
}
指针的类型决定了指针+-n操作时跳过几个字节,即决定了指针的步长。