C和指针 第8章 数组 8.1 一维数组

本文详细介绍了C语言中一维数组的概念,包括数组名表示的含义、数组名与指针的关系以及下标引用的实现原理。文章通过实例展示了数组名在表达式中实际上代表的是指向数组首元素的指针,而不是整个数组。文中还探讨了指针和下标在效率上的差异,并提供了不同方法实现数组复制的代码示例,强调了在追求效率的同时不应忽视代码的可读性和维护性。最后,讨论了作为函数参数的数组名传递时的行为,以及数组参数声明和初始化的各种情况,包括静态和自动初始化、不完整的初始化等。
摘要由CSDN通过智能技术生成

数组
更加高级的数组话题,如多维数组、数组和指针以及数组的初始化等。
    8.1 一维数组
    这个概念实际上是以一种相当优雅的方式把一些完全不同的概念联系在一起的。
    8.1.1 数组名
    考虑下面这些声明:
    int a;
    int a[20];
    变量a称为变量,因为它是单一的值,这个变量的类型是一个整数。变量b称为一个数组,因为它是一些值的集合。下标和数组名一起使用,用于标识集合中的某个特定的值。b[0]表示数组b的第1个值。每个特定值都是一个标量,可以用于任何能够使用标量数据的上下文环境中。b表示的又是什么?一个合乎逻辑的答案是它表示整个数组,但事实上并非如此。在C中,在几乎所有使用数组名的表达式中,数组名的值是一个指针常量,也就是数组第1个元素的地址。它的类型取决于数组元素的类型:如果它们是int类型,那么数组名的类型就是“指向int的指针常量”;如果它们是其他类型,那么数组名的类型就是“指向其他类型的指针常量”。
    数组具有一些和指针完全不同的特征。例如,数组具有确定数量的元素,而指针只是一个标量值。编译器用数组名来记住这些属性。只有当数组名在表达式中使用时,编译器才会为它产生一个指针常量。
    注意,这个值是指针常量,而不是指针变量。常量的值是不能修改的。只要稍微回想一下,就会认为这个限制是合理的:指针常量所指向的是内存中数组的起始位置,如果修改这个指针常量,唯一可行的操作就是把整个数组移动到内存的其他位置。但是,在程序完成链接之后,内存中的数组的位置是固定的,所以当程序运行时,再想移动数组就为时已晚了。因此,数组名的值是一个指针常量。
    只有在两种场合下,数组名并不用指针常量来表示---当数组名作为sizeof操作数或单目操作符&的操作数时。sizeof返回整个数组的长度,而不是指向数组的指针的长度。取一个数组名的地址所产生的是一个指向数组的指针(指向数组的指针),而不是一个指向某个指针常量值的指针。
    现在考虑下面这个例子:
    int a[10];
    int b[10];
    int *c;
    ...
    c = &a[0];
    表达式&a[0]是一个指向数组第1个元素的指针。但那正是数组本身的值,所以下面这条赋值语句和上面那条赋值语句所执行的任务是完全一样的:
    c = a;
    这条赋值语句说明了为什么理解表达式中数组名的真正含义是非常重要的。如果数组名表示整个数组,这条语句就表示整个数组被复制到一个新的数组。但事实上完全不是这样,实际被赋值的是一个指针的拷贝,c所指向的是数组的第1个元素。因此,像下面这样的表达式:
    b = a;
是非法的。不能使用赋值符把一个数组的所有元素复制到另一个数组,而是必须使用一个循环,每次复制一个元素。
    考虑下面这条语句:
    a = c;
    c被声明为一个指针变量。这条语句看上去像是执行某种形式的指针赋值,把c的值复制给a,但这个赋值是非法的。在这个表达式中,a的值是个常量,不能被修改。
    8.1.2 下标引用
    *(b + 3)表达式是什么意思?
    首先,b的值是一个指向整型的指针,所以3这个值根据整型值的长度进行调整。加法运算的结果是另一个指向整型的指针,它所指向的是数组第1个元素向后移3个整数长度的位置。其次,间接访问操作访问这个新位置,或者取得那里的值(右值),或者把一个新值存储于该处(左值)。
    它和下标引用的执行过程完全相同。我们现在可以解释第5章所提到的一句话:除优先级之外,下标引用和间接访问完全相同。例如,下面这两个表达式是等同的:
    array[subscript]
    *( array + ( subscript ) )
    在上面的第1个下标表达式中,子表达式subscript首先进行求值。然后,这个下标值在数组中选择一个特定的元素。在第2个表达式中,内层的那个括号保证子表达式subscript像第1个表达式那样首先进行求值。经过指针运算,加法运算的结果是一个指向所需元素的指针。然后,对这个指针执行间接访问操作,访问它指向的那个数组元素。
    在使用下标引用的地方,可以使用对等的指针表达式来代替。在使用上面这种形式的指针表达式的地方,也可以使用下标表达式来代替。
    这里有个小例子,可以说明这种相等性:
    int array[10];
    int *ap = array + 2;
    写出使用array的对等表达式
    ap == array + 2 == &array[2];
    *ap == array[2] = *(array + 2);
    ap[0] “不能这样做,ap不是一个数组”如果你是这样想的,就陷入了“其他语言不能这样做”这个惯性思维中了。记住,C的下标引用和间接访问表达式是一样的。在现在这样情况下,对等的表达式是*(ap+(0)),除去0和括号,其结果是与前一个表达式相等。因此,它的答案和上一题相同:array[2]。
    ap+6 == array + 8 == &array[8]
    *ap + 6 == array[2] + 6
    *(ap+6) == array[8]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值