汇聚点滴启迪思维(五)

指针和数组在C语言中既有区别又有密切联系‌。利用这种关系,可以增强处理数组的灵活性,加快运行速度,下面聊一聊指针和数组的爱恨情仇。

数组和指针的联系

指针可以指向数组‌:当一个指针变量被初始化为数组名时,该指针变量就指向了这个数组。此时,指针可以被用来访问数组的元素,就像使用数组下标一样‌。

char str[20], *ptr;
ptr=str;

ptr被置为数组str的第一个元素的地址,因为数组名就是该数组的首地址,也是数组第一个元素的地址。此时可以认为指针ptr就是数组str(反之不成立)

内存表示‌:数组和指针在本质上都代表一块内存。数组名代表这块内存的地址,而指针在赋值后也表示一块有意义的内存地址‌。一维数组是一个线形表,它被存放在一片连续的内存单元中。C语言对数组的访问是通过数组名(数组的起始地址)加上相对于起始地址的相对量(由下标变量给出),得到要访问的数组元素的单元地址,然后再对计算出的单元地址的内容进行访问。通常把数据类型所占单元的字节个数称为扩大因子。实际上编译系统将数组元素的形式a[i]转换成*(a+i),然后才进行运算。对于一般数组元素的形式:<数组名>[<下标表达式>],编译程序将其转换成:*(<数组名>+<下标表达式>),其中下标表达式为:下标表达式*扩大因子。整个式子计算结果是一个内存地址,最后的结果为:*<地址>=<地址所对应单元的地址的内容>。由此可见,C语言对数组的处理,实际上是转换成指针地址的运算。数组与指针暗中结合在一起。因此,任何能由下标完成的操作,都可以用指针来实现,一个不带下标的数组名就是一个指向该数组的指针。

数组和指针的差异

参数传递

在C语言中,当你将数组作为参数传递给一个函数时,数组名会“退化”为一个指向数组首元素的指针。这是C语言的一个特性,也是数组和指针之间紧密联系的一个体现。

数组退化为指针的具体表现,当你声明一个数组,并将其作为参数传递给函数时,例如:

void processArray(int arr[], int size) {
    // 函数体
}

int main() {
    int myArray[];
    // ... 初始化myArray ...
    processArray(myArray, 10);
    return 0;
}

processArray函数的参数列表中,arr被声明为int类型的数组,但实际上在函数内部,arr是一个指向int类型的指针,它指向myArray的首元素。这就是数组名退化为指针的含义。

为什么数组会退化为指针

数组名退化为指针的原因主要与C语言的内存模型和函数调用的实现方式有关。在C语言中,数组名本身代表数组首元素的内存地址,而函数参数传递时通常是通过值传递的。但是,如果直接传递整个数组,那么将会导致大量的内存开销(特别是当数组很大时)。因此,C语言选择将数组名退化为指向数组首元素的指针,这样只需要传递一个地址值即可。

数组退化为指针的影响

1‌、内存效率‌:通过传递指针而不是整个数组,可以显著提高内存效率。

2、函数内部无法获取数组大小‌:由于传递的是指针,函数内部无法直接获取原始数组的大小(除非通过额外的参数传递)。

3、修改原数组‌:通过指针,函数内部可以修改原数组的元素,因为指针指向的是原始数组的内存位置。

注意事项

当数组作为参数传递给函数时,即使你在函数内部修改了数组的元素,这些修改也会反映到原始数组中。为了避免在函数内部修改原始数组,你可以传递数组的副本或者通过其他方式保护原始数据。由于数组名会退化为指针,所以在函数参数中声明数组大小是无效的,例如int arrint arr[]在函数参数中是等价的。

数组名可作为指针常量

在C语言中,数组名在大多数上下文中会被视为一个指针常量,这意味着它可以被用作指针来访问数组的元素,但其值(即指向的地址)是不可改变的。这里有几个关键点需要理解

数组名与指针的关系‌:

数组名代表数组首元素的内存地址。在表达式中(除了sizeof和取地址&操作符的情况外),数组名会被编译器自动转换为指向数组首元素的指针。

指针常量的特性‌:

指针常量是一个指向特定地址的指针,其值(即地址)在初始化后不可改变。数组名作为指针常量时,它指向数组的首元素,并且这个指向是不可变的。你不能像修改普通指针那样修改数组名的指向。

数组名不可作为左值‌:

由于数组名被视为指针常量,因此它不能作为赋值语句的左值。也就是说,你不能尝试给数组名赋一个新的地址值。例如,array = otherArray; 这样的语句是不合法的,其中array是一个数组名。

与指针变量的区别‌:

指针变量是一个可以改变的指针,它可以被重新指向不同的内存地址。数组名则不同,它始终指向数组的首元素,并且这个指向是固定的。

其他

1、编译时不会为指针分配存储空间, 但是指针在结构体中, 是会默认分配的。

2、数组的内部实现也是依靠指针, 只是数组名是一个指针常量, 数组一次寻址(即通过数组名直接找到数组元素), 指针需要两次寻址。(先确定指针变量的己值,然后定位到指针的他值)

3、指针变量+1, 不是加一个地址量(即一个字节), 而是加一个内存单元, 具体的长度由指针类型决定。

4、指针指向数组的时候, 只是指向数组的首地址, 他不代表数组类型, 可以通过 指针++的方式依次获取数组内容。

5、两个指针不能做加法运算,但是可以做减法运算,做减法是得到两个指针的间距。

6、数组名是指针常量, 所以没有办法再次对一个数组名重新分配内存地址; 换言之, 可以对指针变量赋值, 但是不能对数组名赋值。

7、指针对比数组的一个优势: 可以扩容, 因为指针的内存可以通过malloc分配, 所以也可以通过realloc扩容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值