14 数组的相关概念,数组的定义、(越界)访问、长度计算、循环遍历

2024-08-23 04:12

本文主要是介绍14 数组的相关概念,数组的定义、(越界)访问、长度计算、循环遍历,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1 数组的概念

1.1 为什么需要数组

1.1.1 需求分析1

1.1.2 需求分析2

1.1.3 容器的概念

1.2 什么是数组

1.3 数组相关概念

1.4 数组的特点

2 数组操作

2.1 数组的定义

2.2 访问数组元素

2.3 数组越界访问

2.4 计算数组长度

2.5 遍历数组

2.5.1 输出各个元素

2.5.2 初始化各个元素

2.6 案例演示

2.6.1 计算元素和与平均数

2.6.2 取元素最大值

3 测试题


1 数组的概念

1.1 为什么需要数组

1.1.1 需求分析1

        需要统计某公司 50 个员工的工资情况,例如计算平均工资、找到最高工资等。用之前知识,首先需要声明 50 个变量来分别记录每位员工的工资,这样会很麻烦。因此我们可以将所有的数据全部存储到一个容器中统一管理,并使用容器进行计算

1.1.2 需求分析2

        左边图例中有许多条新闻信息,如果用变量来表示一条新闻信息,我们将需要非常多的变量,如果将多条新闻信息存储到一个容器中统一管理将会非常方便。右边图例中有许多条外卖商家数据,也是同样的道理,将多条外卖商家数据存储到一个容器中统一管理将会非常方便。

1.1.3 容器的概念

        生活中的容器:水杯(装水等液体),衣柜(装衣服等物品),集装箱(装货物等)。

        程序中的容器:将多个数据存储到一起,每个数据称为该容器的元素

1.2 什么是数组

        数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个标识符命名,并通过编号(索引,亦称为下标或角标)的方式对这些数据进行统一管理。

1.3 数组相关概念

        数组名:本质上是一个标识符常量,命名需要符合标识符规范

        元素:同一个数组中的元素必须是相同的数据类型

        下标(索引、角标):从 0 开始的连续数字

        数组的长度:表示元素的个数

1.4 数组的特点

        创建数组时会在内存中开辟一整块连续的空间,占据的空间的大小,取决于数组的长度和数组中元素的类型

        数组中的元素在内存中是依次紧密排列的且有序的

        数组一旦初始化完成,其长度就是确定的,数组的长度一旦确定,就不能修改

        我们可以直接通过索引(下标)获取指定位置的元素,速度很快。


2 数组操作

2.1 数组的定义

        方式一:先指定元素的个数和类型,后面再进行初始化。

// 定义数组,数组名字是 arr1,元素类型是 int,元素个数是 3 个  
int arr1[3];// 定义完成后再给元素赋值
arr1[0] = 100;
arr1[1] = 200;
arr1[2] = 300;

        方式二:指定元素的类型和个数并同时进行初始化。

        当初始化的元素个数与定义的数组长度相等时,所有的元素都会被赋值。

        当初始化的元素个数少于定义的数组长度时,未被初始化的元素将默认被赋值为 0

        当初始化的元素个数多于定义的数组长度时,编译器会报错,因为多余的初始化值没有对应的位置存储。

// 定义完数组直接进行初始化
int arr2[3] = {4,5,6};// 赋值的元素个数和定义的不一致,多
int arr3[3] = {4,5,6,7};   // 报错// 赋值的元素个数和定义的不一致,少,后面的元素值默认为 0
int arr4[5] = {4,5};   // arr4[0] = 4, arr4[1] = 5, arr4[2] …… arr4[4] 均为 0

        方式三:指定元素的类型,不指定元素个数(系统会自动计算),同时进行初始化。

// 没有指定元素个数,系统会自动计算
int arr3[] = {7,8,9,10};

2.2 访问数组元素

        通过 “数组名[下标]” 可以访问数组中的元素,案例如下 :

#include <stdio.h>int main()
{// 定义一个包含 4个 整数的数组,并初始化这些元素为 10, 20, 30, 40int nums[4] = {10, 20, 30, 40};// 修改数组中元素的值nums[0] += 10;nums[1] += 20;nums[2] += 30;nums[2] = 66; // 再次修改nums[3] = 88;// 读取并打印数组中每个元素的值printf("第一个元素的值:%d\n", nums[0]); // 输出第一个元素的值:20printf("第二个元素的值:%d\n", nums[1]); // 输出第二个元素的值,40printf("第三个元素的值:%d\n", nums[2]); // 输出第三个元素的值:66printf("第四个元素的值:%d\n", nums[3]); // 输出第四个元素的值:88return 0;
}

2.3 数组越界访问

        数组下标必须在指定范围内使用,超出范围视为越界

#include <stdio.h>int main()
{// 定义一个包含 4个 整数的数组,并初始化这些元素为 10, 20, 30, 40int nums[5] = {10, 20, 30, 40, 50};// 修改数组中元素的值nums[0] += 10;nums[1] += 20;nums[2] += 30;nums[2] = 66; // 再次修改nums[3] = 88;nums[4] = 99;// 越界访问,修改到了其它内存空间,危险行为nums[6] = 300;// 读取并打印数组中每个元素的值printf("第一个元素的值:%d\n", nums[0]); // 输出第一个元素的值:20printf("第二个元素的值:%d\n", nums[1]); // 输出第二个元素的值,40printf("第三个元素的值:%d\n", nums[2]); // 输出第三个元素的值:66printf("第四个元素的值:%d\n", nums[3]); // 输出第四个元素的值:88printf("第五个元素的值:%d\n", nums[4]); // 输出第五个元素的值:99// 越界访问// 尝试访问下标为 -1,5的元素,这是未定义行为,可能输出垃圾值printf("越界访问,垃圾数据 nums[-1]:%d\n", nums[-1]); // 不确定的垃圾值printf("越界访问,垃圾数据nums[5]:%d\n", nums[5]);    // 不确定的垃圾值// 上面 nums[6] = 300; 修改了这个内存地址的值为 300,不安全printf("越界访问,不安全行为 nums[6]:%d\n", nums[6]); // 越界访问 nums[6]:300return 0;
}

        输出结果如下所示:

        注意:C 语言在越界访问数组时通常不会直接报错(即不会像一些高级语言那样在运行时抛出异常或错误)。这是因为 C 语言是一种低级语言,它直接与硬件打交道,提供了对内存的直接访问能力,但同时也要求程序员负责内存的管理和安全。

        提示:在 C 语言中,数组是通过指针进行访问的,而数组名在表达式中会被转换成指向数组首元素的指针。当你通过数组名加上索引来访问数组元素时,实际上是在进行指针运算,即根据索引值计算出目标元素的地址,然后访问该地址处的数据。如果索引超出了数组分配的内存范围,编译器并不会检查这一点,因为 C 语言的设计哲学之一就是“相信程序员”。因此,编译器会生成直接访问该内存地址的代码,如果那个地址是可访问的(比如没有超出进程的地址空间),程序就会继续执行,但是访问到的数据可能不是预期的,这可能导致数据损坏、程序崩溃或安全漏洞。 

2.4 计算数组长度

        数组长度(元素个数)是在数组定义时明确指定且固定的,我们不能在运行时直接获取数组长度,但是,我们可以通过 sizeof 运算符间接计算出数组长度,计算步骤如下:

  1. 使用 sizeof 运算符计算出整个数组的字节长度。sizeof(array)
  2. 由于数组成员是同一类型,每个元素字节长度相等,用整个数组的字节长度除以单个元素的字节长度就可以得到数组的长度。 常用:sizeof(array) / sizeof(array[0]);
  3. 也可以用整个数组的字节长度除以数组的数据类型得到数组的长度。 sizeof(array) / sizeof(数组的基本数据类型);

#include <stdio.h>int main()
{// 定义一个整型数组,没有显式指定数组的长度// 但编译器会根据初始化时提供的元素数量自动确定长度int nums1[] = {10, 20, 30, 40, 50, 60, 70};int nums2[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};// 使用 sizeof 运算符计算整个数组所占用的字节长度// sizeof 是编译时运算符,所以 arrByteLen 的值是在编译时就确定的// 计算基本数据类型的大小,必须使用括号将数据类型关键字包裹起来。// 对于字面量和变量,sizeof 运算符可以直接作用于它们,括号是可选的,可以省略括号。int arrByteLen1 = sizeof nums1;  // 可以不加括号int arrByteLen2 = sizeof(nums2); // 加上括号更直观// 用整个数组的字节长度除以数组中单个元素(即 int 类型)的字节长度// 以计算出数组中元素的数量(即数组的长度)int arrLen1 = arrByteLen1 / sizeof nums1[0];int arrLen2 = arrByteLen2 / sizeof(nums1[0]);int arrLen3 = arrByteLen2 / sizeof(nums1[1]); // 随便一个元素都行(都是同类型的)// 也可以除以数组的基本数据类型int arrLen4 = arrByteLen2 / sizeof(int);// 打印计算出的数组长度printf("数组nums1的长度:%d\n", arrLen1); // 输出:数组的长度:7printf("数组nums2的长度:%d\n", arrLen2); // 输出:数组的长度:10printf("数组nums2的长度:%d\n", arrLen3); // 输出:数组的长度:10printf("数组nums2的长度:%d\n", arrLen4); // 输出:数组的长度:10return 0;
}

         知识点回顾:sizeof 计算基本数据类型的大小,必须使用括号将数据类型关键字包裹起来。对于字面量和变量,sizeof 运算符可以直接作用于它们,括号是可选的,可以省略括号。

2.5 遍历数组

2.5.1 输出各个元素

        遍历数组是指按顺序访问数组中的每个元素,以便读取或修改它们,编程中一般使用循环结构对数组进行遍历。

#include <stdio.h>int main()
{int arr[10] = {12, 2, 31, 24, 15, 36, 67, 108, 29, 51};// 计算数组的总长度(即元素个数)// sizeof arr 计算的是整个数组所占用的字节数// sizeof arr[0] 计算的是数组中单个元素所占用的字节数// 将两者相除得到的就是数组的长度(元素个数)int len = sizeof arr / sizeof arr[0];// 遍历数组中的每个元素// 使用 for 循环,循环变量 i 从 0 开始,直到小于数组的长度(即最后一个元素的索引)printf("遍历数组中的元素:\n");for (int i = 0; i < len; i++){printf("%d: %d \n", i, arr[i]);}return 0;
}

        输出结果如下所示:

2.5.2 初始化各个元素

        我们还可以通过数组遍历完成数组的初始化赋值,看下面案例。

        创建长度为 10 的数组,元素依次赋值为 100,200,300,400,500,600,700,800,900,1000,并按逆序输出每个元素,代码如下:

#include <stdio.h>int main()
{// 声明一个整型数组 arr,大小为 10,初始时数组中的元素值未定义int arr[10];int len = sizeof arr / sizeof arr[0];// 遍历数组进行初始化赋值,依次将元素赋值为 100……1000for (int i = 0; i < len; i++){arr[i] = (i + 1) * 100;}// 通过遍历逆序输出数组元素// 从数组的最后一个元素开始,直到第一个元素// 注意逆序第一个下标不是 len 而是 len - 1for (int i = len - 1; i >= 0; i--){printf("%d ", arr[i]); // 1000 900 800 700 600 500 400 300 200 100}return 0;
}

2.6 案例演示

2.6.1 计算元素和与平均数

        计算数组中所有元素的和以及平均数。

#include <stdio.h>int main()
{// 定义并初始化一个整型数组 arr,包含 10 个元素int arr[10] = {12, 2, 31, 24, 15, 36, 67, 108, 29, 51};// 计算数组的长度int len = sizeof arr / sizeof arr[0];// 定义一个整型变量 sum,用于存储数组所有元素的总和int sum = 0;// 使用 or 循环遍历数组中的每个元素// i 是循环变量,从 0 开始,直到小于数组的长度 lenfor (int i = 0; i < len; i++){// 在每次循环中,将当前元素的值加到 sum 上sum += arr[i];}// 计算平均值// 将总和 sum 除以元素数量 len,得到平均值double avg = (double)sum / len;printf("数组元素之和:%d\n", sum);     // 375printf("数组元素平均值:%.2f\n", avg); // 37.50return 0;
}

2.6.2 取元素最大值

        取出数组中之值最大的元素。

#include <stdio.h>int main()
{// 定义一个整型数组 arr,包含 10 个元素,并初始化它们int arr[10] = {12, 2, 31, 24, 15, 36, 67, 108, 29, 51};// 计算数组的长度。int len = sizeof arr / sizeof arr[0];// 定义一个整型变量 max,用于存储数组中的最大值,初始化为数组的第一个元素的值// 先假设第一个元素为最大值,然后循环遍历int max = arr[0];// 方法一:使用 for 循环遍历数组中的每个元素for (int i = 0; i < len; i++){// 在循环体内,使用 if 语句检查当前元素(arr[i])是否大于 max// 如果是,就将当前元素的值赋给 max,更新 max 为当前找到的最大值if (arr[i] > max){max = arr[i];}}printf("最大的元素值:%d\n", max); // 108// 方法二:使用 for 循环遍历数组中的每个元素for (int i = 0; i < len; i++){// 或者用三元运算符max = arr[i] > max ? arr[i] : max;}printf("最大的元素值:%d\n", max); // 108return 0;
}

3 测试题

1. 如何计算数组的长度

【答案】(1)使用 sizeof 运算符计算出整个数组的字节长度。(2)由于数组成员是同一类型,每个元素字节长度相等,用整个数组的字节长度除以单个元素的字节长度就可以得到数组的长度。sizeof(array) / sizeof(数组的基本数据类型);  或常用:  sizeof(array) / sizeof(array[0]);

这篇关于14 数组的相关概念,数组的定义、(越界)访问、长度计算、循环遍历的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1098316

相关文章

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

本地搭建DeepSeek-R1、WebUI的完整过程及访问

《本地搭建DeepSeek-R1、WebUI的完整过程及访问》:本文主要介绍本地搭建DeepSeek-R1、WebUI的完整过程及访问的相关资料,DeepSeek-R1是一个开源的人工智能平台,主... 目录背景       搭建准备基础概念搭建过程访问对话测试总结背景       最近几年,人工智能技术

Ollama整合open-webui的步骤及访问

《Ollama整合open-webui的步骤及访问》:本文主要介绍如何通过源码方式安装OpenWebUI,并详细说明了安装步骤、环境要求以及第一次使用时的账号注册和模型选择过程,需要的朋友可以参考... 目录安装环境要求步骤访问选择PjrIUE模型开始对话总结 安装官方安装地址:https://docs.

解读静态资源访问static-locations和static-path-pattern

《解读静态资源访问static-locations和static-path-pattern》本文主要介绍了SpringBoot中静态资源的配置和访问方式,包括静态资源的默认前缀、默认地址、目录结构、访... 目录静态资源访问static-locations和static-path-pattern静态资源配置

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

Python判断for循环最后一次的6种方法

《Python判断for循环最后一次的6种方法》在Python中,通常我们不会直接判断for循环是否正在执行最后一次迭代,因为Python的for循环是基于可迭代对象的,它不知道也不关心迭代的内部状态... 目录1.使用enuhttp://www.chinasem.cnmerate()和len()来判断for