C语言指针详解与应用(不断更新)
指针简介
指针(Pointer)是C语言的一个重要知识点,其使用灵活、功能强大,是C语言的灵魂
指针与底层硬件联系紧密,使用指针可操作数据的地址,实现数据的间接访问
指针生活实例化
指针的本质是地址,在生活中比如你取快递时的快递单号,所发的位置地址,比如中国北京清华大学,这个就是地址,在生活中int(c语言的基本类型),就好比装water的容器,int a=0;可以这么理解有一个int类型的水杯,它的名字叫a,里面存放0这个水,但是我们如果想让舍友帮忙拿一下水杯,我们可以怎么说“哥们帮我拿一下我的水杯,在咱们宿舍里,我的桌子上”,其中“我的水杯(水杯类型的指针),在咱们宿舍里,我的桌子上”这个就是目前我的水杯的地址==(int *p=&a),这就是指针的实例化
计算机存储机制
int a = 0x12345678;
short b = 0x5A6B;
char c[ ] = {0x33, 0x34, 0x35};
指针
定义指针
指针即指针变量,用于存放其他数据单元(变量/数组/结构体/函数等)的首地址。若指针存放了某个数据单元的首地址,则这个指针指向了这个数据单元,若指针存放的值是0,则这个指针为空指针 定义一个指针变量:
在定义指针时,它分配的字节大小是由计算机本身决定的,32位操作系统分配四个字节,64位操作系统分配8个字节
指针的操作
若已定义:
int a; //定义一个int型的数据
int *p; //定义一个指向int型数据的指针
q++理解:指向下一个(相邻的内存地址)char类型数据的地址,在内存中移动了sizeof(char)个位置
d++理解:指向下一个(相邻的内存地址)int类型数据的地址,在内存中移动了sizeof(int)个位置
其实可以等效理解为数组q++指向下一个存储单元
数组与指针
数组是一些相同数据类型的变量组成的集合,其数组名即为指向该数据类型的指针。数组的定义等效于申请内存、定义指针和初始化
例如: char c[ ] = {0x33, 0x34, 0x35};
等效于: 申请内存
定义 char *c = 0x4000;
初始化数组数据
利用下标引用数组数据也等效于指针取内容。
例如: c[0]; 等效于: *c;
c[1]; 等效于: *(c+1);
c[2]; 等效于: *(c+2);
#include <stdio.h>
#include <stdlib.h>
int main(void) {
//第6页示例代码
int *e;
e=(int*)malloc(3*4);
printf("(int*)malloc(3*4)= %x\n", (int*)malloc(3*4));//把分配到的首地址给e
*e=10;
*(e+1)=20;
*(e+2)=30;
printf("%d\n", *e);
printf("%d\n", *(e+1));
printf("%d\n", *(e+2));
free(e);
int n[]={1,2,3};
printf("n[0]= %d\n", n[0]);
printf("n[1]= %d\n", n[1]);
printf("n[2]= %d\n", n[2]);
printf("*n= %d\n", *n);
printf("*(n+1)= %d\n", *(n+1));
printf("*(n+2)= %d\n", *(n+2));
char str[] = "Hello, World!";
printf("%s\n", str);
printf(str);
return 0;
}
malloc:属于 #include <stdlib.h> 中的方法分配一个3*4这么大的内存空间,同时把它强转为int*类型,在使用完malloc之后要使用free();释放空间
数组的底层就是指针的操作,数组名e就是数组的地址,也是数组的第一元素的首地址
字符串的底层是数组
在底层,实际存储的时候,c语言还是会帮我们把字符串"abc"转换成字符数组进行保存,并且在未尾还要再加上"\0"
注意事项
在对指针取内容之前,一定要确保指针指在了合法的位置,否则将会导致程序出现不可预知的错误 同级指针之间才能相互赋值,跨级赋值将会导致编译器报错或警告
指针的应用
传递参数
使用指针传递大容量的参数,主函数和子函数使用的是同一套数据,避免了参数传递过程中的数据复制,提高了运行效率,减少了内存占用
使用指针传递输出参数,利用主函数和子函数使用同一套数据的特性,实现数据的返回,可实现多返回值函数的设计
#include <stdio.h>
// 函数:计算和与差
void calculate(int a, int b, int *sum, int *difference) {
*sum = a + b; // 计算和
*difference = a - b; // 计算差
}
int main() {
int x = 10;
int y = 5;
int result_sum; // 存放和
int result_diff; // 存放差
// 调用函数
calculate(x, y, &result_sum, &result_diff);
// 输出结果
printf("Sum: %d\n", result_sum);
printf("Difference: %d\n", result_diff);
return 0;
}
传递返回值
将模块内的公有部分返回,让主函数持有模块的“句柄”,便于程序对指定对象的操作
#include <stdio.h>
#include <stdlib.h>
// 定义一个结构体作为句柄
typedef struct {
int *data; // 动态数组指针
int size; // 数组大小
} ArrayHandle;
// 模块函数:创建动态数组
ArrayHandle createArray(int size) {
ArrayHandle handle;
handle.data = (int *)malloc(size * sizeof(int));
handle.size = size;
// 初始化数组
for (int i = 0; i < size; i++) {
handle.data[i] = i + 1; // 示例初始化
}
return handle; // 返回句柄
}
// 模块函数:释放动态数组
void freeArray(ArrayHandle *handle) {
if (handle->data != NULL) {
free(handle->data);
handle->data = NULL; // 避免悬空指针
}
}
// 模块函数:打印数组
void printArray(ArrayHandle handle) {
for (int i = 0; i < handle.size; i++) {
printf("%d ", handle.data[i]);
}
printf("\n");
}
int main() {
// 创建动态数组句柄
ArrayHandle myArray = createArray(5);
// 打印数组内容
printArray(myArray);
// 释放动态数组
freeArray(&myArray);
return 0;
}
直接访问物理地址下的数据
访问硬件指定内存下的数据,如设备ID号等
将复杂格式的数据转换为字节,方便通信与存储
关于CLion的安装可以参考CLion安装、配置、使用、调试(完全小白向)-CSDN博客。