目录
1.指针是什么?
指针是什么?
指针理解的
2
个要点:
1.
指针是内存中一个最小单元的编号,也就是地址
2.
平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量
理解内存
指针变量
我们可以通过&(取地址操作符)取出一个变量在内存中的地址,并把这个地址存放在一个变量中
这个变量就是指针变量。
- #include<stdio.h>
- int main()
- {
- int a = 10;//创建一个临时变量
- int* pa = &a;//用&操作符找到内存中a的地址,并把这个地址存放在一个变量中。
- //这里pa 就是一个指针变量,类型为int型
- return 0;
- }
summary
指针变量:能用来存放地址的变量。
扩展:
最小的一个单元格是多大?
一个字节
如何编码形成地址?
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0)
那地址将会是:
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000001
……
1111111111111111111111111111111111111
这里将会出现2^32中电压表达式,即2^32个地址。
每个地址给予一个字节大小的空间,那么根据进制转换
2^32 type = 4GB
同理对于64位机器,也可使用同样的方法。
总结:
1.指针是用来存放地址的,地址是唯一标识一块地址空间的
2.指针的大小在32位(X86)平台是4个字节,在64位上是8个字节。
2.指针和指针类型
指针类型,针对不同的变量类型,指针类型也分多种
变量类型 | 指针类型 |
int | int * |
char | char* |
short | short* |
... | ... |
type | type * |
编写一个程序并调试
a的地址,内存中存放数据
修改数据
只有最低位被修改为0
由此可知:指针类型决定解引用时,一次能访问几个字节(指针的权限)。
指针类型 | 访问权限 |
int* | 4 |
char* | 1 |
double* | 8 |
…… | …… |
- #include<stdio.h>
-
- int main()
- {
- int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
- int* pa = arr;//数组名就是数组首元素地址
- char* pc = arr;
- printf("pa = %p\n", pa);
- printf("pc = %p\n", pc);
- printf("pa+1 = %p\n", pa + 1);
- printf("pc+1 = %p\n", pc + 1);
-
- return 0;
-
- }
运行结果
打印的地址都相同,int* +1 走4个字节,char*+1走1个字节。
结论:指针类型决定指针向前或向后走一步走多大距离(单位:字节)
3.野指针
定义:野指针就职指针指向的位置是不可知的
野指针成因:
1.未初始化
- #include<stdio.h>
-
- int main()
- {
- int* pa;
- *pa = 10;
- return 0;
- }
2.越界访问
- #include<stdio.h>
-
- int main()
- {
- int arr[5] = { 0 };
- int* p = arr;
- for (int i = 0; i <= 5; i++)
- *p++ = i;//当越界访问时,就形成了野指针了。
- return 0;
- }
3.指针指向的空间释放
- #include<stdio.h>
- void test()
- {
- int a;
- int* pa = &a;//局部指针变量,出了作用域生命周期结束。
- //原来分配的内存空间将会被回收
- *pa = 10;
- }
- int main()
- {
- test();
- printf("%d\n", *pa);//非法访问地址,这时候*pa就成了野指针
- return 0;
- }
如何规避野指针
1.
指针初始化
2.
小心指针越界
3.
指针指向空间释放即使置
NULL
4.
避免返回局部变量的地址
5.
指针使用之前检查有效性
- #include<stdio.h>
-
- int main()
- {
- int a;
- int* p = NULL;
- p = &a;
- if (p != NULL)//判断p是否为空指针
- *p = 10;
- printf("%d\n", *p);
- return 0;
- }
4.指针运算
1.指针+-整数
意义:向前或向后走多大的距离
- #include<stdio.h>
-
- int main()
- {
- int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
- int* p = arr;
- for (int i = 0; i < 10; i++)
- printf("%d ", *(p + i));
- return 0;
- }
2.指针-指针
- //计算字符串长度
- #include<stdio.h>
- int my_strlen(char* str)
- {
- char* ret = str;
- while (*ret != '\0')
- ret++;
- return ret - str;
- }
- int main()
- {
- char arr[] = "abcdefg";//7
- printf("%d\n", my_strlen(arr));
- return 0;
- }
可知:指针-指针计算的是指针间的距离
3.指针的关系运算
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。
5.指针和数组
之前提及过,数组名时数组首元素地址
验证
- #include<stdio.h>
-
- int main()
- {
- int arr[10] = { 1,2,3,4,5,6,7,8,9,10};
- printf("%p\n", arr);
- printf("%p\n", &arr[0]);
-
- return 0;
-
- }
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。
- #include <stdio.h>
- int main()
- {
- int arr[] = {1,2,3,4,5,6,7,8,9,0};
- int *p = arr; //指针存放数组首元素的地址
- int sz = sizeof(arr)/sizeof(arr[0]);
- for(i=0; i<sz; i++)
- {
- printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);
- }
- return 0; }
所以
p+i
其实计算的是数组
arr
下标为
i
的地址。
那我们就可以直接通过指针来访问数组。
6.二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
这就是
二级指针
。
上代码
- #include<stdio.h>
-
- int main()
- {
- int a = 10;
- int* pa = &a;//一级指针
- int** ppa = &pa;//二级指针, 类型为int*
- return 0;
- }
二级指针运算
*pa先对pa进行解引用处理,找到的是pa,*ppa访问的就是pa
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a
- #include<stdio.h>
-
- int main()
- {
- int a = 10;
- int* pa = &a;//一级指针
- int** ppa = &pa;//二级指针, 类型为int*
- **ppa = 30;
- printf("%d\n", a);//30
- return 0;
- }
7.指针数组
指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组
那指针数组是怎样的?
int*
arr3
[
5
];
//
是什么?
arr3
是一个数组,有五个元素,每个元素是一个整形指针。