C语言指针高级用法和技巧

指针是C语言最强大也是最容易出错的特性之一。掌握指针的高级用法对于编写高效、优雅的C代码至关重要。

1. 指针的指针(二级指针)

二级指针在动态内存分配和函数参数传递中非常有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <stdlib.h>

// 使用二级指针修改指针的值
void allocateMemory(int **ptr, int size) {
*ptr = (int*)malloc(size * sizeof(int));
if (*ptr == NULL) {
printf("内存分配失败\n");
return;
}
printf("成功分配 %d 个整数的内存\n", size);
}

int main() {
int *arr = NULL;
allocateMemory(&arr, 10);

if (arr != NULL) {
// 使用分配的内存
for (int i = 0; i < 10; i++) {
arr[i] = i * i;
}

// 打印结果
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");

free(arr);
}

return 0;
}

2. 指针数组与数组指针

指针数组

指针数组是一个数组,其元素都是指针:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main() {
char *fruits[] = {"苹果", "香蕉", "橙子", "葡萄"};
int size = sizeof(fruits) / sizeof(fruits[0]);

printf("水果列表:\n");
for (int i = 0; i < size; i++) {
printf("%d. %s\n", i + 1, fruits[i]);
}

return 0;
}

数组指针

数组指针是指向数组的指针:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main() {
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};

// 数组指针,指向包含4个int的数组
int (*ptr)[4] = matrix;

printf("使用数组指针访问二维数组:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%3d ", ptr[i][j]);
}
printf("\n");
}

return 0;
}

3. 指针运算技巧

指针比较和运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

int main() {
int arr[] = {10, 20, 30, 40, 50};
int *start = arr;
int *end = arr + 4;

printf("数组元素:");
for (int *p = start; p <= end; p++) {
printf("%d ", *p);
}
printf("\n");

// 计算指针间距离
printf("指针间距离:%ld\n", end - start);

// 指针比较
if (start < end) {
printf("start指针在end指针之前\n");
}

return 0;
}

4. const与指针的组合

理解const与指针的不同组合方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

int main() {
int a = 10, b = 20;

// 1. 指向常量的指针(指针可变,指向的值不可变)
const int *ptr1 = &a;
printf("ptr1指向的值:%d\n", *ptr1);
// *ptr1 = 30; // 错误!不能修改指向的值
ptr1 = &b; // 正确!可以修改指针指向
printf("ptr1现在指向的值:%d\n", *ptr1);

// 2. 常量指针(指针不可变,指向的值可变)
int * const ptr2 = &a;
*ptr2 = 30; // 正确!可以修改指向的值
printf("通过ptr2修改后a的值:%d\n", a);
// ptr2 = &b; // 错误!不能修改指针指向

// 3. 指向常量的常量指针(指针和值都不可变)
const int * const ptr3 = &b;
printf("ptr3指向的值:%d\n", *ptr3);
// *ptr3 = 40; // 错误!不能修改指向的值
// ptr3 = &a; // 错误!不能修改指针指向

return 0;
}

5. 指针与结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
char name[50];
int age;
float salary;
} Employee;

// 通过指针修改结构体
void updateEmployee(Employee *emp, const char *name, int age, float salary) {
strcpy(emp->name, name);
emp->age = age;
emp->salary = salary;
}

// 打印员工信息
void printEmployee(const Employee *emp) {
printf("姓名:%s,年龄:%d,薪资:%.2f\n",
emp->name, emp->age, emp->salary);
}

int main() {
Employee emp;
updateEmployee(&emp, "张三", 28, 8500.0);
printEmployee(&emp);

// 动态分配结构体数组
Employee *employees = (Employee*)malloc(3 * sizeof(Employee));
if (employees == NULL) {
printf("内存分配失败\n");
return 1;
}

// 初始化员工数据
updateEmployee(&employees[0], "李四", 25, 7000.0);
updateEmployee(&employees[1], "王五", 30, 9500.0);
updateEmployee(&employees[2], "赵六", 35, 12000.0);

printf("\n员工列表:\n");
for (int i = 0; i < 3; i++) {
printf("%d. ", i + 1);
printEmployee(&employees[i]);
}

free(employees);
return 0;
}

6. 指针常见陷阱与避免方法

野指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>

int main() {
int *ptr;

// 错误:使用未初始化的指针
// printf("%d\n", *ptr); // 危险!

// 正确:初始化指针
ptr = NULL;
if (ptr != NULL) {
printf("%d\n", *ptr);
} else {
printf("指针为空\n");
}

// 分配内存
ptr = (int*)malloc(sizeof(int));
if (ptr != NULL) {
*ptr = 42;
printf("值:%d\n", *ptr);

// 释放内存并置空指针
free(ptr);
ptr = NULL; // 避免悬空指针
}

return 0;
}

内存泄漏预防

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <stdlib.h>

// 安全的字符串复制函数
char* safeStrdup(const char *src) {
if (src == NULL) {
return NULL;
}

size_t len = strlen(src) + 1;
char *dest = (char*)malloc(len);
if (dest == NULL) {
return NULL;
}

strcpy(dest, src);
return dest;
}

int main() {
char *str1 = safeStrdup("Hello, World!");
if (str1 != NULL) {
printf("复制的字符串:%s\n", str1);
free(str1);
str1 = NULL;
}

return 0;
}

总结

指针的高级用法包括:

  1. 二级指针:用于修改指针的值和动态内存分配
  2. 指针数组与数组指针:理解两者的区别和应用场景
  3. 指针运算:合理使用指针算术运算
  4. const与指针:掌握不同const组合的含义
  5. 指针与结构体:高效操作复杂数据结构
  6. 避免常见陷阱:防止野指针、内存泄漏等问题

掌握这些技巧能让你写出更安全、更高效的C代码。记住:指针是工具,正确使用它们是关键。

版权所有,如有侵权请联系我