1、数组
1.1、数组声明格式
float candy[365]; /* 内含365个float类型元素的数组 */
char code[12]; /* 内含12个char类型元素的数组 */
int states[50]; /* 内含50个int类型元素的数组 */
访问数组中的元素,使用数组下标数(索引)表示各元素,candy[0]表示candy数组中第一个元素。
1.2、初始化数组
int power[8]={1,2,4,6,8,32,64}; //数组下标从0开始。
程序员有责任来保证程序只使用有效的下标值:[0, 数组大小-1]
使用const声明数组,把数组设置为只读,程序只可从数组中检索值,不能改写数组。
#define MONTHS 12
const int days[MONTHS]={31,28,31,...,31};
注意:使用数组前必须要初始化,必须要给他们赋初值。因为编译器使用的值是内存相应位置上的现有值。不初始化读的值可能是以前在内存中存入的值。如果部分初始化数组里的元素,剩余元素就被初始化为0。也可以省略方括号里的数字,让编译器自动匹配数组大小和初始化列表中的项数。
1.3、指定初始化器
指定初始化器(designated initializer),可初始化指定的数组元素。
int arr[6]={[5]=211}; //把arr数组的第六个元素初始化为211。
一般初始化,在初始化一个元素后,未初始的元素会被设置为0。
int days[6]={31, 21, [3]=29, 30, 34, [1]=33};
结果:31,33,0,29,30,34,0
注意两点:第一,如果指定初始化器后面有更多的值,例如[3]=29, 30, 34,那么后面这些值被用于初始化指定元素后面的元素,在days[3]初始化29后,days[4]和days[5]被初始化为30和34;第二,如果再次初始化指定元素,则最后那次的初始化会覆盖之前的,比如[1]=33会覆盖之前的元素21,现在[1]的值是33。
1.4、给数组元素赋值
可借助数组下标给数组元素赋值,但不许把数组作为一个单元付给另一个数组。
int oxen[4]={5,3,2,8};
int yake[4];
yake=oxen; //不允许
但是可以采用遍历的方式把一个数组中的所有元素交给另外一个数组。
for(i=0, i<length, i++)
{
b[i] = a[i] ;
}
也不可以除初始化以外使用花括号列表的形式赋值。
yake[4]={5, 3, 2, 8}; //不起作用
数组作为函数参数时,往往必须再用另一个参数来传入数组的大小。格式参考下图:
int search(int key, int a[], int length)
{
int ret = -1;
int i;
for ( i = 0; i < length; i++)
{
if (a[i] == key)
{
ret = i;
break;
}
return ret;
}
}
1.5、数组边界
使用数组时,要防止数组下标超出边界,使用越界的数组下标会改变其他变量的值。数组元素下标从0开始,最好在声明数组时使用符号常量来表示数组大小。
1.6、多维数组
多维数组的声明:float rain[5][12] ; // 创建五年内12个月的数组
该数组中主数组有5个元素(每个元素表示一年),每个元素是内含12个元素的数组(每个元素表示一个月)。
rain [5]表示一个内含5个数组元素的数组,float [12]表示一个数组元素内含12个float类型的元素。
#define MONTHS 12 // 一年中的月数
#define YEARS 5 // 年数
const float rain[YEARS][MONTHS] =
{
{ 4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6 },
{ 8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3 },
{ 9.1, 8.5, 6.7, 4.3, 2.1, 0.8, 0.2, 0.2, 1.1, 2.3, 6.1, 8.4 },
{ 7.2, 9.9, 8.4, 3.3, 1.2, 0.8, 0.4, 0.0, 0.6, 1.7, 4.3, 6.2 },
{ 7.6, 5.6, 3.8, 2.8, 3.8, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 5.2 },
};
2、指针
2.1 指针简介
指针是一个值为内存地址的变量(或数据对象),指针变量的值是地址。
指针在某种程度上把程序员想要传达的指令以更接近机器的方式表达,因此使用指针的程序更有效率,尤其,指针能有效处理数组。
数组名是数组首元素的地址:
flizny==&flizny[0]
short * pti; //定义指针
short dates[6]; //定义数组
pti=dates; //把数组首元素地址赋给指针
pti+2; //相当于&dates[3]
地址按字节编址,short类型占用2个字节,double类型占用8个字节,指针加一个数,指针的值递增它所指向类型的大小(以字节为单位)。
C保证在给数组分配空间时,指向数组后面第一个位置的指针仍是有效的指针,但是对这个位置上的值未做任何保证,程序不可访问该位置。
2.2、间接运算符
ptr = &bah ; // ptr指向bah
使用间接运算符 * 找出存储在bah中的值,
2.3、指针操作
指针赋值:ptr1=urn ; //也可写作ptr1=&urn[0]
ptr2=&urn[2] ;
指针加法:ptr3=ptr1+4 ;
递增指针:ptr1++ ;
指针求差:ptr2-ptr1 ;
千万不要解引用未初始化的指针!创建指针时,系统只分配了存储指针本身的内存,并未分配存储数据的内存。所以在使用指针之前,一定要先用已分配的地址初始化指针。
另外,一个数组是一个常量(const)指针,所以数组不能等于另外一个数组。
int b[ ]=a[ ] // error! 这是不允许的
2.3 指针和const
(1) 指针是const
表示一旦得到了某个变量的地址,就不能再指向其他变量
int * const q = &i ; // q is const
*q = 26 ; // ok
q++ ; // error
(2) 所指的是const
表示不能通过指针去修改指针指向的那个变量
const int * p = &i ; // 等价于 int const * p = &i
*p = 26 ; // error ! 不能通过指针去修改指针指向的那个变量
i = 26 ; // ok
p=&j ; // ok
判断哪个被const了的标志是const在*的前面还是后面
2.4 const数组
const int a[ ] = { 1, 2, 3, 4, 5, 6 }/* 表明数组里的每一个单元都是const int,元素不可修改*/
/* 所以必须通过初始化进行赋值 */
如果你把一个数组传递到一个函数中,但又不希望让函数来修改这个数组,就可以设置参数为const,函数原型可写成:
int sum(const int a[ ], int length) ;
3、指针用来做什么?
- 需要传入较大的数据时用指针做参数
- 传入数组后对数组做操作
- 函数返回不止一个结果
- 需要用函数来修改不止一个变量
- 动态申请内存