指针初阶(笔记)

  1. 指针是什么

  1. 指针和指针类型

  1. 野指针

  1. 指针运算

  1. 指针和数组

  1. 二级指针

  1. 指针数组

指针是什么

指针是内存中最小单元的编号也就是地址

我们口头的指针指的是指针变量;

int a=0;
int*pa=&a;

a是整型int类型有4个字节;

pa取得是a的第一个字节的地址(较小的地址)

pa是指针变量,这种变量专门存放地址的;

内存上有编号吗? 没有

都是通过电信号产生二进制序列作为编号找第几个内存空间

32位机器的内存会产生2^32种地址;

一个地址管理一个内存单元,所有可以管理2^32个字节

bit 8

byte 1024

kb 1024

mb 1024

gb 1024

tb 1024

...

2^32byte==4G

一个编号有32个bit位 就是4个byte 所以说地址需要4个字节存储

指针类型

如图

这种类型是有意义的

1.类型决定了,指针解引用时一次性访问几个字节

2.决定了指针偏移多少个字节(指针的步长)

字符char指针加1,跳过1个字节

整型int指针加1,跳过4个字节

其类型数据并不是只能被其类型指针控制,如图

可以发现int类型数据被char类型指针一个一个字节修改;

ps强制类型转换 int a char b 数较小(127~-128)时,a b相等 较大时数据改变

浮点强制类型转换为整型 会精度丢失

会发现指针类型的意义在于

指针变量不同的类型,其实提供了不同的视角来看待和访问内存

char*---一次访问1个字节,+1跳过1个字节

int*-----一次访问4个字节,+1跳过4个字节

类型也会对解引用时操作,指针类型区分对几个字节空间的操作

int 解引用4个字节

char解引用1个字节

野指针

概念:野指针就是指指针指向未可知的(随机的、不确定的、没有明确限制的)

野指针成因

指针未初始化

int*p;
*p=20;

p里面为随机值,*p=20;我们把20放到随机值里,这是有问题的

所以指针要有个明确指向,才可以解引用操作;

指针越界访问

在使用未申请的地址

int main()
{
    int*p=NULL;
    *p = 10;//NULL禁止写入数据
    return 0;
}

内存释放

内存开辟后返回地址后内存销毁

当test函数结束时,内存归还操作系统,返回的地址是野指针不可用其

访问其空间;

看代码

int* fun()
{
    int a = 10;
    return &a;
}

int main()
{
    int* p = fun();
    printf("%d\n", *p);
    return 0;
}

打印结果的确是10 ,只是因为地址内数据为被其他变量使用;

如果是

int* fun()
{
    int a = 10;
    return &a;
}

int main()
{
    int* p = fun();
    printf("%d\n", *p);
   printf("123456\n");
    printf("%d\n", *p);
    return 0;
}

再一次调用一个函数printf,开辟栈帧,将前一个函数fun栈帧数据覆盖此时&a地址的值将改变

如果规避野指针

  1. 指针初始化 --NULL或&变量

注意不可以对空指针NULL访问数据;

在使用指针时尽量判断if(指针变量!=NULL)

  1. 小心指针越界

  1. 指针指向的空间free后,指向空指针

int*p=&a;
free(p);
p=NULL;
  1. 避免返回临时变量的地址

int* fun()
{
    int a = 10;
    return &a;
}

int main()
{
    int* p = fun();//不要使用这样的临时变量的地址
    printf("%d\n", *p);
    return 0;
}

5.检查指针有效性

void fun(char*p)
{
   if(p!=NULL)
   {
      //使用指针;
   }
   else if(p==NULL)
   { 
      //不使用该指针;
    printf("p为空指针,函数直接结束");
    return;
   }
}

PS:程序运行时有些内存是操作系统要使用的(内核区域),用户不可使用的,被规定的,NULL规定不可访问内存

指针运算

指针+-整数

指针-指针

指针的关系运算

指针+-整数

先解引用vp放入0;然后再指针偏移vp++

指针-指针

前提,两个指针指向同一块空间;

int arr[10]={0};
prntf("%d",&arr[9]-&arr[0]);//结果为

指针减去指针得到的是连个指针的元素个数

指针的关系运算

看图

指针比较大小,vp>values[0];再去调整vp,调整后再赋值

如果--vp直接放入for括号内导致先赋值再去调整,会出现2个错误,1.对未开辟空间的使用2.values[0]无法被赋值就结束循环;

看简化代码将--vp放入的正确写法

但会违背标准定义

标准规定

可以向后(数组最后元素之后)越界地址比较,不可以向前(数组第一个元素之前)越界地址比较,注意无论前后都不可访问这种指针内的数据,会造成越界访问,只能进行地址比较;(看一眼银行,和抢银行);

指针和数组

1.指针和地址是不同的对象

指针(指针变量)是一种变量,存放地址用的,大小为4/8字节的(固定的)

数组是一种相同类型元素的集合,是可以放多个元素的,大小取决于元素个数和元素类型

看一个栗子

2.数组的数组名是数组首元素地址(除了sizeof(数组名)和&数组名);

int main()
{
    int arr[10] = { 0 };
    int* pa = arr;
    int i = 0;
    for (i = 1; i <= 10; i++)
    {
        *pa = i;
        pa++;
    }
    pa = arr;
    for (i = 0; i < 10; i++)
    {
        printf("%d ", pa[i]);
        //printf("%d ", *(pa + i));
        //printf("%d ", *(i+pa));
        //printf("%d ", i[pa]);
    }
    return 0;
}

说明[]是操作符

i和arr是两个操作数而已

使用arr[i]==i[arr];

二级指针

二级指针是什么?

用来保存指针的地址的

//指针基本使用
int a=10;
int*pa=&a;
*pa=20;//改变a的值
printf("%d",a);--->打印为20

取pa的地址

//指针基本使用
int a=10;
int*  pa=&a;  //pa是int*  
int**   ppa=&pa;//ppa是int**  
*pa=20;//改变a的值
printf("%d",a);--->打印为20

pa的第一个星告诉我pa是个指针 剩余的为int被指向的整型类型

ppa的第一个星告诉我ppa是个指针 剩余的为int*被指向的整型指针类型

所以pa是一级指针

ppa是二级指针

用*ppa改变a,首先*ppa找到pa,在解引用**ppa找到*pa的a

总结二级指针是用来保存一级指针的地址

指针数组

是数组还是指针

是数组!

char arr[5];//存放char类型的数组
int arr[5];//存放int类型的数组
int* arr[5]={&a,&b,&c,&d,&e};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云的小站

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

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

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

打赏作者

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

抵扣说明:

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

余额充值