C语言指针运算 #
一、指针运算概述 #
1.1 支持的运算 #
指针支持以下运算:
| 运算 | 示例 |
|---|---|
| 加整数 | p + n |
| 减整数 | p - n |
| 指针相减 | p2 - p1 |
| 比较 | p1 < p2 |
| 自增自减 | p++, p– |
1.2 运算单位 #
指针运算以类型大小为单位:
c
int* p;
p + 1;
p + 1 实际偏移 sizeof(int) 字节(通常4字节)。
二、指针加减整数 #
2.1 基本运算 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
printf("p = %p, *p = %d\n", (void*)p, *p);
printf("p+1 = %p, *(p+1) = %d\n", (void*)(p+1), *(p+1));
printf("p+2 = %p, *(p+2) = %d\n", (void*)(p+2), *(p+2));
return 0;
}
输出:
text
p = 0x7fff5fbff8a0, *p = 10
p+1 = 0x7fff5fbff8a4, *(p+1) = 20
p+2 = 0x7fff5fbff8a8, *(p+2) = 30
2.2 不同类型指针 #
c
#include <stdio.h>
int main() {
char arr[5] = {'A', 'B', 'C', 'D', 'E'};
char* p = arr;
printf("p = %p, *p = %c\n", (void*)p, *p);
printf("p+1 = %p, *(p+1) = %c\n", (void*)(p+1), *(p+1));
int arr2[5] = {1, 2, 3, 4, 5};
int* q = arr2;
printf("q = %p, *q = %d\n", (void*)q, *q);
printf("q+1 = %p, *(q+1) = %d\n", (void*)(q+1), *(q+1));
return 0;
}
2.3 指针减整数 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = &arr[4];
printf("p = %p, *p = %d\n", (void*)p, *p);
printf("p-1 = %p, *(p-1) = %d\n", (void*)(p-1), *(p-1));
printf("p-2 = %p, *(p-2) = %d\n", (void*)(p-2), *(p-2));
return 0;
}
2.4 运算原理 #
c
p + n 实际地址 = p的地址 + n * sizeof(类型)
p - n 实际地址 = p的地址 - n * sizeof(类型)
三、指针自增自减 #
3.1 前置与后置 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
printf("*p++ = %d\n", *p++);
printf("*p = %d\n", *p);
printf("*++p = %d\n", *++p);
printf("*p = %d\n", *p);
return 0;
}
输出:
text
*p++ = 10
*p = 20
*++p = 30
*p = 30
3.2 运算优先级 #
| 表达式 | 等价于 | 说明 |
|---|---|---|
| *p++ | *(p++) | 先取值,后移动 |
| (*p)++ | (*p)++ | 先取值,值加1 |
| *++p | *(++p) | 先移动,后取值 |
| ++*p | ++(*p) | 值加1 |
3.3 示例 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
printf("初始: *p = %d\n", *p);
(*p)++;
printf("(*p)++后: *p = %d\n", *p);
++*p;
printf("++*p后: *p = %d\n", *p);
return 0;
}
输出:
text
初始: *p = 10
(*p)++后: *p = 11
++*p后: *p = 12
四、指针相减 #
4.1 计算元素个数 #
c
#include <stdio.h>
int main() {
int arr[10] = {0};
int* p1 = arr;
int* p2 = arr + 5;
printf("p2 - p1 = %ld\n", p2 - p1);
return 0;
}
输出:
text
p2 - p1 = 5
4.2 计算数组长度 #
c
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int* start = arr;
int* end = arr + sizeof(arr) / sizeof(arr[0]);
int length = end - start;
printf("数组长度: %d\n", length);
return 0;
}
4.3 注意事项 #
指针相减要求两个指针指向同一数组:
c
int arr1[5], arr2[5];
int* p1 = arr1;
int* p2 = arr2;
printf("%ld\n", p2 - p1);
五、指针比较 #
5.1 比较运算符 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p1 = arr;
int* p2 = arr + 4;
printf("p1 < p2: %d\n", p1 < p2);
printf("p1 > p2: %d\n", p1 > p2);
printf("p1 == p2: %d\n", p1 == p2);
printf("p1 != p2: %d\n", p1 != p2);
return 0;
}
5.2 遍历数组 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* start = arr;
int* end = arr + 5;
for (int* p = start; p < end; p++) {
printf("%d ", *p);
}
printf("\n");
return 0;
}
5.3 查找元素 #
c
#include <stdio.h>
int* find(int* start, int* end, int value) {
while (start < end) {
if (*start == value) {
return start;
}
start++;
}
return NULL;
}
int main() {
int arr[] = {10, 20, 30, 40, 50};
int* result = find(arr, arr + 5, 30);
if (result != NULL) {
printf("找到: %d, 索引: %ld\n", *result, result - arr);
} else {
printf("未找到\n");
}
return 0;
}
六、指针与下标 #
6.1 等价关系 #
c
arr[i] 等价于 *(arr + i)
&arr[i] 等价于 arr + i
6.2 示例 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
printf("*(arr+%d) = %d\n", i, *(arr + i));
printf("p[%d] = %d\n", i, p[i]);
printf("*(p+%d) = %d\n", i, *(p + i));
printf("---\n");
}
return 0;
}
6.3 负下标 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = &arr[2];
printf("p[-2] = %d\n", p[-2]);
printf("p[-1] = %d\n", p[-1]);
printf("p[0] = %d\n", p[0]);
printf("p[1] = %d\n", p[1]);
return 0;
}
输出:
text
p[-2] = 10
p[-1] = 20
p[0] = 30
p[1] = 40
七、指针运算应用 #
7.1 字符串长度 #
c
#include <stdio.h>
size_t my_strlen(const char* str) {
const char* p = str;
while (*p) {
p++;
}
return p - str;
}
int main() {
printf("长度: %zu\n", my_strlen("Hello"));
return 0;
}
7.2 字符串复制 #
c
#include <stdio.h>
char* my_strcpy(char* dest, const char* src) {
char* p = dest;
while ((*p++ = *src++) != '\0') {
}
return dest;
}
int main() {
char dest[20];
my_strcpy(dest, "Hello, World!");
printf("%s\n", dest);
return 0;
}
7.3 数组求和 #
c
#include <stdio.h>
int sum(int* start, int* end) {
int total = 0;
while (start < end) {
total += *start++;
}
return total;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
printf("总和: %d\n", sum(arr, arr + 5));
return 0;
}
7.4 数组反转 #
c
#include <stdio.h>
void reverse(int* start, int* end) {
end--;
while (start < end) {
int temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);
reverse(arr, arr + len);
for (int i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
八、指针运算注意事项 #
8.1 越界访问 #
c
int arr[5] = {1, 2, 3, 4, 5};
int* p = arr;
printf("%d\n", *(p + 10));
越界访问导致未定义行为。
8.2 未定义行为 #
c
int arr[5] = {1, 2, 3, 4, 5};
int* p = &arr[0];
int* q = &arr[5];
printf("%ld\n", q - p);
printf("%ld\n", p - q);
可以指向数组末尾,但不能解引用。
8.3 不同数组指针运算 #
c
int arr1[5], arr2[5];
int* p1 = arr1;
int* p2 = arr2;
printf("%ld\n", p2 - p1);
结果未定义。
九、总结 #
指针运算规则 #
| 运算 | 公式 |
|---|---|
| p + n | 地址 + n * sizeof(类型) |
| p - n | 地址 - n * sizeof(类型) |
| p2 - p1 | 元素个数 |
| p++, p– | 移动到下一个/上一个元素 |
运算优先级 #
| 表达式 | 含义 |
|---|---|
| *p++ | 先取值,后移动 |
| *++p | 先移动,后取值 |
| ++*p | 值加1 |
| (*p)++ | 先取值,值加1 |
应用场景 #
- 遍历数组
- 字符串操作
- 内存操作
- 数据结构实现
注意事项 #
- 避免越界访问
- 指针相减要求同一数组
- 注意运算优先级
- 检查指针有效性
下一步,让我们学习指针与数组!
最后更新:2026-03-26