【问题标题】:Let an array point to another array with different bounds in C++在 C++ 中让一个数组指向另一个具有不同边界的数组
【发布时间】:2019-03-01 20:46:31
【问题描述】:

我需要使用具有以下 typedef 和方法的库:

typedef short int SomeArray[3];

void method(SomeArray* arr){//doSomething}

在我的主代码中,我有一个大数组,并且想要一个较小的数组,它的索引值与较大的数组完全相同:

short int var[5] = {0, 1, 2, 4, 5};

我需要一个 SomeArray 类型的变量,它的 [0] = var[1], [1] = var[2], [2] = var[3] 将它传递给 test() 方法。这个:

short int* intf = &var[1];

当我通过 intf[?] 访问它时给出我需要的东西。但是如何将其转换为 SomeArray 类型的变量以成为具有 3 个元素的数组?我尝试了不同的方法,例如

SomeArray* arr = intf;
SomeArray* arr = (SomeArray*)intf;
SomeArray* arr = &var[1];

但是要么它不起作用,要么每个 arr 元素的元素地址与更大数组的元素地址(在所需位置上)不匹配。

【问题讨论】:

  • 请注意,C 和 C++ 是两种 非常 不同的语言,它们的很多语义细节都不同。如果您询问 C++,请不要同时标记 C。
  • 另外,数组不是指针,指针也不是数组。数组和指针类型是不同的。数组可以衰减到指向其第一个元素的指针,并且指针可以像数组一样被索引(因为所有数组索引实际上都是指针算术)。
  • @SanderDeDycker 它在编译时给了我错误,例如“无法将 'short unsigned int*' 转换为 'short unsigned int ()[3]”或无法转换 'short unsigned int*' 到 'short unsigned int (*)[3]
  • 至于解决问题的可能方法,为什么不创建SomeArray 的新instance,例如SomeArray intf; 然后copy 需要的元素从varintf?
  • SomeArray 是类型“三个short ints 的数组”,因此SomeArray* 是类型“指向三个short ints 的数组的指针”。 intf 的类型为“指向一个short int 的指针”。指向一个short int 的指针不是指向三个short int 的数组的指针。如果您只是想要一个指向更大的short int 数组的指针,那么您要查找的类型是short int*

标签: c++ arrays pointers


【解决方案1】:

您可能会成功地将var[1] 的地址转换为指向具有三个元素的数组的指针类型。严格来说,这可能是非法的,因为我认为它违反了严格的别名规则(类型化对象只能通过兼容类型的表达式访问)——但只是非常轻微;-)1。语义上没有问题,因为 3 元素数组中预期的短裤都在那里。严格来说,它可能在任何地方都有效:

$ g++ --version && cat arrpassing.cpp && g++ -Wall -o arrpassing -O3 arrpassing.cpp && ./arrpassing
g++ (GCC) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


#include<iostream>
using namespace std;

typedef short int SomeArray[3];

void method(SomeArray* arr)
{
  int i=0;
  for(auto el: *arr) cout << "arr[" << i++ << "]: " << el << '\n';
}

int main()
{
  short arr5[5] = { 0,1,2,3,4 };

  method((SomeArray *)(arr5+1));

  return 0;
}

arr[0]: 1
arr[1]: 2
arr[2]: 3


1这确实是一个边缘问题。显然,您可以通过简单的类型指针访问数组的各个元素;并且 C++ 标准在某些情况下将单个对象视为大小为 1 的数组,因此您可以假设可以通过“子数组”(当然是相同元素类型)访问较大数组的内存。

【讨论】:

    【解决方案2】:

    我需要一个 SomeArray 类型的变量,将其 [0] = var[1], [1] = var[2], [2] = var[3] 传递给 test() 方法

    但是如何将[更大的数组] 转换为SomeArray 类型的变量成为一个包含 3 个元素的数组?

    像这样:

    short big_array[] {0, 1, 2, 4, 5};
    SomeArray small_array {
        big_array[1],
        big_array[2],
        big_array[3],
    };
    method(&small_array);
    

    但是,如果您总是需要一个子数组(即总是需要连续的元素),那么您可以通过更改 method 来简单地获取指向数组第一个元素的指针来避免复制:

    void method2(short arr[3]);
    

    这样,你可以用任意大小数组的子数组调用函数(前提是它有足够的元素):

    short big_array[] {0, 1, 2, 4, 5};
    method2(big_array + 1);
    

    不利的一面是,编译时类型检查并不能避免我们犯错,而且传递一个太小的数组只会导致未定义的行为。


    这个想法可以扩展,您可以通过将method 设为函数模板并接受任意迭代器来支持除数组之外的任何其他(可遍历)数据结构。

    【讨论】:

    • void method2(short arr[3]); 中的索引被忽略,这使得签名等同于void method2(short arr[]);,这只是void method2(short *arr); 的另一种说法。尝试在你的函数中打印sizeof(arr)
    • @PeterA.Schneider 确实如此。它只是函数用户的文档。这意味着将指针传递给具有少于 3 个连续兄弟的元素(计算指向的元素本身)将是错误的。
    • 我确信它让 Natha 感到困惑——它的意图让我感到困惑(因为它看起来非常接近“子数组”这个词,而其中没有一个 ;-))。
    • @PeterA.Schneider “看不到任何东西”是什么意思?一个长度为 N 的数组在 2 个子数组上有 N + 1 个。
    • 事实上它确实有子数组,但你没有产生子数组:我们同意你产生并传递一个指向 short 的指针,没有大小信息。那么:C++ 中的数组在语法上是否包含子数组?换句话说,是否允许**(SomeArray *)&amp;big_array(通过不同的数组类型对 big_array 的内存进行别名化)?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多