Blog Details

  • Home  
  • 详解C语言指针(下):指针解引用,二级指针(结合近些年笔/面试的实际例子)

详解C语言指针(下):指针解引用,二级指针(结合近些年笔/面试的实际例子)

🔥个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、C/C++干货分享&学习过程记录

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平

C++的两个参考文档:

老朋友(非官方文档):cplusplus

官方文档(同步更新):cppreference

一、指针解引用的本质指针解引用(*操作)实际上是通过地址访问内存的过程。每次解引用都相当于一次"寻址-取值"操作。记住这个核心原则:

解引用前必须确保指针指向有效的内存区域

大厂常见坑点案例这里我们以腾讯2023面试题为例:

代码语言:javascript复制int *p = NULL;

*p = 10; 问:会发生什么?

答案:触发段错误(Segmentation Fault),因为试图访问0地址的内存。

实际工程项目中指针解引用的正确用法:

代码语言:javascript复制int value = 100;

int *p = &value; // 先让指针指向有效地址

printf("%d", *p); // 安全解引用二、二级指针的实战理解 二级指针就是“指向指针的指针”,在以下场景特别有用——

1、需要修改指针本身时;

2、处理指针数组时;

3、动态分配二维数组时。

这里展示一个阿里巴巴高频面试案例:

代码语言:javascript复制void allocate_memory(char **ptr, int size)

{

*ptr = (char*)malloc(size); // 通过二级指针修改外部指针

}

int main()

{

char *str = NULL;

allocate_memory(&str, 100); // 传入指针的地址

strcpy(str, "Alibaba");

free(str);

}二级指针与二维数组下面这个字节跳动2024年的一道笔试真题:

代码语言:javascript复制int arr[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};

int (*p)[4] = arr; // 数组指针

int **pp = (int**)arr; // 这种转换是否正确?

printf("%d", arr[1][2]); // 正确

printf("%d", *(*(arr+1)+2)); // 正确

printf("%d", pp[1][2]); // 可能崩溃! 关键点:注意二维数组不是二级指针!它们的内存布局完全不同。

三、指针解引用案例1、结构体指针解引用下面这道题是美团的一个真实工程案例:

代码语言:javascript复制typedef struct

{

int id;

char name[20];

} Employee;

Employee e = {1001, "张三"};

Employee *p = &e;

// 两种访问方式对比

printf("%s", (*p).name); // 传统方式

printf("%s", p->name); // 更推荐的箭头语法2、指针解引用与类型转换下面这道是华为安全部门的一道考题:

代码语言:javascript复制float f = 3.14;

int *p = (int*)&f;

printf("%d", *p); // 输出什么? 答案:输出浮点数的二进制表示(IEEE 754编码)的整数值。

四、二级指针经典应用1、动态字符串数组下面是腾讯云面试实战的一道题:

代码语言:javascript复制char **create_string_array(int count)

{

char **arr = (char**)malloc(count * sizeof(char*));

for(int i=0; i

{

arr[i] = (char*)malloc(50 * sizeof(char));

sprintf(arr[i], "String%d", i+1);

}

return arr;

}

// 释放时也要二级指针操作

void free_string_array(char **arr, int count)

{

for(int i=0; i

{

free(arr[i]);

}

free(arr);

}2、修改外部指针下面是百度搜索部门的考题:

代码语言:javascript复制void change_pointer(int **pptr)

{

static int value = 100;

*pptr = &value; // 修改外部指针的指向

}

int main()

{

int *ptr = NULL;

change_pointer(&ptr);

printf("%d", *ptr); // 输出100

}五、指针操作技巧掌握要领1、指针偏移解引用下面是拼多多2023年的一道笔试题:

代码语言:javascript复制int arr[] = {10,20,30,40,50};

int *p = arr;

printf("%d", *(p + 2)); // 30

printf("%d", p[2]); // 30 (等价写法)

printf("%d", 2[p]); // 30 (这种写法也是合法的!)2、多级解引用下面是阿里“双11”的一道压测题:

代码语言:javascript复制int value = 999;

int *p1 = &value;

int **p2 = &p1;

int ***p3 = &p2;

printf("%d", ***p3); // 999

// 解析过程:

// 1. *p3得到p2

// 2. *p2得到p1

// 3. *p1得到value六、常见错误及排查方法1、悬垂指针问题:

代码语言:javascript复制int *create_int()

{

int x = 10;

return &x; // 返回局部变量地址!

} // 函数结束后x的内存被回收

// 正确做法:使用static或动态分配2、指针运算错误:

代码语言:javascript复制char str[] = "hello";

int *p = (int*)str;

p++; // 移动了4字节!可能破坏字符串结构3、解引用未初始化指针:

代码语言:javascript复制int *p; // 未初始化

*p = 10; // 随机写入内存,是非常危险的!七、性能优化1、减少不必要的解引用操作:

代码语言:javascript复制// 不好的写法

for(int i=0; i<100; i++)

{

sum += *ptr;

ptr++;

} 下面就是优化之后的写法——

代码语言:javascript复制// 优化写法

int temp = *ptr;

for(int i=0; i<100; i++)

{

sum += temp;

temp = *(++ptr);

}2、使用restrict关键字(C99):

代码语言:javascript复制void copy_array(int *restrict dest, int *restrict src, int n)

{

// 告诉编译器两个指针不会重叠

for(int i=0; i

{

dest[i] = src[i];

}

}往期回顾:

详解C语言指针(上):(含大厂面试实战哦!)指针运算、指针和数组、多级函数

结语:本期内容到这里就结束了,希望对大家有帮助!