Arrays and Pointers

本文探讨了C语言中数组与指针之间的常见误解。虽然两者在某些情况下可以互换使用,但它们在内存地址处理、变量性质及运行机制上存在本质区别。文章通过实例对比了使用数组名与指针进行遍历的不同。

There are a large amount of C programmers who will consider arrays and pointers as the same thing, or at least they have the same usage, especially those beginners. But actually that is not correct! I am sure somebody will come out to oppose it, and their reason seems to be sufficient. Suppose we declare an array containing 10 integers: int a[10], and a pointer referring to an integer: int *pa. Now we can iterate over the array a using a for-loop and the subscript operation like this:

#include <stdio.h>

main()
{
    
int a[10];
    
int i;
    
for(i = 0; i < 10; i++)
    
{
        a[i] 
= i;
    }

    
return 0;
}

Also, we can do it using the pointer pa. But first of all, the correct address should be assigned to the pointer:

pa = a;
for(i = 0; i < 10; i++)
{
    
*(pa + i) = i;
}

Another way to express this is to use the pointer just as the array name, with the subscript operation:

pa = a;
for(i = 0; i < 10; i++)
{
    pa[i] 
= i;
}

So somebody comes to the conclusion: arrays and pointers are just the same, because they can replace each other without any change.

Well in this case, the array and the pointer can replace each other without any change, or say, any change in the surface which is more accurate. But inside, the dereferences of the these two things are a little bit different. Let's talk more about that. First of all, the array name can't be assigned to any address or changed, while the pointer can be set to any address, as long as it is not a const pointer. Almost everybody knows it, including the beginners. Secondly, the array name stands for the starting address of the whole array, you can regard it as an identifier other than a variable, but the pointer is surely a variable. It may contains the starting address of some array, while it has got itself an address. Thirdly, which is the most important, if we declare an array, the starting address will be known during the comile time, while the value of a pointer will be got during the run time. What is known in the compile time about the pointer is the address of itself. So when we want to iterate over the array, the dereference mechanisms are different. For the array name, two steps are needed: first add the offset, which is represented by the variable i, to the address of the array(this is known in the compile time, still remember?), second get the content(i.e. the ith element in the array) from the new address. For the pointer, three steps are needed: first get the pointer's value(the starting address of the array) from its own address, second add the offset to its value, third get the content from the new address. See, one more step for the pointer's dereference, and this always cause a confusion.

In the case we discussed above, the compiler and the runtime will handle this difference automatically. But in most cases, it is not what you expected. For example, we have already define an array in one file: int a[10], and we want to use this array in another file. Generally we just use "extern" to declare it in another file: extern int a[10](the size of the array can be omitted). But if you code like this: extern in *a, it won't pass the compilation(in some old compilers, this is OK, but the result of dereferencing the pointer is undefined).

Sometimes, knowing why you can't do one thing is as important as knowing why you can do one thing.

### 题目重述 以下是一组关于C++中指针的控制性问题,涉及指针的基本概念、操作符、初始化、数组关系、指针运算、const修饰、迭代安全、空指针及数组访问机制。 --- ### 详解 **1. 什么是C++中的指针?它的两个主要属性是什么?** 指针是存储变量内存地址的变量。其两个主要属性为: - **值(value)**:所指向内存地址的内容(通过`*ptr`访问)。 - **地址(address)**:指针自身在内存中的位置(通过`&ptr`获取)。 --- **2. `&` 和 `*` 操作符在指针中的区别是什么?** - `&` 是取地址操作符,返回变量的内存地址,如 `&var`。 - `*` 是解引用操作符,访问指针所指向地址的值,如 `*ptr`。 --- **3. 为什么指针初始化至关重要?未初始化的指针有哪些危险?** 未初始化的指针包含随机内存地址,称为“野指针”。 若解引用会导致**程序崩溃**或**未定义行为**,可能破坏系统数据。 --- **4. C++中数组与指针的基本关系是什么?** 数组名在大多数情况下可被解释为指向其首元素的指针。 例如:`int arr[5];` 中,`arr` 等价于 `&arr[0]`。 --- **5. 指针运算如何工作?为何 `ptr + 1` 增加的是所指类型的大小而非1字节?** 指针运算基于所指数据类型的大小自动缩放。 若 `ptr` 指向 `int`(4字节),则 `ptr + 1` 实际增加 $4$ 字节,确保指向下一个有效元素。 --- **6. 数组名和指针变量的区别是什么?为何不能对数组名进行自增?** 数组名是一个**常量指针**,代表首元素地址,不可修改。 而指针变量是可变的左值,可执行 `p++`;数组名 `arr++` 非法,因其地址固定。 --- **7. `const int*`、`int* const` 和 `const int* const` 的区别?** - `const int*`:指向常量的指针,可改指针,不可改值。 - `int* const`:常量指针,不可改指针,可改值。 - `const int* const`:指向常量的常量指针,均不可更改。 --- **8. 如何用指针安全遍历数组?边界风险有哪些?** 使用指针从首地址遍历到末地址: ```cpp for(int* p = arr; p < arr + n; ++p) ``` 风险:越界访问会导致**未定义行为**,必须严格控制终止条件。 --- **9. 什么是空指针?为何解引用前应检查是否为 `nullptr`?** 空指针不指向任何有效内存(值为 `nullptr` 或 `NULL`)。 解引用空指针会引发**运行时错误**或**段错误(segmentation fault)**。 --- **10. 如何用指针语法访问数组元素?编译器如何翻译 `arr[i]`?** 可用 `*(arr + i)` 访问第i个元素。 编译器将 `arr[i]` 内部转换为 `$*(arr + i)$`,利用指针算术实现。 --- ### 知识点 - **指针与内存地址**:指针保存变量地址,通过`*`和`&`实现地址操作与值访问。 - **指针运算机制**:`ptr + n` 实际移动 `$n \times \text{sizeof(type)}$` 字节。 - **数组与指针等价性**:数组名可作指针使用,但为不可修改的常量地址。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值