十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
接下来创建一个变量
a
:int a = 4
,int
类型占四个字节,所以a
在内存中占4个内存单元:
可以用&
对a
进行取地址:&a
,a
是一个整形变量,占用4个字节,每个字节都有自己的地址,这里取出的地址是第一个字节的地址(较小的地址)
所以这里&a
取出值的是0x0012ff44
通过一下代码就能得出指针变量的大小
#includeint main()
{printf("%d\n", sizeof(char *));
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
return 0;
}
结论:指针大小在32位平台是4个字节,64位平台是8个字节
以上结论是根据程序结果得到的,接下来我们也可以通过物理层面去得到指针变量大小:
对于32位机器,它有着32根地址线,每跟线在寻址的时候会产生高电压和低电压也就是1或者0,有着32根地址线,也就是地址有着32歌比特位,1字节等于8比特,所以32位机器中地址占4个字节
这里我们可以继续算下去:32根地址线,就有2的32次方个地址,2^32Byte == 2^32/1024KB ==2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB
,所以在32位机器中,可以给4G的空间进行编址。
这里我们就明白:
总结:
指针有许多类型,如:int*
,short*
,char*
,float*
……
但是从前面得知指针的类型都是4或8字节大小,它们不会存在像如int
和char
不同类型有着不同占用空间的问题,既然指针类型大小一样,那么为什么不把指针设置成一个同一类型的指针并且可以接收不同的类型变量的地址呢?不同的指针类型都有什么意义呢?
首先看一下代码:
#includeint main()
{int a = 0x11223344;
int* pa = &a;
*pa = 0;
return 0;
}
调试后进入内存窗口,找到
a
的地址后可以看见在内存中a
中的存储的值为:44332211
,这样“倒着存放”的原因是在Visual studio这个IDE中采取小端存储,如不懂大小端存储,👉可点击跳转
然后继续运行下一行代码,会发现*pa = 0
使内存中4个字节内容变为0
接着再看一个代码:
#includeint main()
{int a = 0x11223344;
char* pa = &a;
*pa = 0;
return 0;
这个代码与上面代码不同的一点是这次
pa
指针变量是char
类型的,上一个代码中的类型为int
类型的
还是调试后进入内存窗口,找到a
的地址后可以看见在内存中a
中的存储的值为:44332211
接着运行,会发现,内存中只有
44
变为了00
,也就是只有一个字节的内容发生了改变
这两个代码比较得出结论:
int*
类型的解引用会对4个字节内容进行操作char*
类型的解引用会对1个字节内容进行操作float*
类型的解引用会对4个字节内容进行操作double
类型的解引用会对8个字节内容进行操作所以,我们可以通过不同的指针变量按需求对不同字节大小内容进行操作
观看一下代码:
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;
}
得出结果:
可以看出,前两个地址大小差4,后两个地址大小差2pa
的类型为int*
,pa+1
的地址增加了4,pc
的类型为char*
,pc+1
的地址增加了1
得出结论:
野指针概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因
- 指针未初始化
#includeint main()
{int *p;
*p = 20;
return 0;
}
这里的指针p
在定义的时候没有初始化,默认为随机值,也就是指针指向位置不可知。
以随机值为地址,解引用时需要找到那个地址处,是很危险的
此程序在编译器里不会被编译成功,会警告:使用了未被初始化的内存p
- 指针越界访问
#includeint main()
{int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{*(p++) = i;
}
return 0;
}
在arr
数组内有10个元素,循环时,到下标为10的时候,指针指针指向的范围超出数组arr的范围时,p就是野指针
3.指针指向的空间释放
int* test()
{int a = 10;
return &a;
}
int main()
{int* p = test();
printf("%d\n", *p);
return 0;
}
在test
函数中,返回int
类型a
的地址,在主函数中用p
接受这个地址,但是当test
运行完return
语句后,在test
函数中对于变量开辟的空间就会归还给系统,此时&a
已经不存在了,所以p
为野指针
p = NULL
if(p!=NULL)
指针加减整数在前面指针类型意义里提到,这里不多说
这里看一个代码:
int main()
{int values[5];
int * vp;
for(vp = &values[0]; vp< &values[5];)
{*vp++ = 0;
}
}
这个代码很简单,就是通过指针,逐步把数组中元素值赋值为0
这里有一点值得注意的:
*vp++ = 0;
,++
优先级比*
高,又由于++
是后置,先用再加加。
vp
的初始值为&values[0]
,所以才会从values[0]
开始赋值,接着++
,再对下一个位置赋值。若改为前置++,则会先加加,再赋值,就会倒置
values[0]
位置处未被赋值。
指针-指针,前提是:两个指针要指向同一块空间,得到的结果的绝对值是两个指针之间元素个数
int main()
{int arr[10] = {0 };
printf("%d", &arr[9] - &arr[0]);
return 0;
}
输出结果:
这里我们可以利用指针减指针来模拟strlen
函数
假设有一个字符串abcdefghi
,在内存中实际存储的是a b c d e f g h i \0
,所以只要找到首元素的地址和\0
的地址,相减就能得到字符串的长度
代码如下:
int my_strlen(char* s)
{char* begin = s;
while (*s!='\0')
{s++;
}
return s - begin;
}
int main()
{char arr[] = "abcdefghi";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
以数组为例,数组首元素地址是小于数组除首元素其他元素地址
但是标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。
数组尾部的地址不是最后一个元素的地址,而是下标为数组长度处的地址
如上图:可以用&arr[6]
和指针vpp
与数组中其他地址进行比较,但是不可以用指针vp
进行比较
通俗来讲就是:可以用数组后边的地址比较,但是不可以用数组前面的地址比较。
指针与数组的关系主要在这篇文章里👉数组与地址,数组名到底是什么?
我们观察以下代码
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10 };
//用数组下标遍历数组元素
for (int i = 0; i< 10; i++)
{printf("%d ", arr[i]);
}
printf("\n");
//利用指针遍历数组元素
int* p = arr;
for (int i = 0; i< 10; i++)
{printf("%d ", *(p + i));
}
}
因为数组名就是数组元素首地址,所以在这个程序里arr
与p
是完全相同的。
同时这里可以发现用数组下标遍历数组和利用指针遍历数组都可以遍历,所以arr[i]
和*(p+i)
是等价的
也就是有一个指针p
,p[i]<=>*(p+i)
并且我们还可以推理:因为加法有交换律,所以*(p+i)
和*(i+p)
肯定是是等价的,通过*(i+p)
又可以推出i[p]
所以p[i]
是可以写成i[p]
的,只是因为i[p]
这种写法太过于逆天,所以不常见。
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
这就是二级指针
。
int main()
{int a = 10;
int* pa = &a; //一级指针
int** ppa = &pa; //二级指针
return 0;
}
上面代码中的ppa
就是二级指针
二级指针有两个*
,怎么理解呢?
先看一级指针 ,
int* pa = &a
,一级指针中的那个*
就表示pa
是一个指针,剩下的那个int
表示指针pa
指向一个int
类型变量
二级指针也同理int** ppa = &pa
,离ppa
近的那个*
表示ppa
是一个指针变量,剩下的int*
表示ppa
这个指针指向int*
类型
二级指针的解引用也和一级指针一样:**ppa
指针的内容还有很多
还有 字符指针 ~ 指针数组 ~ 数组指针 ~ 函数指针 ~~~~ 等等
~Coming soon~
🎸🎸🎸
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧