【C语言】知识总结·指针篇
前言:
文接上章,在上章节中讲解一些基础函数,循环结构,以及数组,函数的调用。
指针
在 C 语言中,指针是一种极为重要的变量类型,它能够存储内存地址。借助指针,你可以直接对内存进行操作,实现如动态内存分配、传递引用参数等功能。下面将详细讲解 C 语言指针的相关知识。
一·概念
指针是一种变量,其存储的数值是内存地址,通过地址可以改变该地址上的数据
二·指针的声明
数据类型 *指针变量名;
- 数据类型:表明该指针所指向变量的数据类型。
*
:用于声明这是一个指针变量。
int *p; // 声明一个指向整型的指针
float *q; // 声明一个指向浮点型的指针
char *str; // 声明一个指向字符型的指针
三·指针的基本操作
1. 取地址运算符(&
)
&
运算符能够获取变量的内存地址。
int num = 42;
int *p = # // 将num的地址赋值给指针p
2. 解引用运算符(*
)
*
运算符可以访问指针所指向内存地址中的值。
int num = 42;
int *p = #printf("num的值:%d\n", num); // 输出:42
printf("p指向的值:%d\n", *p); // 输出:42(通过指针访问)
printf("p存储的地址:%p\n", (void*)p); // 输出:num的内存地址
3.修改指针指向的值
int num = 42;
int *p = #*p = 100; // 修改指针所指向的值printf("num的值:%d\n", num); // 输出:100
四·指针与数组
在 C 语言里,数组名本质上就是数组首元素的地址,这使得指针和数组之间的关系十分紧密。
1.数组名作为指针
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // 等价于 int *p = &arr[0];printf("arr[0] = %d\n", *p); // 输出:1
printf("arr[1] = %d\n", *(p + 1)); // 输出:2(指针偏移)
2.指针算术运算
- 指针加法(
p + n
):指针向后偏移n
个元素的位置(偏移量为n * sizeof(数据类型)
)。 - 指针减法(
p - n
):指针向前偏移n
个元素的位置。 - 指针自增 / 自减(
p++
,p--
):指针向后 / 向前偏移 1 个元素的位置。
例如
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr;printf("%d\n", *p); // 输出:10
printf("%d\n", *(p+2)); // 输出:30(偏移2个元素)
五·指针作为函数参数
通过指针作为函数参数,可以实现对原始数据的修改(传址调用),还能避免数据的复制,提高效率。
1. 传址调用示例:交换两个整数的值
#include <stdio.h>void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 5, y = 10;swap(&x, &y); // 传递变量地址printf("x = %d, y = %d\n", x, y); // 输出:x = 10, y = 5return 0;
}
2. 数组作为函数参数
数组作为函数参数传递时,会自动转换为指针。
void printArray(int *arr, int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]); // 等价于 *(arr + i)}
}// 调用示例
int arr[5] = {1, 2, 3, 4, 5};
printArray(arr, 5); // 输出:1 2 3 4 5
六·指针与字符串
在 C 语言中,字符串通常用字符数组或字符指针来表示。
1. 字符串字面量与字符指针
char *str = "Hello"; // 字符串字面量存储在常量区
printf("%s\n", str); // 输出:Hello
2. 字符数组与字符指针的区别
// 字符数组(可修改内容)char str1[] = "Hello";
str1[0] = 'J'; // 合法:修改数组元素// 字符指针(指向常量字符串,不可修改)char *str2 = "Hello";
// str2[0] = 'J'; // 非法:修改常量字符串会导致运行时错误
字符数组可修改,字符指针不可修改。
int main()
{
char str[] = "hello world";
str[0] = 'w';
printf("%s", str);
return 0;
}![]()
七·指针数组与数组指针
1. 指针数组
指针数组是由多个指针组成的数组,其每个元素都是一个指针。
int a = 10, b = 20, c = 30;
int *arr[3] = {&a, &b, &c}; // 指针数组printf("%d\n", *arr[2]); // 输出:10
2. 数组指针(指向数组的指针)
数组指针是指向整个数组的指针。
int arr[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &arr; // 数组指针printf("%d\n", (*p)[0]); // 输出:1
八·函数指针
函数指针是指向函数的指针变量,通过它可以动态调用不同的函数。
#include <stdio.h>int add(int a, int b)
{ return a + b;
}
int sub(int a, int b)
{ return a - b;
}int main()
{// 声明函数指针int (*operation)(int, int);// 指向add函数operation = add;printf("5 + 3 = %d\n", operation(5, 3)); // 输出:8// 指向sub函数operation = sub;printf("5 - 3 = %d\n", operation(5, 3)); // 输出:2return 0;
}
2. 函数指针作为参数
void calculate(int a, int b, int (*op)(int, int))
{printf("结果:%d\n", op(a, b));
}// 调用示例
calculate(5, 3, add); // 输出:8
calculate(5, 3, sub); // 输出:2
九·多级指针
多级指针是指向指针的指针,最常见的是二级指针。
示例:二级指针
int x = 10;
int *p = &x; // 一级指针
int **pp = &p; // 二级指针(指向指针的指针)printf("%d\n", **pp); // 输出:10
十·常见的错误
1·未初始化指针:使用未初始化的指针会导致访问非法内存。
int *p; // 声明一个整型指针p,但未初始化
*p = 10; // 错误:对未初始化的指针解引用
正确的是
int num = 0; // 定义一个整型变量 int *p = # // 让p指向num的地址 *p = 10; // 正确:通过p修改num的值为10 printf("%d", num); // 输出:10
2·野指针:指针释放后未置为NULL
,继续使用会导致问题。
int *p = (int*)malloc(sizeof(int));
free(p);
*p = 10; // 错误:p已释放
总结
指针是C语言的重中之重,要多加练习,才能掌握。
难点较多,容易错误。
作用:
- 直接操作内存,提供底层控制能力。
- 高效传递数据,减少内存开销。
- 构建复杂数据结构和实现高级编程技巧。