【C】数组+冒泡排序

简介: 【C】数组+冒泡排序

💻前言

🍁这篇博客总结数组当中的知识点,理解熟悉数组的使用。

💻一.数组的创建和初始化

数组是一组相同类型元素的集合。

1.一维数组

创建格式

类型 数组名[常量表达式] = {初始化部分};
[ ]中的常量表达式用来指定数组的大小

创建实例

//可以不进行初始化
int arr1[10];
char arr2[10];
float arr3[1];
double arr4[20];

注:数组创建,在C99标准之前, [ ] 中要给一个常量才可以,不能使用变量;在C99标准支持了变长数组的概念,但变长数组是不能被初始化的。

#include <stdio.h>
int main()
{
  //支持C99标准的编译器上,数组的大小可以是变量
  int n = 0;
  scanf("%d", &n);
  int arr[n];     //这个数组不能初始化
  int i = 0;
  //输入
  for (i = 0; i < n; i++)
  {
    scanf("%d", &arr[i]);
  }
  //输出
  for (i = 0; i < n; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

初始化

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。

数组在创建的时候如果想不指定数组的确定的大小就得初始化,此时数组的元素个数根据初始化的内容自动确定。

  //不完全初始化,剩余的元素默认初始化为0
  int arr[10] = { 1,2,3 };
  int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 };
  int arr2[] = { 1,2,3 };//数组大小为三
  char ch1[10] = { 'a', 'b', 'c' };
  //a b c 0 0 0 0 0 0 0
  char ch2[10] = "abc";
  //a b c \0 0 0 0 0 0 0

对于下面的代码要区分

  char ch3[] = { 'a', 'b', 'c' };
  //数组大小为3,没有'\0',以字符串的形式打印会乱码
  char ch4[] = "abc";
  //数组大小为4,可以以字符串的形式正常打印

使用实例

[ ] ,下标引用操作符。它其实就数组访问的操作符。

  1. 数组是使用下标来访问的,下标是从0开始。

7fc11c8a2de144ff835420d6c2508286.png

  1. 2. 数组的大小可以通过计算得到。
#include <stdio.h>
int main()
{
    int arr[10] = {0};//数组的不完全初始化,下标的范围是0-9
    //计算数组的元素个数
    int sz = sizeof(arr)/sizeof(arr[0]);
    //对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
    int i = 0;//做下标
    for(i=0; i<10; i++)//这里写10,好不好?
    {
       arr[i] = i;
    } 
    //输出数组的内容
    for(i=0; i<10; ++i)
    {
       printf("%d ", arr[i]);
    }
    return 0;
 }

2.二维数组

创建格式

类型 数组名[常量表达式][常量表达式] = {初始化部分};

创建实例

int arr[3][4];//表示3行4列,可以存放12个元素
char arr[3][5];
double arr[2][4];

初始化

二维数组如果有初始化,行可以省略,列不能省略

//不完全初始化,剩余的元素默认初始化为0
int arr[][4] = {{2,3},{4,5}}
int arr1[3][4] = {1,2,3,4,2,3,4,5,3,4,5,6};
int arr1[3][4] = { {1,2}, {3, 4}, {5, 6}};
int arr2[][4] = { 1,2,3,4,5,6};
//列不可以省略

使用实例

二维数组的使用也是通过下标的方式,行和列的访问都是从0开始!

7fc11c8a2de144ff835420d6c2508286.png

#include <stdio.h>
  int main()
  {
    int arr[3][4] = { 0 };
    int i = 0;
    for (i = 0; i < 3; i++)
    {
      int j = 0;
      for (j = 0; j < 4; j++)
      {
        arr[i][j] = i * 4 + j;
      }
    }
    for (i = 0; i < 3; i++)
    {
      int j = 0;
      for (j = 0; j < 4; j++)
      {
        printf("%d ", arr[i][j]);
      }
    }
    return 0;
  }

7fc11c8a2de144ff835420d6c2508286.png

💻二.数组在内存中的存储

这里我们打印数组中每个元素的地址进行分析!

1.一维数组

7fc11c8a2de144ff835420d6c2508286.png

观察打印结果我们可以知道,数组在内存中是连续存放的,且数组元素由低址到高地址递增存储。

7fc11c8a2de144ff835420d6c2508286.png

2.二维数组

7fc11c8a2de144ff835420d6c2508286.png

与一维数组一样二维数组在内存中也是连续存储的。

7fc11c8a2de144ff835420d6c2508286.png

💻三.数组越界和数组名

1.对于二维数组的理解

对于一维数组的数组名可以很好的理解,这里重点刨析一下二维数组的数组名,以下面这个代码为例:

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

这里的arr便是二维数组的数组名可以理解,我们进入调试打开监视窗口观察这个数组

7fc11c8a2de144ff835420d6c2508286.png

这里的二维数组,由三个模块组成,每个模块里放着四个元素;所以,可以类似的认为,这三个模块便是三个一维数组,而这三个一维数组又作为了二维数组的三个元素,可以把二维数组理解为:一维数组的数组(一维数组作为数组的元素而组成的数组)。

所以,这里二维数组中的每一行其实都是一个一维数组就好理解了,而上面的代码三行的数组名分别为:arr[0],arr[1],arr[2],同时注意一下图片中数组的类型。

7fc11c8a2de144ff835420d6c2508286.png

2.数组名代表什么

对于一维和二维数组,一般情况下数组名表示首元素的地址:
但是有2个例外:

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

一维

7fc11c8a2de144ff835420d6c2508286.png

二维

7fc11c8a2de144ff835420d6c2508286.png

3.数组越界

通过下标访问数组元素,如果超出了下标的范围,也就是超出了数组的合法空间的访问,就称为数组越界访问;越界访问编译器并不会报错,但这样的程序是错误的,所以我们写代码时,一定要自己做越界的检查。

一维数组越界

由于不在数组范围内,所以打印出的是一个随机值。

7fc11c8a2de144ff835420d6c2508286.png

二维数组的越界有俩种情况:

在二维数组范围内越界,arr[1][5]超出了数组arr[1]的空间范围,进入了arr[2]的空间范围,访问到了arr[2]中的第二个元素!

7fc11c8a2de144ff835420d6c2508286.png在二维数组范围外越界,与一维数组一样,打印出的是一个随机值。

7fc11c8a2de144ff835420d6c2508286.png

💻四.理解数组作为函数的参数和冒泡排序

当数组作为函数参数的时候,要知道数组传参传过去的是什么,否则容易写出错误的代码,下面穿插冒泡排序讲解。

首先理解冒泡排序

冒泡排序的核心思想:俩个相邻的元素进行比较!

比如要将一组数据从小到大排序

7fc11c8a2de144ff835420d6c2508286.png

如果有n个元素,将相邻元素俩俩比较交换位置,则需要进行n-1趟冒泡排序,每次排序确定一个数的最终位置;第一趟排序需要进行n-1次比较,下一趟排序比上一趟少一个元素,所以比较次数也会少一次,直到最后剩下一个元素,排序完成。

代码实现:

数组传参的时候,形参有2种写法:
1. 数组
2. 指针

//形参是数组的形式
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 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;
      }
    }
  }
}
int main()
{
  //数组
  //把数组的数据排成升序
  int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
  //0 1 2 3 4 5 6 7 8 9
  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;
}

在求数组的长度时千万不能在自定义函数内部去求,数组传参实际上传递的是数组首元素的地址而不是整个数组,所以在自定义函数内部计算一个函数参数部分的数组的元素个数是错误的。

目录
相关文章
|
6月前
|
前端开发 JavaScript 安全
解锁React Server Components:彻底改变前端渲染方式
解锁React Server Components:彻底改变前端渲染方式
|
人工智能 监控 安全
Honeywell 霍尼韦尔 ControlEdge HC900控制器
Honeywell 霍尼韦尔 ControlEdge HC900控制器
|
域名解析 JSON 测试技术
常见移动端APP测试场景
常见移动端APP测试场景
308 0
|
移动开发 小程序 前端开发
Taro 的实现原理是怎么样的?
Taro 的实现原理是怎么样的?
698 0
|
关系型数据库 MySQL 分布式数据库
使用Sqoop从Mysql向云HBase同步数据
Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具。本文介绍如何使用sqoop将数据从Mysql导入到HBase。从成本的角度考虑,针对没有hadoop集群的用户,重点介绍单机运行sqoop的配置和参数。
5983 0
|
11月前
|
机器学习/深度学习 安全 算法
十大主流联邦学习框架:技术特性、架构分析与对比研究
联邦学习(FL)是保障数据隐私的分布式模型训练关键技术。业界开发了多种开源和商业框架,如TensorFlow Federated、PySyft、NVFlare、FATE、Flower等,支持模型训练、数据安全、通信协议等功能。这些框架在灵活性、易用性、安全性和扩展性方面各有特色,适用于不同应用场景。选择合适的框架需综合考虑开源与商业、数据分区支持、安全性、易用性和技术生态集成等因素。联邦学习已在医疗、金融等领域广泛应用,选择适配具体需求的框架对实现最优模型性能至关重要。
1993 79
十大主流联邦学习框架:技术特性、架构分析与对比研究
|
定位技术 网络虚拟化 数据中心
VLAN与VXLAN技术解析:仅一字之差的深远区别
通过深入了解VLAN与VXLAN的技术细节和应用场景,网络工程师可以根据具体需求选择最合适的技术来优化网络架构。对于现代网络环境,尤其是大规模和多变的网络结构,理解并合理运用这些技术是提高网络效率和安全性的关键。
443 1
|
安全 Java 网络安全
Java Socket编程技术详解:从基础到进阶的全方位指南
【6月更文挑战第21天】Java Socket编程是网络通信的关键,涉及`Socket`和`ServerSocket`类。基础教程展示了如何创建简单的客户端-服务端交互,而进阶内容涵盖了非阻塞I/O、多路复用(如使用`Selector`)以提升性能,以及通过SSL/TLS确保安全通信。学习Socket编程不仅是技术实践,也是理解网络原理的过程,强调了持续学习和实践的重要性。
533 1
|
存储 分布式计算 Apache
Apache Paimon 流式数据湖 V 0.4 与后续展望
摘要:本文整理自阿里云开源大数据表存储团队负责人、阿里巴巴高级技术专家,Apache Flink PMC,Paimon PPMC 李劲松(之信)在 Apache Paimon Meetup 的分享。本篇内容主要分为四个部分: 1. 湖存储上的难点 2. 深入 Apache Paimon 0.4 3. 社会应用实践 4. 后续规划
1262 56
|
NoSQL Redis Python
python flask 使用 redis 写一个例子给我
python flask 使用 redis 写一个例子给我
452 4