【C语言】指针剖析(1)

©作者:末央&
©系列:C语言初阶(适合小白入门)
©说明:以凡人之笔墨,书写未来之大梦

在这里插入图片描述

一、概念

什么是指针,这个东西其实就相当于生活中你的住址,比如说你住到重庆xx街道xx小区。

所以:指针就是地址,地址就是指针

既然我们知道指针就是地址,那么我们怎么获取地址呢。这就要用到我们的&操作符,int a; &a此时就在内存中申请4个字节的空间(因为是int)在这里插入图片描述

二、指针类型

指针类型例如:int* ,char*,float*;怎么理解呢

例如int* pa,*号在说明pa是指针变量,而前面的int说明pa指向的是int类型的对象

三、解引用操作符

在现实生活中,如果你给了我地址,那么我是不是要根据导航来访问你呀,同样在c语言中,想要访问指针那就必须要通过*(解引用操作符)导航地址

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

*pa就是导航到a的地址,可以理解*pa现在就是变量a了

四、指针变量的大小

电脑分别有32地址总线和64地址总线,32地址总线转换成数字信号后变为1或0,就是32个bit位就是4个字节(1字节=8bit),那么64地址总线则是8个字节

结论:
• 32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
• 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
• 注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的。

五、指针变量类型的意义

既然指针变量的大小都是一样的,指针变量类型又有什么用途呢,我们知道int 4个字节,double 8个字节都有区分。

1.各类型访问大小

话不多说咱们先上代码:

在这里插入代码片/代码1
#include <stdio.h>
int main()
{
 int n = 0x11223344;
 int *pi = &n; 
 *pi = 0; 
 return 0;
}

在这里插入图片描述

}
//代码2
#include <stdio.h>
int main()
{
 int n = 0x11223344;
 char *pc = (char *)&n;
 *pc = 0;
 return 0;

在这里插入图片描述

不难看出,我们int *类型的指针一次访问了4个字节,而char *类型的指针只访问了1个字节

综上:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。

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

在这里插入图片描述

指针+ - 整数也受指针类型的影响。指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)

2.空指针

空指针就是void类型的指针,这种指针可以接受任何类型的地址,但是 void 类型的指针不能直接进⾏指针的±整数和解引⽤的运算。

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

这里就体现了void*指针不能进行运算的特性

但不是意味着他没有作用,他用于函数中的形参来接受不同的地址,以实现泛型编程效果,我们后面会了解到。

六、const修饰指针

这个不难理解,就相当于你房间的门,如果你没反锁,那么我在外面就可以直接打开,如果你反锁了,我就无法打开了。const就相当于这把锁

1.*号前修饰

int n = 10;
 int m = 20;
 const int* p = &n;
 *p = 20;
 p = &m;

这里通过调试可知,*p是不可以修改的了,但是p还可以修改,就相当于你房间门有点特殊,大门中还有个小门,我现在把大门(*p)锁住了,但是小门§还是可以打开的吧。

这里是引用 在前面我们就不能修改变量的值了(*o=20)

]

2.*号后修饰

与第1个例子相反,如果在后面我的小门被锁住了,那么我们就不能更改p的地址了。

七、野指针

我们前面说到,指针就相当于我们生活中的住址,但是住址会有人住,也有人不住。野指针就是那个没人要的穷地方。我们不能随便去没人的地方,所以我们应该避免野指针。
那么造成野指针的原因:
1.指针未初始化

#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
 *p = 20;
 return 0;
}

2.指针越界访问

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 int *p = &arr[0];
 int i = 0;
 for(i=0; i<=11; i++)
 {

 *(p++) = i;
 }
 return 0;
}

3.指针指向的空间释放

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

这里要注意知识点,我们知道局部变量是存放在栈区,但是局部变量的生命周期是整个函数的范围内,如果出了所在的函数,则会被销毁。这里调用完test函数n的内存空间已经被销毁,如果再去解引用p就会非法访问

那么野指针那么危险,我们该如何避免出现野指针呢。这里推荐不用指针把指针赋值为NULL值并且指针一定要记得初始化。

int main()
{
 int arr[10] = {1,2,3,4,5,67,7,8,9,10};
 int *p = &arr[0];
 for(i=0; i<10; i++)
 {
 *(p++) = i;
 }
 //此时p已经越界了,可以把p置为NULL
 p = NULL;
 //下次使⽤的时候,判断p不为NULL的时候再使⽤
 //...
 p = &arr[0];//重新让p获得地址
 if(p != NULL) //判断
 {
 //...
 }
 return 0;
}

我们可以把NULL看做标识牌,如果是NULL表示这个住址无人居住,就不要进去。

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值