在c中有可能有数组的并集吗

rsl1atfo  于 2022-12-11  发布在  其他
关注(0)|答案(2)|浏览(171)

我希望有一个类型可以作为两个不同的数组结构使用-取决于上下文。当程序执行时,它们不能互换使用,而是当程序以特定的启动标志执行时,该类型将作为数组类型之一寻址(例如):
阵列1 [2][100]或阵列2 [200];
我对数据的组织方式不感兴趣(当然,我对数据的组织方式感兴趣,但这与我希望实现的目标无关)

union m_arrays
{
   uint16_t array1[2][100];
   uint16_t array2[200];
};

还是必须使用指针并在运行时分配它?

uint16_t * array;

array = malloc(200 * sizeof(uint16_t));
uint16_t  m_value  =100;

*(array + 199) = m_value;
//equivalent uint16_t  array1[1][99] == *(array + 199);
//equivalent uint16_t  array2[199] == *(array + 199);

我还没试过

ezykj2lf

ezykj2lf1#

一个联合体本身包含它的成员中的 * 任一个 *,也就是说,一次只能“绑定”一个成员(这只是一个抽象概念,因为C并不知道哪个成员是“活动的”)。
通常,该联合的有效大小将是其成员的较大字节大小。
让我给予一个例子:

#include <stdio.h>

typedef union m_arrays
{
   int array1[2][100];
   int array2[400];
} a;

int main()
{
    printf("%zu", sizeof(a));

    return 0;
}

在这个例子中,这将输出1600(假设int是4字节长,但是最后它将取决于体系结构),并且是最大的字节数。

kpbwa7wx

kpbwa7wx2#

是的,这确实有效,这实际上正是因为数组与指针的不同。我相信你已经听说过C中的数组实际上只是指针,但事实是,它们之间存在一些重要的区别。
首先,数组总是指向堆栈上的某个位置。你不能用malloc来创建数组,因为malloc返回一个堆地址。指针可以指向任何地方,如果你愿意,你甚至可以将它设置为任意整数(尽管不能保证你可以访问它所指向的内存)。
第二,因为数组是固定长度的,所以当你声明数组时,编译器可以为你分配它们。重要的是,这保证了整个数组在一个连续的内存块中。所以如果你声明int arr[2][100],你将在堆栈的一行中分配200个int槽。这意味着你可以把任何多维数组当作一维数组。例如,你可以用arr[0][y*100+x]来代替arr[y][x]。你也可以用int* arr2 = arr来代替arr2,然后把arr2当作一个常规数组,即使arr在技术上是一个int**(你做这两件事都会得到一个警告,我的观点是,你用can来做它们是因为数组是如何构成的)。
第三个可能也是最重要的区别是第二个的结果。当你在一个结构体或联合体中有一个数组时,结构/联合体不只是保存指向第一个元素的指针,它还保存整个数组。这通常用于复制数组或从函数返回数组。这对您来说意味着,不管有人如何'如果数组只是一个地址,并且通过在该地址上分配来初始化,那么将有两个不同的数组在两个不同的位置初始化,并且将指向它们的指针放在一个并集中将意味着其中一个被覆盖,现在你在某个地方有一个你不能访问的数组。
因此,当所有这些集合在一起时,数组的并集基本上有一个数组,它有两种不同的访问数据的方法(如果我没有弄错的话,这就是你想要的)。

#include <stdio.h>
int main(void) {
    union {
        int arr1[4];
        int arr2[2][2];
    } u;
    u.arr1[0] = 1;
    u.arr1[1] = 2;
    u.arr1[2] = 3;
    u.arr1[3] = 4;
    printf("%d %d\n%d %d\n", u.arr2[0][0], u.arr2[0][1], u.arr2[1][0], u.arr2[1][1]);
    return 0;
}

输出量:
我们还可以快速地了解为什么纯指针不能使用这种方法。假设我们有一个如下的联合:

union {
    int* arr1;
    int** arr2;
} u;

然后我们可以用u.arr1 = (int*) malloc(4 * sizeof (int));初始化。然后我们可以像普通数组一样使用arr1。但是当我们尝试使用arr2时会发生什么呢?好吧,arr2[y][x]当然是*(*(arr2+y)+x))的语法糖。一旦它第一次被解引用,我们现在有一个int,因为地址指向一个int型,所以当我们把x加到这个int型上,然后再解引用它的时候,我们就是在解引用一个int型,C会尝试这样做,如果你运气不好的话,它会成功的;我说unluggy是因为这样你就会扰乱任意的内存,更有可能的是segfault,因为不管int是什么,很可能不是你的程序可以访问的地址。

相关问题