认识理解数组

数组

什么是数组,数组有什么用,在写代码过程中我们为什么要建立数组…

数组的概念

  • 数组是一种数据结构,它是一组相同类型的元素按照一定顺序排列的集合
    • 数组中可以存放一个或多个数据,但元素个数不能为零
    • 数组存放的多个数据,类型是相同的
  • 数组通常储存多个相同的类型数据,在内存中是连续存放多个数据元素的

  • 数组通常分为一维数组多维数组,其中多维数组比较常见:
    数组的分类
  • 那我们为什么要创建数组呢?C语言中建立数组的主要原因包括:

1.有利于存储和访问一系列相同类型的数据。提供了一种方便且高效的方式来处理数据,我们可以通过索引快速定位和操作数组中的元素。

2.节省内存空间。数组在内存中是连续存储的,相邻元素之间没有额外的空间开销,故可以有效地利用内存空间。

3.方便进行数据的遍历和处理。使用循环结构可以方便地遍历数组中的所有元素,以至于我们进行统一的处理操作。

4.支持多维数组。多维的数组,可以方便表示和高效处理多个维度的数据结构。

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

1.1数组的创建

  • 创建一维数组的基本语法:
    type arr_name[常量值];
    • type是指数组中存放的数据类型,可能是int,char,short,float等类型,当然也可以是自定义类型;
    • arr_name指的是数组的名字,在命名时我们尽量要起的有意义;
    • []中的常量值是用来指定数组大小的,具体大小需要我们根据实际来指定;

例如;

  • 我们创建一个数组来储存我们班的语文成绩:
int Chinese[41] ;
  • 创建一个字符类型的数组:
char wwm[10];
  • 创建一个整型数组:
int wwm[41];
  • 双精度浮点型数组:存储双精度浮点数值。
double doubleArray[3]; // 声明一个包含3个双精度浮点数的数组
  • 结构体数组:存储结构体类型的值。
typedef struct {  
    int id;  
    char name[50];  
} Student;  
Student studentArray[10]; // 声明一个包含10个Student结构体的数组

… … … …

1.2数组的初始化

  • 在数组创建以后,我们通常会给数组一个初始值,这些初始值我们常用大括号{}将其括起来;

1.完全初始化

#include <stdio.h>  
int main() {  
    // 初始化一个包含5个学生成绩的数组  
    int scores[5] = {90, 85, 78, 92, 88};  //**完全初始化**
  
    // 打印数组中的每个成绩  
    for (int i = 0; i < 5; i++) {  
        printf("学生%d的成绩是:%d\n", i + 1, scores[i]);  
    }  
    return 0;  
}

2.部分初始化(不完全初始化)

int arr[5] = {6};//不完全初始化;
          //将第一个元素初始化为6,其它剩下的5个元素默认初始化值为0

3.错误初始化

int arrr[2] = {1,2,3,4,5,6};//初始化元素超过了数组定义的元素个数

2.数组的类型

  • 数组的类型是自定义类型,去掉数组名剩下的就是数组的类型

例如:

int arr1[100];

arr1的数组类型就是:int [100]

```c
int arr2[200];

arr2的数组类型是:int [200]

int arr3[300];

arr3的数据类型是:int [300]

3.一维数组的具体使用

  • 一维数组可以存放数据,存放数据是为了方便对其操作,那我们具体该如何使用呢?

3.1数组下标

C语言中数组的下标是从0开始,假如有数组里有n个元素,那么最一个元素的下标就是n-1,下标就是元素在数组中的编号,我们调用索引它的时候就是根据这个下标来访问的。
例如:

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

数组元素和下标

3.2 下标引用操作符[]

  • 我们知道了数组的访问是通过下标编号来访问的,那具体怎么操作呢?没错,这时候就要用到下标引用操作符[]
    比如:
    我们访问下标为6的元素,那我们就可以结合数组名来访问:arr[6]
    再者,访问下标为8的元素:arr[8]
#include <stdio.h>
int main(){
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	printf("%d\n",arr[6]);
	printf("%d\n",arr[8]);
	return 0;
}

3.3数组元素的打印

  • 学会了如何访问数组元素,现在我们就可以同过循环的方式来遍历输出数组中的所有元素
    • 我们知道访问数组只要知道数组的下标就可以,那我们要遍历输出数组中的所有元素,只需要通过循环来产生0 ~ 9的下标即可;

例如:

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

遍历输出数组的全部内容

3.4数组的输入

  • 学习了数组的访问和遍历输出,那么根据实际需求我们也需要输入自己想要的数据,所以我们同样可以将scanffor循环结合起来使用输入我们需要的数据:
#include <stdio.h>
int main(){
	int arr[10] = {0};//数组的初始化
	int i = 0;
	for(i = 0;i < 10;i++){
	scanf("%d",&arr[i]);//for循环遍历每一个数组空间,
	                   //依次让scanf记录我们的数据并赋值到数组中
	}
	
	for(i = 0;i < 10;i++){
	printf("%d ",arr[i]);//遍历输出所有元素
	}
	return 0;
}

在这里插入图片描述

4.一维数组在内存中的储存

  • 学习了数组的访问和遍历输出,那么我们对于数组的使用基本没有问题了,那么要深入来哦姐数组,我们就需要来了解它在内存中是如何储存的;
  • 因此我们首先需要依次打印数组元素的地址:
#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("&arr[%d] = %p\n",i,&arr[i]);
	}
	return 0;
}

数组的地址(32位)

  • 从输出的地址中我们可以看出,数组的地址是随着下标的增长,地址是从小到大变化的,并且相邻两个元素的地址之间相差4(因为一个整型是4个字节);
  • 故我们得出结论:数组在内存中是连续存放的

5.sizeof计算数组元素的个数

  • 遍历数组的时候,我们需要知道数组有多少个元素才能更好的输出,那么C语言中我们可以通过sizeof来确定;
  • sizeof是C语言中的关键字,是用来计算数据类型或对象在内存中的大小(以字节为单位),当然同样也可以计算数组的大小
#include <stdio.h>
int main (){
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	printf("%d\n",sizeof(arr));
	return 0;
}

数组所占内存大小

  • 数组所占内存总大小,输出为40,单位字节**(一个整型是4个字节,10个元素就是10 * 4 = 40)**
  • 数组中的元素的类型是相同的,所以我i们只需要计算出一个元素的所占字节大小,通过数组字节总大小与一个元素字节大小相除即可求出元素个数
#include <stdio.h>
int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", sizeof(arr[0]));//计算一个元素的大小,单位字节
	return 0;
}

在这里插入图片描述

  • 一个元素大小是4个字节
#include <stdio.h>
int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", sizeof(arr)/sizeof(arr[0]));
	return 0;
}

数组大小为10个元素

  • 得出的结果是10,说明数组有10个元素;
  • 所以在代码中我们就可以不用把数组的元素个数固定写死,运用sizeof计算数组的元素个数,不管数组如何变化,数组元素个数的计算同样也会随之变化

6.二维数组的创建

6.1二维数组的概念

  • 前面学习的一维数组的数组元素类型是内置类型,假如我们把一维数组作为数组元素,这是就变成了二维数组,那如果把二维数组作为数组元素的数组就变成了三维数组,以此类推。但是通常我们将二维以上的数组称为多维数组
  • 二维数组是一个可以存储多个一维数组的数组,或者说是一个矩阵。在二维数组中,数据以行和列的形式组织,每个元素都有一个行索引和一个列索引。
    整型,一维整型数组,二维整型数组

6.2 二维数组的创建

  • 二维数组的基本语法:
    type arr_name[常量值1][常量值2];
例如:
int arr[5][2];
char data[3][4];
  • 数组有5行,每行有2个元素,int表示数组的每个元素是整型,arr是数组名;

7.二维数组的初始化

  • 在创建变量时我们通常会给变量赋初值,这个过程叫做初始化;

7.1不完全初始化

  • 当使用二维数组时,我们选择不完全初始化它,这意味着只为数组中的一部分元素提供初始值,而其余元素将自动使用默认值(对于基本数据类型,通常是0)
    例如:
    int arr[3][5] = {2,3};
    int arr[2][3] = {0};
    在这里插入图片描述
#include <stdio.h>  
int main() {  
    int array[3][3] = {  
        {1, 2},  // 第一行初始化了两个元素,第三个元素使用默认值0  
        {3},     // 第二行只初始化了一个元素,其余两个使用默认值0  
        {4, 5, 6}// 第三行初始化了所有元素  
    };  
  
    // 打印数组内容  
    for (int i = 0; i < 3; i++) {  
        for (int j = 0; j < 3; j++) {  
            printf("%d ", array[i][j]);  
        }  
        printf("\n");  
    }  
    return 0;  
}

不完全初始化

  • 使用花括号省略来初始化部分行:
#include <stdio.h>  
int main() {  
    int array[3][3] = {  
        {1, 2},  // 第一行初始化了两个元素  
        {3},     // 第二行只初始化了一个元素  
             // 第三行没有初始化任何元素,所有元素都将使用默认值0  
    };  
  
    // 打印数组内容  
    for (int i = 0; i < 3; i++) {  
        for (int j = 0; j < 3; j++) {  
            printf("%d ", array[i][j]);  
        }  
        printf("\n");  
    }  
    return 0;  
}

在这里插入图片描述

7.2完全初始化

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

#include <stdio.h>  
int main() {  
    int array[2][3] = {  
        {1, 2, 3},  // 第一行完全初始化  
        {4, 5, 6}   // 第二行完全初始化  
    };  
  
    // 打印数组内容  
    for (int i = 0; i < 2; i++) {  
        for (int j = 0; j < 3; j++) {  
            printf("%d ", array[i][j]);  
        }  
        printf("\n");  
    }  
    return 0;  
}

在这里插入图片描述

7.3 按照行初始化

int arr[4][3] = {{1,2},{2,3},{3},{4}}
在这里插入图片描述

  • 初始化过程中可以省略行,但不能省略列
    int arr1[][6] = {1,2,3,4}
    int arr2[][6] = {1,2,3,4,5,6,7}
    int arr3[][6] = {{1,2},{2,3},{3,4}}
    在这里插入图片描述

8.二维数组的使用

8.1 二维数组的下标

  • 根据C语言的规定,二维数组的下标的**行是从0开始,列也是从0开始**;
  • 二维数组的访问同样是通过下标来访问,但是有行和列之分,只要我们确定了行和列就能锁定二维数组中的具体位置的元素;
    例如:
    int arr[3][5] = {1,2,3,4,5,2,3,4,5,6,3,4,5,6,7}
    在这里插入图片描述
  • 如果我们要找2行3列的元素,那么根据图中的下标就能快速找到元素,即2行3列的元素是:6
#include <stdio.h>
int main() {
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	printf("%d",arr[2][3]);
	return 0;
}

在这里插入图片描述

8.2 二维数组的输入和输出

  • 同样的我们只需要按照一定的规律产生行和列,通过forscanf获取行和列的范围,即可对二维数组进行数据的输入和输出
#include <stdio.h>
int main() {
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	int i = 0;//遍历行
	//输入
	for (i = 0; i <= 2; i++) {
		int j = 0;
		for (j = 0; j <= 4; j++) {
			scanf("%d",&arr[i][j]);
		}
	}
	//输出
	for (i = 0; i <= 2; i++)
	{
		int j = 0;//遍历列
		for (j = 0; j <= 4; j++)
		{
			printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
	
	return 0;
}

在这里插入图片描述

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

  • 我们研究二维数组在内存中的储存方式,那么我们可以打印出二维数组中数组元素的所有地址:
#include <stdio.h>
int main()
{
	int arr[3][5] = { 0 };
	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]);
		}
	}
	return 0;
}

在这里插入图片描述
我们可以看出每一行的元内部元素存放都是连续的,地址之间相差4个字节,跨行位置的元素,如:arr[0][4]arr[1][0]之间也是相差4个字节,故我们可以得出结论二维数组中的每个元素都是连续存放的
二维数组中的每个元素都是连续存放的

9.C99中的变长数组

C99标准之前

  • C语⾔在创建数组的时候,数组大小的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组大小
  • 缺点:创建数组不够灵活,数组大了浪费空间,数组又小了不够用
  • 如:
int arr1[10];
int arr2[6+6];
int arr3[];

C99中

  • 提供了一个变长数组(variable-length array,简称VLA
  • 允许我们可以使用变量指定数组大小。
  • 如:
int n = a + b;
int arr[n];

上面的数组arr就是变长数组,因为它的元素个数取决于n的大小,编译器 无法提前得知,只有运行时才知道n的大小;

  • 变长数组的根本特征在于,无法事先知道数组长度,只有运行时才能确定,所以变长数组不能初始化,好处在于,程序员在写代码时不必随意指定数组长度,在运行时才为数组分配精确的长度;
  • 值得注意的是:变长数组是根据变量大小来指定元素个数,而不是说数组的大小时可变的。数组的大小可以根据变量来指定,但是数组的大小一旦创建就无法再改变了。
  • 下面是在gcc编译器上测试的结果:
#include <stdio.h>
int main()
{
	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;
}

10.数组练习

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

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
int main()
{
	char arr1[] = "Welcome to wuahan !!!!";
	char arr2[] = "**********************";

	int left = 0;
	int right = strlen(arr1) - 1;

	while (left <= right)
	{
		Sleep(1000);
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];

		
		/*system("cls");*/
		left++;
		right--;
		printf("%s\n", arr2);
	}
	return 0;
}

在这里插入图片描述

10.2 二分查找(折半查找)

  • 二分查找的前提是有序
#include <stdio.h>  
  
int main()  
{  
    // 定义一个已排序的整数数组  
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };  
  
    // 定义左右指针,初始时左指针指向数组的第一个元素,右指针指向数组的最后一个元素  
    int left = 0;  
    int right = sizeof(arr) / sizeof(arr[0]) - 1; // 注意这里减去1,因为数组索引是从0开始的  
  
    // 定义要查找的关键字  
    int key = 6;  
  
    // 定义标志变量,用来记录是否找到关键字  
    int flag = 0;  
  
    // 计算中间位置,这里使用了一个技巧来防止在left和right值很大时,left + right可能溢出  
    int mid = left + (right - left) / 2;  
  
    // 当左指针不大于右指针时,继续查找  
    while (left <= right) {  
        // 如果中间元素大于关键字,则关键字在左半部分  
        if (arr[mid] > key)  
        {  
            right = mid - 1;  
        }  
        // 如果中间元素小于关键字,则关键字在右半部分  
        else if (arr[mid] < key)  
        {  
            left = mid + 1;  
        }  
        // 如果中间元素等于关键字,则找到关键字  
        else  
        {  
            flag = 1; // 设置找到标志  
            printf("找到了,下标是:%d\n",mid); // 输出找到的关键字下标  
            break; // 跳出循环  
        }  
        // 重新计算中间位置  
        mid = left + (right - left) / 2;  
    }  
  
    // 如果没有找到关键字  
    if (flag == 0) {  
        printf("找不到!\n");  
    }  
  
    return 0;  
}

在这里插入图片描述

  • 注意

1.sizeof(arr) / sizeof(arr[0]) - 1 用于计算数组的长度,并减去1得到右指针的初始值。因为数组索引是从0开始的,所以最后一个元素的索引是数组长度 - 1

2.left + (right - left) / 2 是计算中间索引的公式,这种写法可以避免leftright的和过大时溢出的问题。

3.flag 是一个标志变量,用来标记是否找到了关键字。如果找到了,就输出其下标,并跳出循环。

4.如果循环结束后flag仍然为0,则表示关键字不在数组中,输出“找不到!”。

  • 39
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值