C语言 - 数组

目录

1. 一维数组的创建和初始化

1.1 数组的创建

1.2 数组的初始化

1.3 一维数组的使用

1.4 一维数组在内存中的存储

2. 二维数组的创建和初始化

2.1 二维数组的创建

2.2 二维数组的初始化

2.3 二维数组的使用

2.4 二维数组在内存中的存储

3. 数组越界

4. 数组作为函数参数

4.1 冒泡排序函数的设计

4.1.1 关于冒泡排序函数的错误设计

4.1.2 关于冒泡排序函数的正确设计

4.2 数组名是什么?

对于二维数组的数组名


我们原来要存放一个整数, 就会:

int a = 1;
int b = 2;
int c = 3;

那么如果要存放1~10, 或者要存放1~100呢? 如果创建10或100个变量就不方便了, 于是就有了数组的概念.

什么是数组? 数组是一组相同类型元素的集合.

那么C语言的数组形式是什么呢, 我们一起来看.

1. 一维数组的创建和初始化

1.1 数组的创建

数组的创建方式:

type_t arr_name [const_n];
// type_t 是数组的元素类型
// arr_name 是数组的数组名
// const_n 是一个常量表达式, 用来指定数组的大小

数组创建的实例:

int arr[10];
char ch[5];
double data1[20];
double data2[15+5];

注: 数组创建,在C99标准之前,[]中要给一个常量或者常量表达式才可以,不能使用变量。在C99之后,数组的大小可以是变量,这是为了支持变长数组。

//下面的代码只能在支持C99标准的编译器上编译
int n = 10;
scanf("%d", &n);
int arr2[n];//这种数组是不能初始化

1.2 数组的初始化

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

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

//不完全初始化,剩余的元素默认初始化为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' };
char ch4[] = "abc";

1.3 一维数组的使用

对于数组的使用我们之前介绍了一个操作符: [],下标引用操作符。它其实就数组访问的操作符.

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

当我们去访问上面这个数组的时候, 需要知道它在内存中的情况.

这段代码对应的是在内存中的栈区找了一块连续的空间, 在里面放了1~10.

那么我们可以通过下标引用操作符+下标编号来访问数组中的元素.

printf("%d\n", arr[4]);

如果要打印数组的每个元素:

int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);//顺序打印for (i = 0; i < sz; i++){printf("%d ", arr[i]);}//逆序打印for (i = sz - 1; i >= 0; i--){printf("%d ", arr[i]);}return 0;
}
总结:
1. 数组是使用下标来访问的,下标是从0开始
2. 数组的大小可以通过计算得到。

1.4 一维数组在内存中的存储

在上面的代码中加入:

    for (i = 0; i < sz; i++){printf("&arr[%d] = %p\n", i, &arr[i]);}

可以看到数组的,每个元素的地址:

观察输出的结果,可以知道,随着数组下标的增长,元素的地址,也在有规律的递增.

由此我们得出: 数组在内存中是连续存放的.

那么我们同样也是可以通过调试在内存窗口中看到数组arr在内存中的分布情况.

2. 二维数组的创建和初始化

二维数组相较于一维数组能够存放更多的数据. 它存在的原因就是因为相同的数据是可能会出现很多组. 像这种多组整数需要存储的话就可以考虑二维数组.

2.1 二维数组的创建

int arr[3][4];    // 第一个[]表示行, 第二个[]表示列. 3行4列.
char arr[3][5];
double arr[2][4];
可以看到在数组名后有两个 [], 对于第一行它表示的是三行四列的元素, 就像一个表格一样.
我们知道一维数组是一行, 而二维数组是有多行. 其实这就是一个概念.
比如说要存放下面这几组数据:
1 2 3 4
2 3 4 5
3 4 5 6

那么我们就可以创建如上文第一行代码的那样一个数组.

2.2 二维数组的初始化

int arr1[3][4] = {1,2,3,4,2,3,4,5,3,4,5,6};
int arr2[3][4] = { {1,2}, {3, 4}, {5, 6}}; 
int arr3[][4] = { 1,2,3,4,5,6};//二维数组如果有初始化,行可以省略,列不能省略

可以看到, arr1第一行为1234, 第二行为2345, 第三行为3456. 因为我们前面已经限定了一行能放四个元素, 所以当第一行放了四个元素之后紧接着后面的初始化内容又找了四个给第二行, 再找四个给到第三行.
所以能看到如上图所示的现象.

那么如果初始化的数字不够数的时候, 会在后面初始化成0, 也如上图arr2和arr3所示.

2.3 二维数组的使用

二维数组的使用也是通过下标的方式.

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

运行结果:

2.4 二维数组在内存中的存储

前面在我们假想中的二维数组是多行多列的一个存在, 但是实际上在内存中并不是使用行列这种样子的存储方式, 而是连续的存储.

我们来进行验证, 打印二维数组每个元素的地址:

#include <stdio.h>int main()
{int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 4; j++){printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);}}return 0;
}

输出结果:

通过地址的变化可以观察出: 二维数组在内存中也是连续存放的.

于是, 我们可以进一步这样理解二维数组.

int arr[3][4];
理解为从第一个元素开始向后的连续12个空间, 看成是一个连续的一维数组, 有12个元素.
其实最终, 该代码与
int arr2[12];
在内存中的布局是一样的.
可以把二维数组理解为: 一维数组的数组.

3. 数组越界

数组的下标是有范围限制的。

数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。

所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。

C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的。

所以程序员写代码时,最好自己做越界的检查。

二维数组的行和列也可能存在越界。

4. 数组作为函数参数

往往我们在写代码的时候,会将数组作为参数传个函数,比如: 我要实现一个冒泡排序函数将一个整形数组排序.

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

代码思路:

4.1 冒泡排序函数的设计

4.1.1 关于冒泡排序函数的错误设计

int main()
{//数组//把数组的数据排成升序int arr[] = { 9,8,7,6,5,4,3,2,1,0 };//0 1 2 3 4 5 6 7 8 9int sz = sizeof(arr) / sizeof(arr[0]);//冒泡排序的算法,对数组进行排序bubble_sort(arr);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
void bubble_sort(int arr[])
{//趟数int sz = sizeof(arr) / sizeof(arr[0]);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;}}}
}

执行上述代码之后, 会出问题, 并不能正确的将数据进行排序.

我们进行调试:

在调试到bubble_sort()中发现sz变成了1, 但是我们期望是10, 此时往下1-1=0, 并没有进行任何的对数据排序就退出了这个函数, 所以当整个程序执行完会发现并没有将数据进行排序就输出.

这是函数程序的编写中非常常见的错误.

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

4.2 数组名是什么?

前面提到, 数组名是数组首元素的地址, 这个说法虽然对, 但是其实并不完全对, 有两个例外.

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

2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址

int main()
{int arr[10] = {0};printf("%p\n", arr);//arr就是首元素的地址printf("%p\n", arr+1);printf("----------------------\n");printf("%p\n", &arr[0]);//首元素的地址printf("%p\n", &arr[0]+1);printf("----------------------\n");printf("%p\n", &arr);//数组 的地址printf("%p\n", &arr+1);//int n = sizeof(arr);//40//printf("%d\n", n);return 0;
}

执行结果:


对于二维数组的数组名

#include <stdio.h>int main()
{int arr[3][4] = {0};printf("%d\n", sizeof(arr) / sizeof(arr[0]));//计算行printf("%d\n", sizeof(arr[0]) / sizeof(arr[0][0]));//计算列int sz = sizeof(arr);printf("%d\n", sz);    //48printf("%p\n", arr);//二维数组的数组名也表示数组首元素的地址(第一行的地址)printf("%p\n", arr+1);//第二行return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/97856.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Vue面试题十一】、Vue组件之间的通信方式都有哪些?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;Vue组件之间的通信方式都…

Synchronized的实现和锁升级

1.JVM是如何处理和识别Synchronized的&#xff1f; 我们从字节码角度分析synchronized的实现&#xff1a; Synchronized(锁对象){}同步代码块底层实现方式是monitorenter和monitorexit指令。 修饰普通同步方法时底层实现方式是执行指令会检查方法是否设置ACC_SYNCHRONIZED&am…

从0到1基于ChatGLM-6B使用LoRA进行参数高效微调

从0到1基于ChatGLM-6B使用LoRA进行参数高效微调 吃果冻不吐果冻皮 ​ 关注他 cliniNLPer 等 189 人赞同了该文章 ​ 目录 收起 ChatGLM-6B简介 具备的一些能力 局限性 LoRA 技术原理 环境搭建 数据集准备 数据预处理 参数高效微调 单卡模式模型训练 数据并行模式模型训练 模型推…

Nginx详细学习记录

1. Nginx概述 Nginx是一个轻量级的高性能HTTP反向代理服务器&#xff0c;同时它也是一个通用类型的代理服务器&#xff0c;支持绝大部分协议&#xff0c;如TCP、UDP、SMTP、HTTPS等。 1.1 Nginx基础架构 Nginx默认采用多进程工作方式&#xff0c;Nginx启动后&#xff0c;会运行…

阿里云RDS关系型数据库详细介绍_多版本数据库说明

阿里云RDS关系型数据库大全&#xff0c;关系型数据库包括MySQL版、PolarDB、PostgreSQL、SQL Server和MariaDB等&#xff0c;NoSQL数据库如Redis、Tair、Lindorm和MongoDB&#xff0c;阿里云百科分享阿里云RDS关系型数据库大全&#xff1a; 目录 阿里云RDS关系型数据库大全 …

编译工具链 之二 详解 ELF 格式及标准、UNIX 发展、ABI

在计算机及嵌入式系统中&#xff0c;二进制文件也有一定的标准格式&#xff0c;通常会包含在各平台的应用程序二进制接口 &#xff08;Application Binary Interface&#xff0c;ABI&#xff09;规范中。它是编译工具链必须要遵守的规范&#xff08;编译工具链产生符合 ABI 的二…

C (1094) : DS双向链表—前驱后继

Description 在双向链表中&#xff0c;A有一个指针指向了后继节点B&#xff0c;同时&#xff0c;B又有一个指向前驱节点A的指针。这样不仅能从链表头节点的位置遍历整个链表所有节点&#xff0c;也能从链表尾节点开始遍历所有节点。 对于给定的一列数据&#xff0c;按照给定的…

Legion Y9000X IRH8 2023款(82Y3)原装出厂OEM预装Windows11系统

lenovo联想电脑笔记本拯救者原厂win11系统镜像 下载链接&#xff1a;https://pan.baidu.com/s/15G01j7ROVqOFOETccQSKHg?pwdt1ju 系统自带所有驱动、出厂主题壁纸、Office办公软件、联想电脑管家等预装程序 所需要工具&#xff1a;32G或以上的U盘 文件格式&#xff1a;ISO…

创作2周年?浅记一下~

前言&#xff1a; 最近确实有点缺乏去更新博客的动力&#xff0c;一晃两年过去了&#xff0c;其实也是我新入职公司的两年&#xff0c;两年虽然不长&#xff0c;但是确实发生了太多事情值得去记录下来... 机缘 说是机缘也不是算是&#xff0c;第一次写博客是刚好在CSDN里面查资…

CentOS如何查找java安装路径

目 录 背景 详细步骤 1.使用指令查看有关javad安装路径 2.填入java路径 3.查找java安装路径 4.配置文件展示 背景 准备部署分布式hadoop的时候&#xff0c;校验hadoop版本发现java没配置 但是又有java版本信息 详细步骤 1.使用指令查看有关javad安装路径 java -verb…

高级IO(Linux)

高级IO 五种IO模型高级IO重要概念同步通信 vs 异步通信阻塞 vs 非阻塞 非阻塞IOfcntl实现函数SetNoBlock轮询方式读取标准输入 I/O多路转接之select初识selectselect函数原型参数解释参数timeout取值关于fd_set结构关于timeval结构函数返回值三级目录 理解select执行过程socket…

微信小程序——CSS3渐变

SS3 渐变&#xff08;gradients&#xff09;可以在两个或多个指定的颜色之间显示平稳的过渡。CSS3 定义了两种类型的渐变&#xff08;gradients&#xff09;&#xff1a; 说明 1、线性渐变&#xff08;Linear Gradients&#xff09;- 向下/向上/向左/向右/对角方向&#xff1…

Java版本企业电子招投标采购系统源码之项目说明和开发类型源码

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及…

练[FBCTF2019]RCEService

[FBCTF2019]RCEService 文章目录 [FBCTF2019]RCEService掌握知识解题思路关键paylaod 掌握知识 ​ json字符串格式&#xff0c;命令失效(修改环境变量)–绝对路径使用linux命令&#xff0c;%0a绕过preg_match函数&#xff0c;代码审计 解题思路 打开题目链接&#xff0c;发现…

Python爬虫——爬虫基础模块和类库(附实践项目)

一、简单介绍 Python爬虫是使用Python编程语言开发的一种自动化程序&#xff0c;用于从互联网上获取信息。通过模拟浏览器的行为&#xff0c;爬虫可以访问网页、解析网页内容&#xff0c;并提取所需的数据。 python的爬虫大致可以分为通用爬虫和专用爬虫&#xff1a; 通用爬虫…

【Linux】Vim使用总结

【Linux】Vim使用总结 Vim 的三种模式命令行模式1. 移动2.复制&#xff0c;粘贴&#xff0c;剪切3.撤销4.大小写切换&#xff0c;替换&#xff0c;删除 插入模式底行模式 Vim 的三种模式 一进入VIM就是处于一般模式&#xff08;命令模式&#xff09;&#xff0c;该模式下只能输…

ES 关于 remote_cluster 的一记小坑

最近有小伙伴找到我们说 Kibana 上添加不了 Remote Cluster&#xff0c;填完信息点 Save 直接跳回原界面了。具体页面&#xff0c;就和没添加前一样。 我们和小伙伴虽然隔着网线但还是进行了深入、详细的交流&#xff0c;梳理出来了如下信息&#xff1a; 两个集群&#xff1a;…

架构师-软件工程习题选择题

架构师-软件工程习题选择题

不同数据类型在单片机内存中占多少字节?

文章目录 前言一、不同编译器二、C51* 指针型 三、sizeof结构体联合体 前言 在C语言中&#xff0c;数据类型指的是用于声明不同类型的变量或者函数的一个广泛的系统。变量的类型决定了变量存储占用的空间 一、不同编译器 类型16位编译器大小32位编译器大小64位编译器大小char…

HTTPS工作过程,国家为什么让http为什么要换成https,Tomcat在MAC M1电脑如何安装,Tomcat的详细介绍

目录 引言 一、HTTPS工作过程 二、Tomcat 在访达中找到下载好的Tomcat文件夹&#xff08;这个要求按顺序&#xff09; zsh: permission denied TOMCAT的各部分含义&#xff1a; 引言 在密码中一般是&#xff1a;明文密钥->密文&#xff08;加密&#xff09; &#xff…