当前位置: 首页 > news >正文

【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. 一般情况下&#xff0c;数组名就是数组首元素的地址。 2. 特殊情况1&#xff1a;sizeof(数…...

Rust 泛型使用过程中的 <T> 和 ::<T> 的区别

Rust 的泛型语法中&#xff0c;<T> 和 ::<T> 有不同的用途和上下文&#xff0c;但它们都与泛型有关。 <T> 在类型定义中 当你在定义函数、结构体、枚举或其他类型时&#xff0c;使用 <T> 来表示泛型参数。例如&#xff1a; fn identity<T>(x:…...

C语言 ——注释

1.1 单行注释 - 语法&#xff1a;// 待注释的内容 - 位置&#xff1a;可放在代码后&#xff0c;称之为行尾注释&#xff1b; 也可放代码上一行&#xff0c;称作行上注释。 c // 这是单行注释文字 1.2 多行注释 - 语法&#xff1a;/* 待注释的内容 */ - 注意&#xff1a;多⾏…...

C# 协程的使用

C# 中的协程是通过使用 yield 关键字来实现的&#xff0c;它们允许在方法的执行中暂停和继续。协程通常用于处理异步操作、迭代和状态机等情况。以下是关于C#协程的介绍、使用场景以及优缺点的概述&#xff1a; 介绍&#xff1a; 在 C# 中&#xff0c;协程是通过使用 yield 语…...

程序分享--C语言字母转换大小写的3种方法

关注我&#xff0c;持续分享逻辑思维&管理思维&#xff1b; 可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导&#xff1b; 有意找工作的同学&#xff0c;请参考博主的原创&#xff1a;《面试官心得--面试前应该如何准备》&#xff0c;《面试官心得--面试时如何进行自…...

jmeter发送请求参数如何使用变量

问题描述 发送jmeter请求时&#xff0c;想设置请求参数为变量 解决方法...

go go.mod file not found in current directory or any parent directory

场景&#xff1a; 安装好 liteide 之后创建了第一个 “hello world” 的golang 项目&#xff0c;却报了如下错误。 原因分析&#xff1a; go 的环境配置问题。与 golang 的包管理有关。 解决方案&#xff1a; 如果你是 Windows 系统&#xff0c;快捷键 “WinR”&#xff0c…...

K8s的kubeadm方式部署集群实例

目录 一、准备环境 主机清单 修改主机名 设置防火墙、selinux状态 主机名解析 固定ip 重启网卡 同步时间 关闭swap分区 二、获取镜像 三、安装docker 四、配置kubeadm源 安装依赖包及常用插件 1.配置kubeadm源&#xff0c;安装对应版本 2.加载相关ipvs模块 3.配…...

GRU-深度学习循环神经网络情感分类模型搭建

摘要&#xff1a; 本文详细介绍了基于GRU的深度学习循环神经网络在情感分类任务中的应用&#xff0c;涵盖基础知识回顾、功能实现、技巧与实践、性能优化与测试&#xff0c;以及常见问题解答等环节。 阅读时长&#xff1a;约30分钟 关键词&#xff1a;GRU, 深度学习, 循环神经…...

ELK日志中心搭建(六)- harbor镜像仓库

CentOS 搭建 Harbor 镜像仓库&#xff08;图文详解&#xff09;_centos harbor-CSDN博客...

初识进程状态

&#x1f30e;进程状态【上】 文章目录&#xff1a; 进程状态 发现进程的状态 运行队列 进程排队 进程状态的表述       状态在代码中的表示       运行状态       阻塞状态       挂起状态 总结 前言&#xff1a; 为了搞明白正在运行的进程是什么意思…...

线程的使用

目录 1&#xff0c;创建线程的几种方式 2&#xff0c;示例 3&#xff0c;线程常用方法 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.国家区号列表&#xff08;带字母索引侧边栏&#xff09; 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 概述: 随着工业自动化程度的不断提高&#xff0c;变频器也得到了非常广泛的应用。作为电力电子器件&#xff0c;变频器中要进行大功率二极管整流&#xff0c;大功率晶体管变压&#xff0c;在输入输出回路产生电流高次谐波&#xff0c;干扰供电系统、负载以及附…...

探索Linux世界:基本指令(文件查看、时间相关、grep、打包压缩及相关知识)

今天继续介绍一些指令 文章目录 1.cat - 查看文件1.1输出重定向和追加重定向1.2指令echo 2.more 指令3.less - 逐页查看文本文件内容4.head- 显示文件开头部分内容5.tail - 显示文件末尾部分内容5.1输入重定向&#xff08;<&#xff09;5.2管道&#xff08;|&#xff09; 6.…...

简单使用国产数据库—达梦

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

STM32点亮LED灯与蜂鸣器发声

STM32之GPIO GPIO在输出模式时可以控制端口输出高低电平&#xff0c;用以驱动Led蜂鸣器等外设&#xff0c;以及模拟通信协议输出时序等。 输入模式时可以读取端口的高低电平或电压&#xff0c;用于读取按键输入&#xff0c;外接模块电平信号输入&#xff0c;ADC电压采集灯 GP…...

Android UI: 自定义控件:可换行的布局控件

文章目录 继承ViewGroup重写onMeasure方法&#xff1a;计算并设置布局控件的高度重写onLayout方法&#xff1a;计算并设置每个子控件的位置具体的代码实现小结 继承ViewGroup 重写generateLayoutParams&#xff0c;设置子控件的LayoutParams为MarginLayoutParams类型 Overridep…...

Linux(Ubuntu)中安装vscode

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

MQTT Topic通配符

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...