数组
八、数组
概念:多个同种数据类型变量的集合,数组中每一个组成的变量叫做元素;
是一种构造类型,数组是具有一定顺序关系的若干个变量的集合,组成数组的各个变量称为数组的元素,数组中各元素的数据类型要求相同,用数组名和下标确定,数组可以是一维的也可以是多维的。
特点:同种数据类型,内存连续开辟。
1、一维数组:只有一个下标的数组,在计算机的内存中是连续存储的。
1.1定义格式:<存储类型> <数据类型> <数组名>[<表达式>];
int a[6] auto int a [6]
一维数组初始化/赋值:int a[5]={3,4,5,6,7};(5:表示实际元素个数)
1)首地址:数组名表示内存首地址,是内存地址常量sizeof(数组名)是数组占用的总内存空间,数组名不能改动。
2)编译时分配连续内存:内存字节数=数组维数*sizeof(元素数据类型),且同组元素地址由低向高递增;(对地址的访问用%p表示)
例:int a[6];储存形式:
0 | a[0] |
1 | a[1] |
2 | a[2] |
3 | a[3] |
4 | a[4] |
5 | a[5] |
注意事项:C语言对数组不做越界检查,编译时不会报错,使用时注意不要越界;
1.2数组初始化
初始化方式:在定义数组时为数组元素赋初值。
全部初始化:int a[5]={1,2,3,4,5};
int a[]={1,2,3,4,5,6};//编译系统会根据初值个数确定数组维数。
部分初始化:int a[5]={1,2};//没有赋值的部分自动赋值为0.
int a[5]={};//已经初始化没有赋值,则自动赋值为0.
未初始化:int a[5];//每个元素都是随机值;
注意:数组不初始化,其元素值为随机数
对static数组元素不赋初值,系统会自动赋以0值
若只给部分元素赋值,剩下的元素默认为0.
对数组元素进行赋值:
单个赋值:scanf("%d",&a[2]);/a[2]=2;
for循环赋值(每个元素都赋值):for(int i=1;i<5;i++)
{
scanf("%d"a[i]);
}
例:斐波那契数列
1.3一维数组的引用:
访问:数组名[下标](下标从0开始)例:a[2]=5;(2:表示元素下标,表示第三个数)
1)数组必须先定义后使用
2)只能逐个引用数组元素,不能一次引用整个数组。
int a[10];
printf("%d",a);//错误引用,不能引用整个数组。
1.4循环遍历;(将数组内全部元素输出)
for(int j=0;j<=10;j++)
printf("%d",a[j]);//正确引用,逐个引用数组元素。
循环的变量作为访问元素的下标;
1.5清零函数:将数组内元素清零;
1)bzero:需要加头文件#include<strings.h>
功能:把内存空间设置为0
参数:s:要清零的首地址
n:字节大小
返回值:无,不需要返回值
例:
2)memset:按字节赋值
头文件:#include<string>
功能:清零
参数:s:要清零的数组首地址
c:要设置的值
n:字节大小
返回值:要清空的首地址。
例:
冒泡排序:
从小到大,两两比较。
int a[5]={5,4,3,2,1}
第一轮:找出最大的放到最右面
n个数,比较n-1轮,每轮交换的次数从n-1次开始依次递减1.
选择排序:
先找出最小值的下标暂存(初始化假设第一个值),把假设的第一个值分别与每一个值进行比较,比较的中途,遇到更小的值,会重新赋值,选出最小的值和第一个值交换
过程:
先通过5-1次比较,从5个数中找出最小值,把他和第一个数交换,最小的值被交换到了第一个元素位置上
再通过5-2次比较,从剩余的5-1个数中挑出第二小的值,与第二个元素交换
- 字符数组:存放字符串
2.1概念:元素数据类型都是字符型的数组;
char a[]={'a','b','c'}; //逐个字符赋值 sizeof(a)=3
char b[]={"abc"}; //用字符串赋值 sizeof(b)=4 字符串末尾会自动补'\0'
char c[]="abc";//根据字符串大小开辟空间,sizeof(c)=4;
char d[32]="hello"; //sizeof(d)=32 数组开辟实际空间大小
字符数组是元素的数据类型为字符类型的数组;
如:char a[10],b[2][3];
字符数组初始化:
逐个字符赋值:char a[3]={'a','b','c'};若用%s输出字符数组,字符数组后没有\0,则会连续输出出现错误。
字符串常量赋值:字符串后面一定是\0结尾,可省略;
char a[3]={"abc"};
char a[3]="abc";等价char a[3]={'a','b','c'\0};
ch[0] | ch[1] | ch[2] | ch[3] | ch[4] | ch[5] | |
ch[5]={'h','e','l','l','o'} | h | e | l | l | o | |
ch[5]={'B','o','y'} | B | O | Y | \0(字符零) | \0 | |
ch[6]={“hello”} ch[6]=“hello” ch[]=“hello” | h | e | l | l | o | \0字符串结束标志 |
二维字符数组:char a[][20]={"apple","banana","strawmarry"}
例:输入字符倒序输出;
计算元素实际个数:
2.2格式:字符串类型后面会自动补\0,表示字符串的结束。
2.3字符数组的输入输出
输入:scanf("%s",a);//输入字符串;
1) scanf
char a[32]={};
scanf("%s",a);
printf("%s\n",a);
输入字符串不能有空格,遇到空格或\n默认输入结束
解决方法1:
把%s换成%[^\n],输入结束按回车
char str[10];
scanf("%[^\n]",&str);
printf("%s",str)
解决方法2:
使用getchar()函数,输入结束按Ctrl+Z,再按回车enter键。
char str;
while((str = getchar())!= EOF)//EOF:输入错误
{
printf("%c",str);
}
解决方法3:
使用gets()函数,输入结束按回车。
char str[10];
gets(str);
printf("%s",str);
char s[32]={};
scanf("%[^\n]",s);
printf("%s\n",s);
需要输入空格,直到遇到\n才结束
按字符输入;
char s[32]={};
for(int i=0;i<=6;i++)
{
scanf("%c",&s[i]);//单个输入
}
printf("%s\n",s);
2)gets(数组名)(会报警告)
char*gets(char*s);
功能:从终端获取字符串
参数:s:字符数组的首地址
返回值:字符数组的首地址
3)puts(数组名)
int puts(const char*s);
功能:向终端输出字符串(自动加换行符)
参数:s:字符数组的首地址
返回值:具体输出字符的个数
2.4计算字符串实际元素个数:
1)for循环遍历数组,直到’\0‘为止
2)strlen函数,不包括\0
头文件:#include<string,h>
size_t strlen(const char*s)
功能:计算字符串实际长度,不包括’\0‘
参数:s:要计算的字符串首地址
返回值:字符串的实际长度
strlen与sizeof()区别:
- 本质:strlen是个函数,sizeof是个关键字
- strlen计算字符串实际长度,sizeof计算数据所占空间大小。
- strlen计算不包括\0,sizeof计算包括\0,
(计算字符串实际长度时,元素个数省略的情况下,sizeof比strlen大1)
字符串函数:
常见字符串处理函数;头函数#include<string>
1)strlen:求字符串长度
头文件:#include<string,h>
size_t strlen(const char*s)
功能:计算字符串实际长度,不包括’\0‘\0后的字符不计算
参数:s:要计算的字符串首地址
返回值:字符串的实际长度
strlen与sizeof()区别:
- 本质:strlen是个函数,sizeof是个关键字
- strlen计算字符串实际长度,sizeof计算数据所占空间大小。
- strlen计算不包括\0,sizeof计算包括\0,
(计算字符串实际长度时,元素个数省略的情况下,sizeof比strlen大1)
2)stecpy:字符串拷贝函数
格式:strcpy(字符数组1,字符串2)
功能:将字符串2,拷贝到字符数组1中去。
返回值:返回字符数组1的首地址。
要求:(1)字符数组1必须足够大,不会越界
(2)拷贝时\0同时拷贝。
将a中字符串拷贝到字符数组b中去,\0也同时拷贝
3)strcat:字符串链接函数
格式:strcat(字符数组1,字符数组2)
功能:把字符数组2连接到字符数组1后面
返回:字符数组1的首地址
说明:(1)字符数组1必须足够大
(2)连接前,两串均以\0结束;连接后,串1的\0取消,新串后加\0;
4)strcmp:字符串比较函数
格式:strcmp(字符串1,字符串2)
功能:比较两个字符串;
比较规则:对两串从左向右逐个字符比较ASCII码,直到遇到不同字符或\0为止
返回值:返回int整数
若字符串1<字符串2,返回负整数。
若字符串1>字符串2,返回正整数。
若字符串1==字符串2,返回0。
在str后加n表示处理的字符数量
5)strncpy (p,p1,n)复制指定长度(n)字符串
6)strncat(p,p1,n)附加指定长度字符串
7)strcasecmp忽略大小写比较字符串
8)strncmp(p,p1,n)比较指定长度字符串
9)strchr(p,c)在字符串中查找指定字符;c:表示要找的字符
10)strstr(p,p1)查找字符串;在p中查找p1字符串
11)头函数:#include<cytpe.h>
isalpha()检查是否为字母字符
isupper()检查是否为大写字母字符
islower()检查是否为小写字母字符
isdigit()检查是否为数字
3、二维数组
3.1格式:(声明时列数不能省略,行数可以)元素个数=行数*列数;
<数据类型> <数组名>[行:常量表达式][列:常量表达式];
例:int a[3][4]; float b[5][4];
按行序优先排序;(原因:内存是一维的)
例:int =a[3][2];三行两列
0 | a[0][0] | a[0] |
1 | a[0][1] | |
2 | a[1][0] | a[1] |
3 | a[1][1] | |
4 | a[2][0] | a[2] |
5 | a[2][1] |
行名a[3][2] | [0] | [1] |
a[0] | a[0][0] | a[0][1] |
a[1] | a[1][0] | a[1][1] |
a[2] | a[2][0] | a[2][1] |
3.2访问格式
数组名[行下标][列下标];(下标从0开始)
a[0][0]第一行第一列~a[1][2]第二行第三列,行下标列下标都不能越界
int a[2][3]={3,4,5,6,7,8}
行下标可以省略,列下标不可省略
int a[][3]={3,4,5,6,7,8};正确写法
int a[2][]={3,4,5,6,7,8};错误写法
3.3数组元素个数
行数*列数
3.4二维数组大小
sizeof(数组名)
数据类型大小*行数*列数
3.5数组名
a:第一行首地址
a+1:第二行首地址
a[0]第一行第一列的地址
a[1]第二行第一列地址
3.6二维数组的引用(·初始化)
形式:数组名[下标][下标]
二维数组元素的初始化:列数不能省,行数可以省
1)分行初始化:
全部初始化:int a[2][3]={{1,2,3},{4,5,6}};//1 2 3 4 5 6
元素 | a[0][0] | a[0][1] | a[1][0] | a[1][1] | a[2][0] | a[2][1] |
内容 | 1 | 2 | 3 | 4 | 5 | 6 |
部分初始化,数据不全,不够自动补0:int a[2][3]={{1,2},{4}};//1 2 0 4 0 0
元素 | a[0][0] | a[0][1] | a[1][0] | a[1][1] | a[2][0] | a[2][1] |
内容 | 1 | 2 | 0 | 4 | 0 | 0 |
第一维长度省略初始化,列不能省略初始化:int a[][3]={{1},{4,5}};//1 0 0 4 5 0
元素 | a[0][0] | a[0][1] | a[1][0] | a[1][1] | a[2][0] | a[2][1] |
内容 | 1 | 0 | 0 | 4 | 5 | 0 |
2)按元素排列顺序初始化、
从第一行开始排列,按序排列,剩下的自动补零。
3.7内存分配;二维数组理解
可将二维数组理解为由n个一维数组组成的,如上述二维数组,由三个含两个元素的一维数组组成的。
3.8二维数组遍历:
int a[2][3]={1,2,3,4,5,6};
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
printf("%d",a[i][j]);
}
}
多维数组:具有两个或两个以上下标的数组;
例:打印杨辉三角前十行
例、二维数组求最大值