C语言超详细讲解——数组

前言

从这篇文章开始,我们就要进入C语言的重要模块——数组的学习,本文包括一维数组、二维数组的概念、使用以及介绍一下变长数组,最后会有超有价值的小练习,可根据目录跳转自己需要的内容。

1. 数组的概念

数组是一组相同类型元素的集合。从该概念可得两个关键信息:

  • 数组中存放的是1个或多个数据,数组元素个数不能为0。
  • 数组中存放的多个数据,类型相同。

数组分为一维数组和多维数组,常见的多维数组是二维数组。

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

2.1 数组创建

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

type arr_name[常量值];

  • type指定数组中存放数据的类型,如charshortintfloat等,也可以是自定义类型。
  • arr_name是数组名,应取有意义的名字。
  • []中的常量值用于指定数组的大小,根据实际需求确定。

例如:

int math[20];//用于存储20人的数学成绩。
char ch[8];
double score[10];

2.2 数组的初始化

数组创建时给定初始值,称为初始化。数组初始化一般使用大括号将数据括起来。

//**完全初始化**:`
int arr[5] = {1,2,3,4,5};
//**不完全初始化**:
int arr2[6] = {1};//第一个元素初始化为1,剩余元素默认初始化为0。
//**错误的初始化 - 初始化项太多**:`
int arr3[3] = {1, 2, 3, 4};//,初始化项数量超过数组大小。

2.3 数组的类型

数组是一种自定义类型,去掉数组名留下的就是数组的类型。

  • int arr1[10];arr1数组的类型是int [10]
  • int arr2[12];arr2数组的类型是int [12]
  • char ch[5];ch数组的类型是char [5]

3. 一维数组的使用

3.1 数组下标

C语言规定数组有下标,且从0开始。假设数组有n个元素,最后一个元素的下标是n - 1,下标相当于数组元素的编号。也叫数组的索引。
下标对应符

数组访问使用[]下标引用操作符。例如:

#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
4

3.2 数组元素的打印

要访问整个数组内容,可使用for循环产生数组所有元素的下标,再通过下标访问。这个过程也称为遍历数组。

#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.3 数组的输入

根据需求给数组输入数据:

#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++)
    {
        scanf("%d", &arr[i]);
    }
    for(i=0; i<10; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

输入输出示例

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

通过打印数组元素的地址了解其存储方式:

#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("&arr[%d] = %p\n ", i, &arr[i]);//%p元素的地址
    }
    return 0;
}

运行结果

运行结果是十六进制数,数组随着下标的增长,地址由小到大变化,且相邻元素地址相差4字节(因一个整型是4个字节)。结论:数组在内存中是连续存放的,为后期使用指针访问数组奠定基础。

5. sizeof计算数组元素个数

sizeof是C语言关键字,可计算类型或变量大小,也能计算数组大小。
例如:

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    printf("%d\n", sizeof(arr));
    return 0;
}

输出结果是40,计算的是数组所占内存空间的总大小,单位是字节。

计算数组元素个数:

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int sz = sizeof(arr)/sizeof(arr[0]);
    printf("%d\n", sz);
    return 0;
}

结果是10,表示数组有10个元素。以后在代码中需要数组元素个数的地方,可使用此计算方式,数组变化时,计算出的大小也会相应变化。

6. 二维数组的创建

6.1 二维数组的概念

把一维数组作为数组元素,就是二维数组。将二维数组作为数组元素的数组称为三维数组,二维数组以上的数组统称为多维数组。
对照图

6.2 二维数组的创建

定义二维数组的语法:

type arr_name[常量值1][常量值2];

例如:

int arr[3][5];//表示数组有3行,每行有5个元素,每个元素是整型。
double data[2][8];

7. 二维数组的初始化

在创建变量或数组时给定初始值,称为初始化。二维数组使用大括号初始化。

7.1 不完全初始化

int arr1[3][5] = {1,2};
int arr2[3][5] = {0};

数组内部

7.2 完全初始化

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

7.3 按照行初始化

int arr4[3][5] = {{1,2},{3,4},{5,6}};
arr4

7.4 初始化时省略行,但不能省略列

  • int arr5[][5] = {1,2,3};
  • int arr6[][5] = {1,2,3,4,5,6,7};
  • int arr7[][5] = {{1,2}, {3,4}, {5,6}};

数组内容

8. 二维数组的使用

8.1 二维数组的下标

二维数组访问使用下标形式,行和列都从0开始。锁定行和列就能唯一锁定数组中的一个元素。
对照表
图中最右侧绿⾊的数字表⽰⾏号,第⼀⾏蓝⾊的数字表⽰列号,都是从0开始的,⽐如,我们说:第1
⾏,第4列,快速就能定位出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\n", arr[1][4]);
    return 0;
}

输出结果:

运行结果

8.2 二维数组的输入和输出

访问整个二维数组,可借助循环生成所有的行和列下标。

#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<3; i++) //产生行号
    {
        int j = 0;
        for(j=0; j<5; j++) //产生列号
        {
            scanf("%d", &arr[i][j]); //输入数据
        }
    }
    //输出
    for(i=0; i<3; i++) //产生行号
    {
        int j = 0;
        for(j=0; j<5; j++) //产生列号
        {
            printf("%d ", arr[i][j]); //输出数据
        }
        printf("\n");
    }
    return 0;
}

运行结果实例

9. 二维数组在内存中的存储

通过打印数组所有元素的地址研究其存储方式:

#include <stdio.h>
int main()
{
    int arr[3][5] = { 0 };
    int i = 0;
    for (i = 0; i < 3; i++) {
        int j = 0;
        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个字节。所以二维数组中的每个元素都是连续存放的,了解其内存布局有利于后期使用指针访问数组的学习。

10. C99中的变长数组

在C99标准之前,C语言创建数组时,数组大小只能使用常量、常量表达式,或者初始化数据时省略数组大小。
例如:

  • int arr1[10];
  • int arr2[3+5];
  • int arr3[] = {1,2,3};

这种语法限制导致创建数组不够灵活。C99引入变长数组(VLA)特性,允许使用变量指定数组大小。
例如:

int n = a+b; 
int arr[n]; 

数组arr是变长数组,其长度取决于变量n的值,编译器无法事先确定,只有运行时才能知道。变长数组不能初始化,好处是程序员无需在开发时随意指定数组估计长度,程序可在运行时为数组分配精确长度。需要注意,变长数组的大小在运行时根据变量确定,但数组大小一旦确定就不能再变化。

在VS2022上不支持C99中的变长数组,无法测试。在gcc编译器(比如Dev c++)上测试示例:

#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;
}

测试结果:
运行结果
那么,我在VS2022中也想使用变长数组,该怎么办呢?
1 调整VS2022的配置,可以自行寻找教程,改用gcc编译器(不建议,新手不要去做,浪费时间,没有意义)
2 使用动态分布也能达到同样效果,这部分内容敬请期待,会单独写文章。

11. 数组练习

练习1:多个字符从两端移动,向中间汇聚

编写代码,演⽰多个字符从两端移动,向中间汇聚
过程演示

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

运行结果
这样基本要求就达到了,但我们不妨完善一下,有没有办法体现过程的感觉呢?有的兄弟,有的,这样的方法一共有 ,我们使用一个函数Sleep(),原型和头文件为,括号里填时间,单位为毫秒,可以前线程暂停执行一段时间,注意:不同编译器Sleep的首字母大小写不同,VS2022为大写

#include <windows.h>
void Sleep(DWORD dwMilliseconds);
比如

Sleep(1000);//1s

但是这么打印出怎么一堆也不好看,有没有一个一个出现的办法呢?这里要用到一个代码

system("cls");//清理屏幕

注意:system需要一个头文件#include<stdlib.h>
最终代码为

#include<stdio.h>
#include<string.h>
#include<Windows.h>
#include<stdlib.h>
int main()
{
	char arr1[] = "welcome to C world";

	char arr2[] = "##################";
	int left = 0;
	int right = strlen(arr1) - 1;//strlen不包括‘\0’

	while(left <= right)
	{
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf("%s\n", arr2);
		Sleep(1000);//单位毫秒,看到这个过程
		system("cls");//清理屏幕
		left++;
		right--;
	}
	printf("%s\n", arr1);
	return 0;
}

结果是动态的,这里不演示了,自己试试吧

练习2:二分查找

查找最简单的想法是挨个找,最直接了当,代码为

#include<stdio.h>
int main()
{
	int arr[] = { 9,5,6,7,8,4,2,1,3,0 };
	int n = 0;
	scanf("%d", &n);
	//1挨个找
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int flag = 0;//0没找到
	for (i = 0; i < sz; i++)
	{
		if (arr[i] == n)
		{
			printf("找到了,下标是:%d\n", i);
			flag = 1; //找到了
			break;
		}
	}
	if (flag == 0)
		printf("找不到\n");
	return 0;
}

在升序数组中查找指定数字,二分查找(折半查找)效率更高。

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int n = 0;
	scanf("%d", &n);
	//折半查找
	int sz = sizeof(arr) / sizeof(arr[0]);
	int left = 0;
	int right = sz - 1;
	int flag = 0;//找不到
	
	while(left <=right)
	{
		int mid = (left + right) / 2;//必须在循环里面
		if (arr[mid] < n)
		{
			left = mid + 1;
		}
		else if (arr[mid] > n)
		{
			right = mid - 1;
		}
		else
		{
			printf("找到了,下标是:%d\n", mid);
			flag = 1;
			break;
		}
	}
	if (flag == 0)
		printf("找不到\n");
	return 0;
}

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

 mid = left+(right-left)/2;

(关于查找与排序,后面也会出其他文章详细讲解,敬请期待)

总结

本篇文章主要介绍数组的相关内容,内容需要认真记忆练习,文末的两个小练习需要稍加训练和理解,好了,本篇文章就到此结束,愿我们一直坚持努力,实现自己目标,希望三连支持一下,谢谢。

为了在Windows安装ADB工具,你可以按照以下步骤进行操作: 1. 首先,下载ADB工具包并解压缩到你自定义的安装目录。你可以选择将其解压缩到任何你喜欢的位置。 2. 打开运行窗口,可以通过按下Win+R键来快速打开。在运行窗口中输入"sysdm.cpl"并按下回车键。 3. 在系统属性窗口中,选择"高级"选项卡,然后点击"环境变量"按钮。 4. 在环境变量窗口中,选择"系统变量"部分,并找到名为"Path"的变量。点击"编辑"按钮。 5. 在编辑环境变量窗口中,点击"新建"按钮,并将ADB工具的安装路径添加到新建的路径中。确保路径正确无误后,点击"确定"按钮。 6. 返回到桌面,打开命令提示符窗口。你可以通过按下Win+R键,然后输入"cmd"并按下回车键来快速打开命令提示符窗口。 7. 在命令提示符窗口中,输入"adb version"命令来验证ADB工具是否成功安装。如果显示版本信息,则表示安装成功。 这样,你就成功在Windows安装ADB工具。你可以使用ADB工具来执行各种操作,如枚举设备、进入/退出ADB终端、文件传输、运行命令、查看系统日志等。具体的操作方法可以参考ADB工具的官方文档或其他相关教程。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [windows环境安装adb驱动](https://blog.csdn.net/zx54633089/article/details/128533343)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Windows安装使用ADB简单易懂教程](https://blog.csdn.net/m0_37777700/article/details/129836351)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值