C语言学习——数组

1.数组初体验
生活中我们经常会用到容器,比如我们去超市购物需要使用购物袋装购买的商品。
同样我们在程序中也需要容器,只不过该容器有点特殊,它在程序中 是一块连续的,大小固定并且里面的数据类型一致的内存空间 ,它还有个好听的名字叫 数组 。可以将数组理解为大小固定,所放物品为同类的一个购物袋,在该购物袋中的物品是按一定顺序放置的。
我们来看一下如何声明一个数组:
 数据类型 数组名称[长度]; 
数组只声明也不行啊,看一下数组是如何初始化的。说到初始化,C语言中的数组初始化是有三种形式的,分别是:
1、  数据类型 数组名称[长度n] = {元素1,元素2…元素n};
2、  数据类型 数组名称[] = {元素1,元素2…元素n};
3、  数据类型 数组名称[长度n] 数组名称[0] = 元素1; 数组名称[1] = 元素2; 数组名称[n-1] = 元素n;
我们将数据放到数组中之后又如何获取数组中的元素呢?
获取数组元素时:  数组名称[元素所对应下标]; 
如:初始化一个数组 int arr[3] = {1,2,3}; 那么arr[0]就是元素1。
注意:
1、数组的下标均以0开始;
2、数组在初始化的时候,数组内元素的个数不能大于声明的数组长度;
3、如果采用第一种初始化方式,元素个数小于数组的长度时,多余的数组元素初始化为0;
4、在声明数组后没有进行初始化的时候,静态(static)和外部(extern)类型的数组元素初始化元素为0,自动(auto)类型的数组的元素初始化值不确定。
例子:




2.数组的遍历
当我们去超市回来买了一堆东西,就想要是有个机器人能帮我把东西拿出来放好,就完美了。
那么在程序中,数组就可以采用循环的方式将每个元素遍历出来,而不用人为的每次获取指定某个位置上的元素,例如我们用for循环遍历一个数组:

数组遍历时要注意以下几点:
1、最好避免出现数组越界访问,循环变量最好不要超出数组的长度,比如:
2、C语言的数组长度一经声明,长度就是固定,无法改变,并且C语言并不提供计算数组长度的方法。
由于C语言是没有检查数组长度改变或者数组越界的这个机制,可能会在编辑器中编译并通过,但是结果就不能肯定了,因此还是不要越界或者改变数组的长度



3.数组作为函数参数
前面我们学过,变量可以当作参数是吧!这里数组也是可以当做函数的参数滴,啊?什么?你问数组咋当参数?请看下面知识。
数组可以由整个数组当作函数的参数,也可以由数组中的某个元素当作函数的参数:
1、整个数组当作函数参数,即把数组名称传入函数中,例如:
2、数组中的元素当作函数参数,即把数组中的参数传入函数中,例如:
数组作为函数参数时注意以下事项:
1、数组名作为函数实参传递时,函数定义处作为接收参数的数组类型形参既可以指定长度也可以不指定长度。
2、数组元素作为函数实参传递时, 数组元素类型必须与形参数据类型一致


4.数组的应用(一)
话说,小明(咋又是他)班级年终考试成绩出来了,老师看着这一堆的数,犯愁了,我怎么找最高的分数呢。。。
那么有数组在就好办多了,我们可以将所有的成绩放到数组中,然后用 数组排序 一下,就可以找到最高的分了;话又说回来了,数组排序?数组咋排序?别着急往下看。
排序的方法呢有很多,这里小编给大家介绍一种比较经典且比较容易掌握的排序方法: 冒泡排序
以升序排序为例冒泡排序的思想: 相邻元素两两比较,将较大的数字放在后面,直到将所有数字全部排序。 就像小学排队时按大小个排一样,将一个同学拉出来和后面的比比,如果高就放后面,一直把队伍排好。
班级成绩中,老师把前十名的挑出来了,用冒泡排序把分数排了一下
运行结果为


5.数组的应用(二)
当我们购物之后,拎着购物袋回到家,会一一检查购物袋中的物品看是否缺少或者都是想购之物。
那么应用到程序中,可以使用数组查找功能,看看是否存在该数据,如果存在并返回该元素的下标。数组元素的查找也有很多查找方式,但是我们这里可以最简单的方式,通过遍历实现数组元素的查找。
比如以下程序实现在指定数组中查找指定元素的功能,如果找到该元素返回该元素的下标,否则返回-1:


6. 字符串与数组
字符串是神马?字符串就是由多个字符组合而成的一段话。
在C语言中,是没有办法直接定义字符串数据类型的,但是我们可以使用数组来定义我们所要的字符串。一般有以下两种格式:
1、 char 字符串名称[长度] = "字符串值";
2、 char 字符串名称[长度] = {'字符1','字符2',...,'字符n','\0'};
注意:
1、[]中的长度是可以省略不写的;
2、采用第2种方式的时候最后一个元素必须是'\0','\0'表示字符串的结束标志;
3、采用第2种方式的时候在数组中 不能写中文
在输出字符串的时候要使用: printf(“%s”,字符数组名字); 或者puts(字符数组名字);。例如:
运行结果为

7.字符串函数
常用的字符串函数如下:
使用字符串函数注意以下事项:
1、strlen()获取字符串的长度,在字符串长度中是不包括‘\0’而且汉字和字母的长度是不一样的。比如:
2、strcmp()在比较的时候会 把字符串先转换成ASCII码 再进行比较,返回的结果为 0表示s1和s2的ASCII码相等 ,返回结果为 1表示s1比s2的ASCII码大 ,返回结果为 -1表示s1比s2的ASCII码小 ,例如:
3、strcpy()拷贝之后会覆盖原来字符串且不能对字符串常量进行拷贝,比如:
4、strcat在使用时s1与s2指的内存空间不能重叠,且s1要有足够的空间来容纳要复制的字符串,如:

注意:即使我有一个字符串数组是char arr[100]=""(即里面没有任何东西),也可以通过字符串函数strcpy来将另一个字符串函数的值赋进去。


8.多维数组
多维数组就好比去超市买东西,用购物袋把所买商品分类存放,然后将所有的购物袋放到一个大的购物袋中,这样就形成了一个多维数组了。
多维数组的定义格式是:
数据类型 数组名称[常量表达式1][常量表达式2]...[常量表达式n];
例如:
这样定义了一个 名称为num 数据类型为int 二维数组 。其中 第一个[3]表示第一维下标的长度 ,就像购物时分类存放的购物; 第二个[3]表示第二维下标的长度 ,就像每个购物袋中的元素。
我们可以把上面的数组看作一个3×3的矩阵,如下图:
多维数组的初始化与一维数组的初始化类似也是分两种:
1、 数据类型 数组名称[常量表达式1][常量表达式2]...[常量表达式n] = {{值1,..,值n},{值1,..,值n},...,{值1,..,值n}};
2、 数据类型 数组名称[常量表达式1][常量表达式2]...[常量表达式n]; 数组名称[下标1][下标2]...[下标n] = 值;
多维数组初始化要注意以下事项:
1、采用第一种始化时数组声明必须指定列的维数。 因为系统会根据数组中元素的总个数来分配空间,当知道元素总个数以及列的维数后,会直接计算出行的维数 二维数组定义的时候,可以不指定行的数量,但是必须指定列的数量。
2、采用第二种初始化时数组声明必须同时指定行和列的维数。



9.多维数组的遍历
在超市买东西回来后,就算是东西再多,再怎么分类,我们还是要拿出来看一下所买的商品的。
多维数组也是存在遍历的,和一维数组遍历一样,也是需要用到循环。不一样的就是多维数组需要采用嵌套循环,如:遍历输出int num[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
注意: 多维数组的 每一维 下标均不能越界


10.一维数组的补充
1)数组变量名表示数组在内存中的起始地址,也是数组第一个数组元素在内存中的地址。
2)数组名后面跟着的[ ],是数组的标志,[ ]内必须是整型常量或者整型常量表达式
3) 数组定义后的字节数:
字节数=数组大小 X sizeof(数组元素类型),数组大小即为数组元素个数
4)存储单元的 有效地址
有效地址=数组的起始地址+下标 X sizeof(数组元素类型)
注意:计算出有效地址后,C语言不会帮助检查是否越界
5)&a[0]与数组名a,都表示数组的首地址
6)在定义数组时,如果没有赋初值,那么就不能省略数组大小,而且如果数组不初始化,那么数组元素的值为随机值。
7) 注意:不能用scanf函数对数组进行所谓的“整体输入”,下面程序是错误的:
int a[3];
scanf("%d%d%d",a); /*scanf函数第一个参数有3个%d,所以后面必须跟着其他三个参数*/
更正(“%d%d%d”,&a[0],&a[1],&a[2])
8) 使用memset函数来赋初值
标准库函数memset可实现对某内存块的个字节单元整体赋 同样的值。所以在对数组各字节单元赋某个特定值的情况下,可以使用memset,格式如下:
memset(s,ch,数组大小X sizeof(数组元素类型)) {头文件为string.h}
其功能是: 将s为首地址的一片连续的n个字节内存单元都赋值为ch,注意:是对每个 字节单元都赋值ch,所以memset函数主要 适合于字节型数组的整体赋值,对非字节型数组进行清0也是可以的。

例子:
9)使用memcpy函数实现数组间的赋值
针对:对于两个数据类型和大小相同的数组
格式:memcpy(d,s,n) {头文件为string.h}
功能:将s为首地址的一片连续的n个字节内存单元的值拷贝到以d为首地址的内存单元中
(n个字节的算法:数组大小X sizeof(数组元素类型))

11.二维数组
1)定义和赋值:
a.定义格式: 存储类型 数据类型 数组变量名[整型常量表达式1][整型常量表达式2]
b.可将二维数组看成一个 矩阵形式
c.二维数组在物理上采用 按行存储的顺序存储方式



















注意:二维数组变量名是数组所占内存空间的首地址。如:a的地址就是2000,与a[0](这也是个地址)的值一样
有效地址=数组起始地址+(下标1*第一维的大小+下标2)*sizeof(元素类型)
e.赋值:
1)按行初始化赋值:
如: int a[2][3]={{1,2,3}{4,5,6}}
int a[2][3]={{1},{3}}; (对没有赋值的位,系统自动补0)
int a[][3]={{1,2},{4}}; (编译系统会根据初值表的个数决定第一维的大小,但是 不可省略第二维,同时初值表中至少要包含1个初值)
2)按元素在内存中的排列顺序赋值
int a[2][3]={1,2,3} (第一行的值为1 2 3,第二行则默认为0)
, 3)二维数组在程序中的赋值

12.字符串与数组
1.字符串的本质:字符串是一种以'\0'结尾的字符数组。
2.定义: char str[]="china"
char str[]={'a','b','c' ,'\0'} (即为abc的字符串)
char str[]={"china"}
char str[10]={'a','b','c'} (这里不用加\0,因为数组大小远大于3,故后面没赋值的自动添0)
3.字符串的输入:
1) gets函数 (头文件为stdio.h)
char str[80];
gets(str);
它的功能是接受键盘的输入,将输入的字符串存放在字符数组中,知道遇到回车符时结束,它能接受空格的输入。
2) scanf函数
char str[80];
scanf(“%s”,str)
它任何时候都会忽略前导空格,读取字符送入数组,直到遇到空格或者回车结束,末尾自动加\0。
char str1[80];,char str2[80], char str3[80];
scanf("%s%s%s",str1,str2,str3);
(可以输入多个字符串,字符串之间用空格隔开)

4.字符串的输出:
1) puts函数(stdio.h)
输出时将字符串结束符 '\0'自动换成换行符
例如:
char str[]="china"
puts(str);(则输出结果为:china)
puts("china"); (则输出结果为:china)
2)printf函数:
输出时候可以控制格式,%ns当n为 正数的时候,向右对齐,当n为 负数的时候,向左对齐
例如:
char str[]="china"
printf("%s",str或者&str[0]) (printf函数是从所给的地址开始依次输出字符,直到遇到结束符,结束符号不会被输出,例如:printf("%s",&str[3])),则把第四个单元开始的字符全部输出
或者:printf("%s","china")
5)字符串的长度:strlen(字符串地址) 【string.h】
例如:char str[]="0123456789";
printf("%d",strlen(str));
printf("%d",strlen(&str[5])) (从第六个开始起,看有多少个字符)——输出结果为5
(有些时候,字符串中会出现又数字构成的转义字符,这时候只被看做是一个字符,如:\045)
6)字符串的复制:strcpy(复制目标地址,字符串或者被复制的数组地址) 【string.h】
例如:char str[]="EGG"
char str1[10];
strcpy(str1,str);
strcpy(str1,"EGG")

strncpy(复制目标地址,字符串或者被复制的数组地址,n) 【string.h】
将被用者的前n个字符复制到目标数组去

7)字符串的比较:strcmp(字符串1,字符串2) 【string.h】
(字符串1,2可以是常量,也可以是字符数组地址)
如果字符串1大于2,那么返回一个正整数,小于就负整数,等于就为0
stricmp(该函数不区分大小写字母,使用和上述一样) 【string.h】
strncmp(比较前n个字符) 【string.h】

8)字符串的连接:strcat(字符数组1,字符串2或者字符数组2)










































  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值