欢迎光临
我们一直在努力

让新手更好的理解指针

指针是什么

在C语言中,指针本质上就是内存地址,它是用来存储变量在内存中位置的特殊变量。每个变量在内存中都有唯一的地址,通过指针可以间接访问或修改该变量的值。

这里我们可以类比一下其他的数据类型:

int类型它储存的是一个整型。
指针类型它储存的就是一个无符号的地址号码。

而这一串地址号码可以让程序知道变量储存在电脑内存的哪个位置,方便直接对这个位置的数据进行操作,如:改写数据,删除数据(将这个地址的数据赋值为NULL)。

指针的定义

定义指针变量的一般形式为:

类型名 *指针变量名;\\\\空格在*前面
类型名* 指针变量名;\\\\空格在*后面
注:两种定义方法均可;

例如:

int *p_n;//定义的是int类型的指针
char *p_c;//定义的是char类型的指针
double *p_f;//定义的是double类型的指针

注意:指针只能存放同一类型变量的地址。
如:int类型变量的地址只能储存在int类型指针中,其他的变量(包括结构体)亦是如此。

指针储存地址的方式

首先指针的本质也是一个变量,只是这个变量有点特殊,它储存的是别的变量的地址,但是因为是变量的原因指针本身也有一个地址来储存数据(别的变量的地址)。

因此指针的值也是可以修改的,这个和普通变量可以修改存储的数值是同一个逻辑。这也是指针必须指定基础类型(如int*、char*、float*),这与普通变量的类型约束一致。

基础类型决定也了两个关键因素:一是解引用时能访问的内存字节数,二是指针加减运算的步长。

解引用(Dereferencing)指通过指针或引用访问其指向的内存地址中存储的实际数据。在编程中,指针保存的是内存地址,解引用操作允许直接操作该地址处的值。

让我们通过代码和图示来直观理解指针的存储方式。

int n=10;//1.定义一个整型变量
int *p_n;//2.定义一个int类型指针
p_n=&n;//3.将n的地址赋值给p_n

第一步定义一个int并赋值,然后再定义一个int指针类型的变量。

在这里插入图片描述
此时n的值已经储存在地址为“0x12345”的内存中了,而对于指针p_n我们虽然已经定义好了,它储存在地址为“0x11115”的内存中但是并没有赋值(是一个野指针),因此如果现在我们直接用的话是非常危险的一件事。

每次执行一次程序时,每个变量都会重新分配一次地址,也就是说重新一次程序变量的地址就会改变

野指针是指向无效内存地址的指针,通常由以下情况导致:
指针未被初始化,指向随机内存地址。
指针指向的内存被释放(如free或delete后未置空)。
指针超出变量作用域(如指向局部变量的指针在函数返回后继续使用)。
野指针的危害
程序崩溃:访问野指针可能导致段错误(Segmentation Fault),程序异常终止。
数据损坏:野指针可能意外修改其他有效内存区域的数据,引发不可预测的行为。
安全漏洞:攻击者可能利用野指针实施内存篡改或代码注入攻击。

第二步给指针赋值。
在这里插入图片描述
此时变量n的地址就储存在了p_n指针中了,到了此刻p_n才可以用了,不再是一个野指针了,我们就可以用这个指针来做一些操作了。

理解指针这个变量

首先来定义一个指针

int a=10;
int *p=&a;

然后我们可以进行如下理解:

当我们单独看p时,它是一个指针
此时我们操作p时,就是在操作它指向的那个变量的地址,也就是a的地址

当我们将 *p 当做一个整体来看时,它是一个变量
此时 *p 的值等于a的值也就是10,我们操作 *p 时就相当于操作变量a的值

#include<stdio.h>
int main()
{
int a = 10;
int* p;
p = &a;
printf("a的地址:%p\\n", &a);
printf(" p的值:%p\\n", p);
printf("p的地址:%p\\n", &p);
printf(" *p的值:%d\\n", *p);
printf(" a的值:%d\\n", a);
return 0;
}

执行出来的结果如下:
在这里插入图片描述
从每一次运行的规律我们可以看出指针p的值都是等于a的地址的,由此也证明了指针本质上就是内存地址,它是用来存储变量在内存中位置的特殊变量。同时也说明了p是a的地址,*p是a的值。

我们接下来对*p和p进行操作看看我会得出什么样的效果:

对p进行操作

printf(" p原来的值:%p\\n", p);
p++;//对p进行加1的操作
printf(" a的地址:%p\\n", &a);
printf("p加一后的值:%p\\n", p);

运行结果:
在这里插入图片描述

我们可以看到我们对p++后p的值却直接加了4;

这个是因为:

指针的算术运算(如 p++)会根据指针所指向的数据类型的大小进行调整。当一个指针指向某种数据类型时,p++ 操作会让指针移动到下一个相同类型的数据位置,而不是简单地增加 1。

对于 int* p, int 类型在系统中占 4 个字节,p++ 会让指针的值增加 4(即 sizeof(int)为4)。这是为了让指针指向下一个 int 变量的起始地址。

char* p:p++ 增加 1(sizeof(char) 为 1)。
short* p:p++ 增加 2(sizeof(short) 为 2)。
int* p:p++ 增加 4(sizeof(int) 为 4)。
double* p:p++ 增加 8(sizeof(double) 为 8)。

对*p进行操作

printf("*p和a原始的值:\\n");
printf(" *p的值:%d\\n", *p);
printf(" a的值:%d\\n", a);

*p=20;//对*p进行赋值的操作
printf("对*p进行赋值的操作\\n");
printf(" *p的值:%d\\n", *p);
printf(" a的值:%d\\n", a);

a++;//对a进行自增的操作
printf("对a进行自增的操作\\n");
printf(" *p的值:%d\\n", *p);
printf(" a的值:%d\\n", a);

(*p)++;//对*p进行自增的操作
//对*p进行自增时要打括号,运算符优先级(后置 ++ 优先级高于解引用 *),不加括号会变成*(p++),导致指针指向无效地址,
printf("对*p进行自增的操作\\n");
printf(" *p的值:%d\\n", *p);
printf(" a的值:%d\\n", a);

运行结果
在这里插入图片描述
我们可以看出:
当指针指向某变量时,操作指针指向的值(*p)等价于操作变量本身(a),二者的修改会互相同步。

思考题:

int a = 10;
int* p;
p = &a;

int b= 10 ;
a = b;

此时p的值是a的地址还是b的地址?

赞(0)
未经允许不得转载:171主机测评 » 让新手更好的理解指针
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址