-
指针
-
指针 是用来 存放地址 的,地址是唯一标示 一块地址空间 的。指针的大小在 32 位平台是 4 个字节,在 64 位平台是 8 个字节。
-
指针 就是 地址 ; 平时口语中说的指针,通常指的是 指针变量, 是用来 存放内存地址 的变量。
-
指针变量
-
我们可以通过 &( 取地址操作符)取出 变量 的内存 实际地址 ,把 地址 可以存放到一个变量中,这个 变量就是 指针变量。
-
指针变量 ,用来 存放地址 的 变量 。(存放在指针中的值都被当成地址处理)。
-
code示例
#include <stdio.h> int main() { int a = 10;//在内存中开辟一块空间 int* p = &a;//对变量a,取出它的地址,可以使用&操作符。 //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个指针变量。 printf("%d %d %d %d %d \n", p, &p, *p, a, &a);// 869463732 869463768 10 10 869463732 return 0; }
-
-
-
在 32 位的机器上,地址是 32 个 0 或者 1 组成二进制序列,那地址就得用 4 个字节的空间来存储,所以 一个指针变量的大小就应该是 4 个字节。 那如果在 64 位机器上,如果有 64 个地址线,那一个指针变量的大小是 8 个字节,才能存放一个地 址。
-
-
指针类型
-
指针 +- 整数
-
指针的类型 决定了指针 向前或者向后 走 一步 有 多大 ( 距离 )
-
code示例
#include <stdio.h> int main() { char* pc_1 = NULL; // char* 类型的指针是为了存放 char 类型变量的地址。 short* ps_1 = NULL; // short* 类型的指针是为了存放 short 类型变量的地址。 int* pi_1 = NULL; // int* 类型的指针是为了存放 int 类型变量的地址。 long* pl = NULL; float* pf = NULL; double* pd = NULL; int n = 1111111; printf("%d\n", n); // 1111111 char* pc = (char*)&n; int* pi = &n; printf("%d\n", n); // 1111111 printf("%p\n", &n); // 000000C7FA05FC74 printf("%p\n", pc); // 000000C7FA05FC74 printf("%d\n", *pc); // 71 printf("%p\n", pc + 1); // 000000C7FA05FC75 printf("%p\n", pi); // 000000C7FA05FC74 printf("%d\n", *pi); // 1111111 printf("%p\n", pi + 1); // 000000C7FA05FC78 return 0; }
-
-
指针的解引用
-
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。比如: char * 的指针 解引用就只能访问一个字节,而 int * 的指针的 解引用就能访问 四个字节。
-
code示例
#include <stdio.h> int main() { int n = 11223344; char* pc = (char*)&n; int* pi = &n; printf("%d\n", n); // 11223344 printf("%p\n", &n); // 000000187D50F5B4 printf("%p\n", pc); // 000000187D50F5B4 printf("%d\n", *pc);// 48 printf("%p\n", pi); // 000000187D50F5B4 printf("%d\n", *pi);// 11223344 *pc = 0; //重点在调试的过程中观察内存的变化。 *pi = 0; //重点在调试的过程中观察内存的变化。 return 0; }
-
-
-
野指针
-
野指针概念
-
野指针就是 指针指向的位置 是 不可知 的(随机的、不正确的、没有明确限制的)
-
-
野指针成因
- 野指针形成的三个原因
- 指针未初始化
-
指针越界访问
-
指针指向的空间释放
-
code示例
#include <stdio.h> int main() { int* p_0;// 1. 指针未初始化:局部变量指针未初始化,默认为随机值 *p_0 = 20; int arr[10] = { 0 }; int* p = arr; int i = 0; for (i = 0; i <= 11; i++) { //2. 指针访问越界:当指针指向的范围超出数组arr的范围时,p就是野指针 *(p++) = i; } return 0; }
- 野指针形成的三个原因
-
如何规避野指针
- 规避野指针的几种方式
1. 指针初始化2. 小心指针越界3. 指针指向空间释放即使置NULL4. 避免返回局部变量的地址5. 指针使用之前
- code示例
#include <stdio.h> int main() { int* p = NULL; // 1. 指针初始化 int a = 10; p = &a; if (p != NULL) // 5. 指针使用之前检查有效性 { *p = 20; } return 0; }
- 规避野指针的几种方式
-
-
指针运算
-
指针有哪些运算
-
指针 +- 整数
-
指针 - 运算
-
指针的关系运算
-
-
实际在绝大部分的编译器上是可以顺利的完成指针关系运算,但应该避免这样写,因为标准规定中并不保证它可行。
-
标准规定:
-
允许 指向数组元素的指针 与 指向数组最后一个元素后面的那个内存位置的指针 比较,但是 不允许 与 指向第一个元素之前的那个内存位置的指针 进行比较。
-
-
code示例
#define N_VALUES 5 #include <stdio.h> int main() { char* s = "abc"; char* p = s; while (*p != '\0') { p++; // 1. + 指针 printf("%d %p\n", *p, p); } /* * 98 00007FF676509C21 * 99 00007FF676509C22 * 0 00007FF676509C23 */ // 2. - 指针 printf("%p %p %d\n",p, s, p - s); // 00007FF676509C23 00007FF676509C20 3 float values[N_VALUES]; float* vp; for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--) { *vp = 0; // 3. 指针的关系运算 printf("%d %p\n", *vp, vp); } /* * 0 000000CED870F738 * 0 000000CED870F734 * 0 000000CED870F730 * 0 000000CED870F72C * 0 000000CED870F728 */ return 0; }
-
-
指针和数组
-
数组名表示的是数组首元素的地址
- 数组名和数组首元素的地址是一样的
-
把 数组名 当成 地址 存放到一个 指针 中,不仅可以通过 数组下标来访问数组,也可以 使用指针来访问一个数组
- code示例
#include <stdio.h> int main() { int arr[5] = { 1,2,3 }; printf("arr = %p\n", arr); // arr = 000000810BD4FB98 printf("&arr[0] = %p\n", &arr[0]); // &arr[0] = 000000810BD4FB98 int* p = arr; // 指针 p 存放的是数组首元素的地址 printf("p = %p\n", p); // p = 000000810BD4FB98 int sz = sizeof(arr) / sizeof(arr[0]); // 5 for (int i = 0; i < sz; i++) { printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i); printf("arr[%d] = %d <====> *(p+%d) = %d\n", i, arr[i], i, *(p + i)); // 通过指针来访问数组 } /* * &arr[0] = 000000810BD4FB98 ? <====> p+0 = 000000810BD4FB98 * arr[0] = 1 ? <====> *(p+0) = 1 * &arr[1] = 000000810BD4FB9C ? <====> p+1 = 000000810BD4FB9C * arr[1] = 2 ? <====> *(p+1) = 2 * &arr[2] = 000000810BD4FBA0 ? <====> p+2 = 000000810BD4FBA0 * arr[2] = 3 ? <====> *(p+2) = 3 * &arr[3] = 000000810BD4FBA4 ? <====> p+3 = 000000810BD4FBA4 * arr[3] = 0 ? <====> *(p+3) = 0 * &arr[4] = 000000810BD4FBA8 ? <====> p+4 = 000000810BD4FBA8 * arr[4] = 0 ? <====> *(p+4) = 0 */ return 0; }
-
-
二级指针
-
指针变量 也是变量,是变量就有地址,那 指针变量的地址 存放在哪里?这就是 二级指针 。
-
二级指针的运算
-
*ppa 通过对 ppa 中的地址进行 解引用 ,这样找到的是 pa , *pa 访问的就是 pa 。
-
**ppa 先通过 *ppa 找到 pa , 然后对 pa 进行 解引用 操作,那找到的是 a 。
-
code示例
#include <stdio.h> int main() { int a = 111; int* pa = &a; int** ppa = &pa; // 二级指针 // a的地址 = 000000E01CBCF8B4, pa中存放的内容 = 000000E01CBCF8B4 printf("a的地址 = %p, pa中存放的内容 = %p\n", &a, pa); // pa的地址 = 000000E01CBCF8D8, ppa中存放的内容 = 000000E01CBCF8D8, ppa的地址 = 0000002BF390F668 printf("pa的地址 = %p, ppa中存放的内容 = %p, ppa的地址 = %p\n", &pa, ppa, &ppa); int b = 20; *ppa = &b;//等价于 pa = &b; printf("%p\n", &b); // 0000002BF390F684 printf("%p %p\n", *ppa, pa); // 0000002BF390F684 0000002BF390F684 **ppa = 30; //等价于*pa = 30; //等价于a = 30; return 0; }
-
-
-
指针数组
-
指针数组是数组。是存放指针的数组。
-
code示例
#include <stdio.h> int main() { int arr1[5]; char arr2[6]; int* arr3[5];//arr3是一个数组,有五个元素,每个元素是一个整形指针。 return 0; }
-