C语言处理批量数据的好伙伴——C语言数组的介绍与应用

举报
未见花闻 发表于 2022/08/31 22:26:56 2022/08/31
【摘要】 1.数组 1.1数组概述数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。数组是用于储存多个相同...

1.数组

1.1数组概述

数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。
数组是用于储存多个相同类型数据的集合。
(摘自360百科)

在这里插入图片描述

1.2为什么要用数组?

假如你要向计算机输入并储存50个学生的C语言期末考试的成绩,如果不使用数组,意味着你要创建50个变量,非常的繁琐。如果你并不觉得繁琐,当你需要向计算机输入全校学生C语言成绩时,你还会觉得不繁琐吗?
当遇到这个问题时,仔细思考,你会发现这些数据是具有一定的联系的,比如它们都是同一学校,同一科目的成绩。
所以,为了解决这个问题C语言提供了能够一次性储存这些数据的数据类型——数组
因为数组有以下几个特点:

  • [ ] 数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,下标代表数据在数组中的序号。
  • [ ] 用数组名和下标即可唯一地确定数组中的元素。
  • [ ] 数组中的每一个元素都属于同一个数据类型。

2.一维数组

2.1定义与初始化

2.1.1一维数组的定义

(1) 数组名的命名规则和变量名相同,遵循标识符命名规则。
(2) 在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
(3) 常量表达式中可以包括常量和符号常量,不能包含变量。

类型说明符  数组名[常量表达式]
//例如
int a[10];

在这里插入图片描述
数组元素的下标从0开始,用“int a[10];”定义数组,则最大下标值为9,不存在数组元素a[10],定义的数组元素分别为:
在这里插入图片描述
一维数组储存地址是连续的。

#include <stdio.h>

int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%p \n", &a[i]);//打印数组各元素的地址
	}
	return 0;
}

输出结果

0079FCA8
0079FCAC
0079FCB0
0079FCB4
0079FCB8
0079FCBC
0079FCC0
0079FCC4
0079FCC8
0079FCCC

D:\gtee\C-learning-code-and-project\test_731\Debug\test_731.exe (进程 27748)已退出,代码为 0。
按任意键关闭此窗口. . .

每个元素储存地址都是相邻的。

2.1.2一维数组初始化

为了使程序简洁,常在定义数组的同时给各数组元素赋值,这称为数组的初始化。
初始化数组时有以下几种方法:
(1) 在定义数组时对全部数组元素赋予初值。

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

将数组中各元素的初值顺序放在一对花括号内,数据间用逗号分隔。花括号内的数据就称为“初始化列表”。
(2) 可以只给数组中的一部分元素赋值。

int a[10]={0,1,2,3,4};

定义a数组有10个元素,但花括号内只提供5个初值,这表示只给前面5个元素赋初值,系统自动给后5个元素赋初值为0。
(3) 给数组中全部元素赋初值为0。

int a[10]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//或
int a[10]={0};	//未赋值的部分元素自动设定为0

(4) 在对全部数组元素赋初值时,由于数据的个数已经确定,因此可以不指定数组长度。

int a[5]={1,2,3,4,5};
//或
int a[ ]={1,2,3,4,5};

但是,如果数组长度与提供初值的个数不相同,则方括号中的数组长度不能省略。

2.1.3如何使用一维数组中的元素呢?

数组名[下标]
//例如
int i = a[2];
//访问第三个元素

只能引用数组元素而不能一次整体调用整个数组全部元素的值。
数组元素与一个简单变量的地位和作用相似。
“下标”可以是整型常量或整型表达式。而数组定义时C99之前只支持常量表达式,要注意区分。
数组的大小可以通过sizeof得到数组总大小除以数组第一个元素大小得到

a[]={1,2,3,4,5,6,7,8,9,0};
size = sizeof(a) / sizeof(a[0]);//size = 10

2.2简单程序举例

对10个数组元素依次赋值为0,1,2,3,4,5,6,7,8,9,要求按逆序输出。

#include<stdio.h>
//对10个数组元素依次赋值为0,1,2,3,4,5,6,7,8,9,要求按逆序输出。

int main()
{
	int i, a[10];
	for (i = 0; i <= 9; i++)	//对数组元素a[0]~a[9]赋值
		a[i] = i;
	for (i = 9; i >= 0; i--)	//输出a[9]~a[0]共10个数组元素
		printf("%d ", a[i]);
	printf("\n");
	return 0;
}

在这里插入图片描述

用数组来处理求Fibonacci数列问题,用数组求斐波拉契数列前20个元素

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//用数组来处理求Fibonacci数列问题

int main()
{
	int i;
	int f[20] = { 1,1 };				//对最前面两个元素f[0]和f[1]赋初值1
	for (i = 2; i < 20; i++)
		f[i] = f[i - 2] + f[i - 1];		//先后求出f[2]~f[19]的值
	for (i = 0; i < 20; i++)
	{
		if (i % 5 == 0) 
			printf("\n"); 			//控制每输出5个数后换行
		printf("%d \t", f[i]);		//输出一个数
	}
	printf("\n");
	return 0;
}

在这里插入图片描述

2.3冒泡排序

设计一个程序,将一个整型数组内的十个数按从小到大的规则排列
思路:从数组首位元素开始将数组的相邻两个元素进行比较,如果前面的元素比后面大,则进行交换否则不交换,每进行一趟排序就能将一个最大的数放在最后,如果需要把所有元素都排好序,需要进行数组元素个数减一趟排序。因为每一趟排序都会排出一个最大的数放在后面,也就是说每排序一趟就有一个数排序完成,所以每完成一趟排序,排序比较次数就减一,假设数组元素个数为size,则一共要进行size-1趟排序,第n趟排序比较次数为size-n。比如10个元素进行冒泡排序,一共要进行9趟排序,第一趟需排序比较9次,第二趟8次,第三趟7次,以此类推。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//冒泡排序(int) 从小到大
void bubble_sort(int* arr, int size)
{
	int i = 0;
	for (i = 0; i < size - 1; i++)
	{
		int j = 0;
		int flag = 1;//判断数据是否发生交换,默认没有发生交换
		for (j = 0; j < size - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;
			}
		}
		if (flag)
			break;
	}
}
int main()
{
	int arr[] = { 9,7,5,2,0,1,8,3,6,4 };
	int i = 0;
	int size = sizeof(arr) / sizeof(arr[0]);

	for (i = 0; i < size; i++)
	{
		//scanf("%d", &arr[i]);
		printf("%d ", arr[i]);
	}
	printf("\n");
	bubble_sort(arr, size);//排序

	for (i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

3.二维数组

3.1定义与初始化

3.1.1二维数组的定义

二维数组常称为矩阵(matrix)。把二维数组写成行(row)列(column)的排列形式,可以有助于形象化地理解二维数组的逻辑结构。

//二维数组定义格式
类型说明符  数组名[常量表达式][常量表达式]

在这里插入图片描述

	float a[3][4], b[5][10];
	//定义a为3×4(3行4列)的浮点数数组,b为5×10(5行10列)的浮点数数组
	int a[2][5] = { {1,2,3,4,5},{6,7,8,9,10} };
	int b[][5] = { {1,2,3,4,5},{6,7,8,9,10} };
	//定义2行5列的整型数组
	//其中行可以省略,但是列不能省

二维数组可被看作一种特殊的一维数组: 它的元素又是一个一维数组。
例如,float a[3][4];可以把a看作一个一维数组,它有3个元素:a[0], a[1], a[2],每个元素又是一个包含4个元素的一维数组:

a[0] —— a[0][0] a[0][1] a[0][2] a[0][3] 
a[1] —— a[1][0] a[1][1] a[1][2] a[1][3] 
a[2] —— a[2][0] a[2][1] a[2][2] a[2][3]

既然说二维数组是一个特殊的一维数组,所以二维数组的储存地址也是连续的,只是我们将二维数组理解为矩阵中行与列的形式。
矩阵形式(如3行4列形式)表示二维数组,是逻辑上的概念,能形象地表示出行列关系。而在内存中,各元素是连续存放的,不是二维的,是线性的。

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

输出结果

00F7F728
00F7F72C
00F7F730
00F7F734
00F7F738
00F7F73C
00F7F740
00F7F744
00F7F748
00F7F74C

D:\gtee\C-learning-code-and-project\test_731\Debug\test_731.exe (进程 31064)已退出,代码为 0。
按任意键关闭此窗口. . .

3.1.2二维数组的初始化

//二维数组引用
数组名[下标] [下标]

(1)分行给二维数组赋初值。(最清楚直观)

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

(2)可以将所有数据写在一个花括号内,按数组元素在内存中的排列顺序对各元素赋初值。

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

(3)可以对部分元素赋初值。

int a[3][4]={{1},{5},{9}};//①
int a[3][4]={{1},{0,6},{0,0,11}};	//②
int a[3][4]={{1},{5,6}};	//③
int a[3][4]={{1},{},{9}};	//④

erweishuzhu

(4)如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对第1维的长度(行)可以不指定,但第2维的长度(列)不能省。

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

在定义时也可以只对部分元素赋初值而省略第1维(行)的长度,但应分行赋初值。

int a[][4]={{0,0,3},{},{0,10}};

3.2简单程序举例

逆置矩阵:BC107 矩阵转置

描述
KiKi有一个矩阵,他想知道转置后的矩阵(将矩阵的行列互换得到的新矩阵称为转置矩阵),请编程帮他解答。
输入描述
第一行包含两个整数n和m,表示一个矩阵包含n行m列,用空格分隔。 (1≤n≤10,1≤m≤10)
从2到n+1行,每行输入m个整数(范围-231~231-1),用空格分隔,共输入n*m个数,表示第一个矩阵中的元素。
输出描述
输出m行n列,为矩阵转置后的结果。每个数后面有一个空格。

输入:
2 3
1 2 3
4 5 6
输出:
1 4 
2 5 
3 6 

#include <stdio.h>

int main()
{
    int n = 0;
    int m = 0;
    int arr1[15][15] = {0};
    int arr2[15][15] = {0};
    scanf("%d%d",&n,&m);
    int i = 0;
    int j = 0;
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            scanf("%d",&arr1[i][j]);
            arr2[j][i] = arr1[i][j];//将矩阵1的元素储存在矩阵2,其中它们的行列数相反
        }
    }
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            printf("%d ",arr2[i][j]);//打印
        }
        printf("\n");
    }
    return 0;
}

3.2三子棋

小时候玩过的三子棋(井字棋),你还记得吗?C语言实现简单的三子棋小游戏(点击直达)

3.3扫雷

当心!前面有地雷!C语言实现简单扫雷小游戏(点击直达)

4.字符数组

4.1定义与初始化

4.1.1字符数组的定义

用来存放字符数据的数组是字符数组。在字符数组中的一个元素内存放一个字符。

char c[10];
c[0]='I'; 
c[1]=' ';
c[2]='a';
c[3]='m';
c[4]=' ';
c[5]='h';
c[6]='a';
c[7]='p';
c[8]='p';
c[9]='y';

在这里插入图片描述
由于字符型数据是以整数形式(ASCII代码)存放的,因此也可以用整型数组来存放字符数据。

int c[10];
c[0]='a'; 	//合法,但浪费存储空间,因为char占1字节,int占4字节

4.1.2字符数组初始化

char c[10]={'I',' ', 'a','m',' ','h','a','p','p','y'};		
//把10个字符依次赋给c[0]~c[9]这10个元素

如果在定义字符数组时不进行初始化,则数组中各元素的值是不可预料的。
如果花括号中提供的初值个数(即字符个数)大于数组长度,则出现语法错误。

char c[10]={'c',' ','p', 'r','o','g','r','a','m'};

在这里插入图片描述

如果初值个数小于数组长度,则只将这些字符赋给数组中前面那些元素,其余的元素自动定为空字符(即′\0′)。

char c[]={'I',' ', 'a','m',' ','h','a','p','p','y'};
//数组c的长度自动定为10

字符数组可以用来初始字符串,字符串最后都会含有一个’\0’,是结束转义符。当以数组打印字符串时,会以’\0’为标志,从数组第一个元素输出到数组’\0’前一个元素。

	char ch1[20] = { 'F','B','I',' ','o','p','e','n',' ','t','h','e',' ','d','o','o','r','!','\0'};
	char ch2[20] = "FBI open the door!";
	//这两个是子是等价的

字符数组和一维数组一样,储存地址是连续的,字符数组只是类型为char的数组。

4.2简单程序举例

使用数组输出FBI open the door!

#include <stdio.h>

int main()
{
	char ch1[20] = { 'F','B','I',' ','o','p','e','n',' ','t','h','e',' ','d','o','o','r','!','\0'};
	char ch2[20] = "FBI open the door!";
	printf("%s\n", ch1);
	printf("%s\n", ch2);
	return 0;
}

输出结果

FBI open the door!
FBI open the door!

D:\gtee\C-learning-code-and-project\test_731\Debug\test_731.exe (进程 688)已退出,代码为 0。
按任意键关闭此窗口. . .

4.3简要介绍与字符相关的库函数

4.3.1输出输入字符串的函数

puts(字符数组);//输出
gets(字符数组);//输入

返回的函数值是字符串str的第一个元素的地址。
用puts和gets函数只能输出或输入一个字符串。

puts作用:将一个字符串(以′\0′结束的字符序列)输出到终端。
用puts函数输出的字符串中可以包含转义字符。
在用puts输出时将字符串结束标志′\0′转换成′\n′,即输出完字符串后换行。
gets作用:从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址。

4.3.2字符串连接函数

strcat(字符串1, 字符串2);

作用:把两个字符数组中的字符串连接起来,把字符串2接到字符串1的后面,结果放在字符数组1中,函数调用后得到一个函数值——字符数组1的地址。
字符数组1必须足够大,以便容纳连接后的新字符串。
连接前两个字符串的后面都有′\0′,连接时将字符串1后面的′\0′取消,只在新串最后保留′\0′。

4.3.3字符串复制函数

strcpy(字符串1, 字符串2);

作用:将字符串2复制到字符数组1中去。
字符数组1必须定义得足够大,以便容纳被复制的字符串2。字符数组1的长度不应小于字符串2的长度。
“字符数组1”必须写成数组名形式,“字符串2”可以是字符数组名,也可以是一个字符串常量。
若在复制前未对字符数组1初始化或赋值,则其各字节中的内容无法预知,复制时将字符串2和其后的′\0′一起复制到字符数组1中,取代字符数组1中前面的字符,未被取代的字符保持原有内容。
不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组。字符数组名是一个地址常量,它不能改变值,正如数值型数组名不能被赋值一样。
可以用strncpy函数将字符串2中前面n个字符复制到字符数组1中去。
将str2中最前面2个字符复制到str1中,取代str1中原有的最前面2个字符。但复制的字符个数n不应多于str1中原有的字符(不包括′\0′)。

4.3.4字符串比较函数

strcmp(字符串1, 字符串2);

对两个字符串比较不能直接用str1>str2进行比较,因为str1和str2代表地址而不代表数组中全部元素,而只能用 (strcmp(str1,str2)>0)实现,系统分别找到两个字符数组的第一个元素,然后顺序比较数组中各个元素的值。

作用:比较字符串1和字符串2。
字符串比较的规则是: 将两个字符串自左至右逐个字符相比(按ASCII码值大小比较),直到出现不同的字符或遇到′\0′为止。
(1) 如全部字符相同,则认为两个字符串相等;
(2) 若出现不相同的字符,则以第1对不相同的字符的比较结果为准。
比较的结果由函数值带回。
(1) 如果字符串1与字符串2相同,则函数值为0。
(2) 如果字符串1>字符串2,则函数值为一个正整数。
(3) 如果字符串1<字符串2,则函数值为一个负整数。

4.3.5测字符串长度的函数

strlen(字符串);

作用:测试字符串长度的函数。函数的值为字符串中的实际长度(不包括′\0′在内)。

4.3.6转换为大小写的函数

strlwr(字符串);//大写字母转小写字母
strupr(字符串)//小写字母转大写字母

作用:
srtlwr将字符串中大写字母换成小写字母。
strupr将字符串中小写字母换成大写字母。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。