我用两种不同的方式在C中创建了两个2D数组(矩阵) 我不明白它们在记忆中表现的方式与我不能以同样方式引用它们的原因之间的区别:
scanf("%d", &intMatrix1[i][j]); //can't refer as &intMatrix1[(i * lines)+j])
scanf("%d", &intMatrix2[(i * lines)+j]); //can't refer as &intMatrix2[i][j])
实现这两个数组的方式之间有什么区别?为什么我必须以不同方式引用它们?
如何以相同的方式引用每个数组中的元素(??????
函数中的printMatrix
)?
int main()
{
int **intMatrix1;
int *intMatrix2;
int i, j, lines, columns;
lines = 3;
columns = 2;
/************************* intMatrix1 ****************************/
intMatrix1 = (int **)malloc(lines * sizeof(int *));
for (i = 0; i < lines; ++i)
intMatrix1[i] = (int *)malloc(columns * sizeof(int));
for (i = 0; i < lines; ++i)
{
for (j = 0; j < columns; ++j)
{
printf("Type a number for intMatrix1[%d][%d]\t", i, j);
scanf("%d", &intMatrix1[i][j]);
}
}
/************************* intMatrix2 ****************************/
intMatrix2 = (int *)malloc(lines * columns * sizeof(int));
for (i = 0; i < lines; ++i)
{
for (j = 0; j < columns; ++j)
{
printf("Type a number for intMatrix2[%d][%d]\t", i, j);
scanf("%d", &intMatrix2[(i * lines)+j]);
}
}
/************** printing intMatrix1 & intMatrix2 ****************/
printf("intMatrix1:\n\n");
printMatrix(*intMatrix1, lines, columns);
printf("intMatrix2:\n\n");
printMatrix(intMatrix2, lines, columns);
}
/************************* printMatrix ****************************/
void printMatrix(int *ptArray, int h, int w)
{
int i, j;
printf("Printing matrix...\n\n\n");
for (i = 0; i < h; ++i)
for (j = 0; j < w; ++j)
printf("array[%d][%d] ==============> %d\n, i, j, ??????);
}
答案 0 :(得分:5)
您要取消引用Matrix1
两次..
Matrix1[i][j] ;
这意味着它是一个2D数组或一个像这样声明的双指针。
int **Matrix1 ;
可以将double pointer
视为指针数组。它的每个元素都是一个指针本身,所以它被解除引用一次到达指针元素,并且解引用两次以访问该成员指针或数组的数据成员。你写的这句话等同于这个......
Matrix1[i][j] ; //is ~ to
*( *(Matrix1 + i) + j) ;
对于像这样的单个指针。
int *Matrix2 ;
你可以这样只去一次。
Matrix2[i] ; //is ~ to
*(Matrix2 + i) ;
你写的这句话..
Matrix2[(i * lines)+j] ;
|-----------|
此部分评估为单个数字,因此它会反驳一次。
(i * lines) + j ;
对于printmatrix()
函数,传递给它的ptArray
是一个指针。所以你不能两次取消引用它。
也许你可以从我的答案中更好地理解静态和动态2D数组。
答案 1 :(得分:3)
两个矩阵都是内存中的字节序列。但是,它们之间的区别在于您如何定义用于表示矩阵的内存接口。在一种情况下,您只是定义一个内存段,其中的元素数等于矩阵中的元素,而在另一种情况下,您将专门分配内存来表示每个特定的行。
以下情况在计算上更昂贵,因为您更多次调用 malloc():
intMatrix1 = (int **)malloc(lines * sizeof(int *));
for (i = 0; i < lines; ++i)
intMatrix1[i] = (int *)malloc(columns * sizeof(int));
然而,它带来的优点是您可以更清晰地参考矩阵元素:
intMatrix1[i][j];
如果你只是分配一个元素序列等于矩阵中元素的数量,你必须考虑行/列索引计算来引用内存中正确的矩阵元素。
为了尝试提高代码的一致性程度,我可以建议一个接收矩阵行参考和矩阵列数的函数并打印一行吗?
void PrintLine(int *ptrLine, int lineLen) {
unsigned int i;
for(i = 0; i < lineLen; i++)
printf("%d ", ptrLine[i]);
printf("\n");
}
然后,对于每种矩阵类型,您只需:
// Case 1
for(i = 0; i < lines; i++)
PrintLine(intMatrix1[i], columns);
// Case 2
for(i = 0; i < lines; i++) {
PrintLine(intMatrix2 + i*columns, columns);
}
答案 2 :(得分:2)
区别在于第一个数组:
intMatrix1 = (int **)malloc(lines * sizeof(int *));
创建一个指针数组intMatrix1
。这些指针中的每一个都指向一个int数组(这里你是malloc)。
for (i = 0; i < lines; ++i)
intMatrix1[i] = (int *)malloc(columns * sizeof(int));
这就是为什么你需要声明中的2星(取消引用指针数组,然后是int数组)和双括号来访问单个元素:
int **intMatrix1;
int i = intMatrix[row][column];
int i = *(*(intmatrix + row) + column);
对于第二个矩阵,只创建一个大小为*行的int数组。
int *intMatrix2 = (int *)malloc(lines * columns * sizeof(int));
int i = intMatrix[row + column];
int i = *(intMatrix + row + column);
要打印2个数组,您必须使用不同的打印功能,因为2矩阵的内部结构不同,但您已经知道访问这两个数组的不同方法。
答案 3 :(得分:2)
在C中,数组访问运算符[]
实际上只是执行pointer arithmetic的一种更简洁的方法。对于type_s
类型的一维元素数组,arr[i]
相当于*(arr + (i * sizeof(type_s)))
。剖析那个表达:
arr
将是基地址,即存储此数组的最低内存地址i
是数组sizeof
返回char
中的一个元素占用arr
的数量(通常与字节数相同,但不是C规范强制要求)在记忆中。编译器将确定元素的大小,并负责为您执行此数学运算。作为旁注,这种语法的副作用是arr[i]
等同于i[arr]
,尽管将索引放在括号中是普遍接受的。
所有这些都说明了,让我们来看看两个声明之间的差异:
intMatrix1[i][j]
相当于*(*(intMatrix1 + i * sizeof(int)) + j * sizeof(int))
。因此,该表达式中有两个解除引用运算符,这意味着intMatrix是一个数组数组(它包含指针指针)。
另一方面,intMatrix2[(i * lines)+j]
相当于*(intMatrix2 + ((i * lines) + j) * sizeof(int))
,它只包含一个解除引用运算符。你在这里做的是定义一维数组,其中包含与原始二维数组相同数量的元素。如果您的数据最好用矩阵表示,那么我建议您使用第一个版本:intMatrix1[i][j]
。