Pointers Fundamentals
指针是C语言中最重要也是最强大的特性之一。理解指针是掌握C语言的关键,它让我们能够:
指针是一个变量,它存储的是另一个变量的内存地址。换句话说,指针"指向"内存中的某个位置。
内存布局示例:
// 声明和初始化示例
int x = 42; // 普通变量
int *ptr = &x; // 指针变量,指向 x 的地址
printf("x 的值: %d\n", x); // 输出: 42
printf("x 的地址: %p\n", &x); // 输出: 0x1000 (示例地址)
printf("ptr 的值: %p\n", ptr); // 输出: 0x1000 (与 &x 相同)
printf("ptr 指向的值: %d\n", *ptr); // 输出: 42 (与 x 相同)
& 操作符用于获取变量的内存地址。它是"取地址"的意思。
int num = 100;
int *pointer;
pointer = # // 将 num 的地址赋给 pointer
printf("num 的值: %d\n", num); // 输出: 100
printf("num 的地址: %p\n", &num); // 输出: 0x7fff5fbff6ac (示例)
printf("pointer 存储的地址: %p\n", pointer); // 输出: 0x7fff5fbff6ac (与上面相同)
每次程序运行时,变量的地址可能会不同,这是正常的。重要的是理解指针和变量之间的关系。
int i = 10; int *int_ptr = &i;
float f = 3.14; float *float_ptr = &f;
char c = 'A'; char *char_ptr = &c;
double d = 2.718; double *double_ptr = &d;
// 打印各种类型的地址
printf("int地址: %p\n", int_ptr);
printf("float地址: %p\n", float_ptr);
printf("char地址: %p\n", char_ptr);
printf("double地址: %p\n", double_ptr);
* 操作符用于访问指针指向的变量的值。这个过程叫做"解引用"或"间接访问"。
int *ptr; - 声明一个指向int的指针*ptr - 访问指针指向的值int x = 50;
int *ptr = &x;
// 通过指针读取值
printf("x 的值: %d\n", x); // 输出: 50
printf("*ptr 的值: %d\n", *ptr); // 输出: 50 (相同的值)
// 通过指针修改值
*ptr = 75; // 通过指针改变 x 的值
printf("修改后 x 的值: %d\n", x); // 输出: 75
printf("修改后 *ptr 的值: %d\n", *ptr); // 输出: 75
解引用步骤:
在C语言中,数组名本身就是指向数组第一个元素的指针。这种特性使得指针和数组密切相关。
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr; // arr 等价于 &arr[0]
// 以下三种访问方式是等价的:
printf("第一个元素: %d\n", arr[0]); // 数组下标
printf("第一个元素: %d\n", *arr); // 数组名解引用
printf("第一个元素: %d\n", *ptr); // 指针解引用
// 访问其他元素
printf("第二个元素: %d\n", arr[1]); // 数组下标
printf("第二个元素: %d\n", *(arr+1)); // 指针算术
printf("第二个元素: %d\n", *(ptr+1)); // 指针算术
数组在内存中的布局:
arr[0] arr[1] arr[2] arr[3] arr[4]
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr;
// 指针算术示例
printf("ptr 指向: %d\n", *ptr); // 10
printf("ptr+1 指向: %d\n", *(ptr+1)); // 20
printf("ptr+2 指向: %d\n", *(ptr+2)); // 30
// 移动指针
ptr++; // ptr 现在指向 arr[1]
printf("移动后 ptr 指向: %d\n", *ptr); // 20
当对指针进行 +1 操作时,实际移动的字节数取决于指针的类型。对于 int* 指针,+1 意味着移动 sizeof(int) 个字节(通常是4字节)。
指针在函数中有两个主要用途:传值 vs 传引用 和 返回多个值。
// 传值 (Pass by Value) - 不能修改原变量
void increment_value(int x) {
x++; // 只修改副本,不影响原变量
printf("函数内 x = %d\n", x);
}
// 传引用 (Pass by Reference) - 可以修改原变量
void increment_pointer(int *x) {
(*x)++; // 修改指针指向的值
printf("函数内 *x = %d\n", *x);
}
int main() {
int num = 10;
printf("调用前: num = %d\n", num); // 10
increment_value(num); // 传值
printf("传值后: num = %d\n", num); // 10 (没有改变)
increment_pointer(&num); // 传引用
printf("传引用后: num = %d\n", num); // 11 (改变了)
return 0;
}
// 使用指针返回多个值
void calculate(int a, int b, int *sum, int *product, int *difference) {
*sum = a + b;
*product = a * b;
*difference = a - b;
}
int main() {
int x = 15, y = 5;
int sum, product, difference;
// 传递变量的地址
calculate(x, y, &sum, &product, &difference);
printf("和: %d\n", sum); // 20
printf("积: %d\n", product); // 75
printf("差: %d\n", difference); // 10
return 0;
}
// 数组参数实际上是指针
void print_array(int arr[], int size) {
// 或者写成: void print_array(int *arr, int size)
for (int i = 0; i < size; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
}
void modify_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] *= 2; // 修改原数组的值
}
}
int main() {
int numbers[4] = {1, 2, 3, 4};
printf("原数组:\n");
print_array(numbers, 4);
modify_array(numbers, 4);
printf("修改后:\n");
print_array(numbers, 4); // 输出: 2, 4, 6, 8
return 0;
}
// 错误示例 int *ptr; // 指针未初始化 *ptr = 10; // 危险!可能导致程序崩溃 // 正确示例 int x; int *ptr = &x; // 先初始化指针 *ptr = 10; // 安全
// 错误示例
int *ptr = NULL;
*ptr = 5; // 程序崩溃!
// 正确示例
int *ptr = NULL;
if (ptr != NULL) {
*ptr = 5; // 先检查再使用
} else {
printf("指针为空,无法使用\n");
}
// 错误示例 int x = 10; float *ptr = &x; // 类型不匹配警告 // 正确示例 int x = 10; int *ptr = &x; // 类型匹配
printf 打印地址和值来调试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;
}
void find_min_max(int arr[], int size, int *min, int *max) {
*min = *max = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] < *min) {
*min = arr[i];
}
if (arr[i] > *max) {
*max = arr[i];
}
}
}
int main() {
int numbers[] = {64, 34, 25, 12, 22, 11, 90};
int size = sizeof(numbers) / sizeof(numbers[0]);
int min, max;
find_min_max(numbers, size, &min, &max);
printf("最小值: %d\n", min);
printf("最大值: %d\n", max);
return 0;
}
int string_length(char *str) {
int length = 0;
while (*str != '\0') { // 直到遇到字符串结束符
length++;
str++; // 移动指针到下一个字符
}
return length;
}
int main() {
char message[] = "Hello, World!";
int len = string_length(message);
printf("字符串 '%s' 的长度是: %d\n", message, len);
return 0;
}
掌握指针是C语言编程的重要里程碑。通过大量练习和实际应用,你将能够熟练使用指针来构建更高效、更强大的程序。