我有一个函数concat
来连接矩阵mat1
以形成mat2
。这里mat1
和mat2
使用固定尺寸(即DIM1 = 2,DIM2 = 2,DIM3 = 3,DIM1_1 = 4),但实际上我需要它们具有可变尺寸,因此我声明了尺寸3d数组的最大大小,如下面我的代码所述(即DIM2 = 20,DIM3 = 30),但是当我这样做时,程序会给出垃圾值。有人可以建议不使用malloc()如何使用可变大小的3d数组吗?
#include <stdio.h>
#include <string.h>
//!< Dimensions of a 3d array
#define DIM1 2
#define DIM2 2
#define DIM3 3
#define DIM1_1 4
void Concat(int (*mat1)[DIM2][DIM3], int (*mat2)[DIM2][DIM3], int len);
// void Concat(int (*mat1)[20][30], int (*mat2)[20][30], int len);
int main()
{
int mat1[DIM1][DIM2][DIM3] = {{{1,2,3},{4,5,6}},{{1,2,3},{4,5,6}}};
int mat2[DIM1_1][DIM2][DIM3];
Concat(mat1,mat2,2);
return 0;
}
// void Concat(int (*mat1)[20][30], int (*mat2)[20][30], int len){
void Concat(int (*mat1)[DIM2][DIM3], int (*mat2)[DIM2][DIM3], int len){
/*concatenate mat1 to mat2 */
memcpy(mat2[0], mat1, DIM1*DIM2*DIM3 * sizeof mat1);
memcpy(mat2[0+len], mat1, DIM1*DIM2*DIM3 * sizeof mat1);
}
答案 0 :(得分:2)
很抱歉,但是无法完成(事先不知道最大长度)。当您的函数生成mat1
时,它将在数组的堆栈上精确地保留2*2*3
int
s的内存,并将每个子数组紧挨着。如果是静态分配的,则无法在完成后对其进行更改。
但是 ...通过动态内存分配(即malloc
和朋友)可以做到这一点。具体来说,使用realloc
分配额外的空间。
对不起。
答案 1 :(得分:2)
我在下面的代码中声明将3d数组的大小声明为最大大小(即DIM2 = 20,DIM3 = 30),但是程序执行此操作时会给出垃圾值。
我希望在运行时获取垃圾值之前,编译器警告您有关以这种方式创建的类型不匹配的信息。如果没有,那么通过弄清楚如何提高警告级别或选择一个更有用的编译器,将对您很有帮助。
无论哪种方式,Concat()
函数的参数都是指向特定尺寸的2D数组的指针。如果实际参数是指向其他内容(甚至是维数不同的数组)的指针,那么结果差就不足为奇了。实际上,这违反了所谓的“严格别名规则”,因此行为是不确定的。
有人可以建议不使用malloc()如何使用可变大小的3d数组吗?
我的解释是,您想要一个单一的函数可用于各种尺寸的数组,而不是任何单个数组的尺寸都会随时间变化。您可以做几件事,但是这里有一些不错的选择:
如果您的实现支持VLA (在C99中是必需的,但自C11起是可选的),则可以使用它们来支持Concat()
功能。这种东西是我最喜欢的VLA用法之一,因为它避免了对VLA使用的最大实际关注,它围绕着自动分配可用的空间。这样的方法可能看起来像这样:
void Concat(size_t dim1, size_t dim2, size_t dim3 int (*source)[dim2][dim3],
int (*dest)[dim2][dim3]) {
size_t source_size = dim1 * sizeof(*source);
memcpy(dest, source, source_size);
memcpy(dest + dim1, source, source_size);
}
您会注意到,这要求您将源数组的尺寸传递给 all 作为单独的参数,并且除两个数组的第一个匹配之外的所有尺寸。您将非常简单地使用它:
int mat1[DIM1][DIM2][DIM3] = /* ... */
int mat2[DIM1 * 2][DIM2][DIM3];
Concat(DIM1, DIM2, DIM3, mat1, mat2);
当然,您可以在同一程序中使用相同的函数来连接各种维数的数组对,前提是已满足已描述的约束。
如果您不能或不想依靠VLA ,那么最好的选择就是简单地使上述内容适应这种情况,就像这样:
void Concat(size_t dim1, size_t dim2, size_t dim3, void *source, void *dest) {
size_t source_size = dim1 * dim2 * dim3 * sizeof(int);
memcpy((char *) dest, source, source_size);
memcpy((char *) dest + source_size, source, source_size);
}
您可以使用与上一个相同的方式来调用该函数。
如果您想变得更通用,同时提供更简单的函数签名,则可以将以上内容转换为连接任意对象:
void Concat(size_t source_size, void *source, void *dest) {
memcpy((char *) dest, source, source_size);
memcpy((char *) dest + source_size, source, source_size);
}
这通过将调用者的职责放在计算上并传递源对象的大小(以字节为单位)来实现完全的通用性,尽管这不一定是一个大问题。例如,
int mat1[DIM1][DIM2][DIM3] = /* ... */
int mat2[DIM1 * 2][DIM2][DIM3];
Concat(sizeof(mat1), mat1, mat2);