当前位置: 首页 > 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;按照屏幕上的提…...

终极QMC音频解密指南:3分钟解锁QQ音乐加密文件

终极QMC音频解密指南&#xff1a;3分钟解锁QQ音乐加密文件 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder 还在为QQ音乐下载的加密音频无法在车载音响、智能音箱上播放而烦…...

网工入门必看!4 种网络设备登录方式全解析,从 Console 到 SSH 一次搞懂

做网络运维、数通调试的朋友都知道&#xff1a;所有设备配置的第一步&#xff0c;都是成功登录设备。不管是企业级交换机、路由器、防火墙&#xff0c;还是无线 AC 控制器&#xff0c;主流的登录方式无非 4 种&#xff1a;Console 口登录、Web 界面登录、Telnet 登录、SSH 登录…...

Fluvio 实时数据处理实战指南:如何构建高性能流式传输应用程序

Fluvio 实时数据处理实战指南&#xff1a;如何构建高性能流式传输应用程序 【免费下载链接】fluvio &#x1f980; event stream processing for developers to collect and transform data in motion to power responsive data intensive applications. 项目地址: https://g…...

GLM-OCR嵌入式部署轻量化实践:从服务器到边缘设备的模型压缩

GLM-OCR嵌入式部署轻量化实践&#xff1a;从服务器到边缘设备的模型压缩 最近在做一个智能零售柜的项目&#xff0c;需要实时识别商品包装上的文字信息。一开始我们用的是云端API&#xff0c;识别效果确实不错&#xff0c;但网络延迟和稳定性成了大问题——有时候网络一波动&a…...

008.S3C2440中断分析|千篇笔记实现嵌入式全栈/裸机篇

1. 流程 S3C2440中断流程如下&#xff0c; 发生中断时&#xff0c;[SUB]SRCPND源挂起寄存器对应的bit位会置位&#xff0c; 然后[SUB]MASK屏蔽寄存器对应的bit位会卡一下&#xff0c;决定中断流要不要继续&#xff0c; 也就是说不管中断有没有被屏蔽&#xff0c;源挂起寄存…...

城通网盘直链解析:三步实现免费高速下载的完整方案

城通网盘直链解析&#xff1a;三步实现免费高速下载的完整方案 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 还在为网盘下载速度慢而烦恼吗&#xff1f;ctfileGet为你提供了一个智能解决方案&#xf…...

如何安装Dr. Memory:Windows、Linux、Mac完整安装教程

如何安装Dr. Memory&#xff1a;Windows、Linux、Mac完整安装教程 【免费下载链接】drmemory Memory Debugger for Windows, Linux, Mac, and Android 项目地址: https://gitcode.com/gh_mirrors/dr/drmemory Dr. Memory是一款功能强大的内存调试工具&#xff0c;能够检…...

终极指南:Dunst在Wayland环境下的完美通知解决方案

终极指南&#xff1a;Dunst在Wayland环境下的完美通知解决方案 【免费下载链接】dunst Lightweight and customizable notification daemon 项目地址: https://gitcode.com/gh_mirrors/du/dunst Dunst是一款轻量级且高度可定制的通知守护进程&#xff0c;专为现代Linux桌…...

别再暴力求素数了!用C++实现埃氏筛和欧拉筛,性能提升百倍(附完整代码)

素数筛法性能优化实战&#xff1a;从暴力枚举到欧拉筛的百倍飞跃 在算法竞赛和工程开发中&#xff0c;素数筛选是一个经典问题。当数据规模达到百万级别时&#xff0c;传统的暴力枚举方法往往力不从心。本文将深入探讨三种素数筛选算法——暴力枚举、埃拉托斯特尼筛法&#xff…...

OpenClaw资源监控:Phi-3-vision-128k-instruct长任务运行状态实时追踪

OpenClaw资源监控&#xff1a;Phi-3-vision-128k-instruct长任务运行状态实时追踪 1. 为什么需要监控OpenClaw长任务 上周我在本地运行一个长达6小时的OpenClaw自动化流程时&#xff0c;遇到了令人头疼的问题——凌晨3点任务突然中断&#xff0c;第二天检查才发现是GPU内存耗…...