指针初阶理解

指针初阶理解(0基础必看)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


1.指针是什么

1.1理解内存

1.1.1 内存单元的概念

内存单元:内存被划分为一个个小的内存单元。

一个基本的内存单元的大小是一个字节

如图: 在这里插入图片描述

每个内存单元都有自己的编号,内存单元的编号可以快速定位到一个内存的单位。

1.1.2内存单元的编号是如何产生的呢?

32位机器——> 32根地址线——>通电——>高电频/低电频——>1/0

编号是由硬件电路直接产生的

00000000000000000000000000000000

11111111111111111111111111111111

总共可以有2的32方次个内存编号

每个内存编号对应一个字节的内存单元 总共可以管理4GB 的内存。

64位机器也是如此,可以有2的64次方个内存编号,管理8GB的内存。

1.2代码理解指针

#include<stdio.h>
int main()
{
    int a = 0;
    return 0;
}

当我们创建一个int类型的变量a时,内存会给 变量 a分配4个内存单元

在这里插入图片描述

调试查看 a的内存,可以得知变量 a的地址是首编号。如图所示:
在这里插入图片描述

#include<stdio.h>
int main()
{
    int a = 0;
    int* pa = &a;  //存下a的地址
    return 0;
}

int 是指针类型,pa是指针变量,pa可以存放 a的地址,在代码中,pa存的是pa的地址(也就是存的是变量a的第一个内存单元的编号)。*

由于地址是32个0/1组成的,即32个bit位,4个字节的大小,所以指针变量的大小为固定的4个字节(32位机器下)

1.3 总结

指针是用来存放地址的,地址唯一表示一块地址空间。

指针的大小为4个字节(32位机器下) 8个字节(64位机器下)

2.指针和指针类型

2.1指针的解引用

#include<stdio.h>
int main()
{
    int a = 0x11223344;
    int* pa = &a;
    *pa = 0;            //将a的内容改为 00 00 00 00
    return 0;
}

*是解引用操作符
在这里插入图片描述

成功将a 4个字节的内容都改为 0。

2.2指针类型的影响

如果将int* 改为 char* 呢?

#include<stdio.h>
int main()
{
    int a = 0x11223344;
    char* pa = &a;
    *pa = 0;           
    return 0;
}

在这里插入图片描述

经过调试 我们可以得知 我们只改变了一个字节的内容

结论1: 指针类型觉得了在解引用时一次可以访问几个字节(指针权限)

#include<stdio.h>
int main()
{
    int a = 0x11223344;
    int* pa = &a;
    char* pc = &a;
    printf("%p\n",pa);
    printf("%p\n",pa+1);
    printf("%p\n",pc);
    printf("%p\n",pc+1);
    return 0;
}

可以得到结果:

在这里插入图片描述

我们可以通过编译结果 得出 pa+1 跳过了 4个字节,而pc+1却只跳过了1个字节。

结论2:指针类型决定了指针向前走一步或者向后走一步走多大的距离(单位是字节)

实际运用代码:打印数组

#include<stdio.h>
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int* pa = arr; //数组名是首元素的地址,数组是连续的(已学知识)
    int i= 0for(i=0;i<10;i++)
    {
        printf("%d ",*(p+i));
    }
    return 0;
}

2.3 总结

指针类型觉得了在解引用时一次可以访问几个字节(指针权限)

指针类型决定了指针向前走一步或者向后走一步走多大的距离(单位是字节)

3.野指针

3.1 野指针的概念

指针指向的位置是不可知的(随机的,不确定的,无明确限制的)

3.2野指针出现的情况

3.2.1 指针未初始化
#include<stdio.h>
int main()
{
    int a ;
    int* p;
    *p = 20;   
    return 0;
    
}

产生报错信息:在这里插入图片描述

3.2.2 指针越界访问
#include<stdio.h>
int main()
{
    int arr[10] = {0};
    int* p = arr;
    int i= 0;
    for(i=0;i<=10;i++)
    {
        *p = i;
        p++;
    }
    return 0;
    
}

产生异常信息:在这里插入图片描述

指针指向的地址超过了 arr的范围。(越界访问造成的野指针问题)。

3.2.3 局部生命周期导致的野指针问题
#include<stdio.h>
int* test()
{
    int a = 100;   //为a开辟空间
    return &a;     //返回 a 的地址
}
int main()
{
    int* p = test();
    printf("%d",*p);
    return 0;
}

尽管有的编译器该代码可以打印出 a 的值。但是 a 有自己的生命周期,变量 a 在test 函数结束之后会被销毁

所以 将局部变量的地址放在指针变量中 ,也会导致野指针出现

3.3 如何避免野指针

3.3.1指针初始化。

#include<stdio.h>
int main()
{
    int a = 10;
    int* pa = &a;
    int* p = NULL;
    return 0;
    return 0;
}

给不需要使用的指针赋值为空指针,在使用空指针时最后用if语句判断一下是否为空,切勿使用空指针。(检测指针的有效性)

3.3.2 小心数组越界。

3.3.3 在一个指针不需要使用时,及时赋值为空指针。

3.3.4 避免返回局部变量的地址

3.3.5指针使用之前检验其有效性

4 指针运算

4.1 指针 ± 整数

指针加减整数跳过多少个字节不仅与整数有关,与指针类型也有关

4.2 指针 - 指针

(+ 没有意义)

前提: 两个指针指向同一块连续的空间

#include<stdio.h>
int main()
{
    int a[10] = {0};
    printf("%d\n",&a[9] - &a[0]);
    printf("%d\n",&a[0] - &a[9]);
    return 0;
}

可以得到两个地址之间的元素个数。

写一个球字符串长度的函数:

#include<stdio.h>
int my-strlen(char* s)
{
    char* star = s;
    while(*s != '\0')
    {
        s++;
    }
    return s - star;//得到 数组之间的元素个数
}
int main()
{
    char arr[] = "abc";
    int len = my-strlen(arr);
    printf("%d",len);
    return 0;
}

4.3 指针的关系运算

指针可以进行关系运算 ,主要运用在数组相关的运算中

标准规定:

允许指针数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

在这里插入图片描述

5 指针和数组

可以通过指针访问数组

#include<stdio.h>
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int* p = arr;
    int i = 0;
    for(i=0;i<10;i++)
    {
        printf("%p = %p \n",p+i,&arr[i]);
    }
    return 0;
}

6.二级指针

直接代码理解:

#include<stdio.h>
int main()
{
    int a = 10;
    int* pa = &a;
    int** ppa = &pa;//二级指针存放一级指针的地址。
    int*** pppa = &ppa;//pppa就是三级指针。
    return 0;
}

也就是说 二级指针存的是一级指针的地址,多级指针存放的是低一级的指针变量的地址。

7指针数组

初阶简单理解:

存放指针的数组

  • 36
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小连~

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值