数组
-
数组的定义
-
数组是一组数据的集合,用于将一种类型的数据存储到一段连续的空间中,可在一定程度上面加快搜索速度。(这个是数组很重要的特性,注意和链表的区别)
-
组成数组的元素是若干个独立的变量,这些变量的类型必须相同。
-
按照数组元素的类型的不同又可以分为:数值数组、字符数组、指针数组、结构体数组等。
-
数组属于构造类型,因为其是以后基本数据类型组成的,像结构体也是的。
<存储类型> <数据类型> <数组名> [<常量表达式>]
-
数组的类型实际上说的是数组元素的类型,其所有的元素的数据类型是相同的。
-
数组名不能与其他变量同名。
-
数组结构与存储大小
数组的存储空间在内存中是连续的,会根据数组元素的个数,来分配数组的大小
数组的大小 = 数组元素的大小 * 数组元素的个数
数组名用于记录数组首元素的地址,可以通过数组名来获取数组首元素的地址
-
-
一维数组
一维数组的定义
数据类型 数组名[常量表达式]
-
[]: 运算优先级是最高的,而且具有右结合性。
-
数组的存储空间在物理上是连续的,所以访问数组的元素可以通过首元素的地址就加偏移量来访问。
数组元素的地址 = 数组首元素的地址 + 下标 * 数组元素的大小
-
若数组定义时指定n个元素,则数组下标的范围是0~n-1;
-
注意:千万不能出现数组越界访问的问题,数组越界访问相当于内存访问越界,后果不可预知。如:定义 int a[n] = {0};却去访问a[n],就发生了数组访问越界,因为访问了超出数组范围的未知内存
一维数组初始化
-
局部数组未初始化
对于普通局部数组(相当于局部变量),若定义时未初始化,则数组中未初始化元素的值是不确定的。
-
static修饰的局部数组未初始化
static数组若定义时未初始化,则数组中的元素值默认为0。(即相当于数组所有元素都以静态存储的方式进行存储)。
-
全局数组未初始化
数组中的元素也会默认为0。
-
一维数组全部初始化
注意在对数组进行初始化使只能放在一行,即初始化只能发生在数组定义的时候。
如:
int a[10] = {0,1,2,3,4,5,6,7,8,9,};
这样写就是错的:
int a[10]; a[10] = {0,1,2....};
后面一句相当于是对数组调用,显然是错误的。即,数组若要初始化则只能发生在定义数组的时候。
数组初始化的赋值方式只能用于数组的定义,定义之后再赋值只能一个一个进行的赋值。
-
部分初始化
当{}中元素的个数小于赋值的个数时,则前面的元素被初始化,后面的元素自动为0。
int a[10] = {1,2,3}; //则该数组中,a[0]为1、a[1]为2、a[2]为3,其余的元素的值都为0 //利用该性质,我们可以将数组清0,如:`a[10]={0}`
-
-
数组全部初始化
若对数组中元素全部赋值则可以省略下标。
int a[] = {1,2,3,4,5}; //则我们定义了一个有五个元素的素组元素,且每个元素已经进行了初始化 //此时编译器会自动识别我们的数组的元素个数
-
数组全部初始化为0
a[10] ={0}
;当然了将数组初始化为0,还可以采用以下几种方法:
-
使用循环;
-
使用库函数memset:
memset(数组名,初始化的值,素组大小);
example:memset(a,0,n);
-
使用库函数bzero,将数组清零,头文件strings.h
bzero(数组名,数组大小);
bzero(a,sizeof(a)/sizeof(a[0]);数组元素的个数的计算方法:
数组元素个数 = sizeof(数组名) /sizeof(数据类型)
-
-
多维数组
-
定义形式:
<存储类型> <数据类型> <数组名> <常量表达式> <常量表达式2>...<常量表达式n>
多维数组只是增加了下标,其特性与一维数组基本相同。
-
二维数组
-
二维数组初始化
-
降维给二维数组初始化,即按行初始化,每一组的初始值都用"{}"括起来。
如:
a[2][3] = {{1,2,3},{4,5,6}};
-
按照线性存储给二维数组初始化
如
a[2][3] = {1,2,3,4,5,6};
即将二维数组中元素全部初始化。 -
可以省略左边下标的方式,初始化二维数组
如:a[][3] = {1,2,3,4,5,6}
编译器能够识别这是一个两行三列的数组。
注意:第二维的长度不能省略,即可以省略行标识,但是不能省略列标识
-
-
二维数组的内存分配
- 二维数组给我们平面的形式(行,列)但是实际上,二维数组也是在内存中也是连续的。即二维数组采用了和一维数组类似的存储方式。
- 扩展:
二维数组以一维数组为元素
,这样我们能更加深刻的理解二维数组的形式。
字符数组
-
字符数组的定义
有一定顺序关系的若干个字符变量的集合,就是字符数数组。可以是多维的也可以是一维的。
-
字符数组初始化
-
和普通数组相同,逐个进行初始化
如:
char a[5] = {'','','','',''}
char b[][4] = {{'a','b','b','\0'},{'q','w','e','\0'}}
-
使用字符串常量进行初始化
`char a[6] ="hello";`
字符串以’\0’结尾,内存访问不能越界。利用字符串初始化字符数组的时候会默认加上’\0’。
-
字符串
- 在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串。
- 存放一个字符串时,编译器会自动加上’\0’作为结束标志。
- 当用scanf函数输入字符串时,用空格作为字符串的结束符。(即当我们从终端上面进行字符串的输入时,当遇到空格时输入会终止,scanf函数会读取空格前的字符串)。
常见的字符串处理函数:
-
字符串拷贝函数
char *strcpy(char *dest,const char *src)
-
字符串连接函数
char* strcat(char* dest,const char* src)
将字符串src连接到字符串dest的后面。
-
字符串比较函数
int strcmp(const char* s1,const char* s2)
- 字符串相等,返回值为0
- 字符串1>字符串2,返回值>0
- 字符串1<字符串2,返回值<0
-
求字符串长度
size_t strlen(const char* s)
返回字符串的长度,不包括’\0’(注意:利用strlen函数来计算字符串的长度时,其所计算的长度是不包含’\0’的),举个例子
可以看到,该字符串实际上是占据了6字节的内存的,但是我们用strlen函数来计算的话,结果却是5。因为它只计算了字符串的实际长度,即不含’\0’。 -
字符串分界函数
char* strtok(char* s,const char* delim)
- 功能:将字符串分解成一个个片断
- 参数:s为要分解的字符串,delim为分隔符字符串
- 返回值:分解出的字符串的地址
-
注意点
- 当程序中,需要用户输入一个字符串时,我们也可以使用字符串输入函数gets,该函数没有输入长度限制,若我们利用该函数进行字符串的输入时,一定要注意字符数组的长度,避免发生发生内存越界。
- 好啦,数组相关的知识就介绍到这里了,后面会写文章分析一下数组与指针结合起来使用的技巧,这也是C语言的难点之一。