前言
大家好,我们又见面了,本次带来的内容是浅谈指针,与大家讲讲指针相关的内容,是关于指针入门篇的,在后续还会为大家补上指针进阶的内容,尽情期待哦。
一.指针定义
1.指针是内存中一个最小单元(1个字节)编号,就是地址。
2.平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
通俗的来说,我们可以通过&取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量。如下图所示,十分简单的介绍了指针,内存,地址。
一般一个字节对应一个地址,对于32位的机器,就有2^32次方个地址,即有2^32Byte ,即为4G空间进行编址,所以在32位机器上,地址用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。同理,64位机器指针变量大小为8个字节。
二.指针类型
指针类型决定了指针进行解引用操作时,一次性访问几个字节
1.如果是char*的指针,解引用访问一个字节,存放char类型的地址。
2.如果是int*的指针,解引用访问4个字节,存放short类型的地址。
3.如果是float*的指针,解引用访问4个字节,存放int类型的地址。
1. 指针+-整数
指针的类型决定了指针向前或者向后走一步有多大,看下图:
由上图可以看出pi,pc,&n是输出是一样的,因为pi是整形类型,一次跳过四个字节;pc是char类型,一次跳过一个字节,&pi取出的是pi的地址,&pi+1是跳过它,即跳过四个字节。
2.指针解引用
指针的类型决定了,对指针解引用时一次能操作几个字节。
char*类型解引用就只能访问一个字节,而int*的指针解引用就能访问4个字节,看下面这串代码
int main()
{
int a = 0x11223344;
char* pc = (char*)&a;
int i = 0;
for (i = 0; i < 4; i++)
{
*pc = 0;
pc++;
}
}
将int类型的地址通过强制类型转换,使其存放在char类型的指针中,此时char类型一次访问一个字节,我们来看看这里是怎么变化的,看下图,由于我电脑是小端存储,所以它是44 33 22 11,如下图
记过一次循环后,此时44就变成了00,如下
之后使变成00 00 00 00就停止,此时i也变为了4。
三.野指针
野指针就是指针期间指向的位置是不可知的。
1.野指针形成的原因
a.指针为初始化
看下面这个代码,int* p未初始化,这就是野指针。
int main()
{
int* p;
*p = 20;
return 0;
}
b.指针越界访问
看下面的代码,此时数组访问越界了,超出范围了,p就是野指针。
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 11; i++)
{
*(p++) = i;
}
return 0;
}
c.指针指向空间的释放
通过free函数使得指针空间的释放,导致形成野指针,而这又分为4种
使用free释放非动态开辟的空间
如下面代码,int a【10】是在栈区上创建的局部变量,free不能释放在栈区上的变量,这里就会变成野指针。
int main()
{
int a[10] = { 0 };
int* p = a;
free(p);
p = NULL;
return 0;
}
使用free释放动态内存开辟的一部分
如下面代码所示,因为*p++一直是在增加的,在释放时p是从中间开始释放的,中途释放是存在风险的,而且此时没人知道这块空间的起始位置,这就存在了内存泄漏的关系。
int main()
{
int* p = malloc(10 * sizeof(int));
if (p == NULL)
{
return 1;
}
int i = 0;
for (i = 0; i < 5; i++)
{
*p++ = i;
}
free(p);
p = NULL;
return 0;
}
对同一块动态内存的重复释放
如下面的代码,使用两次free造成动态内存的重复释放,如果要使他变正确,最好是在第一个free后面叫p=NULL,使p为空。
int main()
{
int* p = (int*)malloc(100);
free(p);
free(p);
return 0;
}
动态开辟内存忘记释放
看下面代码,因为出test函数的时候,p会被销毁,malloc开辟的空间就找不到了。
void test()
{
int* p = (int*)malloc(100);
if (p == NULL)
{
return;
}
}
int main()
{
test();
return 0;
}
四.指针和数组
1.指针和数组是不同的对象
指针是一种变量,存放地址的,大小是4/8个字节的。
数组是一组相同类型元素的集合,是可以放多个元素的,大小是取决于元素个数和元素的类型的。
2.访问形式不同
数组的数组名是数组首元素的地址,地址是可以放在指针变量中 。
可以通过指针访问数组。
总结: ;允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
五.指针数组
指针数组是数组,是存放指针的数组
我们可以通过使用指针数组来模拟二维数组,如以下代码
int main()
{
int a[] = { 1,2,3,4 };
int b[] = { 2,3,4,5 };
int c[] = { 3,4,5,6 };
int* arr[3] = { a,b,c };
}
这就模拟了int arr[3][4]这二维数组,arr是一个数组,有3个元素,每个元素是一个整形指针,我自己画了一个图,能更清楚的认识指针数组。
总结
本次指针入门的内容到这就结束了,在之后还有复杂指针的讲解,那是一个大块,下次博客内容就是结构体了,尽情期待。看到这里,不关注,点赞一下,你们的关注点赞是博主码文的动力 😍,各位点赞的小伙伴,偷偷告诉你,作者会在评论区回访哦⊙∀⊙!