初探C语言
前言
本文将详细介绍C语言中的指针基本概念,通过本文,读者能够更深入地理解指针的工作原理及其应用场景,进而在C语言的编程中游刃有余。
什么是指针?
指针是一个存储内存地址的变量。它指向某个变量在内存中的位置。
指针变量
代码语言:javascript代码运行次数:0运行复制通过
&
操作符取出变量的地址,将其存入一个变量,这个变量就是指针变量。
#include <stdio.h>
int main() {
int a = 10; // 在内存中为变量 a 分配空间
int *p = &a; // 使用 & 操作符取 a 的地址,p 存储这个地址
return 0;
}
- 这里,
a
占用4个字节的内存空间,p
存储的是a
的内存地址。 p
是一个指针变量,指向a
的内存地址。
指针类型
定义方式:
代码语言:javascript代码运行次数:0运行复制type* pointer_name;
常见指针类型:
char*
int*
float*
double*
void*
:它是一个通用指针类型,可以指向任意类型的地址,但不能直接进行指针运算。
指针类型的意义
指针的类型决定了指针移动的步长(即每次加减操作的单位大小)。
示例:指针加减整数
代码语言:javascript代码运行次数:0运行复制#include <stdio.h>
int main() {
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n); // 输出 n 的地址
printf("%p\n", pc); // 输出 pc 指向的地址
printf("%p\n", pc+1); // char* 每次移动 1 个字节
printf("%p\n", pi); // 输出 pi 指向的地址
printf("%p\n", pi+1); // int* 每次移动 4 个字节
return 0;
}
输出结果分析:
char*
步长为 1int*
步长为 4float*
步长为 4double*
步长为 8short*
步长为 2
指针的解引用
解引用操作符 *
用来通过指针访问存储在地址中的值。
*pa 表示通过 pa 存储的地址,找到并访问该地址对应的内存内容。
例如:
代码语言:javascript代码运行次数:0运行复制int a = 10;
int* pa = &a;
printf("%d\n", *pa); // 输出 a 的值,10
野指针
定义:野指针是未初始化或指向非法内存的指针,可能导致程序崩溃或内存泄漏。
常见的野指针情况:
1. 指针未初始化:
代码语言:javascript代码运行次数:0运行复制int main() {
int *p; // 未初始化指针
*p = 20; // 使用未初始化的指针,结果是未定义行为
return 0;
}
2. 指针越界访问:
代码语言:javascript代码运行次数:0运行复制int main() {
int *p;
*p = 20; // 访问越界内存,可能导致程序崩溃
return 0;
}
3. 指针指向已释放的内存:
代码语言:javascript代码运行次数:0运行复制int* test() {
int a = 10;
return &a; // 返回局部变量的地址,局部变量离开作用域后内存被释放
}
int main() {
int* p = test();
printf("%d\n", *p); // 未定义行为
return 0;
}
注意: 返回局部变量的地址是危险的,因为局部变量在函数结束时会被销毁。
野指针的规避方法
- 避免未初始化指针: 初始化指针时,可以将其设为
NULL
。
int* p = NULL; // NULL 指针是一个特殊的指针值,表示指针未指向任何有效内存
- 指针指向空间释放后立即将其置为
NULL
。
free(p);
p = NULL; // 防止指针悬挂
- 避免返回局部变量的地址。
指针运算
指针减指针
当两个指针指向同一数组或内存块时,它们的差值表示它们之间的元素个数。
示例:计算字符串长度
代码语言:javascript代码运行次数:0运行复制int my_strlen(char* str) {
char* start = str;
while (*str != '\0') {
str++;
}
return str - start; // 返回字符串的长度
}
int main() {
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len); // 输出 6
return 0;
}
二级指针(和更高层次指针)
二级指针的定义
二级指针(pointer to pointer
)是指指向另一个指针的指针。简单来说,二级指针存储的是一级指针的地址。通过二级指针,可以间接地访问一级指针指向的内存地址,从而实现多级间接访问。
type** pointer_name;
这里,type
是指针指向的变量类型,pointer_name
是二级指针的名称。
示例:
代码语言:javascript代码运行次数:0运行复制#include <stdio.h>
int main() {
int a = 10; // 定义一个整数变量 a
int *p = &a; // 一级指针 p 存储 a 的地址
int **pp = &p; // 二级指针 pp 存储 p 的地址
// 输出
printf("a = %d\n", a); // 输出 a 的值
printf("*p = %d\n", *p); // 通过一级指针 p 输出 a 的值
printf("**pp = %d\n", **pp); // 通过二级指针 pp 输出 a 的值
return 0;
}
输出结果:
代码语言:javascript代码运行次数:0运行复制a = 10
*p = 10
**pp = 10
解释:
a
是一个普通变量。p
是一个一级指针,存储了变量a
的地址。pp
是一个二级指针,存储了一级指针p
的地址。
通过二级指针 pp
,我们可以间接地访问 a
的值。首先通过 **pp
获取 p
指向的地址,再通过 *p
获取该地址存储的值,即 a
。
应用场景:
- 动态内存分配: 二级指针常用于动态内存分配时,特别是在函数中修改指针的指向。
- 多维数组: 二级指针可以用来处理动态的二维数组。
- 修改指针值: 通过二级指针可以修改一级指针的值,从而改变其指向的内存位置。
二级指针和三级指针
代码语言:javascript代码运行次数:0运行复制int main() {
int a = 0;
int* pa = &a; // 一级指针
int** ppa = &pa; // 二级指针
int*** pppa = &ppa; // 三级指针
return 0;
}
总结
指针是 C 语言中强大而复杂的工具,理解指针的使用、类型以及相关操作是掌握 C 语言的关键。正确使用指针能提高程序效率和灵活性,但不当的使用则可能导致难以发现的错误,甚至程序崩溃。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-01-13,如有侵权请联系 cloudcommunity@tencent 删除变量程序内存指针存储
发布评论