目录

一.数组名的理解

二.使用指针访问数组

三.一维数组传参的本质 

四.冒泡排序

五.二级指针 

六.指针数组

6.1--指针数组的定义

6.2--指针数组模拟二维数组


🔥个人主页:@草莓熊Lotso的个人主页

🎬作者简介:C++方向学习者

📖个人专栏:《C语言》


一.数组名的理解

--在前面的学习中,我们使用指针访问数组时一般会采用以下两种形式,它们所到达的效果也是相同的。

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* pa = &arr[0];int* pb = arr;printf("&arr[0] = %p\n", pa);printf("arr = %p\n", pb);return 0;
}

在上述代码中我们分别使用&arr[0]和arr的方式拿到了数组的第一个元素的地址,这是因为数组名本身就是地址,而且是数组首元素的地址。

但是有两个例外我们需要注意一下:

  • sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表示整个数组,计算的是整个数组的⼤小,单位是字节
  • &数组名,这里的数组名表示整个数组,取出的是 整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)

那么我们就通过两个例子具体分析一下吧~

例子1:

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0;
}

如果arr是数组首元素的地址,那输出的应该是4/8 ,但这串代码的输出结果最后是40,这就证明的sizeof(数组名)计算的是整个数组的大小。

例子2:

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0]   = %p\n", &arr[0]);printf("&arr[0]+1 = %p\n", &arr[0] + 1);printf("arr       = %p\n", arr);printf("arr+1     = %p\n", arr + 1);printf("&arr      = %p\n", &arr);printf("&arr+1    = %p\n", &arr + 1);return 0;
}

我们来分步解析一下这串代码:

  1. 我们可以发现光看&arr,arr,&arr[0]打印出来的地址并没有任何区别,这是因为数组的起始地址也是首元素的地址,所以我们接下来对它们分别+1 来找区别。
  2. +1之后我们会发现,&arr[0]和&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,但是&arr 和 &arr+1相差40个字节。
  3. 这是因为&arr[0] 和 arr 都是⾸元素的地址,+1就是跳过⼀个元素,但是&arr是数组的地址,+1 操作是跳过整个数组的。

到这里想必大家都对数组名的意义有了正确的理解,我们接着往下看吧。


二.使用指针访问数组

--学习了前面的知识后,再结合数组的特点,我们就可以更方便的使用指针访问数组了。

#include <stdio.h>
int main()
{int arr[10] = { 0 };//输⼊int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);//输⼊int* p = arr;for (i = 0; i < sz; i++){scanf("%d", p + i);//scanf("%d", arr+i);//也可以这样写}//输出for (i = 0; i < sz; i++){printf("%d ", *(p + i));//*(p+i)等价于*(arr+i)也可写成arr[i]}return 0;
}

 通过上述代码我们可知,在这里arr和p是等价的,那我们可以使用arr[i]访问数组,是不是也可以使用p[i]呢?

答案是当然可以,其实本质上p[i]是等价于*(p+i)的,那么同理arr[i] 应该等价于 *(arr+i),数组元素的访问在编译器处理的时候,也是转换成⾸元素的地址+偏移量求出元素的地址,然后解引⽤来访问的,所以这几个使用那个都可以正确的打印出来结果。

还有一个比较有意思的等价关系给大家分享一下,但是不推荐使用:

arr[i] == *(arr+i) == *(i+arr) == i[arr]

大家可以发现,后面两个等价的很怪,但确实是可行的,其实就是用了交换律而已。


三.一维数组传参的本质 

--数组我们学过了,之前也讲了,数组是可以传递给函数的,这个小节我们讨论⼀下数组传参的本质。

首先从⼀个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把数组传给⼀个函数后,函数内部求数组的元素个数吗?
#include <stdio.h>
void test(int arr[])
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

我们通过上面这串代码的输出结果可以看出在函数内部没有正确获得数组的元素个数。这就涉及到数组传参的本质了。

之前我们学习了:数组名是数组首元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参传递的是数组首元素的地址。
        -- 所以函数形参的部分理论上应该使⽤指针变量来接收首元素的地址。那么在函数内部我们写sizeof(arr)计算的是⼀个地址的大小(单位字节),也就是计算一个指针变量的大小,而不是数组的大小(单位字节)。正是因为函数的参数部分的本质是指针,所以在函数内部是没办法求数组元素个数的。
void test(int arr[])//参数写成数组形式,本质上还是指针
{printf("%d\n", sizeof(arr));
}
void test(int* arr)//参数写成指针形式
{printf("%d\n", sizeof(arr));//计算⼀个指针变量的⼤⼩
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };test(arr);return 0;
}

 总结:一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。


四.冒泡排序

--冒泡排序的核心思想:两两相邻的元素进行比较。

//方法一
#include<stdio.h>
#include<string.h>void bubble_sort(int arr[], int sz)
{int i = 0;//趟数=元素个数-1=sz-1;for (i = 0;i < sz - 1;i++){int j = 0;//每一趟要比较的次数=元素个数-当前趟数-1=sz-i-1;for (j = 0;j < sz - i - 1;j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}
void print_arr(int arr[], int sz)
{for (int i = 0;i < sz;i++){printf("%d ", arr[i]);}
}
int main()
{int arr[10] = { 0 };//如果是arr[],后面就无法自己输入数字,要注意int sz = sizeof(arr) / sizeof(arr[0]);printf("请输入待排序的数字: ");for (int n = 0;n < sz;n++){scanf("%d", arr + n);}bubble_sort(arr, sz);printf("排序完成后的数字是: ");print_arr(arr, sz);return 0;
}
//方法二--优化
#include<stdio.h>
#include<string.h>
void bubble_sort(int arr[], int sz)
{int i = 0;//趟数=元素个数-1=sz-1;for (i = 0;i < sz - 1;i++){int j = 0;int flag = 0;//假设这趟是有序的//每一趟要比较的次数=元素个数-当前趟数-1=sz-i-1;for (j = 0;j < sz - i - 1;j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;flag = 0;//只要这趟有一次发生交换的,则无序}}if (flag == 1);//这一趟一次交换都没发生就说明已经有序了,不用继续排序了break;}
}
void print_arr(int arr[], int sz)
{for (int i = 0;i < sz;i++){printf("%d ", arr[i]);}
}
int main()
{int arr[10] = { 0 };//如果是arr[],后面就无法自己输入数字,要注意int sz = sizeof(arr) / sizeof(arr[0]);printf("请输入待排序的数字: ");for (int n = 0;n < sz;n++){scanf("%d", arr + n);}bubble_sort(arr, sz);printf("排序完成后的数字是: ");print_arr(arr, sz);return 0;
}

优化后的方法可以减少比较的次数,大大减少了程序运行的时间。


五.二级指针 

 --指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里呢。

那就是存放在二级指针里。

对于二级指针的运算有:

  • *ppa 通过对ppa中的地址进⾏解引⽤,这样找到的是 pa *ppa 其实访问的就是 pa 。
1  int b = 20;
2  *ppa = &b;//等价于 pa = &b;
  • **ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引⽤操作:*pa ,那找到的是 a 
1 **ppa = 30;
2 //等价于*pa = 30;
3 //等价于a = 30; 

六.指针数组

6.1--指针数组的定义

--我们先来思考一下指针数组是指针还是数组呢?

我们类比⼀下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
那指针数组呢?那肯定就是存放指针的数组。

 指针数组的每个元素都是用来存放地址(指针)的。指针数组的每个元素都是地址,又可以指向一块区域。

6.2--指针数组模拟二维数组

#include <stdio.h>
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数组中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;
}

parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数组中的元素。

上述的代码可以模拟出二维数组的效果,实际上并非完全是二维数组,因为每一行并非是连续的。

往期回顾:

【C语言】--指针超详解(一)

【C语言】--指针超详解(二)

 结语:本篇文章就到此结束了,继前面两篇文章后在此篇文章中给大家分享了大量数组和指针之间相联系的知识点,还有冒泡排序等,如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持,后续会继续更新指针相关内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/82318.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/82318.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/82318.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux防火墙

1.防火墙是一种位于内部网络与外部网络之间的网络安全系统&#xff0c;它依照特定的规则&#xff0c;允许或限制传输的数据通过&#xff0c;以保护内部网络的安全。以下从功能、分类、工作原理等方面为你详细讲解&#xff1a; 功能访问控制&#xff1a;这是防火墙最主要的功能。…

嵌入式培训之C语言学习完(十七)结构体、共用体、枚举、typedef关键字与位运算

目录 一、结构体&#xff08;struct关键字&#xff09; &#xff08;一&#xff09;声明一个结构体数据类型 &#xff08;二&#xff09;结构体的成员初始化与赋值 a、结构体变量赋值 b、结构体成员初始化 c、结构体的定义形式 &#xff08;三&#xff09;考点&#xff…

Python字典:数据操作的核心容器

在Python编程生态中&#xff0c;字典&#xff08;dict&#xff09;是最常用且功能强大的内置数据结构之一。它以键值对&#xff08;Key-Value Pair&#xff09;的形式存储数据&#xff0c;为快速查找、灵活映射关系提供了天然支持。无论是数据清洗、算法实现还是Web开发&#x…

按位宽提取十六进制值

需求&#xff1a;给出一个十六进制值&#xff0c;要求提取high和low位之间的值。比如16ha0f0&#xff0c;这是一个16bit宽的十六进制数0xa0f0&#xff0c;提取[15:12]范围内的值。 def extract_bits(value, high, low):"""从 value 中提取 [high:low] 位的值:p…

LeRobot 项目部署运行逻辑(六)——visualize_dataset_html.py/visualize_dataset.py

可视化脚本包括了两个方法&#xff1a;远程下载 huggingface 上的数据集和使用本地数据集 脚本主要使用两个&#xff1a; 目前来说&#xff0c;ACT 采集训练用的是统一时间长度的数据集&#xff0c;此外&#xff0c;这两个脚本最大的问题在于不能裁剪&#xff0c;这也是比较好…

SSTI模版注入

1、概念 SSTI是一种常见的Web安全漏洞&#xff0c;它允许攻击者通过注入恶意模板代码&#xff0c;使服务器在渲染模板时执行非预期的操作。 &#xff08;1&#xff09;渲染模版 至于什么是渲染模版&#xff1a;服务器端渲染模板是一种Web开发技术&#xff0c;它允许在服务器端…

关于点胶机的精度

一、精度&#xff1a; 1:X/y轴定位精度常通在5个丝左右&#xff0c;Z轴在3个丝左右&#xff0c; 如果采用伺服电机丝杆配置&#xff0c;可提升至于个2丝左右。 2&#xff1a;胶水控制精度&#xff1a;通过喷阀驱动器&#xff0c;气压等参数&#xff0c;实现胶量控制&#xf…

gitee推送更新失败问题记录:remote: error: hook declined to update refs/heads/master

问题描述&#xff1a; gitee推送更新时&#xff0c;提示&#xff1a; 解决方法&#xff1a; 登录Gitee&#xff0c;进入【个人主页】 点击【个人设置】 更改邮箱的配置&#xff0c;如下&#xff1a; 更改“禁止命令行推送暴露个人邮箱”&#xff0c;将其关闭&#xff1a;

Java如何获取电脑分辨率?

以下是一个 Java 程序示例&#xff0c;用于获取电脑的主屏幕分辨率&#xff1a; import java.awt.*; public class ScreenResolutionExample { public static void main(String[] args) { // 获取默认的屏幕设备 GraphicsDevice device GraphicsEnvironm…

WPF 3D图形编程核心技术解析

一、三维坐标系系统 WPF采用右手坐标系系统&#xff0c;空间定位遵循&#xff1a; X 轴 → 右 Y 轴 → 上 Z 轴 → 观察方向 X轴 \rightarrow 右\quad Y轴 \rightarrow 上\quad Z轴 \rightarrow 观察方向 X轴→右Y轴→上Z轴→观察方向 三维坐标值表示为 ( x , y , z ) (x, y,…

【库(Library)、包(Package)和模块(Module)解析】

在Python中&#xff0c;**库&#xff08;Library&#xff09;、包&#xff08;Package&#xff09;和模块&#xff08;Module&#xff09;**是代码组织的不同层级&#xff0c;而import语句的导入行为与它们密切相关。以下是详细对比和解释&#xff1a; &#x1f4e6; 1. 核心概…

裸机上的 printf:在无操作系统环境下构建 C 标准库

在嵌入式开发和底层系统编程领域&#xff0c;裸机开发是一项极具挑战性但又至关重要的任务。想象一下&#xff0c;在没有操作系统支持的情况下&#xff0c;让 C 语言的标准库函数&#xff0c;如printf正常工作&#xff0c;这听起来是不是很有趣又充满挑战&#xff1f;今天&…

基于STM32F103的智能机械臂识别与控制项目(课件PPT+源代码)

以下是基于 STM32F103 的智能机械臂识别与控制项目的详细介绍&#xff1a; 项目概述 该项目以 STM32F103 为核心控制器&#xff0c;结合多种传感器和技术&#xff0c;实现了机械臂的智能识别与控制功能&#xff0c;可完成仓库货物的识别、搬运等任务&#xff0c;并支持多种控…

Codeforces Round 1023 (Div. 2)

Dashboard - Codeforces Round 1023 (Div. 2) - Codeforces 一个构造问题&#xff0c;我把最大的数放在一个数组&#xff0c;其余数放在另一个数组&#xff0c;就能保证gcd不同 来看代码&#xff1a; #include <bits/stdc.h> using namespace std;int main() {int t;ci…

6.01 Python中打开usb相机并进行显示

本案例介绍如何打开USB相机并每隔100ms进行刷新的代码,效果如下: 一、主要思路: 1. 打开视频流、读取帧 self.cam_cap = cv2.VideoCapture(0) #打开 视频流 cam_ret, cam_frame = self.cam_cap.read() //读取帧。 2.使用定时器,每隔100ms读取帧 3.显示到Qt的QLabel…

JVM——即时编译

分层编译模式&#xff1a;动态平衡启动速度与执行效率 分层编译是现代JVM&#xff08;如HotSpot、GraalVM&#xff09;实现高性能的核心策略之一&#xff0c;其核心思想是根据代码的执行热度动态选择不同的编译层次&#xff0c;实现启动速度与运行效率的最佳平衡。以HotSpot虚…

Auto DOP:让并行执行实现智能调优 | OceanBase 实践

随着数据量的迅速增长&#xff0c;企业数据库往往面临着一个困局&#xff1a;复杂的分析查询需要充分的资源来保证性能&#xff0c;但过多增加并行执行又会造成资源竞争&#xff0c;影响系统稳定性。传统基于DBA人工干预的并行度调节机制&#xff0c;既低效又难以适应动态变化的…

【区块链】Uniswap之滑点(Slippage)

一、滑点是什么&#xff1f; 滑点&#xff08;Slippage&#xff09;是指你下单预期价格和最终成交价格之间的差距。 在 DEX 中&#xff0c;你的交易会影响池子的价格&#xff08;AMM机制&#xff09;&#xff0c;所以&#xff1a; 下单越大&#xff0c;滑点越大&#xff1b;…

[前端]Javascript获取元素宽度

元素宽度属性对比示意图 ---------------------------------- | 外边距&#xff08;margin&#xff09; | -------------------------------- | | 边框&#xff08;border&#xff09; | | | -------------------------- | | | …

数字人驱动/动画方向最新顶会期刊论文收集整理 | AAAI 2025

会议官方论文列表&#xff1a;https://ojs.aaai.org/index.php/AAAI/issue/view/624 以下论文部分会开源代码&#xff0c;若开源&#xff0c;会在论文原文的摘要下方给出链接。 语音驱动头部动画/其他 EchoMimic: Lifelike Audio-Driven Portrait Animations through Editabl…