一维数组
1.作用
需要保存大量的类型相同的数据
比如:保存全班同学的成绩
2.定义数组
类型名 数组名[数组元素个数]
任何合法的C语言类型,都可以定义成数组
char array[10]; //最多可以存放10个字符
int array[50]; //最多可以存放50个整数
3.数组的初始化以及赋值
(1)初始化以及赋值
写法一:
int a[5]={45,85,74,96,63}; //列表初始化
char b[10]="hello";
写法二:
int a[5]={45,25}; //部分初始化,其它没有初始化的都是0
char b[10]={'h','e','l','l','o'};
写法三:
int a[]={85,96}; //[]不写元素个数,只能在定义数组的时候立马初始化才可以
char b[]="world";
写法四:
int a[]; //错误写法
a[0]=78;
写法五:
int a[3]; //定义了数组,但是没有初始化
a[3]=88; //数组越界了,下标0--2
写法六: 把数组前面50个元素初始化为100,后面50个初始化为200
int b[100]={[0 ... 49]=100, [50 ... 99]=200};
注意:…左右两边必须要有空格
下面是具体实例:
- int类型数组
#include <stdio.h>
int main()
{
int i;
//写法1:定义数组,不初始化 结论:里面是随机数
// int buf[5];
//写法2:定义数组马上完全初始化 结论:里面的值就是初始化的值
// int buf[5] = {11,22,33,44,55};
//写法3:定义数组部分初始化 结论:没有初始化的默认都是0
// int buf[5] = {11,22};
//写法4:定义数组没有初始化,后面通过下标来赋值 结论:没有赋值的为随机数
// int buf[5]; //定义时数组中为随机数
// buf[2] = 11; //11把原来的随机数覆盖了
// buf[3] = 22; //22把原来的随机数覆盖了
//写法5:定义数组,省略括号中的元素个数(编译器根据右值确定数组元素个数) 结论:没有赋值的为随机数
// int buf[] = {11,22}; //正确的
// int buf[]; //错误的 error: array size missing in ‘buf’ :数组大小丢失
// buf[0] = 11;
// buf[1] = 22;
//访问数组中的元素:通过下标(从0开始)来访问
// for(i=0;i<5;i++)
// {
// printf("buf[%d]数组中的元素值是:%d\n",i,buf[i]);
// }
// 写法6:笔试题中会出
// 把数组前面50个元素初始化为100,后面50个初始化为200
// 结论:buf[0]-buf[49] 为100,buf[50]-buf[99] 为200
// 注意:...左右两边必须要有空格
int buf[100] = {[0 ... 49] = 100,[50 ... 99] = 200};
for(i=0;i<100;i++)
{
printf("buf[%d]数组中的元素值是:%d\n",i,buf[i]);
}
}
/*
执行结果:
写法1:
buf[0]数组中的元素值是:0
buf[1]数组中的元素值是:0
buf[2]数组中的元素值是:-1373101952
buf[3]数组中的元素值是:21909
buf[4]数组中的元素值是:1211320880
写法2:
buf[0]数组中的元素值是:11
buf[1]数组中的元素值是:22
buf[2]数组中的元素值是:33
buf[3]数组中的元素值是:44
buf[4]数组中的元素值是:55
写法3:
buf[0]数组中的元素值是:11
buf[1]数组中的元素值是:22
buf[2]数组中的元素值是:0
buf[3]数组中的元素值是:0
buf[4]数组中的元素值是:0
写法4:
buf[0]数组中的元素值是:0
buf[1]数组中的元素值是:0
buf[2]数组中的元素值是:11
buf[3]数组中的元素值是:22
buf[4]数组中的元素值是:-500139952
写法5:
buf[0]数组中的元素值是:11
buf[1]数组中的元素值是:22
buf[2]数组中的元素值是:-1912202240
buf[3]数组中的元素值是:-1254381533
buf[4]数组中的元素值是:0
*/
- char类型数组初始化—赋值
#include <stdio.h>
int main()
{
int i;
char buf[5] = "hello";
//打印数组中的元素(%c与%s的区别)
//第一种:与int类型的数组一样,一个一个元素打印
for(i=0;i<5;i++)
{
printf("buf[%d] = %c\n",i,buf[i]);
}
//第二种,整个字符串一起打印
printf("数组中存放的字符串是:%s\n",buf);
}
/*
执行结果:
buf[0] = h
buf[1] = e
buf[2] = l
buf[3] = l
buf[4] = o
数组中存放的字符串是:hello
*/
- char数组存放键盘输入的字符串
#include <stdio.h>
int main()
{
int i;
char buf[5];
printf("输入一个字符串:\n");
//写法1:
scanf("%s",buf);
//写法2:(正常不这样写)
// for(i=0;i<5;i++)
// {
// scanf("%c",&buf[i]);
// }
printf("输入的字符串是:%s\n",buf);
return 0;
}
/*
执行结果:
写法1:
输入一个字符串:
nihao
输入的字符串是:nihao
写法2:
输入一个字符串:
h
l
l
输入的字符串是:h
l
l
结论:键盘输入的字符是存放在输入输出缓冲区的,当输入字符后回车(\n)也算为一个字符,
所以输入输入的顺序为h\nl\nl,循环读取5个字符的结果为hll。
*/
4.数组元素的下标
从0开始,使用的时候不要越界
数组越界的危害(容易引起段错误)
int a[10]; //下标范围0--9之间
第一种:往前越界
a[-2]; //访问a[0]前面8个字节的地址里面的数据
第二种:往后越界
a[11]; //访问a[9]后面8个字节的地址里面的数据
段错误:segment fault
由于程序员在代码中访问了非法地址导致的(经常见于指针没有初始化,数组越界)
示例:
#include <stdio.h>
int main()
{
int i;
int buf[5] = {11,22,33,44,55};
//段错误:访问了非法内存地址
//for(i=0;i<10000;i++) //往后越界
// for(i=0;i>-10000;i--) //往前越界
for(i=0;i<10;i++)
{
printf("buf[%d] = %d\n",i,buf[i]);
}
return 0;
}
/*
执行结果:
buf[0] = 11
buf[1] = 22
buf[2] = 33
buf[3] = 44
buf[4] = 55
buf[5] = 32766
buf[6] = -1878191872
buf[7] = -155369220
buf[8] = 0
buf[9] = 0
结论:因为只定义了buf[0]-buf[4]的内存,如果buf[5]之后的内存被其它程序所占用的话,程序员在使用这块内存,
就会引发段错误。(现在这个程序没引发段错误是因为buf[5]-buf[10]这块
内存没被其它程序使用,把i<10改为10000就会引发段错误了)
*/
5.数组的存储
数组在计算机中是连续存储(数组元素的地址是紧挨着的)
6.数组的大小
sizeof(); //求任何类型数据的大小
示例:
#include <stdio.h>
int main()
{
int a[5];
float b[5];
double c[5];
char d[50] = "hello world";
//求sizeof大小公式:元素个数*sizeof(类型)
//1、
printf("数组的大小:a:%ld,b:%ld,c:%ld,d:%ld\n",sizeof(a),sizeof(b),sizeof(c),sizeof(d));
//2、
char buf1[] = "hello";
int buf2[] = {11,22};
printf("数组大小:buf1:%ld,buf2:%ld\n",sizeof(buf1),sizeof(buf2));
return 0;
}
/*
执行结果:
1、
数组的大小:a:20,b:20,c:40,d:50
2、
数组大小:buf1:6,buf2:8
*/
strlen(); //专门用来求字符串的实际长度
#include <string.h>
size_t strlen(const char *s);
返回值:字符串的实际长度
参数:s --》你要计算长度的字符串
原理:计算字符串实际长度,遇到\0认为字符串结束了
示例:
#include <stdio.h>
#include <string.h>
int main()
{
char array[64] = "hello world"; //11个字符,空格也算一个字符
//求字符串的实际长度
printf("数组array中存放的字符串长度是:%ld\n",strlen(array));
return 0;
}
/*
执行结果:
数组array中存放的字符串长度是:11
*/
总结:
第一:sizeof是运算符 strlen是个函数
第二:sizeof适用范围广 strlen只能求字符串的实际长度
第三:sizeof求字符串的长度会把\0算上
strlen求字符串的长度不计算\0
字符串在计算机中的存储方式
字符串默认有一个结束标记\0(ASCII码值就是0)
char buf[10]="hello"; //编译器会自动给字符串的末尾添加\0,
char buf1[5]="hello"; //本来编译器想自动添加\0,但后面没内存了
要注意的特例
char buf[]={'h','e','l','l','o'}; //sizeof求出是5,没有加\0 ;strlen求出是5
char buf[]="hello"; //sizeof求出是6(加上了\0) ;strlen求出是5
- 特别说明:
scanf读取字符串保存到数组会自动添加反斜杠0
#include <stdio.h>
#include <string.h>
int main()
{
int i;
char array[64]; //11个字符,空格也算一个字符
//求字符串的实际长度
printf("输入任意字符串:");
scanf("%s",array);
//证明输入的字符串后面是否自动添加了\0
for(i=0;i<10;i++)
{
printf("输出字符:%c , ASCII值:%d\n", array[i],array[i] );
}
return 0;
}
/*
执行结果:
输入任意字符串:dfgdfdff
输出字符:d , ASCII值:100
输出字符:f , ASCII值:102
输出字符:g , ASCII值:103
输出字符:d , ASCII值:100
输出字符:f , ASCII值:102
输出字符:d , ASCII值:100
输出字符:f , ASCII值:102
输出字符:f , ASCII值:102
输出字符: , ASCII值:0
输出字符:� , ASCII值:-25
结论:在字符串后的一个数的ASCII值必定是0,即对应的字符为'\0',
是编译器自动帮程序员加上去的
*/
ps:%s打印字符串遇到 \0 就结束
#include <stdio.h>
#include <string.h>
int main()
{
//1、%s打印字符串时遇到 \0 就结束打印
char array[20] = {'h','e','l','l','\n','o','\0','o','o',};
printf("打印array的值为: %s,大小为:%ld\n",array,sizeof(array));
//2、strlen求字符串的实际长度,遇到\0就结束,不会把\0计算进去
printf("array实际长度:%ld\n",strlen(array));
return 0;
}
/*
执行结果:
1、
打印array的值为: hell
o,大小为:20
2、
array实际长度:6
*/
7.空字符串,'A’和"A"的区别
char buf[10]=""; //空字符串
'a'; //字符a 单个字符
"a"; //字符串a a和\0
8.char类型数组重复使用,清空数组
1)char类型数组重复使用
char buf[10];
while(1)
{
scanf("%s",buf); //假如第一次输入的字符串长一点,下一次输入的字符串短一点,scanf都会自动帮你在字符串后面添加\0保存到buf中,短一点的字符串覆盖长字符串的前面部分,并且有个\0在后面(容易忽略)
}
示例:
#include <stdio.h>
int main()
{
char array[64];
while(1)
{
printf("输入一个字符串:");
scanf("%s",array);
printf("输入的字符串是:%s\n",array);
}
return 0;
}
/*
执行结果:
输入一个字符串:helloworld
输入的字符串是:helloworld
输入一个字符串:nihao
输入的字符串是:nihao
*/
2)清空数组
数组先清空后使用(数组不清空,里面是随机数)
写法一:
#include <strings.h>
void bzero(void *s, size_t n); //把数组元素全部填充为0
参数: s --》数组名
n --》数组的大小
#include <stdio.h>
#include <strings.h>
int main()
{
int i;
char array[8] = {0};
printf("输入字符串:");
scanf("%s",array);
printf("输入的字符串是:%s\n",array);
//把数组清零:任何类型的数组都可以使用bzero清零 ,如int,double(使用方法一样)
bzero(array,sizeof(array));
// printf("清空后的字符串为:%s\n",array); //清空后无任何输出
printf("清空后的字符串为:\n");
for(i=0;i<8;i++)
{
printf("arrray[%d]ASCII值:%d\n",i,array[i]);
}
return 0;
}
/*
执行结果:
输入字符串:nihao
输入的字符串是:nihao
清空后的字符串为:
arrray[0]ASCII值:0
arrray[1]ASCII值:0
arrray[2]ASCII值:0
arrray[3]ASCII值:0
arrray[4]ASCII值:0
arrray[5]ASCII值:0
arrray[6]ASCII值:0
arrray[7]ASCII值:0
*/
写法二:
初始化的时候就把数组清零
int buf[10]={0}; //部分初始化的原理,其他没有初始化的默认都是0,把数组清零
char buf[5]={0}; //部分初始化的原理,其他没有初始化的默认都是0,把数组清零
9.数组怪异的写法
int buf[10];
buf[0]=11; //等价于0[buf]=11;
#include <stdio.h>
#include <strings.h>
int main()
{
int i;
char array[8] = {0};
array[0] = 'h';
1[array] = 'e';
2[array] = 'l';
array[3] = 'l';
4[array] = 'o';
printf("array中存放的是:%s\n",array);
return 0;
}
/*
执行结果:
array中存放的是:hello
*/
二维数组
1.作用
int a[5][6]; //行列存放整数,有5行,每一行最多可以存放6个整数,总共可以存放30个整数
char b[5][10]; //可以存放5个字符串,每个字符串的最大长度不能超过10个字节,用来保存多个字符串
2.定义二维数组
类型名 数组名[行数][列数]
任何合法的C语言类型,都可以定义成二维数组
char buf[10][20]; //最多存放10个字符串,每个字符串的长度不能超过20个字符
int buf1[50][50]; //50行整数,每一行最多50个整数
3.二维数组的初始化以及赋值
写法一:
int a[5][6]={45,78,96}; //部分初始化,正确
char b[3][10]={"hello","world","gec"};
[0][0] [0][1] [0][2] ....[0][5]
[1][0] [1][1] [1][2] ....[1][5]
......
[4][0] [4][1] [4][2] ....[4][5]
写法二:
int a[][6]={89,9}; //正确
char b[][10]={"hello","world","nihao"};
写法三:
int a[][]={89,9}; //错误`
写法四:
int a[5][]={89,9}; //错误
写法五:
int a[5][6]={{5},{8,9},{89,63}}; //正确,分组初始化
//分组初始化必须从左到右连续(花括号不要跳跃)
int a[5][6]={{5},8,9,{89,63}}; //错误的写法,不满足从左到右连续(花括号中间跳跃了)
char b[3][10]={{'h','e','l','l','o'},{'n','i','h','a','o'}}
写法六:
int a[5][6]={{5},{8,9},89,63}; //正确
写法七:
int a[5][6]; //分别赋值
a[0][0]=99;
a[1][2]=67;
char b[3][10];
b[0][1]='h';
4.数组元素的下标
行和列都是从0开始,使用的时候不要越界
5.二维数组的存储
二维数组在计算机中是连续存储(数组元素的地址是紧挨着的)
二维数组:你可以把它看作是特殊的"一维数组"
可以把二维数组拆分成多个一维数组
6.二维数组的大小
情况一:两个下标都有
int a[5][6]; //公式 行*列*sizeof(类型)
情况二:少了行下标,笔试题常考
int a[][6]={78,96}; //依据初始化列表中值的个数,确定有几行
- int类型二维数组的写法
#include <stdio.h>
int main()
{
int i,j;
//写法1:部分初始化(任何数组部分初始化,其它的都是0)
//int array[3][3] = {12,34,56,78,666};
//写法2:省略中括号里面的下标
// int array[][3] = {342,346,346,47,25,66}; //正确
// int array[5][] = {342,346,346,47,25,25}; //错误
// int array[][] = {342,346,346,47,25,25}; //错误
//写法3:分组初始化(只能从左往右连续分组,不可以间断)
// int array[3][3] = {{12,34},{56,78},{90,88}};//正确
// int array[3][3] = {{12,34},{56,78},666}; //正确
// int array[3][3] = {{12,34},666,{90,88}};//错误
// int array[3][3] = {666,{56,78},{90,88}};//错误
//分组初始化跟省略中括号结合
int array[][5] = {{12,34},{56,78},{123},234,46,57,23,23,11};
printf("sizeof(array)==%ld\n",sizeof(array)); //100
//访问数组元素
for(i=0;i<5;i++) //行
{
for(j=0;j<5;j++) //列
{
printf("array[%d][%d] = %d\n",i,j,array[i][j]);
}
}
return 0;
}
/*
执行结果:
写法1:
array[0][0] = 12
array[0][1] = 34
array[0][2] = 56
array[1][0] = 78
array[1][1] = 666
array[1][2] = 0
array[2][0] = 0
array[2][1] = 0
array[2][2] = 0
*/
- char类型二维数组的写法
#include <stdio.h>
int main()
{
int i,j;
//写法1:部分初始化(任何数组部分初始化,其它的都是0)
char array[5][10] = {"hello","nihao","wohenhao"};
//写法2:分组初始化(只能从左往右连续分组,不可以间断)
// int array[5][10] = {{'h','i'},{'n','i'},'w'};//正确
//访问数组元素
for(i=0;i<5;i++) //行
{
for(j=0;j<10;j++) //列
{
printf("array[%d][%d] = %c ACSII值:%d\n",i,j,array[i][j],array[i][j]);
}
}
//char类型二维数组跟int类型二维数组,输入输出不一样的写法
//读取键盘输入不同的写法
// scanf("%d",&array[i][j]); //int类型二维数组 唯一写法
// scanf("%c",&array[i][j]); //char类型二维数组 一个个字符输入,敲回车也是一个字符
char array1[5][10];
printf("输入5个字符串:\n");
for(i=0;i<5;i++)
{
scanf("%s",array1[i]); //char类型二维数组,只需要使用行下标
}
//打印结果
printf("输入的字符串保存到二维数组中\n");
for(i=0;i<5;i++)
{
printf("array1[%d] = %s\n",i,array1[i]);
}
return 0;
}