【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)
一、数组名的理解 上一篇文章中我们写过一个这样的代码: int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0];这里使用&arr[0] 的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,而且是数组首元素的地址ÿ…...
与 Spring Boot 的无缝集成:ShardingSphere 快速集成实践
ShardingSphere 是一个轻量级的开源分布式数据库中间件,它支持分库分表、分布式事务、读写分离等功能。它能够与各种应用框架进行集成,其中与 Spring Boot 的集成非常流行,因为它能够帮助开发者在 Spring Boot 项目中快速实现高性能的分布式数…...
【QT】窗口/界面置于最前端显示,且激活该窗口
目录 0.环境 1.问题描述 2.具体实现 0.环境 windows11 qt 1.问题描述 我有一个窗口QMainWindow(也适用于QWidget或QDialog),想让其在显示的时候置于最前面,且激活成为当前活动窗口 2.具体实现 mainWindow->show();mainWind…...
DOL-288 多功能电子计时器说明书
新买一个计时器,它的用法不太直观,所以把说明书留在这里,以便以后查询。 DOL-288 多功能电子计时器说明书 1.功能说明: 正计时功能,计时上限为23小时59分59秒倒计时功能,计时上限为23小时59分59秒&#…...
14 常用的负载均衡算法
基于nginx的代理 1. 轮询算法 例如我们在nginx服务器中代理了3台服务器,再每次客户端发起请求的时候按照顺序请求挨次的发送到代理的三台服务器上。该算法比较适合每台服务器性能差不多的场景,如果部分服务器性能比较差,可能会造成性能好的…...
方法建议ChatGPT提示词分享
方法建议 ChatGPT能够根据您的具体需求提供针对性的建议,帮助您选择最合适的研究方法。通过清晰的提示,ChatGPT可以精准地为您提供最契合的研究方案。此外,它还能协助您将这些方法灵活地应用于新的研究环境,提出创新的技术解决方案…...
如何提高自动化测试覆盖率和效率
用ChatGPT做软件测试 在现代软件开发中,自动化测试已经成为保证软件质量的重要手段。然而,在实践中,自动化测试的覆盖率和效率常常受到限制,导致潜在缺陷未能及时发现或测试资源浪费。因此,提升自动化测试的覆盖率和效…...
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》系列文章,每篇文章将以博主理解的角度展开讲解。 温馨提示:博主能力有限,理解水平有限,若有不对之处望指正! 目录 前言安装PHP 稳定版本线程安全版解压使用 PHP配置 配置文件扩展文件…...
渗透测试之SSRF漏洞原理 危害 产生的原因 探测手法 防御手法 绕过手法 限制的手段
目录 SSRF说明: SSRF攻击流程 原理: 危害: SSRF产生的原因 ssrf漏洞利用{危害} 探测手法是否存在SSRF漏洞 如何找ssrf漏洞位置 分享连接地址 google hack url关键字 PHP语言中可能出现的ssrf漏洞函数 file_get_contents sockopen() curl_exec() SSRF…...
微信小程序-base64加解密
思路:先创建一个base64.js的文件,这个文件可以作为专门加解密的文件模块,需要时就引用;创建好后,引用base64.js里的加解密函数。 注意:引用模块一定要引用正确的路径,否则会报错。 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 根据提示,在页面的请求头里找到flag flag{You_Ar3_R3Ally_A_9ooD_d0ctor} 会赢吗 打开控制台,拿到第一部分flag 将地址栏改为提示,去到下一关 控制台调用函数,得到flag …...
【系统架构】如何设计一个秒杀系统?
目录 1. 什么是秒杀? 2. 秒杀系统的特点 3. 如何设计秒杀系统? 3.1 前端秒杀设计 3.2 后端秒杀设计 4. 如何保证不超卖? 4.1 库存扣减方式 4.2 服务端库存处理 5. 总结 * 知识扩展:什么是CDN? 1. 什么是秒杀…...
C++模拟实现queue
C模拟实现queue 1.queue的基本概念2.queue的基本框架3.size()成员函数4.empty()成员函数5.push()成员函数6.pop()成员函数7.front()成员函数8.back()成员函数9.完整代码 🌟🌟hello,各位读者大大们你们好呀🌟🌟 &#x…...
【2025小年源码免费送】
💖学习知识需费心, 📕整理归纳更费神。 🎉源码免费人人喜, 🔥码农福利等你领! 💖山高路远坑又深, 📕大军纵横任驰奔, 🎉谁敢横刀立马行…...
PyQt5 超详细入门级教程上篇
PyQt5 超详细入门级教程 上篇:1-3部分:PyQt5基础与常用控件 第1部分:初识 PyQt5 和安装 1.1 什么是 PyQt5? PyQt5 是 Python 的图形用户界面 (GUI) 框架,它基于强大的 Qt 库。Qt 是一个跨平台的 C 框架,用…...
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.顺序存储的队列:循环队列3.链式存储的队列:链式队列 1.队列的基本概念 队列是一种逻辑结构,是一种特殊的线性表 只能在固定的两端操作线性表 只要满足上述条件,那么这种特殊的线性表就会…...
Cursor的详细使用指南
以下是一份关于 Cursor 的详细使用指南: 一、安装与设置 下载与安装: 首先,访问 Cursor 的官方网站,根据你的操作系统(Windows、Mac 或 Linux)下载相应的安装程序。运行安装程序,按照屏幕上的提…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
