C语言数组的总结
学习完数组的全部知识,是时候来对数组做一些总结了。以下是我对数组的一些理解和总结,欢迎大家来交流。
1.数组的基本知识
(1)数组的概念:数组是具有相同数据类型的元素的集合。
(2)数组的分类:数值数组、字符数组、指针数组、结构数组等。
2.一维数组
(1)创建: 数据类型 数组名[数组长度]
如:int a[100];//定义了长度为100的整型数组,下标从0到99。、
注意:数组在创建时,一般要给定数组长度。[]中要给一个常量,不能使用变量。
如:int count=10; int a[count];这种定义是错误的。
double b[]; b[]={1.1,2.2};这也是错误的,[]有两个操作数,数组名和下标。
(2)初始化:既可以边定义边初始化,也可以先定义,再赋值(通常通过for循环的方法)。
如:int a[5]={1,2,3,4,5};//边定义边初始化
int a[5]; a[5]={1,2,3,4,5};//先定义后赋值
a[5]={1,2,3,4,5}还可以改写为: int i=0; for(i=0;i<5;i++) { a[i]=i+1; }
注意:数组在创建的时候如果不想指定数组的确定的大小就必须初始化,数组的元素个数根据初始化的内容来确定。
如:int a[]={1,2,3,4};这种写法也是正确的。
那么,在创建数组时,内存是怎么为它们分配内存的呢?请看下列例子:
char arr1[]="abc";//在内存中依次是'a' 'b' 'c' '\0',共占4个字节,输出为“abc".
char arr2[3]={'a','b','c'};//在内存中依次是'a' 'b' 'c' 未知数量的随机数 '\0',所占字节数未知,输出为"abc随机值”。
可以明显地看出输出不同,这是因为在输出时,字符串数组应该在遇到'\0'才结束,而arr[2]中初始化的元素不包括'\0',这就需要继续往后读,直到遇到'\0'才结束,所以会输出随机值。
同理,strlen(arr1)的结果是3,strlen(arr2)的值是随机值。
定义字符串数组还可以通过指针的形式,如:
char *p="abcdef"; p指向的是字符串数组首元素的地址,由a开始直到'\0'为止。
printf("%s",p); 用来输出字符串,结果是abcdef。
strlen(p)的值为6。
(3)使用:
a.数组元素的访问是通过下标引用操作符“[]"来实现的。[]有两个操作数,分别是数组名和下标。如a[1]就指数组a中下标是1的元素。
b.此外,定义一个指向数组的指针也可以访问数组元素。如:int a[10]; int *p=&a; 那么,*(p+i)就指数组a中下标是i的元素。
而p+i代表的是下标为i的元素的地址。读者可以自己上机操作证明。
c.数组名也可以用来表示数组的某个元素。这是因为数组名有两个含义,它不仅代表整个数组,还可以表示数组首元素的地址,这时,用法与b的情况类似。*(数组名+i)指的是下标为i的元素。同样,数组名+i 指的就是下标为i的元素的地址。如:
int a[10]={0}; int *p=&a; printf("%p\n",p+5); printf("%p",a+5); printf("%p",&a[5]); 这三个输出一定相同,都是a[5]的地址。
(4)一维数组在内存中的存储
请看下列程序
#include<stdio.h>
int main( )
{
int a[10]={0};
int *p=a;
int i=0;
for(i=0;i<10;i++)
{
printf("%p\n",p+i);//输出下标为i的元素的地址
}
return 0;
}结果如图所示:
可以看到从上到下,地址依次增加了4(恰好是整型的数字在内存中所占字节数)。这说明数组在内存中是连续存储的,而且下标小的元素存储在前,大的元素存储在后。
(5)数组的大小计算。
数组的大小计算要用到sizeof操作符,sizeof是用来计算对象所占字节数的。可以是sizeof(类型)//用来求某种类型所占字节数
也可以用sizeof(变量名)//用来求该变量所占字节数。
在数组中,sizeof(数组名)就是求整个数组在内存中所占字节数,sizeof(数组元素)是求数组中某个元素所占字节数,因为数组里的元素类型都相同,所以sizeof(数组名)/sizeof(数组元素)就可以表示数组的大小。
要注意在c语言中,sizeof是关键字,并不是函数,所以在求变量所占字节时,sizeof后面的括号可以省略。
3.二维数组
(1)创建:数组元素类型 [行数][列数]
如:int a[2][5]; char b[3][7]; double c[5][8];
注意:若在定义二维数组时并不初始化,那么一定要给定大小,行数和列数都不能省略。
(2)初始化:
边定义边初始化:char b[2][3]={'a','b','c','d','e','f'};
int a[3][3]={1,2,3,4,5,6};//不完全初始化,系统自动给剩余元素赋0.
int c[][4]={1,2,3,4,5,6,7,8};//此时可以省略行数,系统根据列数确定每行的元素,进而求得行数。
先定义,后赋值:int a[2][3]; a[2][3]={1,2,3};//直接赋值
int a[2][3]; int i=0; int j=0; for(i=0;i<2;i++) { for(j=0;j<3;j++) { a[i][j]=i+j; } }//通过两层循环给二维数组赋值,分别是0,1,2,3,4,5.
(3)使用
二维数组元素的使用也是通过下标的方式。如:int a[2][3];那么a[1][2]表示第二行第三个元素。因为不管是行的下标还是列的下标,都从0开始,a[0][0]表示第一行第一个元素。
(4)存储
程序如下:
结果如图:
所以,二维数组在内存中也是连续存放的,先放第一行的元素,紧接着就是第二行的各元素。
(5)指针访问
在知道二维数组在内存中连续存放后,我们可以同样定义一个指向首元素的指针,通过指针访问二维数组的各元素。
如:int a[3][4]={0};
int i=0;
int j=0;
int *p=&a[0][0];
for(i=0;i<12;i++)
{
*(p+i)=i;//给a[0][0](包括a[0][0])后面的元素依次赋值i
}
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
int i=0;
int j=0;
int *p=&a[0][0];
for(i=0;i<12;i++)
{
*(p+i)=i;//给a[0][0](包括a[0][0])后面的元素依次赋值i
}
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
for(i=0;i<12;i++)
{
printf("%p\n",p+i);
}
return 0;}
{
printf("%p\n",p+i);
}
return 0;}
结果如图:
这说明指针变量也可以用来访问二维数组。而且p+i指的是从a[0][0]开始的第i个元素的地址。
4.对数组名的几点说明
(1)数组名单独放在sizeof内部表示整个数组,而且sizeof(数组名)计算的是整个数组的大小,单位是字节。
(2)&数组名 数组名表示整个数组,&数组名取的是整个数组的地址。
(3)除(1)(2)外,所有的数组名都表示首元素的地址。