大家好,我是Beilef,许久未见还请多多关照。
前言
今天带给大家的是指针的第一篇。后续还会有下或者还会有中。
指针嘛,对于新手还是不容易接受的。指针就是一把双刃剑,用的好了指哪打哪,用的不好打哪哪不中。
我会尽可能讲的通透一点。O(∩_∩)O。
提示:以下是本篇文章正文内容,下面案例可供参考
一、指针是什么
简单一句话:指针就是保存地址的。
说一个关于我们生活的例子:就像你去一个新的单身公寓,,有那么多房间,如果没有标号你的朋友过来找你他只能一个一个找。但是如果这个公寓的所有房间都有编号那么你的朋友就能很轻松找到你。
如果把上⾯的例⼦对照到计算中,⼜是怎么样呢? 我们知道计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数 据也会放回内存中,那我们买电脑的时候,电脑上内存是8GB/16GB/32GB等,那这些内存空间如何⾼ 效的管理呢? 其实也是把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节。 计算机中常⻅的单位(补充): ⼀个⽐特位可以存储⼀个2进制的位1或者0
bit - ⽐特位 byte - 字节 KB MB GB TB PB
1 byte = 8bit 1KB = 1024byte 1MB = 1024KB 1GB = 1024MB 1TB = 1024GB 1PB = 1024TB
每个内存单元也都有⼀个编号(这个编号就相当 于你的房间的编号),有了这个内存单元的编 号,CPU就可以快速找到⼀个内存空间。在生活中我们把⻔牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址。C语⾔中给地址起 了新的名字叫:指针。 所以我们可以理解为: 内存单元的编号 == 地址 == 指针
二、指针的运用
1.指针变量和地址
理解了内存和地址的关系,我们再回到C语⾔,在C语⾔中创建变量其实就是向内存申请空间,⽐如:
⽐如,上述的代码就是创建了整型变量a,内存中 申请4个字节,⽤于存放整数0,其中每个字节都 有地址.
那我们如何能得到a的地址呢? 这⾥就得学习⼀个操作符(&)-取地址操作符
2.指针变量和解引⽤操作符(*)
指针变量 那我们通过取地址操作符(&)拿到的地址是⼀个数值,⽐如:0x006FFD70,这个数值有时候也是需要 存储起来,⽅便后期再使⽤的,那我们把这样的地址值存放在哪⾥呢?答案是:指针变量中。 ⽐如:
指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址。
2.2 如何拆解指针类型
我们看见p的左边是 int *。这里*就说明他是指针变量。int 是他指向的类型。
解引用操作符
我们将地址保存起来,未来是要使⽤的,那怎么使⽤呢? 在现实⽣活中,我们使⽤地址要找到⼀个房间,在房间⾥可以拿去或者存放物品。 C语⾔中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;
printf("a=%d\n", a);
printf("*p=%d\n", *p);
*p = 0;
printf("*p=%d\n", *p);
return 0;
}
代码运行如下:
上⾯代码中第7⾏就使⽤了解引⽤操作符, *pa 的意思就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量了;所以*pa = 0,这个操作符是把a改成了0. 有同学肯定在想,这⾥如果⽬的就是把a改成0的话,写成 a = 0; 不就完了,为啥⾮要使⽤指针呢? 其实这⾥是把a的修改交给了pa来操作,这样对a的修改,就多了⼀种的途径,写代码就会更加灵活, 后期慢慢就能理解了。
3.指针变量类型及意义
3.1指针大小
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
printf("%zd\n", sizeof(char*));
printf("%zd\n", sizeof(short*));
printf("%zd\n", sizeof(int*));
printf("%zd\n", sizeof(double*));
return 0;
}
指针变量类型的意义 指针变量的⼤⼩和类型⽆关,只要是指针变量,在同⼀个平台下,⼤⼩都是⼀样的,为什么还要有各 种各样的指针类型呢? 其实指针类型是有特殊意义的,我们接下来继续学习
#include <stdio.h>
int main()
{
int n = 0x11223344;
//char *pc = (char *)&n;
int *pi = &n;
*pi = 0;
return 0;
}
调试我们可以看到,代码会将int* 中n的4个字节全部改为0,但是char*中只是将n的第⼀个字节改为0。 结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。 ⽐如: char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节。
3.2指针的+-整数
先看一段代码
我们可以看出, char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。 这就是指针变量的类型差异带来的变化。 结论:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)。
3.3 void* 指针 在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指 针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进 ⾏指针的+-整数和解引⽤的运算。
当我们使用char*接受int类型时会显示不兼容,但是使用viod就不会出现这种现象。
如图所示
虽然使用void可以保存别的指针类型,但是不能进行直接运算
4.指针的运算
指针的基本运算有三种,分别是
: • 指针+- 整数
• 指针-指针
• 指针的关系运算
指针+- 整数 因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸⽠就能找到后⾯的所有元素。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = &arr[0];
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));//p+i 这⾥就是指针+整数
}
return 0;
}
指针减去指针得到的是他们之间的个数
指针的关系运算
6. 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针形成的原因主要有这几个
1.没有初始化。
2.越界访问.
3.指向的内容被释放。
只要我们注意野指针的问题那么我们在使用的时候就大概不会有问题。
如何规避野指针
1. 指针初始化 如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL. NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址 会报错。
2.⼩⼼指针越界 ⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是 越界访问。
3.指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性 当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使⽤这个指针访问空间的 时候,我们可以把该指针置为NULL。因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问, 同时使⽤指针之前可以判断指针是否为NULL。 我们可以把野指针想象成野狗,野狗放任不管是⾮常危险的,所以我们可以找⼀棵树把野狗拴起来, 就相对安全了,给指针变量及时赋值为NULL,其实就类似把野狗栓前来,就是把野指针暂时管理起 来。 不过野狗即使拴起来我们也要绕着⾛,不能去挑逗野狗,有点危险;对于指针也是,在使⽤之前,我 们也要判断是否为NULL,看看是不是被拴起来起来的野狗,如果是不能直接使⽤,如果不是我们再去 使⽤。
4.避免返回局部变量的地址 如造成野指针的第3个例⼦,不要返回局部变量的地址
总结
指针是新手的第一个boss,当然我也有不足的地方。那么请大家把不足之处在评论区告诉我吧
我们一起加油!!!