news 2026/2/28 3:12:35

C语言复习6:指针

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言复习6:指针

一:内存


- 即:软件在运行时,用来临时存储数据的,点击保存后,才会存储到硬盘中
- 内存地址:操作系统为了更好地管理内存里的数据,会把内存以字节为单位进行划分为好多小格子,其中一个字节管理一个内存地址
- 内存地址的规则:
1. 32位操作系统,内存地址以32位的二进制表示,即一共有2^32次方,大概42亿多个不同的地址 --> 4GB内存
2. 64位操作系统,内存地址以64位的二进制表示,即最大内存地址为2^64次方,地址范围:0~2^64,最大支持的内存:2^64(字节) --> 17,592,186(GB) --> 17,179(TB)
- 变量的内存地址:
在电脑中以十六进制形式存储第一个字节的位置
获取方式:&变量名
int a = 10;
printf("%p\n",&a); //0000004FE98B9FB14



二: 指针


-指针就是内存地址
- 把内存地址存起来 -> 指针变量 -> 指针
- (指针变量一般会被说成指针,但是我们要清楚真正的指针其实是变量里面记录的内存地址)
- 指针变量占用的大小,跟数据类型无关,跟编译器有关(32位:4字节;64位:8字节)
- 给指针变量赋值的时候,不能把一个数值赋值给指针
- 指针的作用:
1. 查询数据
2. 存储数据
3. 参数传递
4. 内存管理
……
* 细说指针的作用:
1. 操作其他函数中的变量
2. 函数返回多个值
3. 函数结果和计算状态分开
4. 方便地操作数组和函数



- 指针变量定义格式:`数据类型 * 变量名 ;`
数据类型 -> 要和指向变量的类型保持一致
* -> 标记符号


- 查询数据:`* 指针名`
* -> 解引号运算符(注意和定义格式的*的含义区分开来)


- 存储数据:`* 指针名 = 数据值;`

int a = 10; int * p = &a; printf("%d",*p); //10 *p = 100; //利用指针存储或是修改数据 printf("%d",*p); //100


-给指针变量赋值的时候,不能把一个数值赋值给指针
int a = 10;
int * p = &a; // &a可以。是赋值已分配空间的内存地址
int * p = 500; // 500不可以。不是赋值已分配空间的内存地址



2.1 指针的作用1----操作其他函数中的变量

#include<stdio.h> /* 定义两个变量,要求交换变量中记录的值 注意:交换的代码写在一个新的函数swap中 */ void swap(int* a,int* b); int main() { int a=10, b=20; swap(&a,&b); printf("%d %d",a,b); // 20 10 return 0; } void swap(int* a,int* b) { int temp = *a; *a = *b; *b = temp; } - - >细节: 1. 函数中变量的生命周期跟函数相关,函数结束了,变量也会消失 2. 此时在其他函数中,就无法通过指针使用了 3. 如果不想函数中的变量被回收,可以在变量前面加static关键字 #include<stdio.h> int* method(); int main(){ int* p = method(); printf("拖点时间\n"); printf("拖点时间\n"); printf("拖点时间\n"); printf("拖点时间\n"); printf("拖点时间\n"); printf("%d\n",*p); //没加static之前,a的值为-858993460,加上后:a的值为10 return 0; } int* method() { static int a = 10; return &a; }


2.2 指针的作用2----函数返回多个值

#include<stdio.h> /* 定义一个函数,求数组的最大值和最小值,并进行返回 */ void getMaxAndMin(int arr[],int len,int* max,int *min); int main() { int arr[] = {17,23,5,20,26}; int len = sizeof(arr) / sizeof(arr[0]); int max = arr[0]; int min = arr[0]; getMaxAndMin(arr, len, &max, &min); printf("%d %d\n", max, min); return 0; } void getMaxAndMin(int arr[], int len, int* max, int* min) { // 求数组最大值 *max = arr[0]; for (int i = 1; i < len; i++) { if (*max < arr[i]) { *max = arr[i]; } } //求数组最小值 *min = arr[0]; for (int i = 1; i < len; i++) { if (*min > arr[i]) { *min = arr[i]; } } }


2.3 指针的作用3----函数结果和计算状态分开

#include<stdio.h> /* 定义一个函数,将两数相除,获取它们的余数 */ int getRemainer(int a, int b, int* res); int main() { int a = 10; int b = 1; int res = 0; int flag = getRemainer(a, b, &res); if (!flag) { printf("获取到的余数为:%d\n",res); } return 0; } int getRemainer(int a, int b, int* res) { if (b == 0) { //停止 return 1; } *res = a % b; return 0; }



2.4 指针的作用4----方便地操作数组和函数




三: 指针的计算


- 指针中数据类型的作用:获取字节数据的个数
-指针加1,即一个步长,指针移动一次的字节个数
- 指针有意义的操作:
* 指针跟整数进行加/减操作,每次移动一个步长
* 指针跟指针进行减操作(间隔步长)

- 指针无意义的操作:
* 指针跟整数进行乘除操作
* 指针跟指针进行加/乘/除



四: 指向不明的指针


-野指针:指针指向的空间未分配
-悬空指针:指针指向的空间已分配,但是被释放了
-没有类型的指针void *p;
特点:无法获取数据,无法计算,但是可以接收任意地址,可以接受任意类型指针记录的内存地址
缺点:void类型的指针,无法获取变量里面的数据,也不能进行加/减的计算


五: 二级指针和多级指针


- 二级指针:数据类型(例如:int *)* 二级指针变量;
- 二级指针的作用1:可以操作一级指针记录的地址
- 二级指针的作用2:可以获取一级指针记录的地址中所存的值

#include<stdio.h> int main() { int a = 10; int b = 20; int* a_p = &a; int* b_p = &b; printf("a变量的内存地址为:%p\n",a_p);//000000C5FE52FB64 printf("b变量的内存地址为:%p\n",b_p);//000000C5FE52FB84 int** a_pp = &a_p; int** b_pp = &b_p; printf("a变量的内存地址为:%p\n", *a_pp);//000000C5FE52FB64 printf("b变量的内存地址为:%p\n", *b_pp);//000000C5FE52FB84 printf("a变量存的值为:%d\n",**a_pp);//10 printf("b变量存的值为:%d\n",**b_pp);//20 return 0; }


六: 数组指针


- 数组指针:指向数组的指针
- 数组指针的作用:方便的操作数组中的各种数据
- 指针数组的细节:数组名参与计算的时候,会退化为第一个元素的指针,除了以下两种特殊情况:
1. 进行sizeof运算的时候,不会退化,数组名还是整体,代表数组
2. 利用&数组名获取地址的时候,不会退化,步长 = 数据类型 * 数组长度

#include<stdio.h> /* 利用指针遍历数组 */ int main() { int arr[] = {11,22,33,44,55}; int len = sizeof(arr) / sizeof(arr[0]); //获取数组的指针,实际上获取的就是数组在内存中的首地址 int* p1 = arr; //或写成: int* p2 = &arr[0]; printf("p1指针所存的内存地址为:%p\n",p1); //0000003D614FFA78 printf("p2指针所存的内存地址为:%p\n",p2); //0000003D614FFA78 printf("数组arr占的字节为:%zu\n",sizeof(arr)); //40 printf("arr的值为数组的首地址:%p\n",arr); //0000003D614FFA78 printf("arr的值为数组的首地址:%p\n",&arr);////0000003D614FFA78 printf("这里代表的是数组首地址+1等于:%p", arr + 1);//地址值,移动了4个字节 printf("这里代表的是整个数组+1等于:%p", &arr + 1); // 地址值,移动了40个字节 //获取数组中的元素 printf("arr[0]的值为%d\n", *p1); //11 printf("arr[1]的值为%d\n", *(p1+1)); //22 printf("arr[2]的值为%d\n", *(p1 + 2)); //33 printf("arr[3]的值为%d\n", *(p1 + 3)); //44 printf("arr[4]的值为%d\n", *(p1 + 4)); //55 //利用指针遍历数组: for (int i = 0; i < len; i++) { printf("%d ",*(p1 + i)); //11 22 33 44 55 // printf("%d ",*p++ ); //11 22 33 44 55 } return 0; }


七: 二维数组


- 概念:把多个小数组放到一个大的数组当中
- 定义格式1:

数据类型 数组名[m][n] = { // m是二维数组的长度,代表有多少个一维数组 {3,6}, // n是一维数组的长度,代表每个一维数组有几个元素 {2,7,1,3}, {9,5,4}, … };



- 定义格式2:先定义一维数组,再将一维数组加入二维数组内

int arr1[4] = {3,6}; int arr2[4] = {2,7,1,3}; int* arr[2] = {arr1,arr2};



- 遍历:利用索引进行遍历 / 利用指针进行遍历



7.1 第1种定义格式下的二维数组遍历

#include<stdio.h> int main() { int arr[3][5]{ {1,5,2,3,4}, {9,7,2,4,2}, {6,4,7,4,3} }; //利用索引进行遍历 //arr[0]:表示二维数组当中的第一个一维数组:{1,5,2,3,4} //arr[1]:表示二维数组当中的第二个一维数组:{9,7,2,4,2} //arr[2]:表示二维数组当中的第三个一维数组:{6,4,7,4,3} for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { printf("%d ",arr[i][j]); } printf("\n"); } /* 遍历结果: 1 5 2 3 4 9 7 2 4 2 6 4 7 4 3 */ //利用指针进行遍历 //二维数组指针类型 //int[5] * p = arr; int(*p)[5] = arr; for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { printf("%d ", *(*p + j)); } printf("\n"); //移动二维数组的指针,继续遍历下一个一维数组 p++; } /* 遍历结果: 1 5 2 3 4 9 7 2 4 2 6 4 7 4 3 */ return 0; }


7.2 第2种定义格式下的二维数组遍历

#include<stdio.h> int main() { int arr[3][5]{ {1,5,2}, {9,7,2,4,2}, {6,4,7,7} }; //常规下:利用索引进行遍历 for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { printf("%d ", arr[i][j]); } printf("\n"); } /* 遍历结果: 1 5 2 0 0 9 7 2 4 2 6 4 7 7 0 */ //第一种方法,进行数组拆分,然后重组遍历 //1.定义3个一维数组 int arr1[] = { 1,5,2 }; int arr2[] = { 9,7,2,4,2 }; int arr3[] = { 6,4,7,7 }; int* arrArr[3] = { arr1,arr2,arr3 };//把三个一维数组放到二维数组中去 //2.预先计算每一个数组真实的长度 int len1 = sizeof(arr1) / sizeof(arr1[0]); int len2 = sizeof(arr2) / sizeof(arr2[0]); int len3 = sizeof(arr3) / sizeof(arr3[0]); int lenArr[] = {len1,len2,len3};//把每个一维数组的长度放到一个新数组中 for (int i = 0; i < 3; i++) { for (int j = 0; j < lenArr[i]; j++) { printf("%d ",arr[i][j]); } printf("\n"); } /* 遍历结果: 1 5 2 9 7 2 4 2 6 4 7 7 */ //第二种方法,利用指针进行遍历 //int* arrArr[3] = { arr1,arr2,arr3 }; //这个二维数组的指针类型:int* int** p = arrArr; //第二个*是指针变量标识符 for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) { printf("%d ",*(*p + j)); //或:printf("%d ", (*p)[j]); } printf("\n"); p++; } /* 遍历结果: 1 5 2 -858993460 -858993460 9 7 2 4 2 6 4 7 7 -858993460 */ return 0; }


八: 指针数组


- 顾名思义,就是存放指针的数组



九: 函数指针


- 格式:返回值类型 (*指针名)(形参列表)
- 作用:利用函数指针,可以动态的调用函数

#include<stdio.h> /* 函数指针 */ void method1(); int method2(int a, int b); int main() { //1.定义两个指针分别指向两个函数 void(*p1)() = method1; int (*p2)(int, int) = method2; //2.利用函数指针去调用函数 p1(); // method1()方法被执行了 int num = p2(10,20); printf("%d\n",num); //30 return 0; } void method1() { printf("method1()方法被执行了\n"); } int method2(int a, int b) { return a + b; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/27 9:31:14

Nginx性能优化终极指南:Linux服务器加速实战技巧

想要让你的网站加载速度提升50%以上吗&#xff1f;Nginx作为Linux服务器中最流行的Web服务器&#xff0c;其性能优化配置直接影响用户体验。本教程将为你揭示Nginx性能调优的核心秘诀&#xff0c;帮助你在Linux环境下实现网站性能提升的最佳效果。 【免费下载链接】Linux-Tutor…

作者头像 李华
网站建设 2026/2/27 3:42:36

AI销售自动化与客户管理的最佳获客软件选择--VertGrow AI销冠

AI销售自动化如何重塑客户管理体系在如今的数字化时代&#xff0c;AI销售自动化正在彻底改变客户管理体系。通过智能获客系统&#xff0c;企业能够更高效地获取潜在客户。像VertGrow AI销冠这样的智能获客工具&#xff0c;能够提升销售业绩&#xff0c;实现主动获客。这些获客软…

作者头像 李华
网站建设 2026/2/27 23:19:47

Naive UI 图片预览实用技巧:打造专业画廊效果的高效方法

Naive UI 图片预览实用技巧&#xff1a;打造专业画廊效果的高效方法 【免费下载链接】naive-ui A Vue 3 Component Library. Fairly Complete. Theme Customizable. Uses TypeScript. Fast. 项目地址: https://gitcode.com/gh_mirrors/na/naive-ui 还在为网站图片展示效…

作者头像 李华
网站建设 2026/2/27 20:26:18

Mermaid Live Editor 终极指南:实时图表编辑的完整解决方案

Mermaid Live Editor 终极指南&#xff1a;实时图表编辑的完整解决方案 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-live-e…

作者头像 李华
网站建设 2026/2/27 21:02:35

Drawnix白板工具:用代码思维重塑图形设计工作流

Drawnix白板工具&#xff1a;用代码思维重塑图形设计工作流 【免费下载链接】drawnix 开源白板工具&#xff08;SaaS&#xff09;&#xff0c;一体化白板&#xff0c;包含思维导图、流程图、自由画等。All in one open-source whiteboard tool with mind, flowchart, freehand …

作者头像 李华