【C语言初阶】指针的详细解析(建议收藏)

C/C++
167
0
0
2024-02-25

⛺️生活的理想,就是为了理想的生活!

文章目录
  • 📋 前言
  • 💬 什么是指针?
  • 💭 指针的大小
  • 💭 指针类型的意义
  • 📖 指针的加减
  • 💬 野指针
  • 📖 野指针成因
  • 📝1. 指针未初始化
  • 📝 2. 指针越界访问
  • 📝 3. 指针指向的空间释放
  • 💬 如何规避野指针
  • 📝全篇总结

📋 前言

🌈hello! 各位宝子们大家好啊,今天给大家带来的指针篇的初阶,带你先从底层一步步理解指针! ⛳️指针可以说是C语言最重要的部分了!俗话说,函数是C语言的核心,那么指针可以说就是咱们程序的灵魂了。 📑不过不用但心读完这篇文章你就会发现指针也是那么回事,一学就懂!

💬 什么是指针?

⛳️大家都知道我们计算机存储东西都是存储在内存,或者存储在硬盘里面。那么我们该如何管理我们的内存呢?这时就有人说那么我们把内存划分位一个个的字节,然后每个字节给上编号。这样是不是就容易管理我们的内存了!

在这里插入图片描述

总结:指针就是地址,口语中说的指针通常指的是指针变量

⛳️ 那么我们用什么来管理地址的呢?这时指针就被发明出现了,指针用于专门存放我们的地址来的。
  • 存放可以改变的数据叫变量,那么存放地址的叫什么?
  • 指针是用来存放内存地址的变量,所以我们叫他指针变量。

大家都知道我们变量的创建和数组创建都是在内存中开辟了一块空间,那么就肯定有地址。如果那想把变量或数组的取出来就需要 & 取地址操作符!

📚 代码演示:

#include <stdio.h>
int main()
{
	int a = 100;
	int * pa = &a;//pa是专门用来存放地址(指针)的,
	char* pc = &a;//这里的pa就被称为指针变量
	return 0;
}

总结: 指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。

💭 指针的大小

地址的编号是怎么产生的:

对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);
  • 那么32根地址线产生的地址就会是:

在这里插入图片描述

每个地址标识一个字节,那我们就可以给(2^32Byte == 2^32/1024KB ==232/1024/1024MB==232/1024/1024/1024GB == 4GB)4G的空间进行编址。同样的方法,那64位机器,如果给64根地址线,那能编址多大空间,自己计算。

⛳️这时我们就会知道
  • 在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以 一个指针变量的大小就应该是 4 个字节。
  • 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是 8 个字节,才能存放一个地址。

📑 总结:

  • 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节
  • 我们也可以验证来看看!

📚 代码演示:

#include <stdio.h>
int main()
{
	printf("%d\n", sizeof(char*));
	printf("%d\n", sizeof(short*));
	printf("%d\n", sizeof(int*));
	printf("%d\n", sizeof(long*));
	printf("%d\n", sizeof(float *));
	printf("%d\n", sizeof(double*));

	return 0;
}

📑 代码结果:

在这里插入图片描述

💭 指针类型的意义

⛳️诶这时就会有铁汁们问了,既然指针的大小都是一样的那么指针有类型嘛?答案是有的指针也有各种各样的类型。
#include <stdio.h>
int main()
{
	char* pc = NULL;
	int* pi = NULL;
	short* ps = NULL;
	long* pl = NULL;
	float* pf = NULL;
	double* pd = NULL;

	return 0;
}

这里可以看到,指针的定义方式是: type + **说明了我们是指针变量 其实:

  • char* 类型的指针是为了存放 char 类型变量的地址。
  • short* 类型的指针是为了存放 short 类型变量的地址。
  • int* 类型的指针是为了存放 int 类型变量的地址
⛳️ 而这又有人会问了,指针的大小都是一样那么指针要这么多地址干嘛呢?
  • 其实指针的类型是为了解引用而设计
  • int 类型的解引用,就会访问4个字节
  • 而char 类型 解引用就只能访问一个字节

📚 代码演示:

在这里插入图片描述

🔥 总结:指针类型可以决定指针解引用的时候访问多少个字节(指针的权限)。

📖 指针的加减
⛳️ 前面讲了指针的类型决定了我们解引用的时候访问多少字节,而指针的类型还有一个作用!
  • 指针类型决定了指针 加或减 操作时的步长
  • 整形指针 +1 跳过4个字节
  • 字符指针 +1 跳过1个字节
  • 而其他指针也同理,下面我们就来验证一下

📚 代码演示:

在这里插入图片描述

这里大家就能看到对于不同类型的指针,我们进行加减所能操作的步长时有关系的!
  • 对于 type * p 的指针想要加 nn 是这样计算的
  • n*sizeof(type)

那么这么的用处是什么?假设我们有一串字符 "abcdef/n ” 如果指针指向第一个元素,那么就只能跳过一个字节访问 b

  • 但如果用int 类型的指针进行计算就会跳过4个字节
  • 指向字符 e 了,所以整形指针就应该存放 整形变量的地址
  • 这样才是最合理的。

在这里插入图片描述

🔥 总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

💬 野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
📖 野指针成因
📝1. 指针未初始化
局部变量指针未初始化,默认为随机值。所以它指向了一个不可预料的地址,当我们使用这个指针进行赋值时就会出现问题!
  • 你连指针指向哪里都不知道,结果你想用这个地址赋值!
  • 万一更改了程序配置呢? 这肯定是不允许的!
#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}
📝 2. 指针越界访问
这里明明我们数组只有10个元素,但是使用指针缺访问了却跳过了11个元素。
  • 访问了不属于它管理的地址,就是指针越界了
#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}
📝 3. 指针指向的空间释放
⛳️ 大家可以看一下下面这段代码,变量 a 属于栈区上的空间,所以test函数结束时在其内部创建的变量就会销毁,还给操作系统。
  • 那么这里p 所接收的地址就是一个野指针不确定的。
  • 所以我们打印出来的也是随机值。

📚 代码演示:

#include <stdio.h>((
int*  test()
{
	int a = 110;
	return &a;
}
int main()
{
	int* p = test();
	printf("");
	printf("%d\n",*p);

	return 0;
}

📑 代码结果:

在这里插入图片描述

💬 如何规避野指针

1. 指针初始化 2. 小心指针越界 3. 指针指向空间释放,及时置NULL 4. 避免返回局部变量的地址 5. 指针使用之前检查有效性

这些就是我们需要注意的点了,对于指针一定要避免成为空指针。释放完不用是要及时置为空。

  • 下面就为大家演示一下

📚 代码演示:

#include <stdio.h>
int main()
{
    int *p = NULL;//p是一个空指针,没有指向任何有效空间。   
    int a = 10;  //这个指针不能指针使用
    p = &a;
    if(p != NULL)
   {
        *p = 20;
   }
    return 0;
}

📝全篇总结

✅ 归纳: 好了以上就是关于什么是 指针和指针的注意事项就给大家讲解清楚了!有不会可以评论留言或私信博主呢! 什么是指针指针类型的意义野指针成因如何避免野指针 ☁️ 本章的内容就是这么多啦!