另一个指向数组问题的 C++ 指针

Yet another C++ pointer to array question

我已经超过 25 年没有编写 C++ 了,显然我忘记了很多东西,现在的编译器比以前严格得多。因此,我正在努力创建一个动态分配的指针数组,该指针数组指向 8 个无符号字符的数组。

我相信我需要一个指针变量。 我希望在运行时分配该变量以指向动态分配的指针数组。 然后将每个结果指针分配给一个 8 unsigned char 数组。

我认为我的数组的变量声明应该是:

int (**arr)[8];

但我无法弄清楚如何分配存储空间。

第一步,我尝试了这个想法的多种变体:

arr = new (int*[8])[4];

但都被拒绝为类型不兼容,或完全语法错误。无奈之下,我也尝试过:

arr = malloc(4 * sizeof(void *));

因“无法将‘void*’转换为‘int (**)[8]’”而被拒绝,所以我尝试了转换:

arr = (int**[8])malloc(4 * sizeof(void *));

仍然失败。

编辑: 根据目前的评论,首先,我正在为 ESP32 设备用 C++ 编写,现在已经取得了这些进展(仍然失败)

arr = new (int(*)[8])[4]; // array bound forbidden after parenthesized type

arr = new (int(*)[])[4]; // cannot convert ‘int (**)[]’ to ‘int (**)[8]’

从评论中可以清楚地看出“我需要重新学习很多东西”,甚至“这不是最好的方法”,但现在我只想完成工作。谁能简单地告诉我 a) 我的变量声明是否正确,以及 b) 我如何分配初始指针数组?

相信您想了解**双指针以及如何使用它们。

// explanation of what double pointer is.

    int **arr1; //double pointer: is a pointer to point to pointer
 
    // example
    int* p = new int(1);
    arr1 = &p; // points to pointer int*, note the "&" affront which returns the memory address of p.
    arr1 = new int*[10]; // points to int*, "new" returns the memory address of newly allocated memory space.


// harder example, how to point to a double array [][]
    int num_rows = 10;  
    arr1 = new int*[num_rows];

    for (int i = 0; i < num_rows; ++i)
    {

        int num_cols = i + 1; // the column length can be different for each row
        arr1[i] = new int[num_cols];

        for (int j = 0; j < num_cols; ++j)
            arr1[i][j] = i;

    }

请注意,**不仅指向那些固定长度的行,它还可以指向不等长的数据行,如示例所示。注意跟踪行长度或只使用双数组。

好的,因为我不喜欢这里的其他答案(因为我认为它会把你引向错误的方向),我会试着说服你改用现代 C++ 习语。正如我在评论中不止一次所说的那样,一旦你掌握了它,这将得到回报。

首先,你的问题自相矛盾。首先你这样说:

[...] Each of the resulting pointers would then be assigned to point to an array of 8 unsigned char.

然后你说:

I think that the variable declaration for my array should be:

int (**arr)[8];

那你想要什么?某种 int 的数组或 8 unsigned char 的数组?我将选择后者,因为这就是您所说的目标。如果这实际上不是您想要的,请澄清您的问题 - 专注于您想要表示的数据结构,而不是您认为应该如何实现它 - 我将相应地更新此答案。就像我说的(虽然我现在删除了评论,因为我觉得它有点不友好),XY 问题。请忘记指针。这不是解决这个问题的方法(不管它是什么,或者任何其他问题,差不多)。

因此,在现代 C++ 中,这是 super-easy。为了便于讨论,假设您想要一个数据结构来表示固定数量的 unsigned char 数组(比如 4 个),每个 unsigned char 数组的长度为 8 个字节。好吧,这很简单,您可以使用最简单的 STL 容器 - std::array - 并简单地说:

// Define your types once ('using' is a sort of supercharged typedef) and use them everywhere
using my_array_element_type = std::array <unsigned char, 8>;
using my_array_type = std::array <my_array_element_type, 4>;
my_array_type my_array { };         // { } zero-initialises the array (I'm playing it safe here)

然后,要访问数组中的单个元素,您可以这样做:

auto c = my_array [3] [5]; // 'auto' 'deduces' to unsigned char here

现在这看起来很像分配在堆栈上的二维 C-style 数组,实际上它就是这样,但是有一些重要的区别。

鉴于上述你可以,例如,做这样的事情:

my_array_type make_array ()
{
    my_array_type a { };
    // stuff things into the array, perhaps
    return a;
}

然后,在你想让数组出现的时候,你可以这样做:

auto my_array = make_array ();

你也可以这样写函数:

void use_array_read_only (const my_array_type &a)    // passed by reference, so not copied
{
    // .. do things with a (read-only)
}

还有这个:

void use_array_read_write (my_array_type &a)         // ditto
{
    // .. do things with a (read-write)
}

请注意,这些函数知道所有关于传递给它们的参数的类型,包括它包含多少元素(所以不需要为这些传递额外的 one-day-you 绑定到 get-it-wrong 参数),而且你不能说 C-style 数组。事实上,这些 'decay' 指向一个指针是臭名昭著的,每个人都讨厌它。即使计算出二维数组参数的 type 也是一个挑战,除非我绝对必须这样做,否则我个人不够聪明,无法弄清楚。

作为一个stack-based变量,my_array的生命周期仅限于它定义的范围。我只能猜测这对您来说是否是个问题,但我相信您可以应付。此外,由于它们是在堆栈上分配的,因此 std::arrays 不能太大。

如果你想要一个可以调整大小的数据结构,或者太大而不适合放在堆栈上,你可以使用 std::vector 代替。 std::vector 的 API 在许多方面是 std::array 提供的超集,因此,对于许多用途,一旦填充,它可以以几乎相同的方式使用。


对,tl;dr:

  • 忘记,基本上,所有你知道的C;它只会让你误入歧途。特别是,忘记指针和 C-style 数组的存在。 (无论如何现在。指针确实有它们的位置,但你需要了解 'smart pointers' 才能安全地使用它们,那是另一天)。

  • 忘掉所有 mallocfreenewdelete。你不需要它们。曾经。

  • 学习基本使用作为 STL 主力的三个容器:std::arraystd::vectorstd::string。它们不难使用,如果您 运行 遇到您不知道该怎么做或不理解的事情,您可以随时在 SO 上提问。这就是该网站的用途。

  • 了解什么是引用(和 const 引用)。您将希望将它们用作函数参数,以避免每次将容器传递给函数时都复制容器。它还将允许您在函数内修改该容器,如果您想要这样做的话。

  • 给自己买一个 suitable book。您现在需要它,而不是下周、下个月或明年!

  • 请注意 cppreference 存在。一开始您会发现它很难,但它是一个非常有用的网站,事情会变得更容易。此外,刚开始时,您可能会发现 (cplusplus.com)[https://www.cplusplus.com/] 更容易访问,但 cppreference 更全面、更可靠。

  • 当您想尝试新事物时,可以使用众多在线编译器之一。我发现它们非常宝贵并且个人喜欢 Wandbox。 link 指向一个简单的 std::array 演示,您可能会喜欢。

就是这样。祝你好运!我的是啤酒。如果你陷入困境,你会发现很多人愿意在 SO 上帮助你。如果您坚持使用过时的 C 习语,那就没那么多了。我们看到很多这样的重新,这有点令人沮丧。