第四章节-30-从数组到指针

数组到指针的隐式转换

  • 概念: 在C++中,当你使用数组名时,编译器通常会自动将数组名转换为指向数组第一个元素的指针。这种现象称为“数组到指针的隐式转换”。

    例如,假设你有一个数组 int arr[4] = {0, 1, 2, 3};,当你在函数中传递 arr 时,实际上传递的是指向数组 arr 首元素的指针 int*

  • 隐式转换的影响:

    • 丢失部分类型信息: 由于数组被转换为指针,编译器无法知道原始数组的大小,这可能导致一些边界问题。例如,函数接收到指针后无法知道数组的长度,只知道它是指向 int 类型的指针。

    • 类型信息丢失的场景: 如果在函数中需要知道数组的大小或需要操作整个数组,那么这种转换会让开发者失去对数组大小的控制。

  • 避免隐式转换的方法:

    • 通过引用传递数组: 你可以通过引用来传递数组,以避免隐式转换。例如,声明 void func(int (&arr)[4]) 可以避免数组到指针的隐式转换,因为 arr 是一个引用,它仍然保持对原始数组大小的了解。
    • 举例:
    • #include <iostream>
      using namespace std;
      
      // 函数声明,接收一个包含4个元素的int数组的引用
      void printArray(int (&arr)[4]) {
          for(int i = 0; i < 4; i++) {
              cout << arr[i] << " ";
          }
          cout << endl;
      }
      
      int main() {
          int myArray[4] = {1, 2, 3, 4};
          
          // 通过引用将数组传递给函数
          printArray(myArray);
          
          return 0;
      }
      
  • 右边的示例图
    • 右边的示例图展示了一个指针指向数组首地址的情况:

    • pointer (64): 图中的 pointer 是一个指针,存储的值为 64,表示内存地址 64。这个指针指向数组的第一个元素。
    • array: 数组包含几个整数,每个整数占据4个字节的内存空间。数组的第一个元素位于内存地址 64~67,第二个元素位于 68~71,以此类推。
  • 注意事项
    • 不要使用 extern 指针来声明数组: extern 通常用来声明全局变量,但在声明数组时,不应使用 extern 指针声明数组,而是直接使用 extern 关键字声明数组。例如:

    • extern int arr[10];
      
    • 这样做是为了避免数组被错误地隐式转换为指针,导致类型信息丢失。

    • Unknown Bounded Array 声明: 这部分提到了“未知边界数组声明”,这种情况下,数组的大小未知,在这种声明中也需要小心处理,避免隐式转换的问题。

  • 总结

    • 数组到指针的隐式转换在C++中是常见的现象,但可能导致丢失数组的类型信息,尤其是在传递数组给函数时。
    • 可以通过引用传递数组来避免这种转换,确保函数仍然保留数组的完整类型信息,包括数组的大小。

  • std::beginstd::end

    • 这两个函数用于获取数组或容器的开头和结尾的指针。
    • std::begin 返回指向数组或容器第一个元素的指针,而 std::end 返回指向数组或容器末尾之后一个位置的指针(该位置不包含在数组或容器内)。
    • 注意,std::cbeginstd::cendstd::beginstd::end 的常量版本,返回的是指向常量的指针
  • 指针运算

    • 增加、减少:可以通过加减整数来移动指针,从而指向数组中的不同元素。
    • 比较:可以比较两个指针,判断它们指向的元素在数组中的相对位置。
    • 求距离:可以通过指针的减法运算来计算两个指针之间的距离。
    • 解引用:通过解引用指针,可以访问它指向的数组元素。
    • 指针索引可以通过 指针 + 索引 来访问数组中的元素
#include <iostream>
#include <iterator>  // 包含 begin 和 end
#include <algorithm> // 包含 distance

using namespace std;

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    
    // 使用 begin 和 end 获取数组的指针
    int* beginPtr = begin(arr);
    int* endPtr = end(arr);

    // 访问指针指向的第一个元素
    cout << "First element: " << *beginPtr << endl;
    
    // 指针算术运算 - 访问第二个元素
    cout << "Second element: " << *(beginPtr + 1) << endl;

    // 比较指针
    if (beginPtr < endPtr) {
        cout << "beginPtr is before endPtr" << endl;
    }

    // 计算指针之间的距离
    cout << "Distance between beginPtr and endPtr: " << distance(beginPtr, endPtr) << endl;

    // 使用指针索引访问数组元素
    cout << "Third element (using indexing): " << beginPtr[2] << endl;

    return 0;
}

 输出:

First element: 10
Second element: 20
beginPtr is before endPtr
Distance between beginPtr and endPtr: 5
Third element (using indexing): 30

beginPtr[2] 是一种简写形式,用来访问指针指向的数组中的第 2 个元素(即数组的第 3 个元素)。这个操作背后的原理与数组访问操作符的工作方式有关。

x[y] → *((x) + (y))

数组元素访问表达式 x[y] 实际上是指针运算的一种简写形式。在 C++ 中,x[y] 等价于 *(x + y),这意味着 y 被加到 x 上,然后解引 用指针访问对应的元素。

详细解释:

在 C++ 中,数组访问操作符 [] 实际上是一个指针运算的简写形式。对于指针 beginPtr 和整数索引 ibeginPtr[i] 等价于 *(beginPtr + i)

具体步骤如下:

  1. 指针运算:

    • beginPtr + i 是指针 beginPtr 移动 i 个元素后指向的新地址。假设 beginPtr 指向数组的第一个元素,那么 beginPtr + 2 就是指向数组的第三个元素。
  2. 解引用操作:

    • *(beginPtr + i) 通过解引用操作访问 beginPtr + i 指向的地址处的值。也就是说,它访问的是数组的第 i + 1 个元素(因为索引从 0 开始)。

因此,beginPtr[2] 本质上是指针运算和解引用的组合,它等价于 *(beginPtr + 2),用来访问数组的第三个元素(即 arr[2] 的值)。

举个例子:

假设 beginPtr 指向一个数组 arr,其内容为 {10, 20, 30, 40, 50}

  • beginPtr 指向 arr[0],即值为 10 的位置。
  • beginPtr + 2 指向 arr[2],即值为 30 的位置。
  • *(beginPtr + 2)beginPtr[2] 会访问并返回该位置的值,即 30

总结:

beginPtr[2] 是数组指针的标准访问方式,等效于数组的下标访问操作符。这种方式的好处是它可以直接访问指针所指向的数组中的元素,非常简洁和直观。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值