数组-高级篇
1.关于数组名的详解
如果定义了一个字符型数组data
char data[10];
那么我们知道 data[0]、data[1] …data[9]分别表示数组中的10个元素。
但是data本身是什么意思,有什么意义呢?
data是数组名,但是不能用来表示整个数组,它代表的是数组的第1个元素的地址(也叫数组首地址)。
data是一个指针常量(详解见指针-高级),它的类型取决于数组元素的类型。如果数组是char类型,那么data就是“指向char型的常量指针”,进一步可以分解为“指向char型的值本身是常量的一个指针”。
指针常量的本质是一个常量,而用指针修饰它,那么说明这个常量的值应该是一个指针。指针常量的值是指针,这个值因为是常量,所以不能被赋值。
注意:数组名在程序的表达式中使用时,编译器才会为它产生一个指针常量!数组创建时,并不会产生对应的指针常量。
所以,data本身是不可修改的,示例
char data[10];
char words[10];
int* data_pointer;
data = 1000;//错误
data = words;//错误
data_pointer = data;//正确
data_pointer = &data[0];//与上一句等价
如上代码所示,想要将一个数组中的所有元素放到另一个数组中(不考虑大小问题),直接用数组名赋值给数组名是行不通的!
这种错误尤其是在函数传参时特别容易犯。
在程序完成编译链接后,数组在内存中分配的位置就已经确定了,不可再移动。因此数组名的值是一个指针常量,是不可以被修改的。
特例: 当数组名作为sizeof操作符的操作数时,得到的结果(返回值)是整个数组的长度。该长度以字节为单位。此时数组名并不是作为指针常量使用。
2.指针与数组,下标引用与间接访问运算符,数组表示法与指针表示法
数组表示法即使用下标访问数组中的元素,指针表示法即使用指针运算符(也叫间接操作符)访问数组中的元素。
在C语言中,不管data是数组名还是指针变量,data[i]和(data+i)是等价的。*
举例:
int i;
int data[3] = { 9,5,6};
int* data_pointer;
for(i = 0;i<3;i++)
{
if(data[i] == *(data+i))
{
printf(“use data i =%d,data is %d\n”,i, data[i]);
}
if(data_pointer [i] == *( data_pointer +i))
{
printf(“use data_pointer i =%d, data_pointer is %d\n”,i, data_pointer [i]);
}
}
输出结果为:
use data i =0,data is 9
use data_pointer i =0,data_pointer is 9
use data i =1,data is 5
use data_pointer i =1,data_pointer is 5
use data i =2,data is 6
use data_pointer i =2,data_pointer is 6
但是,他们之间还是有一些区别的,
首先只有当对象为指针变量时,才能使用ar++这样的表达式。
指针表示法更接近机器语言,在编译时效率更高。其次,优先级不同,“[]”操作符的优先级高于 “*”操作符。
3.数组边界
关于越界问题
在C标准中,使用数组越界下标的结果是未定义,数组越界问题是一个编写程序中很容易出现的问题,并且一旦出现,表现出的现象就会五花八门,难以分析解决。
所以在使用数组时,多对边界进行检查和保护。
在计算数组的大小时,推荐使用 sizeof运算符,可以避免一部分容易出现数组越界的问题。sizeof运算符的统计结果是以字节为单位,所以要做一次除法整理运算。
data_len = sizeof( data)/ sizeof( data[0]);
4.数组的序号缺省会怎么样?
如果初始化时缺省“[]”中的序号,编译器会根据初始化列表中的项数来确定数组的大小。
如果只定义未初始化,编译会报错。
如果初始化时缺省“[]”中的序号为变量,有的编译器会报错,有的不会,这跟使用的编译器支持的C标准有关。
int i;
int num = 5;
int data[] = { 9,5,6,8,6};
data_len = sizeof( data)/ sizeof( data[0]);
for(i = 0;i < data_len; i++)
{
printf(“data i = %d is %d\n”,i, data[i] );
}
printf(“data_len = %d \n”,data_len );
输出结果为:
data i =0,data is 9
data i =1,data is 5
data i =2,data is 6
data i =3,data is 8
data i =4,data is 6
data_len = 5
数组的大小的指定规则
不能为0,不能为负数,不能为浮点数。
nt i;
int num = 5;
int data[] = { 9,5,6,8,6};
char data1[5];//正确
char data2[5*3+10]; //正确
char data3[sizeof(char)+1];
char data4[0]; //错误,
char data5[1.5]; //错误
char data6[-5]; //错误
char data7[(int)1.5]; //正确
char data8[num];//根据编译器采用的C标准
5.const修饰数组
有时候数组内的数据需要被设置为只读,这样程序只能从数组中检索值,不能把新值写到数组中。这样可以保护数组中的数据。
创建只读数组需要用const在数组定义时进行修饰声明,并同时完成初始化。
const int data[10] = {0x99,0x35,0x92, 0xa0, 0xb2, 0xc2, 0x92, 0x92, 0x92, 0x92};
这样声明后,程序在运行过程中不能修改该数组中的内容。