C语言指针易混淆知识点总结

打印 上一主题 下一主题

主题 858|帖子 858|积分 2574

指针

界说

指针是一个变量,存储另一个变量的内存地址,它允许直接访问和操作内存中的数据,使得程序可以大概以更机动和高效的方式处理数据和内存。
获取变量地址:使用取地址符 &。
访问地址上的数据:使用解引用符 *。
例子1

指针是存储另一个变量地址的变量。通过使用取地址符 & 和解引用符 *,我们可以机动地访问和操作内存中的数据 。
  1. #include <stdio.h>
  2. int main() {
  3.     int var = 10;     // 定义一个整数变量
  4.     int *p = &var;    // 定义一个指向整数的指针,并将其初始化为变量 var 的地址
  5.     printf("Address of var: %p\n", &var); // 输出变量 var 的地址
  6.     printf("Address stored in pointer p: %p\n", p); // 输出指针 p 中存储的地址
  7.     printf("Value of var using pointer: %d\n", *p); // 通过指针 p 解引用获取 var 的值
  8.     // 修改 var 的值,通过指针 p
  9.     *p = 20;
  10.     printf("New value of var: %d\n", var); // 输出修改后的 var 的值
  11.     return 0;
  12. }
复制代码
例子2

指针类型决定了它指向的变量类型,以及通过指针可以访问的数据巨细。不同类型的指针在操作时会有不同的步长,比如:
int *p = (int *)a;:将 char 类型数组的首地址逼迫转换为 int 指针类型。由于 int 类型通常占用 4 个字节,因此通过 p 访问数据时,每次会读取 4 个字节的数据。
char *q = a;:将 char 类型数组的首地址赋值给 char 指针类型。char 类型占用 1 个字节,因此通过 q 访问数据时,每次只会读取 1 个字节的数据。
  1. #include <stdio.h>
  2. int main() {
  3.     char a[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C};
  4.     int *p = (int *)a; // 将 char 数组的地址赋值给 int 指针
  5.     char *q = a;       // 将 char 数组的地址赋值给 char 指针
  6.    
  7.     // 使用 int 指针访问数据
  8.     printf("Using int pointer:\n");
  9.     for (int i = 0; i < 3; i++) {
  10.         printf("p[%d]: 0x%08x\n", i, *(p + i));
  11.     }
  12.    
  13.     // 使用 char 指针访问数据
  14.     printf("Using char pointer:\n");
  15.     for (int i = 0; i < 12; i++) {
  16.         printf("q[%d]: 0x%02x\n", i, *(q + i));
  17.     }
  18.     return 0;
  19. }
  20. /*
  21. 输出
  22. Using int pointer:
  23. p[0]: 0x04030201
  24. p[1]: 0x08070605
  25. p[2]: 0x0c0b0a09
  26. Using char pointer:
  27. q[0]: 0x01
  28. q[1]: 0x02
  29. q[2]: 0x03
  30. q[3]: 0x04
  31. q[4]: 0x05
  32. q[5]: 0x06
  33. q[6]: 0x07
  34. q[7]: 0x08
  35. q[8]: 0x09
  36. q[9]: 0x0a
  37. q[10]: 0x0b
  38. q[11]: 0x0c
  39. */
复制代码
一级指针和二级指针

一级地址(一级指针)

界说

一级地址指的是指向普通变量的指针,也就是直接存储变量的地址的指针。在C中,通常我们操作的是一级地址,比方指向整数、浮点数或其他基本数据类型的指针。
例子
  1. int *ptr;  // ptr 是一个指向整数的指针,是一级地址
  2. float *ptr_float;  // ptr_float 是一个指向浮点数的指针,也是一级地址
复制代码
二级地址(二级指针)

界说

二级地址是指向指针的指针,也就是存储另一个指针的地址的指针。在C中,可以通过二级指针来操作指向指针的指针,用来间接修改指针指向的值大概传递指针的引用。
例子
  1. int x = 10;
  2. int *ptr1 = &x;  // ptr1 是一个指向 x 的指针,是一级地址
  3. int **ptr2 = &ptr1;  // ptr2 是一个指向 ptr1 的指针,是二级地址
复制代码
例子

分析表达式  *(*(&arr + 1) - 1) 的值:
  1. int arr[5] = {1, 2, 3, 4, 5};
复制代码

  • arr[5] = {1, 2, 3, 4, 5}:这界说了一个包罗 5 个整数的数组 arr,其元素分别是 {1, 2, 3, 4, 5}。
  • &arr:这是数组 arr 的地址。需要注意的是,&arr 的类型是 int (*)[5],即指向一个包罗 5 个整数的数组的指针。
  • &arr + 1:这是 &arr 指针加 1。在这个上下文中,&arr 被看作是一个指向整个数组的指针,因此 &arr + 1 将指向紧随 arr 之后的内存位置。也就是说,它指向 arr 背面的内存地址,而不是数组中的下一个元素。&arr + 1 的类型仍旧是 int (*)[5]。
  • *(&arr + 1):这是对 &arr + 1 解引用。&arr + 1 是一个指向数组的指针,对其解引用后,得到的仍旧是一个指向数组末尾之后的指针。它的类型是 int *,即指向数组末尾之后的指针。
  • *(&arr + 1) - 1:这将刚才得到的指针减去 1。由于指针的减法是以元素为单位的,这个操作将指针向后移动一个 int 的巨细。因为 *(&arr + 1) 指向的是数组 arr 末尾之后的位置,减去 1 后,这个指针将指向数组 arr 的最后一个元素。
  • *(*(&arr + 1) - 1):最后,对指针 *(&arr + 1) - 1 解引用,即获取这个指针所指向的值。这个指针现在指向 arr 的最后一个元素,所以这个表达式的值就是 arr 的最后一个元素的值。
因此,*(*(&arr + 1) - 1) 的值是 5,即数组 arr 的最后一个元素。
指针的自增运算

*++p

这个表达式是先对指针 p 举行自增操作,然后对新的指针举行解引用,得到新的指针所指向的值。
步调

  • ++p:指针 p 先自增,指向下一个元素( 自增的是指针 )。
  • *:对自增后的指针解引用,得到新指针所指向的值。
++*p

这个表达式是对指针 p 所指向的值举行解引用,然后对解引用得到的值举行自增操作。
步调

  • *p:对指针 p 举行解引用,得到指向的值。
  • ++:对解引用得到的值举行自增操作( 自增的是指针指向的值 )。
函数地址与数组地址

函数地址

函数名就是函数的入口地址,因此可以直接把函数名赋给函数指针,也可以加上取地址符号 &。取地址符号 & 是可选的,它只是显式地说明了编译器隐式执行的任务。获取函数的地址时,加不加取地址符号 & 都可以
  1. #include <stdio.h>
  2. int test(int i) {
  3.     return i;
  4. }
  5. int main(void) {
  6.     int (*p1)(int) = test;
  7.     int (*p2)(int) = &test;
  8.     printf("%p, %p\n", (void *)p1, (void *)p2);
  9.     return 0;
  10. }
复制代码
数组地址

数组名本身是数组第一个元素的地址。比方,对于 int 类型的数组来说,数组名 arr 的类型是 int*,它是一个整型指针,不是数组指针。如果要取整个数组的地址,必须在数组名前面加上取地址符号 &,这样才气赋值给数组指针。获取数组的地址时,必须加上取地址符号 &
在下面的例子中,  p1 是一个整型指针,指向数组的第一个元素,而 p2 是一个数组指针,指向整个数组。对 p1 和 p2 分别举行加 1 操作,p1 会加 4 个字节(假设 int 为 4 字节),而 p2 会加 20 个字节(5 个 int)。
  1. #include <stdio.h>
  2. int main(void) {
  3.     int array[5] = {1, 2, 3, 4, 5};
  4.     int* p1 = array;         // 指向数组第一个元素
  5.     int(*p2)[5] = &array;    // 指向整个数组
  6.     printf("p1 %p\n", (void*)p1);
  7.     printf("p2 %p\n", (void*)p2);
  8.     printf("p1+1 %p\n", (void*)(p1+1));  // p1 加 1,增加 4 个字节(假设 int 为 4 字节)
  9.     printf("p2+1 %p\n", (void*)(p2+1));  // p2 加 1,增加 20 个字节(5 个 int)
  10.     return 0;
  11. }
复制代码
指针和数组

不需要严格区分的情况

访问数组元素

对于数组和指针,都可以使用下标形式或指针形式来访问元素。
  1. #include <stdio.h>
  2. int main(void) {
  3.     char array[] = "hello world!";
  4.     char* p = array;
  5.     array[1] = 'x';      // 使用下标访问数组
  6.     *(array + 1) = 'x';  // 使用指针形式访问数组
  7.     p[1] = 'y';          // 使用下标访问指针
  8.     *(p + 1) = 'y';      // 使用指针形式访问指针
  9.     printf("%s\n", array); // 输出: hyllo world!
  10.     printf("%s\n", p);     // 输出: hyllo world!
  11.     return 0;
  12. }
复制代码
作为函数参数传递

实参传递数组时,形参可以是数组或指针。实参传递指针时,形参也可以是数组或指针。编译器会将数组参数退化为指针。
  1. #include <stdio.h>
  2. void printArray(int arr[], int size) {
  3.     for (int i = 0; i < size; i++) {
  4.         printf("%d ", arr[i]);
  5.     }
  6.     printf("\n");
  7. }
  8. int main(void) {
  9.     int array[] = {1, 2, 3, 4, 5};
  10.     printArray(array, 5); // 传递数组
  11.     return 0;
  12. }
复制代码
需要严格区分的情况

使用 sizeof 盘算长度

sizeof(array) 返回数组的字节数。sizeof(pointer) 返回指针的巨细(在64位体系中为8字节,在32位体系中为4字节)。
  1. #include <stdio.h>
  2. int main(void) {
  3.     char array[] = "hello world!";
  4.     char* p = array;
  5.     printf("sizeof(array) = %lu\n", sizeof(array)); // 输出: 13
  6.     printf("sizeof(p) = %lu\n", sizeof(p));         // 输出: 8 (在64位系统中)
  7.     return 0;
  8. }
复制代码
盘算数组长度

当数组作为参数传递时,在函数内部不能使用 sizeof 盘算数组长度,因为数组会退化为指针。
  1. #include <stdio.h>
  2. void test(int arg[]) {
  3.     printf("sizeof(arg) = %lu\n", sizeof(arg)); // 输出指针大小,例如在64位系统中为8
  4. }
  5. int main(void) {
  6.     int array[10];
  7.     test(array); // 传递数组
  8.     return 0;
  9. }
复制代码
声明外部变量

在一个文件中界说指针 p,在另一个文件中不能声明为数组。
  1. //file1.c:
  2. int* p;
  3. // file2.c
  4. extern int* p; // 正确:声明为指针
  5. // extern int p[]; // 错误:不能声明为数组
复制代码
指针常量和常量指针

指针常量

界说

不能改变指向的指针。也就是说,一旦初始化后,就不能再改变指向其它地址,但可以修改指针所指向地址上的内容。
例子

比如指针 p,因为它被 const 修饰,所以 p 不能被修改,它只能指向 str。如果强行对 p 举行 p++ 操作,编译时就会报错。我们称指针 p 为指针常量。尽管 p 本身不能被修改,但可以通过 p 来修改 str 的内容,比方 *p = 'H';。
  1. char str[] = "hello world!";
  2. char *const p = str;
复制代码
常量指针

界说

不能改变所指向的值的指针。也就是说,通过这个指针不能修改它所指向的值,但可以修改指针的指向。
例子

p 是一个指向 char 类型常量的指针。可以修改 p 的指向,比方 p = another_str;,但不能通过 p 修改其指向的内容,比方 *p = 'H'; 是不允许的。
  1. const char *p = "hello world!";
  2. char const *p = "hello world!";
复制代码
指针数组和数组指针

指针数组

界说

本质是一个数组,数组的每个元素都是指针。
例子1

int *p[4]; 这一声明中,p 先与中括号联合,表示 p 是一个有四个元素的数组,每个元素的类型都是 int *(指向整型的指针)。因此,我们称 p 为指针数组。
  1. int *p[4];
复制代码
例子2
  1. int a = 1, b = 2, c = 3, d = 4;
  2. int *p[4] = { &a, &b, &c, &d };
  3. for (int i = 0; i < 4; i++) {
  4.     printf("%d ", *p[i]);
  5. }
  6. // 输出:1 2 3 4
复制代码
数组指针

界说

本质是一个指针,指向一个数组。
例子1

int (*p)[4]; 这一声明中,p 先与 * 联合,表示 p 是一个指针,然后与中括号联合,表示 p 指向一个有四个元素的数组,每个元素的类型都是 int。因此,我们称 p 为数组指针。
  1. int (*p)[4];
复制代码
例子2
  1. int arr[4] = {1, 2, 3, 4};
  2. int (*p)[4] = &arr;
  3. for (int i = 0; i < 4; i++) {
  4.     printf("%d ", (*p)[i]);
  5. }
  6. // 输出:1 2 3 4
复制代码
函数指针和指针函数

函数指针

界说

本质是一个指针,指向一个函数。每个函数在内存中都有一个地址,函数调用就是跳转到这个地址开始执行,函数指针记录了这个地址的变量。
例子

p 是一个指针,指向一个函数,该函数有一个 int 类型的参数,返回值是 int。可以通过函数名 test(1) 来调用函数,也可以通过指针 p 来调用 p(1)大概(*p)(1)
  1. #include <stdio.h>
  2. int test(int i) {
  3.     return i;
  4. }
  5. int main(void) {
  6.     int res = 0;
  7.     int (*p)(int) = test;
  8.     res = test(1);
  9.     printf("%d\n", res);
  10.     res = p(1);
  11.     printf("%d\n", res);
  12.     res = (*p)(1);
  13.     printf("%d\n", res);
  14.     return 0;
  15. }
复制代码
应用

往结构体中放入函数

C语言的结构体不支持成员函数,但可以通过函数指针实现雷同的功能。结构体中可以界说一个函数指针,用来保存函数地址。函数名可以直接赋值给函数指针。C语言的结构体在使用时必须加上 struct 关键字,而 C++ 可以省略。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义一个打印函数
  4. void print(int a, int b) {
  5.     printf("%d %d\n", a, b);
  6. }
  7. // 定义一个结构体,其中包含一个函数指针
  8. struct Test {
  9.     void (*p)(int, int);
  10. };
  11. int main(void) {
  12.     // 动态分配结构体内存
  13.     struct Test* t = (struct Test *)malloc(sizeof(struct Test));
  14.     if (t == NULL) {
  15.         fprintf(stderr, "Memory allocation failed\n");
  16.         return 1;
  17.     }
  18.    
  19.     // 将函数指针指向打印函数
  20.     t->p = print;
  21.    
  22.     // 调用函数指针
  23.     t->p(3, 4); // 输出: 3 4
  24.    
  25.     // 释放动态分配的内存
  26.     free(t);
  27.    
  28.     return 0;
  29. }
复制代码
回调函数

是一种通过函数指针实现的技术,允许在一个函数中调用另一个函数。通常用于事件驱动编程或处理异步操作。
  1. #include <stdio.h>
  2. // 定义一个回调函数类型
  3. typedef void (*Callback)(int);
  4. // 定义一个回调函数
  5. void myCallback(int value) {
  6.     printf("Callback called with value: %d\n", value);
  7. }
  8. // 定义一个执行操作并调用回调函数的函数
  9. void performOperation(int x, Callback callback) {
  10.     printf("Performing operation with value: %d\n", x);
  11.     // 调用回调函数
  12.     callback(x);
  13. }
  14. int main(void) {
  15.     // 使用回调函数
  16.     performOperation(5, myCallback);
  17.     return 0;
  18. }
复制代码
动态函数调用

在需要根据某些条件动态选择和调用不同函数时,函数指针非常有用。比方,在一个盘算器程序中可以动态选择不同的操作函数。
  1. #include <stdio.h>
  2. // 定义操作函数
  3. int add(int a, int b) { return a + b; }
  4. int subtract(int a, int b) { return a - b; }
  5. int multiply(int a, int b) { return a * b; }
  6. int divide(int a, int b) { return a / b; }
  7. int main(void) {
  8.     // 定义一个函数指针数组
  9.     int (*operations[4])(int, int) = { add, subtract, multiply, divide };
  10.    
  11.     int a = 10, b = 5;
  12.     char op = '+';
  13.     // 根据操作符选择对应的函数
  14.     int (*operation)(int, int) = NULL;
  15.     switch (op) {
  16.         case '+': operation = operations[0]; break;
  17.         case '-': operation = operations[1]; break;
  18.         case '*': operation = operations[2]; break;
  19.         case '/': operation = operations[3]; break;
  20.     }
  21.     if (operation != NULL) {
  22.         printf("Result: %d\n", operation(a, b));
  23.     } else {
  24.         printf("Invalid operation\n");
  25.     }
  26.     return 0;
  27. }
复制代码
实现多态行为

通过函数指针数组,可以在C语言中实现雷同C++的多态行为。这种技术广泛应用于计划模式和框架中。
  1. #include <stdio.h>
  2. // 定义一个基类结构体
  3. struct Shape {
  4.     void (*draw)(struct Shape*);
  5. };
  6. // 定义一个派生类结构体
  7. struct Circle {
  8.     struct Shape base; // 基类
  9.     int radius;
  10. };
  11. // 定义一个绘制函数
  12. void drawCircle(struct Shape* shape) {
  13.     struct Circle* circle = (struct Circle*)shape;
  14.     printf("Drawing a circle with radius: %d\n", circle->radius);
  15. }
  16. int main(void) {
  17.     // 创建一个 Circle 对象
  18.     struct Circle c;
  19.     c.base.draw = drawCircle;
  20.     c.radius = 5;
  21.     // 调用绘制函数
  22.     c.base.draw((struct Shape*)&c);
  23.     return 0;
  24. }
复制代码
实现状态机

是一种在不同状态之间转换的编程模式。可以通过函数指针实现状态之间的动态切换。
  1. #include <stdio.h>
  2. // 定义状态函数类型
  3. typedef void (*StateFunction)();
  4. // 定义状态函数
  5. void stateA() {
  6.     printf("State A\n");
  7. }
  8. void stateB() {
  9.     printf("State B\n");
  10. }
  11. void stateC() {
  12.     printf("State C\n");
  13. }
  14. int main(void) {
  15.     // 定义一个状态函数指针数组
  16.     StateFunction states[3] = { stateA, stateB, stateC };
  17.    
  18.     int currentState = 0;
  19.     for (int i = 0; i < 5; i++) {
  20.         // 调用当前状态函数
  21.         states[currentState]();
  22.         // 切换到下一个状态
  23.         currentState = (currentState + 1) % 3;
  24.     }
  25.     return 0;
  26. }
复制代码
代码跳转到指定位置执行

比如((void(*)())0)();代表让程序跳转到地址为0的地方去运行。
解析步调

  • (void (*)()):这是一个类型转换,表示一个指向返回类型为 void、无参数的函数的指针。具体来说,void (*)() 是一种函数指针类型,它指向的函数没有参数并返回 void。
  • 0:这是一个整数常量 0。在C中,可以将整数常量 0 作为空指针常量。
  • (void (*)())0:这将整数 0 转换为类型为 void (*)() 的函数指针。换句话说,这是将 0 解释为一个指向无参数、返回类型为 void 的函数的指针。
  • ((void (*)())0):这只是对前面步调的类型转换举行一次包裹,效果仍旧是一个类型为 void (*)() 的函数指针,指向 0 地址。
  • ((void (*)())0)():这表示对 0 地址的函数指针举行调用。具体来说,这是试图调用位于地址 0 处的函数。
指针函数

界说

本质是一个函数,其返回值是一个指针。
例子

错误示例

下面这个例子是一个典范的错误,因为不能返回一个局部变量的地址。函数调用完毕后,局部变量的内存会被释放,即使返回了这个地址也不能使用。
  1. int* test() {
  2.     int array[5] = {0};  // 局部变量
  3.     return array;  // 错误:返回局部变量的地址
  4. }
  5. int main(void) {
  6.     int* p = test();  // 不安全
  7.     return 0;
  8. }
复制代码
返回堆空间地址
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int* test() {
  4.     int* array = (int*)malloc(sizeof(int) * 5);  // 动态分配堆空间
  5.     if (array != NULL) {
  6.         for (int i = 0; i < 5; ++i) {
  7.             array[i] = i;  // 初始化数组
  8.         }
  9.     }
  10.     return array;  // 返回堆空间地址
  11. }
  12. int main(void) {
  13.     int* p = test();
  14.     if (p != NULL) {
  15.         for (int i = 0; i < 5; ++i) {
  16.             printf("%d ", p[i]);  // 输出:0 1 2 3 4
  17.         }
  18.         free(p);  // 释放动态分配的内存
  19.     }
  20.     return 0;
  21. }
复制代码
返回全局变量地址
  1. #include <stdio.h>
  2. int array[5];  // 全局变量
  3. int* test() {
  4.     for (int i = 0; i < 5; ++i) {
  5.         array[i] = i;  // 初始化数组
  6.     }
  7.     return array;  // 返回全局变量地址
  8. }
  9. int main(void) {
  10.     int* p = test();
  11.     for (int i = 0; i < 5; ++i) {
  12.         printf("%d ", p[i]);  // 输出:0 1 2 3 4
  13.     }
  14.     return 0;
  15. }
复制代码
返回静态变量地址
  1. #include <stdio.h>
  2. int* test() {
  3.     static int array[5];  // 静态变量
  4.     for (int i = 0; i < 5; ++i) {
  5.         array[i] = i;  // 初始化数组
  6.     }
  7.     return array;  // 返回静态变量地址
  8. }
  9. int main(void) {
  10.     int* p = test();
  11.     for (int i = 0; i < 5; ++i) {
  12.         printf("%d ", p[i]);  // 输出:0 1 2 3 4
  13.     }
  14.     return 0;
  15. }
复制代码
指针函数指针

界说

是一个指向返回指针的函数的指针。它不仅是一个指向函数的指针,而且该函数返回的也是一个指针。
例子
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义一个返回整数指针的函数
  4. int* allocateArray(int size) {
  5.     int* array = (int*)malloc(size * sizeof(int));  // 动态分配内存
  6.     if (array != NULL) {
  7.         for (int i = 0; i < size; ++i) {
  8.             array[i] = i;  // 初始化数组
  9.         }
  10.     }
  11.     return array;  // 返回堆空间地址
  12. }
  13. // 定义一个指向返回整数指针的函数的指针类型
  14. typedef int* (*ArrayAllocator)(int);
  15. int main(void) {
  16.     // 定义一个指向返回整数指针的函数的指针
  17.     ArrayAllocator allocator = allocateArray;
  18.    
  19.     int size = 5;
  20.     // 使用指针函数指针调用函数
  21.     int* array = allocator(size);
  22.     if (array != NULL) {
  23.         for (int i = 0; i < size; ++i) {
  24.             printf("%d ", array[i]);  // 输出:0 1 2 3 4
  25.         }
  26.         printf("\n");
  27.         free(array);  // 释放动态分配的内存
  28.     }
  29.     return 0;
  30. }
复制代码
悬挂指针和野指针

悬挂指针

界说

悬挂指针是指向已经释放(通过 free 函数释放)大概已经超出作用域的内存的指针。当我们试图通过这样的指针访问或操作内存时,可能会导致未界说行为,因为那块内存可能已经被操作体系重新分配给其它程序使用了。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. void dangling_pointer_example() {
  4.     int *p = (int *)malloc(sizeof(int));
  5.     *p = 42;
  6.     printf("Value: %d\n", *p); // 输出42
  7.     free(p); // 释放内存
  8.     // p现在是悬挂指针,访问*p将导致未定义行为
  9.     // printf("Value: %d\n", *p); // 不安全,可能导致崩溃或未定义行为
  10. }
  11. int main() {
  12.     dangling_pointer_example();
  13.     return 0;
  14. }
复制代码
解决方法

立即将指针设为NULL:在释放内存后,将指针设置为NULL。
  1. free(p);
  2. p = NULL;
复制代码
避免返回局部变量的指针:不要返回局部变量的指针,因为它们在函数返回后将超出作用域。
  1. int* incorrect_function() {
  2.     int x = 42;
  3.     return &x; // 返回局部变量的指针,错误
  4. }
复制代码
野指针

界说

野指针是一个未初始化的指针,它的值是未知的,可能指向任意内存地址。当我们试图通过这样的指针访问或操作内存时,可能会导致未界说行为。
  1. #include <stdio.h>
  2. void wild_pointer_example() {
  3.     int *p; // 未初始化的指针
  4.     // *p = 42; // 不安全,可能导致崩溃或未定义行为
  5. }
  6. int main() {
  7.     wild_pointer_example();
  8.     return 0;
  9. }
复制代码
解决方法

在声明指针时初始化:声明指针时将其初始化为NULL或有效地址。
  1. int *p = NULL;
复制代码
确保在使用前分配内存:在使用指针之前,确保它已经被正确初始化和分配内存。
  1. int *p = (int *)malloc(sizeof(int));
  2. if (p != NULL) {
  3.     *p = 42;
  4. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立聪堂德州十三局店

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表