目录
《小菜狗 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、详细解释(重点!!!)
我们拆开来看,如下图:
代码:
int a = 10;
创建了整型变量 a,内存中申请 4 个字节``,``用于存放整数 10
,上图中变量 a 的首地址是:0x0012ff40
;
代码:
int \*p = &a;
- 先看 p 左边写的是
int *
,说明指针变量 p 的类型是 int*
; - 其中 星号
*
是在说明p 是指针变量
,⽽前⾯的int
是在说明p 指向的是 int 类型的对象
。
- 总结就是
把变量 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*
,而不是 float
和 char
,它们是完全不同的数据类型,读者要引起注意。
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/后期小程序和机器学习!