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

C语言指针(三):数组传参本质、冒泡排序与二级指针详解

1. 数组名的理解

在上⼀篇blog中我们在使⽤指针访问数组的内容时,有这样的代码:
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;
}
输出结果:数组名和数组⾸元素的地址打印出的结果相同,数组名就是数组⾸元素(第⼀个元素)的地址
但是,数组名如果是数组⾸元素的地址,这句话不够严谨:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%zu\n", sizeof(arr));
return 0;
}
输出的结果是40,如果arr是数组⾸元素的地址,那输出应该的应该是8才对(x64)
数组名的理解有两个特殊情况:
sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的大小
&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
的地址数值上相同,但意义不同)

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

&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] = 0077F820
&arr[0]+1 = 0077F824
相差4个字节
arr = 0077F820
arr+1 = 0077F824
相差4个字节
&arr = 0077F820
&arr+1 = 0077F848
两者相减得0x28,40byte,是整个数组的大小,&arr+1跳过的是整个数组。这个原理和上一篇blog中介绍的不同类型的指针的意义相似,类型不同,单位不同,所能操作的内存空间就不同

除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址

2. 使用指针访问数组

int main()
{int arr[10] = { 0 };//给数组中存值for (int i = 0; i < 10; i++){scanf("%d", *(arr+i));}//打印数组for (int i = 0; i < 10; i++){printf("%d", *(arr+i));}return 0;
}

 不用指针打印数组元素时,一般这样写arr[i],这里用指针的表达方式是这样,二者等价

arr[i] == *(arr + i) 
//加法交换律
arr[i] == *(arr + i) == *(i+arr) == i[arr] ???

发现了一个有趣的点

是否可以这样表示呢??? 

int main()
{int arr[10] = { 0 };//给数组中存值for (int i = 0; i < 10; i++){scanf("%d", (arr + i));}//打印数组for (int i = 0; i < 10; i++){printf("%d ", i[arr]);//没毛病6666}return 0;
}

通过运行发现,编译通过。布什戈门,有点逆天了哈哈哈哈哈

这说明:[]仅仅是一个操作符而已,这是这样子表示的,在计算机内部表示的就是*(i+arr)

3. 一维数组传参的本质

通过一段代码进行观察:
//一维数组传参的本质
size_t test(int a[])
{size_t sz = sizeof(a) / sizeof(a[0]);return sz;
}int main()
{int a[] = { 1,2,3,4,5,6,7 };printf("1. %zu\n", sizeof(a) / sizeof(a[0]));printf("2. %zu\n", test(a));
}

运行结果:两次打印的结果并不相同,第一种就是7,元素个数;第二种则为2(x64)

倒推一下,a[0]为int大小是4,结果是2说明sizeof(a)为8,这就说明这是一个指针。而我们实参就是数组名,也就是首元素的地址

//一维数组传参的本质
size_t test(int a[])//本质上是指针
{size_t sz = sizeof(a) / sizeof(a[0]);//传进来的是a,不是&a,不是sizeof(a)//因此并不能算出来整个数组的大小return sz;
}int main()
{int a[] = { 1,2,3,4,5,6,7 };printf("1. %zu\n", sizeof(a) / sizeof(a[0]));printf("2. %zu\n", test(a));
}
//本质上传的是首元素地址
函数的参数部分是本质是指针,在函数内部是没办法求的数组元素个数的
总结:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式

4. 冒泡排序

冒泡排序的核⼼思想就是:两两相邻的元素进⾏⽐较
//⽅法1
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-i-1; j++){if(arr[j] > arr[j+1]){int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}
}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;
}

在改基础上,还可以进行改良:

如果排序到下一趟时,发现后面已经是升序了,就没必要在依次检索一遍了;若还想知道进行交换了多少次,也可以进行记录 

//⽅法2 - 优化
//冒泡排序
int bubble_sort(int arr[],int sz)
{int cnt = 0;for (int i = 0; i < sz - 1; i++){int flag = 1;for (int j = 0; j < sz - i -1; j++){int tmp = 0;if (arr[j] > arr[j + 1]){cnt++;//每交换一次,记录一下tmp = arr[j + 1];arr[j + 1] = arr[j];arr[j] = tmp;flag = 0;}}if (flag)//排完一趟发现并没有实现交换,则不用再排序了,解释://因为冒泡排序是从前到后依次比较的,没有实现交换,那么则都是整齐的{return cnt;}}return cnt;
}int main()
{int arr[] = { 3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);int cnt = bubble_sort(arr,sz);for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");printf("%d\n", cnt);return 0;
} 

5. ⼆级指针

指针的指针
#include <stdio.h>int main(){int a = 100;int * pa = &a;int* * ppa = &pa;return 0;
}

pa是一个指针变量,势必也会有开辟内存空间,该空间也势必有自己的指针,即使这块空间中存放的就是一个指针

6. 指针数组

//指针数组
//类比 字符数组 整形数组
//存放指针的数组
是存放指针的数组,指针数组的每个元素都是⽤来存放地址(指针)的
指针数组的每个元素是地址,⼜可以指向⼀块区域

7. 指针数组模拟二维数组

//使用指针数组模拟一个二维数组
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };int* arr[] = { arr1,arr2,arr3 };//二维数组for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", arr[i][j]);}printf("\n");}return 0;
}
数组arr中放着各个数组的首元素地址,通过这些地址又可以找到他们数组中的其他元素,可以看成是一个二维数组,但:
上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组,因为每⼀⾏并⾮是连续的。
http://www.dtcms.com/a/307316.html

相关文章:

  • C++异常处理的成本:理解与优化
  • 超宽带测距+测角+无线通信一体化模组:智能门锁、智能遥控器、AR头戴、智能穿戴
  • yolo目标检测基础知识
  • AWS高级解决方案架构师黄海波:GenAI 时代非结构化数据处理的实践与趋势洞察
  • 【最近公共祖先】ST表法
  • 从渠道渗透到圈层渗透:开源链动2+1模式、AI智能名片与S2B2C商城小程序的协同创新路径研究
  • 联通元景万悟 开源,抢先体验!!!
  • 技术速递|GitHub Copilot for Eclipse 迈出重要一步
  • SpringAI:AI工程应用框架新选择
  • 转码刷 LeetCode 笔记[1]:3.无重复字符的最长子串(python)
  • 一对一交友小程序 / APP 系统架构分析
  • n8n为什么建议在数组的每个item中添加json键?
  • python的异步、并发开发
  • 聊下多线程查询数据库
  • YOLO---01目标检测基础
  • C++从入门到起飞之——智能指针!
  • day 40 打卡-装饰器
  • Vulnhub Thales靶机复现详解
  • 02 基于sklearn的机械学习-KNN算法、模型选择与调优(交叉验证、朴素贝叶斯算法、拉普拉斯平滑)、决策树(信息增益、基尼指数)、随机森林
  • 【JEECG】JVxeTable表格拖拽排序功能
  • C语言:逆序输出0到9的数组元素
  • LeetCode Hot 100 搜索旋转排序数组
  • 腾讯云市场排名
  • 借助 Wisdom SSH 的 AI 助手构建 Linux 开发环境
  • 2419.按位与最大的最长子数组
  • duiLib 自定义资源目录
  • 限流算法详解:固定窗口、滑动窗口、令牌桶与漏桶算法全面对比
  • P1036 [NOIP 2002 普及组] 选数
  • 结合C++红黑树与AI人工智能的应用
  • Linux 系统日志管理与时钟同步实用指南