(1)指针是什么?
1. p_a也是一个变量,一个int类型指针变量在内存分配8个字节(64位的操作系统)
p_a也是变量,开辟的空间也有地址,如何表示p_a的地址?&p_a
pp_a也是一个变量,保存地址(指针变量)
指针变量在内存中都是占有四个字节的空间(x86)
2. 取到地址的内容,使用解引用操作符
p_a存储的是边来定a在内存中分配空间的起始地址,是可以对地址进行操作的
指向的地址是对应变量的类型------这里是int类型
3.指针大小在32位平台是4个字节,在64位平台是8个字节。
一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。
将一个字节给一个对应的地址是比较合适的
4.在32位的机器上,地址是32个0或1组成的二进制序列,那地址就得用4个字节的空间来存储,所
以一个指针变量的大小是4个字节。
在64
位的机器上,地址是
64
个
0
或
1
组成的二进制序列,那地址就得用
8
个字节的空间来存储,所以
一个 指针变量的大小是8
个字节。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 10;
int* p_a = &a;
//p_a也是一个变量,一个int类型指针变量在内存分配8个字节(64位的操作系统)
printf("%zd\n", sizeof(p_a));
//p_a也是变量,开辟的空间也有地址,如何表示p_a的地址?&p_a
printf("p_a=%p\n", &p_a);
//pp_a也是一个变量,保存地址(指针变量)
int* *pp_a= &p_a;
//保存指针变量的变量在内存中占有几个字节
printf("%zd\n", sizeof(pp_a));
//指针变量在内存中都是占有四个字节的空间(x86)
printf("%zd\n", sizeof(int*));
//取到地址的内容,使用解引用操作符
printf("");
//p_a存储的是边来定a在内存中分配空间的起始地址,是可以对地址进行操作的
printf("p_a=%p\n", p_a);
//指向的地址是对应变量的类型------这里是int类型
printf("p_a+1=%p\n", p_a+1);
//0地址NULL
return 0;
}
(2)指针和指针类型
1.指针类型决定了对指针解引用时访问几个字节
指针类型并不决定指针所占内存的大小,指针类型决定了指针被解引用时访问几个字节。
int*
的指针被解引用时访问
4
个字节,
char*
的指针被解引用时访问
1个字节。
2.指针类型决定了指针的步长,+1跳过几个字节,也就是向后访问几个字节
int main()
{
int a = 0x11223344;
int* p = &a;
char* pc = &a;
printf("%p\n", p);
printf("%p\n", p + 1);
printf("%p\n", pc);
printf("%p\n", pc + 1);
return 0;
}
综上所述,指针类型是有意义的,指针类型并没有决定指针变量所占内存空间大小,而是
(
1
)指针类型决定了指针在被解引用时访问内存空间几个字节
(
2
)指针类型决定了指针的步长,
+1-1
向后向前访问几个字节,即跳过几个字节
(3
)
float*
和
int*
解引用时同样都是访问
4
个字节,但却不能混用,两者有很大的区别。
3、不要将指针大小和指针访问内存单元空间大小记混,两者完全不同且无任何关系
char*
访问
1
个字节,
int*
访问
4
个字节,
short*
访问
2
个字节
(3)野指针
1.野指针的成因
1.指针未初始化
#include <stdio.h>
int main() {
int a; // 局部变量不初始化,默认是随机值
int* p; // 局部指针变量不初始化,默认也是随机值
*p = 100;
printf("%d", *p);
return 0;
}
2.指针越界访问
#include <stdio.h>
int main() {
int arr[5] = { 0 };
int* p = arr;
for (int i = 0; i < 8; i++) {
// 当指针指向的范围超出数组arr的范围时,p就是野指针。
p++;
}
return 0;
}
3. 指针指向的空间释放
#include <stdio.h>
int* test() {
int a = 10;
return &a;
}
int main() {
int* p = test();
*p = 20;
printf("%d\n", *p);
}
2.如何规避野指针:
1.
指针初始化
,
int* p = NULL;
2.
小心指针越界
3.
指针指向空间释放,及时置空
4.
指针使用之前检查有效性
(4)指针运算
<1>指针+-整数
<2>指针-指针
:
指针
-
指针会得到两个指针中间元素的个数
.
<3>指针的关系运算
(5)指针和数组
int arr[] = { 1,2,3,4,5,6,7 };
int* p = arr; // p存放的是数组首元素的地址
int size = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < size;i++) {
printf("&arr[%d]=%p <-----> p+%d = %p\n",i,&arr[i],i,p+i);
}
p+i 其实就是数组arr下标为i的地址,因此可以通过指针来访问数组。
有两个例外:
1. &
数组名中,数组名不是首元素的地址,数组名表示整个数组,
&
数组名,取出的是整个数组的地址。
2. sizeof(
数组名
)
数组名表示整个数组,
sizeof(
数组名
)
计算的是整个数组的大小。
(6)二级指针
(7)指针数组
指针数组是存放指针的数组
int main() {
int a = 1;
int b = 2;
int c = 3;
int* pa = &a;
int* pb = &b;
int* pc = &c;
/*
整型数组--->存放整型
字符数组--->存放字符
指针数组--->存放指针
*/
int* arr[3] = { pa,pb,pc }; // 指针数组
// 遍历指针数组
for (int i = 0; i < 3;i++) {
printf("%p:%d\n",arr[i],*arr[i]);
}
return 0;
}