我正在尝试创建3个矩阵,这些矩阵是动态类型化的(int,float,double),用于矩阵乘法。我创造了一个虚空**"打字" main中每个矩阵的容器,然后根据用户对类型的选择将它们(作为void ***)传递到init函数中以进行malloc。下面的代码编译,但是我在j循环的一次迭代后得到了一个分段错误,我无法弄清楚为什么会发生这种情况。类似地,如果我在一个单独的2-deep循环中进行初始化(从malloc循环中取出j-loop),那么在i-loop的一次迭代之后仍然会发生分段错误。
这是实现动态类型矩阵乘法目标的好方法吗?非常感谢您的帮助。
void initMat(int type, int matSize, void ***matA, void ***matB, void ***matC)
{
int i, j, k;
switch(type) {
case 0 :
*matA = malloc(matSize * sizeof(int*));
*matB = malloc(matSize * sizeof(int*));
*matC = malloc(matSize * sizeof(int*));
for (i = 0; i < matSize; i++) {
*matA[i] = malloc(matSize * sizeof(int));
*matB[i] = malloc(matSize * sizeof(int));
*matC[i] = malloc(matSize * sizeof(int));
for (j = 0; j < matSize; j++) {
*(int*)matA[i][j] = rand()/RAND_MAX * 10;
*(int*)matB[i][j] = rand()/RAND_MAX * 10;
*(int*)matC[i][j] = 0;
}
}
break;
case 1 :
// with float, double, etc.
break;
default :
printf("Invalid case.\n" );
}
}
int main()
{
int type = 0;
int size = 0;
void **matA, **matB, **matC;
int sizes[6] = {3, 4, 5};
int matSize = sizes[size];
printf("The selected matrix size is: %d. \n", matSize); //allows user to select matrix size
initMat(type, matSize, &matA, &matB, &matC);
// displayMat(matSize, matA);
}
答案 0 :(得分:1)
我自己一直在做一些完全相同的事情。我对如何做到这一点的建议是实际上放弃你做这件事的方式。从它的外观来看,你有一个指针数组(比如一个int指针数组),这些指针中的每一个都有一个自己的数组,基本上是一个声明为int **exampleMatrix
的变量。实际上这是一个很大的问题,你这样做就是缓存未命中。更好的方法是:
#include <stdlib.h>
void *initMat(size_t rows, size_t cols, int type);
int main(void){
int *matrix = initMat();
free(matrix);
return 0;
}
void *initMat(size_t rows, size_t cols, int type){
//check for what type to allocate here
void *matrix = malloc(sizeof(int)*rows*cols);
//check for errors here
return matrix;
}
你当然必须决定你的矩阵是行还是列。我希望这是有道理的,英语不是我的第一语言,而且我有时并不是最好的解释。如果您需要我解释一下,请告诉我:)
答案 1 :(得分:1)
要使用动态分配的2d数组,应使用正确的指针类型。 (int **)
是指向指针的指针,指向指针数组的第一个元素,这些指针本身指向不同的分配。这种代码的结果是锯齿状数组,但不是2d数组。分配的内存不保证是连续的(因为数组分配必须是):
size_t num_rows = 3;
size_t num_cols = 5;
int **jagged_arr = malloc(sizeof *jagged_arr * num_rows);
for (size_t i = 0; i < num_rows; i++) {
jagged_arr[i] = malloc(sizeof *jagged_arr[i] * num_cols);
}
一种可能性是简单地为1d数组分配存储,并从2d数组索引计算该数组的偏移量。这很好,但结果不是二维数组:
size_t num_elems = num_rows * num_cols;
int *simulated_2d_arr = malloc(sizeof *simulated_2d_arr * num_elems);
这不能被索引为2d数组,但是1d索引可以根据列数和2d数组索引计算:
for (size_t i = 0; i < num_rows; i++) {
for (size_t j = 0; j < num_cols; j++) {
simulated_2d_arr[i * num_cols + j] = i * num_cols + j;
}
}
这两种方法都有它们的用途,但是它们的缺点是不能将得到的数组传递给用于2d数组的函数。也就是说,考虑打印二维数组的函数,例如:
void print_2d_arr(size_t rows, size_t cols, int arr[][cols])
{
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
printf("%5d", arr[i][j]);
}
putchar('\n');
}
}
此功能适用于:
int real_2d_arr[2][3] = { { 1, 2, 3 },
{ 4, 5, 6 } };
但它不适用于早期的jagged_arr
:
预期'int(*)[(sizetype)(cols)]'但参数的类型为'int **'
或simulated_2d_arr
:
期望'int(*)[(sizetype)(cols)]'但参数的类型为'int *'
在上面的错误消息中可以看到动态分配2d数组时使用的正确类型。对于int
s的二维数组,这将是int (*)[]
。这是二维数组在大多数表达式中衰减的类型,包括函数调用。因此,要动态分配int
的2d数组,这将起作用:
size_t num_rows = 3;
size_t num_cols = 5;
int (*array_2d)[num_cols] = malloc(sizeof *array_2d * num_rows);
这会为num_rows
num_cols
的{{1}}数组分配空间。请注意,这不会创建VLA,但会使用VLA 类型。当然,VGA是在C99中引入的,但在C11中是可选的(尽管仍然得到广泛的支持)。
对于问题的动态类型部分,一个选项是创建一个int
来保存类型标识符,并将这些枚举常量之一传递给任何需要它们的函数。这些函数需要接受enum
个参数,这些参数将根据类型枚举常量进行适当的转换。这是一个更多的参与,但这是一个示例程序。请注意,(void *)
函数既适用于动态分配的数组,也适用于静态大小的数组。另请注意,不需要三重甚至双重间接!
print_array()
节目输出:
#include <stdio.h>
#include <stdlib.h>
enum Type { CHAR,
INT,
FLOAT,
DOUBLE };
void * get_array(enum Type type, size_t rows, size_t cols);
void init_array(enum Type type, size_t rows, size_t cols, void *arr);
void print_array(enum Type type, size_t rows, size_t cols, void *arr);
int main(void)
{
char (*arr_char)[5] = get_array(CHAR, 4, 5);
int (*arr_int)[5] = get_array(INT, 4, 5);
double (*arr_double)[5] = get_array(DOUBLE, 4, 5);
int arr_static[][3] = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };
if (arr_char) { // check for null pointer
init_array(CHAR, 4, 5, arr_char);
puts("4x5 array of char");
print_array(CHAR, 4, 5, arr_char);
putchar('\n');
}
if (arr_int) { // check for null pointer
init_array(INT, 4, 5, arr_int);
puts("4x5 array of int");
print_array(INT, 4, 5, arr_int);
putchar('\n');
}
if (arr_double) { // check for null pointer
init_array(DOUBLE, 4, 5, arr_double);
puts("4x5 array of double");
print_array(DOUBLE, 4, 5, arr_double);
putchar('\n');
}
puts("Statically sized 3x3 array of int");
print_array(INT, 3, 3, arr_static);
putchar('\n');
/* Cleanup */
free(arr_char);
free(arr_int);
free(arr_double);
return 0;
}
/* Returns null pointer on allocation failure */
void *get_array(enum Type type, size_t rows, size_t cols)
{
size_t array_sz = 0;
void *ret = NULL;
switch (type) {
case CHAR:
array_sz = sizeof (char) * rows * cols;
break;
case INT:
array_sz = sizeof (int) * rows * cols;
break;
case FLOAT:
array_sz = sizeof (float) * rows * cols;
break;
case DOUBLE:
array_sz = sizeof (double) * rows * cols;
break;
default:
fprintf(stderr, "Unrecognized type in get_array()");
}
if (array_sz) {
ret = malloc(array_sz);
}
return ret;
}
void init_array(enum Type type, size_t rows, size_t cols, void *arr)
{
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
int offset = i * cols + j;
switch (type) {
case CHAR:
{
char (*array_char)[cols] = arr;
array_char[i][j] = 'a' + offset;
break;
}
case INT:
{
int (*array_int)[cols] = arr;
array_int[i][j] = 0 + offset;
break;
}
case FLOAT:
{
float (*array_float)[cols] = arr;
array_float[i][j] = 0.0 + offset;
break;
}
case DOUBLE:
{
double (*array_double)[cols] = arr;
array_double[i][j] = 0.0 + offset;
break;
}
default:
fprintf(stderr, "Unrecognized type in get_array()");
}
}
}
}
void print_array(enum Type type, size_t rows, size_t cols, void *arr)
{
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
switch (type) {
case CHAR:
{
char (*array_char)[cols] = arr;
printf("%3c", array_char[i][j]);
break;
}
case INT:
{
int (*array_int)[cols] = arr;
printf("%5d", array_int[i][j]);
break;
}
case FLOAT:
{
float (*array_float)[cols] = arr;
printf("%8.2f", array_float[i][j]);
break;
}
case DOUBLE:
{
double (*array_double)[cols] = arr;
printf("%8.2f", array_double[i][j]);
break;
}
default:
fprintf(stderr, "Unrecognized type in get_array()");
}
}
putchar('\n');
}
}
答案 2 :(得分:0)
您的基本问题是后缀运算符的优先级高于前缀运算符。所以当你说
时*matA[i] = malloc(matSize * sizeof(int));
你正在
*(matA[i]) = malloc(matSize * sizeof(int));
当你想要的是什么
(*matA)[i] = malloc(matSize * sizeof(int));
因此您需要明确的括号才能使其正常工作。同样,而不是
*(int*)matA[i][j] = rand()/RAND_MAX * 10;
你需要
((int**)*matA)[i][j] = rand()/RAND_MAX * 10;
答案 3 :(得分:-1)
你分配内存的方式很奇怪。
*matA = malloc(matSize * sizeof(int*));
matA
指向哪里,除非你在这个函数之外分配了一些内存并让matA
指向它,那么你就是在捣乱你的记忆。
Malloc
返回指向已分配内存的指针,它不会在随机指针指向的任何位置分配它。
您也不需要三个级别的间接***matA
,两个就足够了。
这是你的代码,我建议的更改 - 免责声明:我实际上并没有尝试这个,但我认为它会起作用 - :
void initMat(int type, int matSize, void ***matA, void ***matB, void ***matC)
{
int i, j, k;
switch(type) {
case 0 :
*matA = malloc(matSize * sizeof(int*));
*matB = malloc(matSize * sizeof(int*));
*matC = malloc(matSize * sizeof(int*));
for (i = 0; i < matSize; i++) {
(*matA)[i] = malloc(matSize * sizeof(int));
(*matB)[i] = malloc(matSize * sizeof(int));
(*matC)[i] = malloc(matSize * sizeof(int));
for (j = 0; j < matSize; j++) {
(*matA)[i][j] = rand()/RAND_MAX * 10;
(*matB)[i][j] = rand()/RAND_MAX * 10;
(*matC)[i][j] = 0;
}
}
break;
case 1 :
// with float, double, etc.
break;
default :
printf("Invalid case.\n" );
}
}
并且在致电时:
int type,matSize;
//whatever type you like
Type **matA,**matB,**matC;
//your code here
initMat(type,matSize,&matA,&matB,&matC);
//the rest of your code here