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

【C语言系列】深入理解指针(2)

一、数组名的理解

上一篇文章中我们写过一个这样的代码:

int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];

这里使用&arr[0] 的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,而且是数组首元素的地址,观察下面代码:

#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 = %p\n", arr);   
return 0;
}

运行结果如下图:
在这里插入图片描述
通过运行代码我们可以知道**&arr[0] 拿到了数组第一个元素的地址和数组名拿到的地址是一样的。(即数组名就是数组首元素的地址)**
见下方代码:

#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;}

运行结果如下图:
在这里插入图片描述
观察上述代码,不难看出如果数组名是首元素的地址那么打印出来应该是4或者8。
那么数组名到底是不是首元素的地址呢?出现这种情况又怎样理解呢?
答案是肯定的,数组名就是数组首元素的地址,但是有两种情况下例外:

1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位为字节。
2.&数组名,这里的数组名也是表示整个数组,取出的是整个数组的地址。

除此之外,所有的数组名都是数组首元素的地址。
那么问题又来了,那arr和&arr有啥区别呢?

#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;
}

运行结果如图:
在这里插入图片描述
这里我们发现&arr[0]和&arr[0]+1相差4个字节, arr和arr+1相差4个字节,是因为&arr[0]和arr都是首元素的地址,+1就是跳过一个元素。但是&arr和&arr+1相差40个字节,这就是因为 &arr是整个数组的地址,+1操作是跳过整个数组的地址。

二、使用指针访问数组

#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//打印数组内容
int*p = arr;//int*p = &arr[0];
int sz = sizeof(arr)/sizeof(arr[0]);
int i = 0;
//给数组输入10个值
//for(i = 0;i < sz;i++)
//{
//scanf("%d",&arr[i]);
//}
for(i = 0;i < sz;i++)
{
scanf("%d",p++);
}
//输出
for(i = 0;i < sz;i++)
{
printf("%d",*p);
p++;
//这里可以合起来写成:printf("%d",*(p + i));
}
return 0;
}

观察上述代码后,我们来捋捋可以等价替换的式子,如下图所示:
在这里插入图片描述

三、一维数组传参的本质

我们之前都是在函数外部计算数组的元素个数,现在我们把数组传给⼀个函数后,在函数内部求数组的元素个数,代码如下:

#include <stdio.h>
void test(int arr[])//这里括号中可以替换为int*arr
{
int sz2 = sizeof(arr)/sizeof(arr[0]);
printf("sz2 = %d\n",sz2);//1
}
int main()
{
int arr[10] = {0};
int sz1 =sizeof(arr)/sizeof(arr[0]);//10
printf("sz1 = %d\n",sz1);
test(arr);//本质上arr是指针
//这里的arr没有单独放在sizeof内部也没有&,所以arr是数组首元素的地址。
return 0;
}

运行结果如下图:
在这里插入图片描述
观察上述代码和运行结果可得:在函数内部是没有正确获得数组的元素个数。数组名是数组首元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参传递的是数组首元素的地址,所以函数形参的部分理论上应该使用指针变量来接收首元素的地址。sizeof(arr) 计算的是一个地址的大小(单位字节)而不是数组的大小(单位字节)。正因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。
总结:1.一维数组传参的时候,传过去的是数组首元素的地址。
2.形参的部分可以写成指针的形式,也可以写成数组的形式,但本质上都是指针,写成数组的形式是为了方便理解。

四、冒泡排序

排序算法:
1.冒泡排序
2.选择排序
3.插入排序
4.快速排序
5.堆排序
6.希尔排序

冒泡排序的思想:
1.两两相邻的元素进行比较,如果不满足顺序就交换,满足顺序就找下一对。
在这里插入图片描述
代码如下:

#include <stdio.h>
void bubble_sort(int arr[],int sz)
{
int i = 0;
//趟数
for(i = 0;i < sz-1;i++)
{
//一趟冒泡排序
int j = 0;
for(j = 0;j < sz-1-i;j++)
{
if(arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
void printf_arr(int arr[],int sz)
{
int i = 0;
for(i = 0;i < sz;i++)
{
printf("%d",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = {9,8,7,6,5,4,3,2,1,0};//降序
//实现排序,排成升序
int sz = sizeof(arr) / sizeof(arr[0]);
printf_arr(arr,sz);
bubble_sort(arr,sz);
printf_arr(arr,sz);
return 0;
}

运行结果如图:
在这里插入图片描述
这个代码还可以优化一下,代码如下:

#include <stdio.h>
int count = 0;
void bubble_sort(int*arr,int sz)
{
int i = 0;//趟数
for(i = 0;i < sz;i++)
{
//一趟冒泡排序
int flag = 1;
int j = 0;
for(j = 0;j < sz-1-i;j++)
{
count++;
if(*(arr + j) > *(arr + j +1))
{
int tmp = *(arr +j);
*(arr + j) = *(arr + j + 1);
*(arr + j + 1) = tmp;
flag = 0;//不是有序
}
}
if(flag == 1)
{
break;
}
}
}
int main()
{int arr[] = {3,1,7,5,8,9,0,2,4,6};int sz = sizeof(arr)/sizeof(arr[0]);bubble_sort(arr, sz);int i = 0;for(i=0; i<sz; i++){printf("%d ", arr[i]);}return 0;
}

运行结果如下图:
在这里插入图片描述

五、二级指针

一级指针变量也是变量,是变量就有地址,那一级指针变量的地址存放在哪⾥?存放在⼆级指针中。
二级指针的介绍如下图:
在这里插入图片描述

#include <stdio.h>
int main()
{
int a = 10;
int*p = &a;
int**pp = &p;
**pp = 20;//两次解引用才能拿到初始变量a,依次解引用只能拿到一级指针p的地址。
printf("%d\n",a);
return 0;
}

运行结果如下图:
在这里插入图片描述

六、指针数组

指针数组是指针还是数组?
指针数组是存放指针的数组即它本质上是数组。
指针数组的每一个元素都是用来存放地址(指针)的,指针数组的每一个元素是地址,又可以指向一块区域。
在这里插入图片描述

七、指针数组模拟二维数组

代码如下:

#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语言系列】深入理解指针(2)

一、数组名的理解 上一篇文章中我们写过一个这样的代码&#xff1a; int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0];这里使用&arr[0] 的方式拿到了数组第⼀个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;而且是数组首元素的地址&#xff…...

与 Spring Boot 的无缝集成:ShardingSphere 快速集成实践

ShardingSphere 是一个轻量级的开源分布式数据库中间件&#xff0c;它支持分库分表、分布式事务、读写分离等功能。它能够与各种应用框架进行集成&#xff0c;其中与 Spring Boot 的集成非常流行&#xff0c;因为它能够帮助开发者在 Spring Boot 项目中快速实现高性能的分布式数…...

【QT】窗口/界面置于最前端显示,且激活该窗口

目录 0.环境 1.问题描述 2.具体实现 0.环境 windows11 qt 1.问题描述 我有一个窗口QMainWindow&#xff08;也适用于QWidget或QDialog&#xff09;&#xff0c;想让其在显示的时候置于最前面&#xff0c;且激活成为当前活动窗口 2.具体实现 mainWindow->show();mainWind…...

DOL-288 多功能电子计时器说明书

新买一个计时器&#xff0c;它的用法不太直观&#xff0c;所以把说明书留在这里&#xff0c;以便以后查询。 DOL-288 多功能电子计时器说明书 1.功能说明&#xff1a; 正计时功能&#xff0c;计时上限为23小时59分59秒倒计时功能&#xff0c;计时上限为23小时59分59秒&#…...

14 常用的负载均衡算法

基于nginx的代理 1. 轮询算法 例如我们在nginx服务器中代理了3台服务器&#xff0c;再每次客户端发起请求的时候按照顺序请求挨次的发送到代理的三台服务器上。该算法比较适合每台服务器性能差不多的场景&#xff0c;如果部分服务器性能比较差&#xff0c;可能会造成性能好的…...

方法建议ChatGPT提示词分享

方法建议 ChatGPT能够根据您的具体需求提供针对性的建议&#xff0c;帮助您选择最合适的研究方法。通过清晰的提示&#xff0c;ChatGPT可以精准地为您提供最契合的研究方案。此外&#xff0c;它还能协助您将这些方法灵活地应用于新的研究环境&#xff0c;提出创新的技术解决方案…...

如何提高自动化测试覆盖率和效率

用ChatGPT做软件测试 在现代软件开发中&#xff0c;自动化测试已经成为保证软件质量的重要手段。然而&#xff0c;在实践中&#xff0c;自动化测试的覆盖率和效率常常受到限制&#xff0c;导致潜在缺陷未能及时发现或测试资源浪费。因此&#xff0c;提升自动化测试的覆盖率和效…...

Django学习笔记(安装和环境配置)-01

Django学习笔记(安装和环境配置)-01 一、创建python环境 1、可以通过安装Anaconda来创建一个python环境 # 创建一个虚拟python环境 conda create -n django python3.8 # 切换激活到创建的环境中 activate django2、安装django # 进入虚拟环境中安装django框架 pip install …...

【PHP】部署和发布PHP网站到IIS服务器

欢迎来到《小5讲堂》 这是《PHP》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言安装PHP 稳定版本线程安全版解压使用 PHP配置 配置文件扩展文件…...

渗透测试之SSRF漏洞原理 危害 产生的原因 探测手法 防御手法 绕过手法 限制的手段

目录 SSRF说明: SSRF攻击流程 原理&#xff1a; 危害: SSRF产生的原因 ssrf漏洞利用{危害} 探测手法是否存在SSRF漏洞 如何找ssrf漏洞位置 分享连接地址 google hack url关键字 PHP语言中可能出现的ssrf漏洞函数 file_get_contents sockopen() curl_exec() SSRF…...

微信小程序-base64加解密

思路&#xff1a;先创建一个base64.js的文件&#xff0c;这个文件可以作为专门加解密的文件模块&#xff0c;需要时就引用&#xff1b;创建好后&#xff0c;引用base64.js里的加解密函数。 注意&#xff1a;引用模块一定要引用正确的路径&#xff0c;否则会报错。 base64.js:…...

Linux shell 批量验证端口连通性

脚本 #!/bin/bash # #database check #set -o nounset LOCALIPifconfig | grep inet | head -1 | awk {print $2} | sed s/addr\:// IPLIST192.168.1.99 192.168.1.98 192.168.1.97 PORTLIST81 82 83 84 85 86 check_nc(){ for CHECK_IP in $IPLIST dofor CHECK_PORT in $PORT…...

2025-1-21 Newstar CTF web week1 wp

文章目录 week1headach3会赢吗智械危机 week1 headach3 根据提示&#xff0c;在页面的请求头里找到flag flag{You_Ar3_R3Ally_A_9ooD_d0ctor} 会赢吗 打开控制台&#xff0c;拿到第一部分flag 将地址栏改为提示&#xff0c;去到下一关 控制台调用函数&#xff0c;得到flag …...

【系统架构】如何设计一个秒杀系统?

目录 1. 什么是秒杀&#xff1f; 2. 秒杀系统的特点 3. 如何设计秒杀系统&#xff1f; 3.1 前端秒杀设计 3.2 后端秒杀设计 4. 如何保证不超卖&#xff1f; 4.1 库存扣减方式 4.2 服务端库存处理 5. 总结 * 知识扩展&#xff1a;什么是CDN&#xff1f; 1. 什么是秒杀…...

C++模拟实现queue

C模拟实现queue 1.queue的基本概念2.queue的基本框架3.size()成员函数4.empty()成员函数5.push()成员函数6.pop()成员函数7.front()成员函数8.back()成员函数9.完整代码 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x…...

【2025小年源码免费送】

&#x1f496;学习知识需费心&#xff0c; &#x1f4d5;整理归纳更费神。 &#x1f389;源码免费人人喜&#xff0c; &#x1f525;码农福利等你领&#xff01; &#x1f496;山高路远坑又深&#xff0c; &#x1f4d5;大军纵横任驰奔&#xff0c; &#x1f389;谁敢横刀立马行…...

PyQt5 超详细入门级教程上篇

PyQt5 超详细入门级教程 上篇&#xff1a;1-3部分&#xff1a;PyQt5基础与常用控件 第1部分&#xff1a;初识 PyQt5 和安装 1.1 什么是 PyQt5&#xff1f; PyQt5 是 Python 的图形用户界面 (GUI) 框架&#xff0c;它基于强大的 Qt 库。Qt 是一个跨平台的 C 框架&#xff0c;用…...

qiankun+vite+vue3

基座与子应用代码示例 本示例中,基座为Vue3,子应用也是Vue3,由于qiankun不支持Vite构建的项目,这里还要引入 vite-plugin-qiankun 插件 基座(主应用) 加载qiankun依赖 npm i qiankun -S qiankun配置(src/qiankun) src/qiankun/config.ts export default {subApp…...

【数据结构】顺序队列与链式队列

顺序队列与链式队列 1.队列的基本概念1.顺序存储的队列&#xff1a;循环队列3.链式存储的队列&#xff1a;链式队列 1.队列的基本概念 队列是一种逻辑结构&#xff0c;是一种特殊的线性表 只能在固定的两端操作线性表 只要满足上述条件&#xff0c;那么这种特殊的线性表就会…...

Cursor的详细使用指南

以下是一份关于 Cursor 的详细使用指南&#xff1a; 一、安装与设置 下载与安装&#xff1a; 首先&#xff0c;访问 Cursor 的官方网站&#xff0c;根据你的操作系统&#xff08;Windows、Mac 或 Linux&#xff09;下载相应的安装程序。运行安装程序&#xff0c;按照屏幕上的提…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...