C Prime Plus---------------------------一维数组(第十章)

本文详细介绍了C语言中一维数组的基本概念,包括数组声明、初始化、元素赋值及数组边界的重要性。讨论了数组与指针的关系,以及在函数中处理数组的方法,强调了防止数组越界和保护数组数据不变的策略。
摘要由CSDN通过智能技术生成

一、基本概念

1.1数组声明

typename 数组名字[数组大小];

eg float candy [365];  char code [12]; int states[50];

注意:

1.数组下标从0开始,到n-1结束;

2.数组大小必须用整型常量来声明(并且表达式的值必须大于0);

3. C99 和 C11引入了变长数组,数组大小可以用变量来声明,后续介绍。

1.2数组初始化:

①  int states[5] = {1,2,3,4,5}; 如果括号内的数字不足5个,编译器会把剩余的元素都初始化为0。为了在写程序时保证数组大小一致,一般采用宏定义一个SIZE,int states[SIZE] = {1,2,3,4,5}.

② 有时需要把数组设置为只读,应该用const声明和初始化函数。 const int states[5] = {1,2,3,4,5}

③指定初始化器,利用该特性,可以初始化指定的数组元素。 例如要指定初始化最后一个元素,int states[5] = {0,0,0,0,5};利用指定初始化器可以int states[5] = { [4]=5 }.如果指定初始化器后边有更多的值,那么后边的值将被用于初始化指定元素后面的元素。如果再次初始化指定的元素,那么最后的初始化将会取代之前的初始化。

eg int days [12] = { 31,28,[4] = 31, 30, 31, [1] = 29};

days[ 0 ] = 31;  days[ 1 ] = 29;  days[ 2 ] = 0;  days[ 3 ] = 0;  days[ 4 ] = 31;  days[ 5 ] = 30;

days[ 6 ] = 31;  days[ 7 ] = 0;  days[ 8 ] = 0;  days[ 9 ] = 0;  days[ 10 ] = 0;  days[ 11 ] = 0;

注意:

1.如果初始化数组时省略方括号中的数字,编译器会根据初始化列表中的项数来确定数组的大小。 

2.如果初始化列表的项数多余数组元素的个数,会报错。  

3.必须先初始化,在使用数组,否则结果不是我们所期望的。(自动存储类别对于未初始化的变量,里边都是垃圾值;但对于一些其他存储类别的未初始化的变量和数组,编译器会自动把他们的值设置为0)。

1.3数组元素赋值

C语言中,数组被看作是派生类型,因此数组声明后,需要借助下标给数组元素逐一赋值,不允许把数组作为一个单元赋给另一个数组,除初始化以外也不允许使用花括号列表的形式赋值。

int oxen [5] = {5,6,4,8};    // 正确

int yaks [5];

yaks = oxen;                 //错误

yaks [5] = {5,6,4,8};     //不起作用

for (  int j = 0; j< 5; j++)

  yaks[j] = j;                    //正确

1.4 数组边界

在使用数组时,要防止数组下标超出边界,因为编译器不会检查数组下标是否使用得当,使用越界的数组下标会导致程序改变其他变量的值

二、一维数组和指针

2.1指针和数组的关系

① 数组名是数组首元素的地址, 如果 flizny是一个数组, 那么 flizny = &flizny[0].这两者都是常量,可以将他们赋值给指针变量,然后可以修改指针变量的值。

( fizny++;这句就是错的,因为他是常量;错不在与加1或者减1,在于自加后改变了值。

但是 int * p = flizny; p++; 把该地址赋值给一个指针变量,就可以自加)

② 指针的值+1指的是增加一个他所指向类型的大小(以字节为单位)flizny +2 = &flizny[2]

③在指针前使用*运算符可以得到该指针所指的对象。 *(flizny +2) = flizny[2]

④一个较大对象的地址通常是该对象第一个字节的地址。

明白了数组和指针的关系,便可以适时使用数组表示法或指针表示法。

2.2函数、数组和指针

如果要编写一个处理数组的函数,应该如何编写这个函数呢?

① 函数原型中的形参应该为一个指针(数组名是第一个元素的地址)

② 地址参数并没有包含数组元素个数的信息,有两种方法解决: 1.再加一个数组大小的参数(推荐) 2.在函数定义代码中写上固定的数组大小(不推荐)

③ 因为数组名就是一个指针,因此只有在函数声明或者函数定义中,才可以用 int ar[ ] 代替 int * ar(也就是只有在函数定义和声明中有中括号的出现,在调用时直接使用数组名)

④函数原型可以省略参数名,所以下边4中等价,但是函数定义中不能省略参数名,并且ar只是一个指针,而不是数组

int sum (int * ar,int n)        int sum (int ar[] ,int n)

int sum (int *   ,int   )         int sum (int []   ,   int )

⑤除了用一个指针和一个表示数组大小的参数来作为形参,也可以使用两个指针(一个指针形参标识数组的开始,一个表示数组的结束)作为形参,C保证在给数组分配空间时,指向数组后边第一个位置的指针仍然是有效的指针,但该位置不能访问,因为存储在该位置的值未知。

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

answer = sump(marbles, marbles + 5);

int sump(int* start, int* end)

int total = 0;

while (start < end)

{
	total += *start;

	start++;
}

2.3指针操作

①赋值  数组名、带地址运算符的变量名、另一个指针进行赋值(不允许把不同类型的指针进行赋值,例如不能把double类型的地址赋给指向int的指针)

②解引用 *运算符给出指针指向地址上存储的值,不要解引用未初始化的指针,会发生严重错误

③取址  指针变量也有自己的地址

④指针与整数相加 整数会和指针所指向的类型的大小相乘,然后把结果与初始地址相加,超出了初始数组的范围,计算结果未定义。

⑤递增指针 指针移动至数组的下一个元素

⑥指针减去一个整数 指针必须是第一个运算对象,如果结果超出了初始数组的范围,计算结果未定义。

⑦递减指针 指针移动至数组的上一个元素

⑧指针求差 要求两个指针指向相同的数组,可以得到两个地址之间的距离(指针-指针/指针-数字)

⑨比较 关系运算符可以比较两个指针的值,但必须指向相同类型的对象

2.4 保护数组中的数据

在函数章节,我们知道参数传递时有两种,第一种传递相同类型的值,在主调函数中的值不会改变;第二种是传递指针,主调函数中的值也会改变,对于形参是数组的情况,我们只能传递指针,那么如何保护数组中的数据使其不改变呢?----------对形式参数使用const

①对形式参数使用const

int sum (const int ar[ ], int n);

这样使用并不是要求原数组是常量,而是该函数在处理数组时将其视为常量。

②const的其他用法

除了const关键字保护数组,还可以创建 const 数组(数组内容不能变), const 指针(指针只得位置不能变),指向const的指针(指针解引用的值不能变)

指向const的指针 :一般用于函数形参中,表示该函数不会使用指针改变数据,const double *p=rates(数组名);对于指向const的指针,可以把 const数据或者非const数据的地址赋值给指向const的指针;

对于一个普通指针,则只能把非const数据的地址赋值给该指针,const数据的地址赋值给普通指针无效

const指针:  double * const pc = rates

也可以构建指向const数据的const指针,是哪种情况主要看const位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值