深入理解指针(1)
🎁个人主页:工藤新一¹
🔍系列专栏:C++面向对象(类和对象篇)
🌟心中的天空之城,终会照亮我前方的路
🎉欢迎大家点赞👍评论📝收藏⭐文章
文章目录
- 深入理解指针(1)
- 一、内存和地址
- 1.1内存
- 1.2如何理解编址
- 二、指针变量和地址
- 2.1取地址操作符(&)
- 三、指针变量类型的意义
- 3.1指针类型的解引用
- 3.2指针的算数运算
- 3.3void* 指针(auto)
- 四、指针的算数运算
- 4.1指针 +- 整数
- 4.2错误经验
- 4.3指针 - 指针
- 4.3.1用途 - 模拟实现 strlen 函数
- 4.3.2自增操作与while循环的执行逻辑
- 4.4指针的关系运算
- 4.4.1深度理解解引用*
深入理解指针(1)
指针是 C语言 中非常主要的知识,有了指针才能使 C语言 完成一些复杂的程序
指针就是内存编号或地址,在 C/C++
中,将具体的地址抽象的表达为指针
一、内存和地址
为了更好的管理,我们将内存划分为一个一个的内存单元
1.1内存
在讲内存和地址之前,我们想有个⽣活中的案例:
假设有⼀栋宿舍楼,把你放在楼⾥,楼上有100个房间,但是房间没有编号,你的⼀个朋友来找你玩, 如果想找到你,就得挨个房⼦去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给 每个房间编上号,如:
⼀楼:101,102,103...
⼆楼:201,202,203...
...
如果把上⾯的例⼦对照到计算机中,⼜是怎么样呢?
我们知道计算机上 CPU(中央处理器)
在处理数据的时候,需要的数据是在内存中读取的,处理后的 数据也会放回内存中,那我们买电脑的时候,电脑上内存是 8GB/16GB/32GB
等,那这些内存空间如 何⾼效的管理呢?
其实也是把 内存划分为⼀个个的内存单元(每个内存单元的大小是1个字节)。 计算机中常⻅的单位(补充): ⼀个⽐特位可以存储⼀个2进制的位1或者0
内存是计算机上的存储空间,程序运行在内存中,程序所使用的空间,也来源自内存,其中一个字节相当于一个内存单元
1.2如何理解编址
二、指针变量和地址
2.1取地址操作符(&)
创建变量的本质:向内存申请空间
向内存申请 4 个字节的空间,存储整形元素 10
int a = 10;
通过 &(取地址)
操作符,我们就能知道变量在内存中的存储位置
- 拆解指针类型
三、指针变量类型的意义
指针变量的⼤⼩和类型⽆关,只要是指针变量,在同⼀个平台下,⼤⼩都是⼀样的,为什么还要有各 种各样的指针类型呢?
其实指针类型是有特殊意义的,我们接下来继续学习
3.1指针类型的解引用
**结论:**指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)
- ⽐如:
char*
的指针解引⽤就只能访问⼀个字节,而int*
的指针的解引⽤就能访问四个字
3.2指针的算数运算
3.3void* 指针(auto)
在指针类型中有一种特殊的类型是 void*
类型,可以理解为无具体类型的指针(或者叫 泛型指针),这种类型的指针可以用来接收任意类型的地址,但也存在局限性,void*
类型的指针不能直接进行指针的 +-
整数,以及解引用的运算
这是因为,指针变量 pv
它只知道自己的数据类型是 void*
,但它指向的数据类型,它也含糊不清(因此,当解引用时 pv
不知道自己应访问多少字节:1?2?… 这是不确定的)
void*
- 暂时存储变量的地址
- 无法解引用操作
- 无法进行指针的算数运算
那么 void*
类型的指针到底有什么⽤呢?
⼀般 void*
类型的指针是使⽤在函数参数的部分,⽤来接收不同类型数据的地址,这样的设计可以实现 泛型编程 的效果,使得⼀个函数来处理多种类型的数据
四、指针的算数运算
指针的基本运算有三种,分别是:
- 指针 ± 整数
- 指针 - 指针
- 指针的关系运算
4.1指针 ± 整数
因为数组在内存中是连续存储的,因此只要得知首元素的地址,就可顺藤摸瓜找到数组中存储的所有元素
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
因为 指针变量 p
是指向数据类型为 int
的 数组arr
,因此 p + 1
移动的距离是 一个 int
注意:自增/自减操作会改变指针所指向的数组的位置
4.2错误经验
4.3指针 - 指针
注意:在进行 指针 - 指针 的算数运算中,两个指针需要指向同一块内存空间
4.3.1用途 - 模拟实现 strlen 函数
size_t
:unsigned int
无符号整形
size_t my_strlen(char* arr)
{size_t num = 0;char* src = arr;while (src[num] != '\0'){num++;}return num;
}size_t my_strlen(char* p)
{size_t num = 0;while (*p != '\0'){num++; p++;//指针 + 整数}return num;
}//最优版
size_t my_strlen(char* p)
{//先进行了自增操作(优先级)p->p' 后,返回 p//再对 p 进行解引用,*p != '\0'char* src = p; while (*p++);//包含'\0'//指针 - 指针return p - src - 1;//-1:p指向了'\0'
}size_t my_strlen(char* p)
{char* src = p; while (*p)//不包含'\0'{p++;};return p - src;
}
int main()
{ char arr[] = "abcdef";size_t len = my_strlen(arr);printf("%zd\n", len);system("pause");return 0;
}
4.3.2自增操作与while循环的执行逻辑
- 出现这样的情况在于 优先级:自增运算符 > 解引用运算符,因此即使
while(*p++);
,p
此时指向了‘\0’
,但因为运算符的优先级,依然会先执行了自增操作, 使p’
指向‘\0’
下一位置时,才返回p
(指向‘\0’
),进行while
循环的条件判断
4.4指针的关系运算
指针的关系运算:两个指针比较大小
4.4.1深度理解解引用*
总结:指针对于数组的访问是基于数组的存储,是存储在一块连续的存储空间上的,有了数组的首元素地址,就可以通过指针对整个数组进行访问
🌟 各位看官好,我是工藤新一¹呀~
🌈 愿各位心中所想,终有所致!