C语言指针基础 #
一、指针概述 #
1.1 什么是指针 #
指针是一个变量,其值为另一个变量的地址。
c
int a = 10;
int* p = &a;
a是一个整数变量,值为10&a是变量a的地址p是一个指针,存储a的地址
1.2 内存与地址 #
text
内存地址 值
┌─────────┬─────────┐
│ 0x1000 │ 10 │ ← 变量 a
├─────────┼─────────┤
│ 0x1004 │ 0x1000 │ ← 指针 p
└─────────┴─────────┘
1.3 为什么需要指针 #
- 直接访问内存
- 函数间传递大数据
- 动态内存分配
- 实现数据结构
二、指针声明与初始化 #
2.1 声明指针 #
c
int* pi;
float* pf;
char* pc;
double* pd;
void* pv;
语法:类型* 指针名;
2.2 初始化指针 #
c
int a = 10;
int* p = &a;
& 是取地址运算符,返回变量的地址。
2.3 空指针 #
c
int* p = NULL;
int* q = 0;
NULL 是空指针常量,表示指针不指向任何有效地址。
c
#include <stdio.h>
#include <stddef.h>
int main() {
int* p = NULL;
if (p == NULL) {
printf("指针为空\n");
}
return 0;
}
2.4 未初始化指针 #
c
int* p;
printf("%p\n", p);
*p = 10;
未初始化的指针包含随机地址,使用会导致未定义行为。
三、指针使用 #
3.1 取地址运算符 & #
c
int a = 10;
printf("a的值: %d\n", a);
printf("a的地址: %p\n", &a);
输出:
text
a的值: 10
a的地址: 0x7fff5fbff8ac
3.2 解引用运算符 * #
c
int a = 10;
int* p = &a;
printf("p的值: %p\n", p);
printf("p指向的值: %d\n", *p);
* 是解引用运算符,获取指针指向的值。
3.3 通过指针修改值 #
c
#include <stdio.h>
int main() {
int a = 10;
int* p = &a;
printf("修改前: a = %d\n", a);
*p = 20;
printf("修改后: a = %d\n", a);
return 0;
}
输出:
text
修改前: a = 10
修改后: a = 20
3.4 指针大小 #
c
#include <stdio.h>
int main() {
printf("char*: %zu字节\n", sizeof(char*));
printf("int*: %zu字节\n", sizeof(int*));
printf("double*: %zu字节\n", sizeof(double*));
printf("void*: %zu字节\n", sizeof(void*));
return 0;
}
输出(64位系统):
text
char*: 8字节
int*: 8字节
double*: 8字节
void*: 8字节
所有指针大小相同,因为它们都存储地址。
四、指针类型 #
4.1 不同类型指针 #
c
int a = 10;
float b = 3.14;
char c = 'A';
int* pi = &a;
float* pf = &b;
char* pc = &c;
4.2 void指针 #
void指针可以指向任何类型:
c
#include <stdio.h>
int main() {
int a = 10;
void* p = &a;
int* pi = (int*)p;
printf("%d\n", *pi);
return 0;
}
void指针使用前需要类型转换。
4.3 指针类型的作用 #
c
#include <stdio.h>
int main() {
int a = 0x12345678;
char* p = (char*)&a;
printf("int值: 0x%x\n", a);
printf("第一个字节: 0x%x\n", *p);
return 0;
}
指针类型决定了解引用时读取的字节数。
五、指针运算 #
5.1 指针加减整数 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
printf("p[0] = %d\n", *p);
printf("p[1] = %d\n", *(p + 1));
printf("p[2] = %d\n", *(p + 2));
return 0;
}
p + 1 实际偏移 sizeof(int) 字节。
5.2 指针减指针 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p1 = &arr[0];
int* p2 = &arr[4];
printf("元素个数: %ld\n", p2 - p1);
return 0;
}
输出:
text
元素个数: 4
5.3 指针比较 #
c
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr;
while (p < arr + 5) {
printf("%d ", *p);
p++;
}
printf("\n");
return 0;
}
六、指针与数组 #
6.1 数组名与指针 #
c
int arr[5] = {1, 2, 3, 4, 5};
int* p = arr;
数组名是首元素的地址。
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, *(p+%d) = %d\n",
i, arr[i], i, *(p + i));
}
return 0;
}
arr[i] 等价于 *(arr + i)。
6.3 遍历数组 #
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("%d ", *p++);
}
printf("\n");
return 0;
}
七、指针与函数 #
7.1 指针作为参数 #
c
#include <stdio.h>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
printf("交换前: x=%d, y=%d\n", x, y);
swap(&x, &y);
printf("交换后: x=%d, y=%d\n", x, y);
return 0;
}
输出:
text
交换前: x=10, y=20
交换后: x=20, y=10
7.2 返回指针 #
c
#include <stdio.h>
int* find_max(int* arr, int size) {
int* max = arr;
for (int i = 1; i < size; i++) {
if (arr[i] > *max) {
max = &arr[i];
}
}
return max;
}
int main() {
int arr[] = {3, 1, 4, 1, 5, 9, 2, 6};
int* max = find_max(arr, 8);
printf("最大值: %d\n", *max);
return 0;
}
注意:不要返回局部变量的地址。
八、常量指针 #
8.1 指向常量的指针 #
c
int a = 10;
const int* p = &a;
*p = 20;
不能通过指针修改值,但可以改变指针指向。
8.2 常量指针 #
c
int a = 10;
int b = 20;
int* const p = &a;
p = &b;
指针本身是常量,不能改变指向。
8.3 指向常量的常量指针 #
c
int a = 10;
const int* const p = &a;
既不能修改指向的值,也不能改变指针指向。
8.4 总结 #
| 类型 | 能否修改指向 | 能否修改值 |
|---|---|---|
| int* p | 是 | 是 |
| const int* p | 是 | 否 |
| int* const p | 否 | 是 |
| const int* const p | 否 | 否 |
九、指针安全 #
9.1 空指针检查 #
c
void func(int* p) {
if (p == NULL) {
return;
}
*p = 10;
}
9.2 避免野指针 #
c
int* p = NULL;
p = malloc(sizeof(int) * 10);
if (p != NULL) {
free(p);
p = NULL;
}
9.3 指针初始化 #
c
int* p = NULL;
int* q = &a;
始终初始化指针,避免未定义行为。
十、总结 #
指针要点 #
| 概念 | 说明 |
|---|---|
| 声明 | 类型* 指针名; |
| 初始化 | int* p = &a; |
| 取地址 | &变量 |
| 解引用 | *指针 |
| 空指针 | NULL |
指针运算 #
| 运算 | 说明 |
|---|---|
| p + n | 偏移 n * sizeof(类型) |
| p - n | 向后偏移 |
| p2 - p1 | 元素个数 |
| p1 < p2 | 地址比较 |
常量指针 #
c
const int* p;
int* const p;
const int* const p;
安全建议 #
- 始终初始化指针
- 使用前检查NULL
- free后置NULL
- 避免返回局部变量地址
下一步,让我们学习指针运算!
最后更新:2026-03-26