【问题标题】:Pointer casting with unknown array size in C++C ++中具有未知数组大小的指针转换
【发布时间】:2020-09-15 16:02:13
【问题描述】:

当我在编译时不知道数组大小时,如何将 void 指针转换为二维数组(指向整数数组的指针数组)?有可能吗? (我这样做是因为,我将一个未知大小的二维数组传递给一个函数。所以我将二维数组转换为一个 void 指针,然后在该函数中我希望它重新转换。)

int i = 5;

int tab1[i][i];

//cast to void pointer
void *p = (void *)tab1;

//and recast back
int (*tab2)[5] = (int (*)[5])p;   //this is working
int (*tab3)[i] = (int (*)[i])p;   // but this is not

【问题讨论】:

  • i 不是编译时间常数时,你不能int tab1[i][i];
  • 请注意,int tab1[i][i]; 不是标准 C++ 并且是编译器扩展。对于在运行时确定大小的数组,请使用std::vector
  • 你不能。无论您的原始问题是什么,您都需要提出不同的解决方案。
  • 另外,二维数组(整数)不是指向整数数组的指针数组。它是一个整数数组的数组。那不是一回事。

标签: c++ arrays pointers casting


【解决方案1】:
  1. int i = 5; int tab1[i][i]; 是一个VLA。它不是标准的 C++,应该避免。

  2. 指针数组(和向量的向量)不会像真正的二维数组那样有效,因为它不再是连续的(int tab1[5][5] 是真正的二维数组并且连续存储在内存中,但尺寸必须在编译时已知)。

  3. 您可以轻松创建自定义 2D 容器类,将数据存储在连续的 1D vector 中,并应用一些简单的数学运算 (x + y*width) 来访问元素。

例子:

class Matrix {
    std::vector<int> data;
public:
    const int width;
    const int height;

    Matrix(int width, int height) : width(width), height(height), data(width*height) {}

    int operator()(int x, int y) const {
        return data[y * width + x];
    }

    int& operator()(int x, int y) {
        return data[y * width + x];
    }

};

void print(Matrix const& mat) {
    for (int y = 0; y < mat.height; y++) {
        for (int x = 0; x < mat.width; x++)
            std::cout << mat(x, y) << " ";
        std::cout << std::endl;
    }
}

int main() {
    Matrix mat(5, 5);
    mat(1, 1) = 1;
    mat(2, 2) = 2;
    mat(3, 3) = 3;

    print(mat);
}

为方便起见,这会重载() 运算符。 [] 运算符仍然可以使用,但这需要代理类来访问内部维度,并且还要将 y 放在 x 之前,因为维度实际上是相反的。

【讨论】:

  • 哦,第二条评论是我没有意识到的。感谢您的通知
  • 我不确定,中间可能有填充。但我的意思确实是指针数组。已更新。
【解决方案2】:

当我在编译时不知道数组大小时,如何将 void 指针转换为二维数组(指向整数数组的指针数组)?

你不能。您只能转换为编译时已知的类型。

您可以做的是转换为指向第一行第一个元素的指针:int* p = static_cast&lt;int*&gt;(tab1);。然后,您可以将数组视为一维1。将二维索引转换为一维需要一些简单的数学运算:x, y -&gt; x + y * i


1 只要您不介意跨子数组边界的指针算术在技术上可能是标准不允许的。但这条规则很愚蠢。如果您对此感到担忧,那么您应该首先创建一个一维数组。

【讨论】:

  • 是的,想过这个,但我试图寻找另一种解决方案,然后是一维数组。感谢您的回复
【解决方案3】:

首先我建议不要在 C/C++ 中对数组使用运行时大小,除非您使用 STL 向量作为数组。所以而不是:

int i = 5;

你必须使用:

const int i = 5;

除非你使用比内部数组更安全且更好的 Vector。

当我在编译时不知道数组大小时,如何将 void 指针转换为二维数组(指向整数数组的指针数组)?有没有可能?

如果我们谈论C内在数组,那是不可能的!

为什么不可能? 因为 C/C++ 编译器不知道您的数组大小、边框......所以如果您将 2d 数组转换为 1d 数组,这是可能的。这就是 tab2 数组可以访问数组的第 5 个元素的原因。真的 C/C++ 编译器无法区分

int a[3][3]

int a[3*3]

所以您必须知道数组的至少一维:

int main() {
    const int i = 3,j = 4;

    int tab1[i][j] = {1,2,3,4,5,6,7,8,9,10,11};

//cast to void pointer
    void *p = (void *)tab1;

    auto a = (int (*)[i][12/i])p;
    return 0;
}

在上面的例子中,我知道 i 和总计数(12),我计算了第二个维度。 我使用了很容易推断数据类型的 auto 关键字。

【讨论】:

    【解决方案4】:

    您在这里遇到的问题是数组的大小必须在编译时定义。

    在您的情况下,您有多种选择:

    • 使i 成为constexpr 喜欢constexpr int i = 5;
    • 改用int **

      int i = 5;
      
      int tab1[i][i];
      
      //cast to void pointer
      void *p = (void *)tab1;
      // cast to int **
      auto tab1_p = (int **)p;
      // use it like it was an array
      tab1_p[1][3] = 5;
      

    【讨论】:

    • 这看起来像我要找的。谢谢
    • @DanielŠebík 这是错误的。最后一行具有未定义的行为,因为 tab1_p 没有指向 int * 对象。如果幸运的话,程序会崩溃。
    • 哦,是的,@eerorika 你是对的。我忽略了这一点。
    【解决方案5】:

    int tab1[i][i]; 是可变长度数组的非标准编译器扩展。最好避免这种情况,因为它不便携且难以处理,如您所见。你会更好:

    std::vector<std::vector<int>> tab1(i, std::vector<int>(i));
    

    那么你的函数可以简单地采用这个向量:

    void foo(const std::vector<std::vector<int>>& array) { ....
    

    【讨论】:

    • 听起来不错,但我尝试仅使用基本语言选项来解决它。我会看看那个图书馆,谢谢。
    • 这不是某个库,它是 c++ 标准的一部分。任何给你 c++ 的编译器都会为你提供这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多