C语言数组

声明

C语言中只有一维数组,其元素可以是任何类型的,也可以是另外一个数组,如:

int array[5][10];
该表达式声明了一个array一维数组,其元素个数是5,元素类型是一个含有10个整型元素的数组。


数组的大小必须在编译期作为一个常数确定,如程序中存在如下代码:

int buf_size = 512;
int buf[buf_size]; 

可能会导致编译出错(没问题,也不推荐这样写),改成如下可编译通过

const int buf_size = 512;
int buf[buf_size];

最好是将buf_size定义成一个宏,如要动态申请,则用malloc之类的函数。


对于一个数组,你需要知道的是该数组的大小,及其首地址,即数组下标为0的元素的指针,亦数组名所代表的地址。

其有关的数组操作,哪怕看上去是通过下标去操作的,实质也是通过指针进行的。



初始化

这里就说下二维数组的初始化(要转换其实质是一维数组),如下:  

int array[2][4] = {0} // 将整个数组初始化为0
int tmp[2][4] = {{1,2}, {3,4}}

一维数组的初始化用{}表示,首先tmp是一维数组,先在最外层使用{},其元素是含4个整型的数组,所以内部每个元素也用一个{}表示,则{1,2}用于初始化tmp[0],那么1用于初始化tmp[0][0], 2用于初始化tmp[0][1],tmp[0][2]和tmp[0][3]则初始化为0。



数组名

数组名作为sizeof的操作数,则是用于计算该数组的大小,其余情况都转换成起始元素首地址。

对数组名进行取地址操作,如&array,这种写法在ANSI C中是非法的,或者就等于array。



数组操作,亦理解指针的操作

先从简单的一维数组介绍:

int array[10];
array是一个含有10个元素的一维数组,其元素是一个整型数据。

要访问第5个元素,数组下标操作就是array[4],指针操作则是 *(array+4)。


那如何声明一个指针指向该数组呢?

声明一个指针就是要确定该指针的类型,也就需要明白所指向的数组元素类型是什么,对于上述一维数组,其元素类型是int整型数据,那么指针的类型就是int整型:

int *p = array;
如要访问第5个元素,相应的操作就是 *(p+4)


现在来说下二维数组,声明如下:

int array[2][2] = {{1, 2}, {3, 4}};

那么如何声明一个指针指向该二维数组呢,通过上述理解,亦就是找出该array一维数组的元素类型是什么,其类型是含有2个元素的数组,则声明指针如下:

int (*p)[2];
p = array;

那么该二维数组中的值2所对应的读取操作是  *((*p)+1), 而值4所对应的读取操作是   *(*(p+1)+1) 。

这里需要重点理解的是 指针加1操作后指针指向了哪? 我在这里有吃过不少亏!  指针加1操作所移动的步长是该指针类型的长度,在该例子中p+1指向了p所指向地址的后8个字节(2*sizeof(int))!   在平常类似的指针操作中都要注意!



作为参数的数组声明

前面有提到数组名除作sizeof的操作数外,其他情况都会转换成数组第一个元素首地址,所以像下面这样的写法:

int fun(int array[], int array_size)
{
      // do something
}


与下面的写法是一样的:

int fun(int *p_array, int array_size)
{
      // do something
}



而二维数组的写法则与前面声明一个指针指向二维数组一样:

int fun(int (*p_array)[10], int array_size)
{
      // do something
}
也可以写成如下形式:

int fun(int **p_array, int array_size)
{
      // do something
}


数组在栈中的分配

变量在栈中的分配是由高到低进行的,如进行如下声明:

int i = 0;
int a[3];

for (int i = 0; i <= 3; i++)
{
    a[i] = 0;
}

那么就会进入死循环,当i = 3时,a[3] = 0; 相当与 i = 0。  因为a[3]所指向的地址就是i。

可以printf(" &i = %p", &i) 、printf("&a[3] = %p", &a[3]) 将这两者的地址打印出来,是一样的。

注:a[3]作为数组中实际不存在的“溢出”元素的地址位于数组所占内存之后,这个地址可以用于进行赋值和比较,但如果引用该元素,就是非法操作。



参考《C陷阱与缺陷》


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值