C语言处理批量数据的好伙伴——C语言数组的介绍与应用
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}}; //④
(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扫雷
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将字符串中小写字母换成大写字母。
- 点赞
- 收藏
- 关注作者
评论(0)