[C语言]第八节 数组一基础知识到高级技巧的全景探索

news2024/12/27 13:14:32

目录

8.1 数组概念的引入

8.2.⼀维数组的创建和初始化

8.2.1 数组的创建

8.2.2数组的初始化

 8.2.3 数组的类型

8.3 ⼀维数组的使⽤

8.3.1 数组下标

8.3.2 打印数组元素

8.3.3 输入数组元素

8.4 ⼀维数组在内存中的存储

8.5 sizeof计算数组元素个数

8.5.1 sizeof 关键字

8.5.2 计算数组的元素个数

8.6 ⼆维数组的创建

8.6.1 二维数组的概念

 什么是二维数组?

8.6.2 ⼆维数组的创建  

8.7  ⼆维数组的初始化

8.7.1 不完全初始化

8.7.2 完全初始化

8.7.3 按行初始化

8.7.4 省略行但不能省略列 

8.8  ⼆维数组的使⽤与输入输出

8.8.1 使用

8.8.2 输入输出

8.9 ⼆维数组在内存中的存储

8.10  数组练习

 8.10.1 多个字符从两端移动,向中间汇聚

8.10.2 ⼆分查找


8.1 数组概念的引入

在没有学习数组之前,如果我们想要定义10个类型相同的变量,我们需要分开写 10 行,

#include <stdio.h>
int main()
{
    int a=1;
    int b=2;
    int c=3;
    int d=4;
    int e=5;
    int f=6;
    int g=7;
    int h=8;
    int i=9;
    int l=10;
    return 0;
 )

由于逐一定义变量不仅繁琐且会导致代码占用更多的内存空间,因此我们引入了数组的概念,以更高效地管理和存储数据,那么,什么是数组呢?

数组是一个用于存储相同类型元素的集合。基于这一概念,可以提炼出两个关键点:

  1. 数组中可以存储一个或多个元素,但数组的元素个数不能为零。
  2. 数组中的所有元素必须是相同的数据类型。

数组可以分为一维数组和多维数组,其中多维数组中最常见的是二维数组

8.2.⼀维数组的创建和初始化

8.2.1 数组的创建

创建一维数组的基本语法如下:

type arr_name[常量值];

在创建数组时,可以指定数组的大小和元素类型。具体说明如下:

1.type :指定数组中存储的数据类型,可以是基本数据类型如 charshortintfloat 等,也可以是用户自定义的类型。

2.arr_name :数组的名称,应根据实际情况赋予一个有意义的名字。

3.[] :括号内的常量值用于指定数组的大小,大小根据实际需求决定。

 例如,如果我们需要存储某个班级75人的C语言成绩,可以创建如下数组:

int C[75];

当然,也可以根据需要创建其他类型和大小的数组,例如: 

char ch[20];
double score[10];

8.2.2数组的初始化

在某些情况下,数组在创建时需要指定初始值,这个过程称为数组的初始化。数组的初始化通常通过大括号 {} 来实现,将初始值放在大括号内。

完全初始化

int arr1[5]={1,2,3,4,5}

不完全初始化    // 第一个元素初始化为1,剩余元素默认初始化为0

int arr2[6] = {1}; 

错误的初始化    // 初始化项太多,数组大小为3,初始值有4个

int arr3[3] = {1, 2, 3, 4}; 

 8.2.3 数组的类型

数组也是一种数据类型,属于自定义类型。数组的类型由元素类型和数组大小共同决定。

int arr1[10];
int arr2[12];
char ch[5];

 在上述例子中:

arr1 数组的类型是 int[10]  注意不能只写int int是数组的元素的类型

arr2 数组的类型是 int[12]

ch 数组的类型是 char[5]

8.3 ⼀维数组的使⽤

了解了一维数组的基本语法后,我们可以用它来存储和操作数据。接下来,让我们看看如何具体使用一维数组。

8.3.1 数组下标

在C语言中,数组的元素是通过下标来访问的。数组的下标从0开始,假如数组有n个元素,那么最后一个元素的下标是n-1。下标就像是数组元素的编号。比如:

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

要访问数组中的某个元素,我们使用 [] 这个下标引用操作符。比如,要访问第8个元素(下标为7),可以用 arr[7];要访问第4个元素(下标为3),可以用 arr[3]。看下面的代码示例: 

#include <stdio.h>

int main() {
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
    printf("%d\n", arr[7]); // 输出 8
    printf("%d\n", arr[3]); // 输出 4
    return 0;
}

8.3.2 打印数组元素

如果我们想打印整个数组的内容,该怎么办呢?很简单,只要遍历数组的所有下标,然后依次访问每个元素。用 for 循环可以轻松实现:

#include <stdio.h>

int main() {
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
    for(int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

8.3.3 输入数组元素

不仅可以访问数组元素,我们还可以根据需要向数组中输入数据。下面的示例展示了如何使用 scanf 函数输入数组的值,然后打印出来:

#include <stdio.h>

int main() {
    int arr[10];
    for(int i = 0; i < 10; i++) {
        scanf("%d", &arr[i]);
    }
    for(int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

8.4 ⼀维数组在内存中的存储

为了更好地理解数组,我们可以看看它们在内存中的存储方式。C语言中,数组的元素在内存中是连续存放的。我们可以打印数组元素的内存地址来验证这一点。以下代码展示了如何查看每个数组元素的地址:

#include <stdio.h>

int main() {
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
    for(int i = 0; i < 10; i++) {
        printf("&arr[%d] = %p\n", i, &arr[i]);
    }
    return 0;
}

 输出结果分析:

你会发现,数组元素的地址随着下标的增加而递增。对于 int 类型数组,相邻元素的地址差为4字节(因为一个 int 占用4个字节)。这说明数组在内存中是连续存放的。

8.5 sizeof计算数组元素个数

在遍历数组时,我们通常需要知道数组的元素个数。C语言中可以通过 sizeof 关键字来计算数组的元素个数。

8.5.1 sizeof 关键字

sizeof 是C语言中的一个关键字,用于计算类型或变量所占的内存空间大小。实际上,它也可以计算数组的大小。

来看一个简单的示例:

#include <stdio.h>

int main() {
    int arr[10] = {0};
    printf("数组的总大小: %lu 字节\n", sizeof(arr));
    return 0;
}

在这个例子中,sizeof(arr) 计算的是数组 arr 所占内存的总大小,单位是字节。对于 int 类型的数组,每个元素占4个字节,所以输出结果是40字节。 

8.5.2 计算数组的元素个数

因为数组中的所有元素类型相同,所以我们可以通过计算单个元素的大小,再除以整个数组的大小,得到数组的元素个数。例如:

#include <stdio.h>

int main() {
    int arr[10] = {0};
    int elementSize = sizeof(arr[0]); 
    printf("一个元素的大小: %lu 字节\n", elementSize);
    return 0;
}

接下来,我们可以计算数组的元素个数:

#include <stdio.h>

int main() {
    int arr[10] = {0};
    int numOfElements = sizeof(arr) / sizeof(arr[0]);
    printf("数组的元素个数: %d\n", numOfElements);
    return 0;
}

这种方法非常实用,不论数组大小如何变化,计算出的元素个数都能自动更新。这种灵活性使代码更具适应性,避免了手动计算的麻烦。

8.6 ⼆维数组的创建

8.6.1 二维数组的概念

  我们之前学习过的一维数组是指数组的元素都是基本数据类型(如 intchar 等)。当我们把一个一维数组作为另一个数组的元素时,就得到了二维数组。再进一步,如果把二维数组作为元素,这时就得到了三维数组。所有超过二维的数组统称为多维数组

 什么是二维数组?

二维数组可以看作是一个“数组的数组”。换句话说,二维数组的每个元素都是一个一维数组。

8.6.2 ⼆维数组的创建  

创建方法

type arr_name[常量值1][常量值2];
例如:
int arr[3][5];
double data[2][8];
3表⽰数组有3⾏
  5表⽰每⼀⾏有5个元素
int 表⽰数组的每个元素是整型类型
  arr 是数组名,可以根据⾃⼰的需要指定名字

8.7  ⼆维数组的初始化

当我们创建一个变量或数组时,如果同时给它赋值,这个过程就称为初始化。对于二维数组,初始化的方式与一维数组类似,也是使用大括号 {} 来进行。

8.7.1 不完全初始化

在不完全初始化中,只为数组的部分元素赋值,未赋值的部分会自动初始化为零。

#include <stdio.h>

int main() {
    int arr1[3][5] = {1, 2}; // 只有前两个元素被初始化,其他元素自动初始化为 0
    int arr2[3][5] = {0};    // 所有元素都被初始化为 0

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", arr1[i][j]);
        }
        printf("\n");
    }
    return 0;
}

8.7.2 完全初始化

完全初始化时,所有元素都显式赋值。每个元素都指定了一个值,数组中没有剩余的元素需要自动初始化。

#include <stdio.h>

int main() {
    int arr3[3][5] = {
        {1, 2, 3, 4, 5},
        {2, 3, 4, 5, 6},
        {3, 4, 5, 6, 7}
    };

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", arr3[i][j]);
        }
        printf("\n");
    }
    return 0;
}

 

8.7.3 按行初始化

按行初始化时,每一行可以单独使用一对大括号进行初始化。这种方式更清晰地展示了数组的行结构。

#include <stdio.h>

int main() {
    int arr4[3][5] = {
        {1, 2},       // 第一行的前两个元素被赋值
        {3, 4},       // 第二行的前两个元素被赋值
        {5, 6}        // 第三行的前两个元素被赋值
    };

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", arr4[i][j]);
        }
        printf("\n");
    }
    return 0;
}

8.7.4 省略行但不能省略列 

在初始化时,可以省略数组的行数,但不能省略列数。省略行数时,编译器会根据初始值的数量自动确定行数。

#include <stdio.h>

int main() {
    int arr5[][5] = {1, 2, 3};  // 自动推导出行数,这里是1行
    int arr6[][5] = {1, 2, 3, 4, 5, 6, 7}; // 自动推导出行数,这里是2行
    int arr7[][5] = {             // 3行
        {1, 2},
        {3, 4},
        {5, 6}
    };

    printf("arr5: \n");
    for (int i = 0; i < 1; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", arr5[i][j]);
        }
        printf("\n");
    }

    printf("arr6: \n");
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", arr6[i][j]);
        }
        printf("\n");
    }

    printf("arr7: \n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 5; j++) {
            printf("%d ", arr7[i][j]);
        }
        printf("\n");
    }

    return 0;
}

 

 这种灵活的初始化方式可以让你的代码更简洁,并且更加适应各种不同的需求

8.8  ⼆维数组的使⽤与输入输出

8.8.1 使用

现在我们已经了解了如何访问二维数组的单个元素,接下来我们看看如何处理整个二维数组。关键是要以一定的结构生成所有可能的行和列索引。以数组 arr 为例,它有3行5列,行的范围是0到2,列的范围是0到4。我们可以使用嵌套循环来生成这些索引。

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

 

8.8.2 输入输出

要访问二维数组的所有元素,只需按行和列的顺序生成对应的下标即可。以 arr 数组为例,它有3行5列,行的范围是0到2,列的范围是0到4。我们可以使用嵌套的循环来生成这些下标,并遍历整个数组。 

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

8.9 ⼆维数组在内存中的存储

为了更好地理解二维数组在内存中的存储方式,我们可以通过打印出数组中每个元素的地址来进行研究。以下是示例代码:

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

通过结果可知:

1.每一行内部的元素地址是连续的,地址之间相差4个字节(假设整数是4字节)。

2.相邻行之间的元素地址也相差4个字节

这表明,二维数组在内存中是按行连续存储的。了解这个布局有助于我们更深入地学习如何使用指针来访问和操作数组。

8.10  数组练习

 8.10.1 多个字符从两端移动,向中间汇聚

要实现字符从两端向中间汇聚的效果,可以使用以下代码。这个代码展示了如何逐步将字符从一个字符串(arr1)移动到另一个字符串(arr2)中,并在每一步打印出当前的状态。

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "Wishing you happiness every day";
	char arr2[] = "###############################";
	int left = 0;
	int right = strlen(arr1) - 1;
	while (left <= right)
	{
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		left++;
		right--;
		printf("%s\n", arr2);
	}
	return 0;
}

8.10.2 ⼆分查找

   在⼀个升序的数组中查找指定的数字n,很容易想到的⽅法就是遍历数组,但是这种⽅法效率⽐较低。 ⽐如我买了⼀本书,你好奇问我多少钱,我说不超过50元。你还是好奇,你想知道到底多少,我就让 你猜,你会怎么猜?你会1,2,3,4...这样猜吗?显然很慢;⼀般你都会猜中间数字,⽐如:55,然 后看⼤了还是⼩了, 二分查找是一种高效的搜索算法,用于在有序数组中查找指定元素。它通过每次将查找范围减半来快速找到目标元素。

#include <stdio.h>

int main() {
    char arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
    int k = 6;
    int find = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    int left = 0;
    int right = sz - 1;
    int mid = 0; // 在循环外声明 mid

    while (left <= right) 
    {
        mid = (left + right) / 2; // 更新 mid 的值
        if (arr[mid] < k) {
            left = mid + 1; // 中间值小于目标值, 将左边界更新为中间值的下一位
        }
        else if (arr[mid] > k) {
            right = mid - 1; // 中间值大于目标值, 将右边界更新为中间值的前一位
        }
        else {
            find = 1; 
            break;
            }
     }

    if (find == 1)
        printf("找到了, 下标是 %d\n", mid); 
    else
        printf("找不到\n");

    return 0;
}

求中间元素的下标,使⽤ mid = (left+right)/2 ,如果left和right⽐较⼤的时候可能存在问
题,可以使⽤下⾯的⽅式:
mid = left+(right-left)/2;

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

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

相关文章

第4章-05-用WebDriver下载页面csv到本地

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲,后续完整更新内容如下。 文章…

Java 入门指南:Java 并发编程 —— JMM Java内存模型

JMM&#xff08;Java Memory Model&#xff0c;Java 内存模型&#xff09;&#xff08;抽象模型&#xff09;是用来描述和控制多线程之间内存可见性、有序性、原子性、指令重排等问题的规范。 JMM 定义了一组规则&#xff0c;规定了在多线程环境下&#xff0c;线程在执行共享变…

尚品汇-MQ模块搭建测试、消息不丢失(重)(四十三)

目录&#xff1a; &#xff08;1&#xff09;消息不丢失 &#xff08;2&#xff09;消息确认 &#xff08;3&#xff09;消息确认业务封装 &#xff08;4&#xff09;封装发送端消息确认 &#xff08;5&#xff09;封装消息发送 &#xff08;6&#xff09;发送确认消息测试…

【C#】Visual Studio 2017开发C#,按F1键没有跳转到C#帮助文档,反而跳到了Qt的帮助文档

1. 原因 Visual Studio中安装了Qt的插件&#xff0c;所以将F1的跳转链接转到了Qt的帮助文档。 2. F1改回微软帮助文档方法 工具 - 选项 - Qt - General - Try Qt Documentation when F1 is pressed改为Flase

Web服务端通过SSE推送消息给浏览器客户端的实现方案(附详细代码和仓库地址)

目录 1、SSE&#xff08;Server-Sent Events&#xff09;简介2、SSE 的工作原理3、SSE 与客户端轮询的区别和优势比较区别优势 4、SSE简单实现(单机应用Demo)演示效果SSE-Demo仓库地址下面直接贴代码&#xff1a;前端实现&#xff1a;后端实现&#xff1a; 5、SSE简单实现(分布…

【pycharm】汉化及翻译插件

汉化插件 翻译插件 使用 选中右键翻译

一键解决LBP2900通信错误的问题(同样支持Win 11系统)

**目录** **前言****常见解决方式****方案一&#xff1a;端口排除****方案二&#xff1a;服务重启****方案三&#xff1a;注册表注入修复** 前言 佳能LBP2900向来是经典耐用款的打印机。想必各位可能遇到过&#xff0c;由于老旧会出现奇葩的问题&#xff0c;譬如 就算USB接口已…

【C++篇】~类和对象(上)

【C篇】 类和对象上 一类二实例化内存对齐原因&#xff08;用空间换时间&#xff0c;提高效率&#xff09; 一类 ‘类’class可以理解为C语言阶段的‘结构体’&#xff0c;它的用法与struct大差不差很多地方都相同&#xff0c;但是C毕竟是C&#xff0c;类的用法肯定比结构体的…

Linux Kernel 6.12版预计将支持在崩溃后显示二维码 后续可以解码排查错误

7 月份时红帽工程师基于 systemd 255 版的全屏显示错误消息功能为 Linux Kernel 开发崩溃后显示二维码选项&#xff0c;这与微软在 Windows 10/11 蓝屏死机后显示二维码有异曲同工之妙。 不过 Linux 与 Windows 在崩溃时显示的二维码内容则有本质区别&#xff0c;因为 Window…

单链表反转(C语言)

1 问题描述 力扣&#xff08;LeetCode&#xff09;--反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 例如&#xff1a; 输入&#xff1a;head [1,2,3,4,5]输出&#xff1a;[5,4,3,2,1] 输入&#xff1a;head [1,2]输出&#x…

11 Java 方法引用、异常处理

文章目录 前言一、Java接口之函数式编程 --- 接口知识补充1 Function<T,R>泛型接口2 BiFunction<T, U, R>泛型接口3 自定义泛型函数式编程接口 二、方法引用1 方法引用初体验&#xff08;以Array.sort()方法为例&#xff09;2 引用静态方法3 引用其他类成员方法 前…

【面试五】PID控制算法

一、 PID算法简介 PID&#xff08;Proportional-Integral-Derivative&#xff09;控制算法是一种经典的反馈控制方法&#xff0c;广泛应用于自动控制系统&#xff0c;例如温度控制、速度控制、位置控制等。 PID控制算法的核心包含三个部分&#xff1a;比例项&#xff08;P&…

@antv/g6 业务场景:流程图

1、流程图是流经一个系统的信息流、观点流或部件流的图形代表。在企业中&#xff0c;流程图主要用来说明某一过程。这种过程既可以是生产线上的工艺流程&#xff0c;也可以是完成一项任务必需的管理过程。业务场景流程图如下&#xff1a; 2、绘制流程图的 Tips 流程图一般是用…

计算机毕业设计选题推荐-果树生长信息管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Redis三种集群模式:主从模式、哨兵模式和Cluster模式

1. 总结经验 redis主从&#xff1a;可实现高并发(读)&#xff0c;典型部署方案&#xff1a;一主二从 redis哨兵&#xff1a;可实现高可用&#xff0c;典型部署方案&#xff1a;一主二从三哨兵 redis集群&#xff1a;可同时支持高可用(读与写)、高并发&#xff0c;典型部署方…

探索Python数据持久化的秘密:ZODB库的神奇之旅

文章目录 探索Python数据持久化的秘密&#xff1a;ZODB库的神奇之旅背景ZODB是什么&#xff1f;如何安装ZODB&#xff1f;简单库函数使用方法场景应用常见Bug及解决方案总结 探索Python数据持久化的秘密&#xff1a;ZODB库的神奇之旅 背景 在Python的广阔世界中&#xff0c;数…

基于单片机的水箱水质监测系统设计

本设计基于STM32F103C8T6为核心控制器设计了水质监测系统&#xff0c;选用DS18B20温度传感器对水箱水体温度进行采集&#xff1b;E-201-C PH传感器获取水体PH值&#xff1b;选用TS-300B浊度传感器检测水体浊度&#xff1b;采用YW01液位传感器获取水位&#xff0c;当检测水位低于…

网络压缩之知识蒸馏(knowledge distillation)

因为直接训练一个小的网络&#xff0c;往往结果就是没有从大的网络剪枝好。知识蒸馏的概念是 一样的&#xff0c;因为直接训练一个小的网络&#xff0c;没有小的网络根据大的网络来学习结果要来得 好。 因而&#xff0c;先训练一个 大的网络&#xff0c;这个大的网络在知识蒸馏…

Flutter 初识:Chip控件

Flutter Chip控件小结 Chip属性解析示例 InputChip属性解析示例 ChoiceChip属性解析示例 FilterChip属性解析示例 ActionChip属性解析示例 在 Flutter 中&#xff0c;Chip 是一种用于显示简洁信息的组件。它通常用来展示标签、属性、短的文本片段等&#xff0c;并可以包含可选的…

C语言推箱子迷宫

目录 开头程序程序的流程图程序游玩的效果下一篇博客要说的东西 开头 大家好&#xff0c;我叫这是我58。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <Windows.h> typedef stru…