1. 指针是什么?
指针是什么? 指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量
int age;// 定义一个普通变量
num = 10;
int *pnAge; // 定义一个指针变量
pnAge = &age;
指针变量 我们可以通过&(取地址操作符)取出变量的内存真实地址,把地址可以存放到一个变量中,这个 变量就是指针变量
总结:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那这里的问题是:
一个小的单元到底是多大?(1个字节)
指针是用来存放地址的,地址是唯一标示一块地址空间的。
指针的大小在32位平台是4个字节,在64位平台是8个字节。
2. 指针和指针类型
2.1定义指针变量的格式
char ch = 'a';
char *p; // 一个用于指向字符型变量的指针
p = &ch;
int num = 666;
int *q; // 一个用于指向整型变量的指针
q = #
- 其中,*表示这是一个指针变量
- 变量名即为定义的指针变量名
- 类型说明符表示本指针变量所指向的变量的数据类型
- 需要注意的黄金重点--指针类型不一样不代表指针所占空间大小不一样,因为指针所占的大小是由地址线决定的,而地址线是硬件出厂后就固定的,因此不同类型指针的大小都是一样的。
2.2指针初始化常犯的错误
指针变量只能存储地址, 不能存储其它类型
int *p;
p = 250; // 错误写法
给指针变量赋值时,指针变量前不能再加“*”
int *p;
*p=&a; //错误写法
在定义变量的时候 * 是一个类型说明符,说明定义的这个变量是一个指针变量
int *p=NULL; // 定义指针变量
在不是定义变量的时候 *是一个操作符,代表访问指针所指向存储空间
int a = 5; int *p = &a;
printf("a = %d", *p); // 访问指针变量
2.3 指针+-整数
#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.4指针的解引用
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。 比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
3. 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
3.1 野指针成因
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;
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
3.指针指向的空间释放
free(tail->next);
tail->next = NULL;//释放后要记得把尾部指针置空,否则将导致尾指针为野指针
3.2 如何规避野指针
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址
局部变量,是分配在栈上的变量,随着函数调用的返回而失效。
函数调用结束之后,局部变量的指针,也就是野指针了,不能在函数外继续使用。
5. 指针使用之前检查有效性
4.指针和数组
数组名表示的是数组首元素的地址。
#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的地址。 那我们就可以直接通过指针来访问数组。
如下:
int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; int *p = arr; //指针存放数组首元素的地址 int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i<sz; i++) { printf("%d ", *(p + i)); } return 0;
5. 二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里? 这就是 二级指针 。
- *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa
int b = 20; *ppa = &b;//等价于 pa = &b;
- **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
**ppa = 30; //等价于*pa = 30; //等价于a = 30;
6.字符指针
7.数组指针
8.指针数组
9.数组传参和指针传参
10. 函数指针
11. 函数指针数组
12.指向函数指针数组的指针
13.回调函数
14.指针和数组面试题的解析
未完