《小菜狗 C 语言入门 + 进阶笔记》(32)指针入门 2 -- 指针到底是什么?(非常重要,解刨得很透彻)


《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介

1、指针是什么?

我们上一章节 (2.30)指针入门1 – 内存与地址 学过这句话:

生活中我们把门牌号也叫地址,在计算机中我们把内存单元的编号也称为地址。

C 语⾔中给地址起了新的名字叫:指针

所以我们可以理解为:内存单元的编号 == 地址 == 指针

2、指针变量(重点!!!)

2.1、概念

我们通过取地址操作符 (&) 拿到的地址是⼀个数值,比如:0x006FFD70,这个数值是需要存储起来,⽅便后期再使用,那我们把这样的地址值存放在哪⾥呢?

答案是:指针变量中!

指针是内存地址,指针变量是用来存放内存地址的变量。

指针变量的值就是某份数据的地址,这样的一份数据可以是数组、字符串、函数,也可以是另外的一个普通变量或指针变量。

2.2、声明定义

像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明定义。

指针变量声明的一般形式为:

type *var_name;

在这里,type 是指针的数据类型var_name指针变量的名称。用来声明指针的星号 \* 与乘法中使用的星号是相同的。但是,在这个语句中,星号 * 是用来表示这是一个指针变量

运算符 *:

指针变量存储了数据的地址,通过指针变量能够获得该地址上的数据。

这里的*称为指针运算符,也叫解引用操作符:

  • 声明时是用来表示这是一个指针变量;
  • 使用时是用来取得某个地址上的数据。

以下是有效的指针声明:

int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch;    /* 一个字符型的指针 */

不同数据类型的指针之间唯一的不同是:指针所指向的变量或常量数据类型不同

2.3、指针变量初始化
int a = 10;
int *p = &a;

在定义指针变量 p 的同时对它进行初始化,并将变量 a 的地址赋予它,此时 指针变量 p 就指向了 a

值得注意的是:指针变量 p 需要的是一个地址,a 前面必须要加取地址符&,否则是不对的。

2.3.1、详细解释(重点!!!)

我们拆开来看,如下图:

在这里插入图片描述

  1. 代码:int a = 10;
  • 创建了整型变量 a,内存中申请 4 个字节``,``用于存放整数 10,上图中变量 a 的首地址是:0x0012ff40
  1. 代码:int \*p = &a;
  • 先看 p 左边写的是 int *,说明指针变量 p 的类型是 int*
  • 其中 星号* 是在说明 p 是指针变量,⽽前⾯的 int 是在说明 p 指向的是 int 类型的对象
  1. 总结就是把变量 a 的地址赋值给了指针变量 p ,官方说法就是指针变量 p 就指向了 变量 a 的地址
2.4、输出变量地址
2.4.1、输出定义的变量地址

代码如下:

#include <stdio.h>
 
int main ()
{
     int var_runoob = 10;
     int *p;

     p = &var_runoob;

     printf("var_runoob 变量的地址: %p\n", p);
     return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

var_runoob 变量的地址: 0x7ffeeaae08d8

在这里插入图片描述

2.4.2、带 * 与不带 *(重点!!!)

有同学会问为什么 p = &var_runoob; 语句前面的指针变量 p 为什么不带 * 号了?初始化就有带 * 星号?

部分代码如下:

     int *p;

     p = &var_runoob;

给 p 赋值时,因为已经知道了它是一个指针变量,就没必要多此一举再带上*,后边可以像使用普通变量一样来使用指针变量。

前面 2.2、声明定义 章节讲过了,* 使用时是用来取得某个地址上的数据!

  • 原先是 p = &var_runoob;,也就是地址 = 地址
  • 你带上 * 的话,就变成了 *p = &var_runoob;,也就是数据 = 地址,明显就不对!懂了吧?理解这个非常的重要!

也就是说:声明定义指针变量时必须带*,给指针变量赋值时不能带*

2.5、改变指针变量的值(扩展)

和普通变量一样,指针变量也可以被多次写入,只要你想,随时都能够改变指针变量的值

如下代码:

//定义普通变量
float a = 99.5, b = 10.6;
char c = '@', d = '#';
//定义指针变量
float *p1 = &a;
char *p2 = &c;
//修改指针变量的值
p1 = &b;
p2 = &d;
2.5.1、对上面的代码举例

假设变量 a、b、c、d地址分别为 0X1000、0X1004、0X2000、0X2004,下面的示意图很好地反映了 p1、p2 指向的变化:

在这里插入图片描述

需要强调的是,p1、p2 的类型分别是 float*char*,而不是 floatchar,它们是完全不同的数据类型,读者要引起注意。

2.5.2、连续定义

指针变量也可以连续定义。

例如:

int *a, *b, *c;  //a、b、c 的类型都是 int*

注意:

每个变量前面都要带 *。如果写成下面的形式,那么只有 a 是指针变量,b、c 都是类型为 int 的普通变量。

int *a, b, c;

3、通过指针变量取得数据(重点**)

补充一下之前初始化说的例子,并且使用两种方式都可以输出变量 a 的值。

代码如下:

#include <stdio.h>

int main()
{
    int a = 15;
    int *p = &a;
    printf("%d, %d\n", a, *p);
    return 0;
}

运行结果:

15, 15

可以从运行结果看出,*p 和 a 是等价的

  • 假设 a 的地址是 0X1000,p 指向 a 后,p 本身的值也会变为 0X1000,*p 表示获取地址 0X1000 上的数据,也即变量 a 的值。

普通变量和指针变量都是地址的助记符,虽然通过 *p 和 a 获取到的数据一样,但它们的运行过程稍有不同:

  • a 只需要一次运算就能够取得数据;
  • 而 *p 要经过两次运算,多了一层“间接”。

再举个详细例子你就更清楚了:

假设变量 a、p 的地址分别为 0X1000、0XF0A0,它们的指向关系如下图所示:

在这里插入图片描述

程序被编译和链接后,a、p 被替换成相应的地址

  • 使用 *p 的话,要先通过地址 0XF0A0 取得变量 p 本身的值,这个值是变量 a 的地址,然后再通过这个值取得变量 a 的数据,前后共有两次运算
  • 而使用 a 的话,可以通过地址 0X1000 直接取得它的数据,只需要一步运算

也就是说:使用指针是间接获取数据,使用变量名是直接获取数据,前者比后者的代价要高。


《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介

每日一更!

公众号、CSDN等博客:小菜狗编程笔记

谢谢点赞关注哈!目前在飞书持续优化更新~

日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小菜狗编程笔记

你的鼓励将是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值