【C语言_指针[2]_复习篇】
目录
一、数组名的理解
二、使用指针访问一维数组中的每个元素
三、一维数组传参的本质
四、冒泡排序
五、二级指针
六、指针数组
七、指针数组模拟二维数组
一、数组名的理解
1. 一般情况下,数组名就是数组首元素的地址。
2. 特殊情况1:sizeof(数组名),这里的数组名指的是整个数组,sizeof计算的结果也将是整个数组的大小。
3. 特殊情况2:&数组名,这里取到的地址是整个数组的地址。
4. 数组首元素的地址和数组的地址两者的区别:指针变量进行+-整数操作时,向前向后一步移动的距离是有差异的,例如下图代码,arr == &arr[0] != &arr,当arr和&arr的地址同时进行+1操作时,arr的地址移动的是4个字节,而&arr的地址移动的是40个字节。
0x....A4 - 0x....CC = 10*16+4+1 - 12*16+12*1= -40。
5. 注意不要混淆:数组名一般情况下是数组首元素的地址,函数名是函数的地址,而变量名不能理解成变量的地址,它仅仅代表变量本身而已。
二、使用指针访问一维数组中的每个元素
1. 请注意!指针变量本身就是地址,p == arr。如果想直接使用拿到的地址,也可以不进行把地址存入指针变量的操作,直接将地址当作指针变量进行解引用、+- 整数操作也行。
2. arr[i] 的不同写法理解:.......
① arr[i] 本质是 *(arr+i),通过数组首元素地址偏移并解引用地址,即可找到数组中的每一位元素。
② [i]arr 是 *(arr+i) 交换律的产物,即 [i]arr 的本质是 *(i+arr),不过很少在代码中如此表达。
3. 总之,当我们想要访问一个数组每个元素时,可以利用数组首元素地址arr或存有数组首元素地址的指针p+ [i],表示利用数组首元素地址偏移并解引用找到地址所指向的变量,arr[i] == p[i],或写成 i[arr]==i[arr];也可以写成这种形式 *(arr+i)=*(p+i) 。
//使用指针访问一维数组中的每个元素
int main()
{int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;//数组名是数组首元素的地址,地址所指向的变量是int类型int i = 0;//循环变量for (i = 0; i < sz; i++){//一边输入,一边输出scanf("%d", p + i);printf("%d ", *(p + i));//利用地址偏移并解引用地址找到指针所指向的数组元素//写法二:利用地址直接代替指针//scanf("%d", arr + i);//printf("%d ", *(arr + i));//写法三:arr与i实行交换律的产物//scanf("%d", p + i); //arr[i]==*(p + i)==*(arr + i)//printf("%d ", i[arr]); //*(arr + i)==*(i + arr)==i[arr]//即arr[i]本质是*(arr+i)//即[i]arr本质是*(i+arr)}return 0;
}
三、一维数组传参的本质
1. 一维数组传参,本质上传递的是数组⾸元素的地址,而不是整个数组,也不是整个数组的地址。
2. 数组的大小只能在自己所被创建的函数中求,所以我们常常把数组的大小作为一个函数的参数一起传给自定义函数。test(arr, sz);//sz是数组arr的大小
3. ⼀维数组传参,形参的部分的两种写法:① 直接写成数组的形式,②写成指针变量的形式,但这两种写法形参的本质都是数组首元素地址,只是有不同写法而已。
void test(int arr[ ]); == void test(int* p);
4. 注意理解:一维数组传参属于传址调用。
//在函数内部求数组的大小
//结论:数组传参本质上传递的是数组⾸元素的地址,而不是整个数组
// 数组的大小只能在自己所被创建的函数中求void test(int arr[])//现在的arr是存有数组首元素地址的指针,x86下指针的大小是4字节
{int sz2 = sizeof(arr) / sizeof(arr[2]);//这里的arr[i]==*(arr+i)表示一个整型变量//大小为4字节printf("sz2=%d\n", sz2);//打印1
}int main()
{int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1=%d\n", sz1);//打印10test(arr);//掉用test函数求arr的大小return 0;
}
//用函数调用的方式打印一维数组中的内容//形参写法一:
void Print(int* p, int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", *(p + i));}
}形参写法二:
//void Print(int arr[], int sz)
//{
// int i = 0;
// for (i = 0; i < sz; i++)
// {
// printf("%d ", arr[i]);
// }
//}int main()
{int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int sz = sizeof(arr) / sizeof(arr[0]);Print(arr, sz);//将一维数组首元素的地址和数组的大小一并传给了Print函数return 0;
}
四、冒泡排序
1. 排序的趟数==元素个数-1。
2. 每趟排序结束后,下一趟最高的数组下标要在现有基础上-1。
3. 在开始冒泡排序前利用flag=1假设原本数组的排序就是最终想要的序列,如果一旦在第一趟冒泡排序中,程序没有进入到交换阶段,那么这个序列一定就是最终想要的序列,否则就继续正常进行冒泡排序。
void Bubble_sort(int arr[], int sz)
{int flag = 1;int i = 0, j = 0;for (i = 0; i < sz - 1; i++){for (j = 0; j < sz - i; j++)//趟数==元素个数-1{if (arr[j] < arr[j + 1]){flag = 0;int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}if (flag){break;}}
}void Print(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}int main()
{int arr[] = { 1, 2, 3, 4, 5, 6 ,7 ,8 ,9 ,10 };int sz = sizeof(arr) / sizeof(arr[0]);Bubble_sort(arr, sz);Print(arr, sz);return 0;
}
五、二级指针
1. 二级指针就是存放指针变量地址的指针变量。
2. 对二级指针两次解引用就可以找到其对应一级指针所指向的变量。
int main()
{int n = 0;int* p = &n;int** p2 = &p;//二级指针,第二颗*表示p2是一个指针变量,int*表示所指向的变量类型**p2 = 20;//*p2==p, 而*p==n,所以**p2==nprintf("%d\n", n);//打印20return 0;
}
六、指针数组
1. 指针数组就是存放指针的数组,数组中的每个元素都是指针(地址)。
2. 指针数组的类型是由数组中每个指针的类型决定的。
int main()
{int arr1[] = { 1, 2, 3 };int arr2[] = { 2, 3, 4 };int arr3[] = { 3, 4, 5 };int* arr[3] = { arr1, arr2, arr3 };//指针数组//由于数组名是数组首元素的地址,每个数组首元素的地址又是int*类型的//所以arr指针数组的类型是int*[3]return 0;
}
七、指针数组模拟二维数组
1. 模拟的⼆维数组,并⾮完全是⼆维数组,因为每⼀⾏的数据在内存中是⾮是连续的。
2. 下图代码的解释:parr是数组首元素的地址,而parr首元素的地址是数组arr1的地址,我们可以通过对parr+-整数拿到parr中每个元素的地址,即内部每个数组的地址,再通过对这些地址解引用拿到,每个内部数组首元素地址,最后通过首元素的地址偏移和解引用,找到parr内部数组中的每个元素,即有了 *(*(arr+i) + j) == parr[i][j] 。
int main()
{int arr1[] = {1,2,3,4,5};int arr2[] = {2,3,4,5,6};int arr3[] = {3,4,5,6,7};int* parr[3] = {arr1, arr2, arr3};int i = 0;int j = 0;for(i=0; i<3; i++){for(j=0; j<5; j++){printf("%d ", parr[i][j]);}printf("\n");}return 0;
}
相关文章:

【C语言_指针[2]_复习篇】
目录 一、数组名的理解 二、使用指针访问一维数组中的每个元素 三、一维数组传参的本质 四、冒泡排序 五、二级指针 六、指针数组 七、指针数组模拟二维数组 一、数组名的理解 1. 一般情况下,数组名就是数组首元素的地址。 2. 特殊情况1:sizeof(数…...
Rust 泛型使用过程中的 <T> 和 ::<T> 的区别
Rust 的泛型语法中,<T> 和 ::<T> 有不同的用途和上下文,但它们都与泛型有关。 <T> 在类型定义中 当你在定义函数、结构体、枚举或其他类型时,使用 <T> 来表示泛型参数。例如: fn identity<T>(x:…...

C语言 ——注释
1.1 单行注释 - 语法:// 待注释的内容 - 位置:可放在代码后,称之为行尾注释; 也可放代码上一行,称作行上注释。 c // 这是单行注释文字 1.2 多行注释 - 语法:/* 待注释的内容 */ - 注意:多⾏…...
C# 协程的使用
C# 中的协程是通过使用 yield 关键字来实现的,它们允许在方法的执行中暂停和继续。协程通常用于处理异步操作、迭代和状态机等情况。以下是关于C#协程的介绍、使用场景以及优缺点的概述: 介绍: 在 C# 中,协程是通过使用 yield 语…...
程序分享--C语言字母转换大小写的3种方法
关注我,持续分享逻辑思维&管理思维; 可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导; 有意找工作的同学,请参考博主的原创:《面试官心得--面试前应该如何准备》,《面试官心得--面试时如何进行自…...

jmeter发送请求参数如何使用变量
问题描述 发送jmeter请求时,想设置请求参数为变量 解决方法...

go go.mod file not found in current directory or any parent directory
场景: 安装好 liteide 之后创建了第一个 “hello world” 的golang 项目,却报了如下错误。 原因分析: go 的环境配置问题。与 golang 的包管理有关。 解决方案: 如果你是 Windows 系统,快捷键 “WinR”,…...

K8s的kubeadm方式部署集群实例
目录 一、准备环境 主机清单 修改主机名 设置防火墙、selinux状态 主机名解析 固定ip 重启网卡 同步时间 关闭swap分区 二、获取镜像 三、安装docker 四、配置kubeadm源 安装依赖包及常用插件 1.配置kubeadm源,安装对应版本 2.加载相关ipvs模块 3.配…...
GRU-深度学习循环神经网络情感分类模型搭建
摘要: 本文详细介绍了基于GRU的深度学习循环神经网络在情感分类任务中的应用,涵盖基础知识回顾、功能实现、技巧与实践、性能优化与测试,以及常见问题解答等环节。 阅读时长:约30分钟 关键词:GRU, 深度学习, 循环神经…...
ELK日志中心搭建(六)- harbor镜像仓库
CentOS 搭建 Harbor 镜像仓库(图文详解)_centos harbor-CSDN博客...

初识进程状态
🌎进程状态【上】 文章目录: 进程状态 发现进程的状态 运行队列 进程排队 进程状态的表述 状态在代码中的表示 运行状态 阻塞状态 挂起状态 总结 前言: 为了搞明白正在运行的进程是什么意思…...
线程的使用
目录 1,创建线程的几种方式 2,示例 3,线程常用方法 3.1 std::thread类 3.1.1 成员变量 3.1.2 thread成员函数 3.1.2.1 thread 构造函数 3.1.2.2 thread 析构函数 3.1.2.3 get_id 获取线程id 3.1.2.4 joinable 3.1.2.5 join 加入 …...

flutter选择国家或地区的电话号码区号
1.国家区号列表(带字母索引侧边栏) import package:generated/l10n.dart; import package:widget/login/area_index_bar_widget.dart; import package:flutter/material.dart; import package:flutter_screenutil/flutter_screenutil.dart;class LoginA…...

信号隔离器在PLC/DCS控制系统的应用
彭姝麟 Acrelpsl 概述: 随着工业自动化程度的不断提高,变频器也得到了非常广泛的应用。作为电力电子器件,变频器中要进行大功率二极管整流,大功率晶体管变压,在输入输出回路产生电流高次谐波,干扰供电系统、负载以及附…...

探索Linux世界:基本指令(文件查看、时间相关、grep、打包压缩及相关知识)
今天继续介绍一些指令 文章目录 1.cat - 查看文件1.1输出重定向和追加重定向1.2指令echo 2.more 指令3.less - 逐页查看文本文件内容4.head- 显示文件开头部分内容5.tail - 显示文件末尾部分内容5.1输入重定向(<)5.2管道(|) 6.…...

简单使用国产数据库—达梦
达梦数据库是一款由中国的达梦软件公司开发的关系数据库管理系统(RDBMS),它在业界以其高性能、可扩展性和安全性而著称。该系统广泛应用于各种应用程序的数据存储和管理,满足用户对于数据处理和管理的多样化需求。 安装好的达梦数…...

STM32点亮LED灯与蜂鸣器发声
STM32之GPIO GPIO在输出模式时可以控制端口输出高低电平,用以驱动Led蜂鸣器等外设,以及模拟通信协议输出时序等。 输入模式时可以读取端口的高低电平或电压,用于读取按键输入,外接模块电平信号输入,ADC电压采集灯 GP…...
Android UI: 自定义控件:可换行的布局控件
文章目录 继承ViewGroup重写onMeasure方法:计算并设置布局控件的高度重写onLayout方法:计算并设置每个子控件的位置具体的代码实现小结 继承ViewGroup 重写generateLayoutParams,设置子控件的LayoutParams为MarginLayoutParams类型 Overridep…...

Linux(Ubuntu)中安装vscode
①首先去vscode的官网下载.deb文件 网址:https://code.visualstudio.com/docs/?dvlinuxarm64_deb 注:如果linux端无法打开网页下载文件,可以在Windows端下载好用WinSCP传输到Linux。下载前注意下你的系统架构是arm还是amd,系统…...

MQTT Topic通配符
🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 往期热门专栏回顾 专栏…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...