©作者:末央&
©系列: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表示这个住址无人居住,就不要进去。