为什么我的二维数组有如此奇怪的行为?
Why does my 2D array have such strange behavior?
编辑:代码已根据其中一个答案进行了更新,但仍然出现同样的问题。
我最近遇到了 C 中的多维数组并将它们作为参数传递的问题。我正在使用一个指针数组来模拟多维数组。数组中的每个指针都指向另一个包含行中值的数组。
我为矩阵创建了一个结构,其中包含指针数组以及行数和列数。指针数组实际上只是指向指针的指针。我发现您可以采用任何具有非 void 数据类型的指针并将其用作数组。
主 C 文件非常基本,实际上只是几个函数调用。
#include <stdio.h>
#include <stdlib.h>
#include "matrix.h"
int main() {
float myData[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
puts("going to create matrix");
matrix myMatrix = createMatrix(3, 3, myData);
puts("matrix created");
printf("Pointer to array of pointers:\n%p\n", myMatrix.data);
puts("Pointers to rows:");
int i;
for(i = 0; i < myMatrix.rows; i++) {
printf("%p\n", myMatrix.data[i]);
}
puts("going to print matrix");
printMatrix(myMatrix);
puts("printed matrix");
return 0;
}
实际的矩阵编程在头文件中:
//matrix.h
#pragma once
typedef struct matrix {
int columns;
int rows;
float **data;
} matrix;
matrix createMatrix(int columns, int rows, float initialData[]) {
//allocate struct
matrix *newMatrix = malloc(matrix);
if(newMatrix == NULL) puts("struct allocation failed");
memset(newMatrix, 0, sizeof(*newMatrix));
newMatrix -> columns = columns;
newMatrix -> rows = rows;
//create initial data if none is given
if(initialData == NULL) {
initialData = malloc(sizeof(float) * columns * rows);
if(initialData == NULL) puts("Array allocation for initial data failed");
memset(initialData, 0, sizeof(*initialData) * columns * rows);
}
//get the elements of each row
float **rowPointers;
rowPointers = malloc(sizeof(float) * rows);
if(rowPointers == NULL) puts("Array allocation for pointers failed");
memset(rowPointers, 0, sizeof(float) * rows);
float *rowData;
int i;
int j;
for(i = 0; i < rows; i++) {
printf("On row: %i\n", i + 1);
//allocate data to store row data
rowData = malloc(sizeof(*rowData) * columns); //create array for row and record pointer
if(rowData == NULL) printf("Array allocation for matrix row %i failed", i + 1);
memset(rowData, 0, sizeof(*rowData) * columns);
rowPointers[i] = rowData; //store pointer to row data
for(j = 0; j < columns; j++) {
rowData[j] = initialData[(i * columns) + j];
printf("%f ", rowPointers[i][j]);
}
printf("\n");
}
newMatrix -> data = rowPointers;
return *newMatrix;
}
void printMatrix(matrix matrix) {
printf("Confirming pointer to array of pointers:\n%p\n", matrix.data);
int i;
puts("Confirming pointers to rows:");
for(i = 0; i < matrix.rows; i++) {
printf("%p\n", matrix.data[i]);
}
int j;
for(int i = 0; i < matrix.rows; i++) {
printf("On row: %i\n", i + 1);
for(int j = 0; j < matrix.columns; j++) {
printf("%f ", matrix.data[i][j]);
}
printf("\n");
}
}
到目前为止,几乎一切正常。创建矩阵所涉及的一切都有效。我什至可以打印矩阵中的大部分数据。 大部分 的数据。运行代码给出输出:
going to create matrix
On row: 1
1.000000 2.000000 3.000000
On row: 2
4.000000 5.000000 6.000000
On row: 3
7.000000 8.000000 9.000000
matrix created
Pointer to array of pointers:
0x7f9a9ad00020
Pointers to rows:
0x7f9a9ad00030
0x7f9a9ad000e0
0x7f9a9ad000f0
going to print matrix
Confirming pointer to array of pointers:
0x7f9a9ad00020
Confirming pointers to rows:
0x7f9a9ad00030
0x7f9a9ad000e0
0x7f9a9ad000f0
On row: 1
-0.000000 0.000000 3.000000
On row: 2
4.000000 5.000000 6.000000
On row: 3
7.000000 8.000000 9.000000
printed matrix
如您所见,第 2 行和第 3 行中的所有内容都可以正确打印,甚至第 1 行中的第 3 列也可以正确打印。我觉得很奇怪,在第 1 行中,第 1 列和第 2 列不正确,但第 3 列正确。如果您查看指向行的指针,您会注意到在内存中第 1 行与第 2 行的距离比第 2 行与第 3 行的距离远得多。每次我运行它时都是如此。第 1 行始终与第 2 行相距 0x70,第 2 行始终与第 2 行相距 0x10。
不一致的是第 1 行第 1 列的数据。它并不总是 -0。有时它是一个非常大的数字,有时是一个非常小的数字。但是第 1 行第 2 列的数据始终为 0。
其他输出示例:
On row: 1
1704328922398720.000000 0.000000 3.000000
On row: 2
4.000000 5.000000 6.000000
On row: 3
7.000000 8.000000 9.000000
printed matrix
我一直无法解决这个问题,而且根据打印语句中的所有信息,我也不知道是什么原因造成的。为什么矩阵中的前两个元素打印错误,为什么第 1 行在内存中总是离第 2 行那么远?
A struct
可能包含成员之间的填充以保持内存对齐。这意味着 struct
的大小并不总是与其成员的大小之和相同。
因此,在 createMatrix()
中,这一行:
matrix *newMatrix = malloc((sizeof(int) * 2) + (sizeof(float*) * rows));
...应该是:
matrix *newMatrix = malloc(sizeof(matrix));
另请注意,您 float **
已经是 matrix
类型的一部分,并且
它指向的 float *
数组稍后动态分配,因此您不需要
为此处的行指针添加额外的 space。
在传递 NULL
时分配 initialData
后的 memset()
仅将第一行归零——应将其更改为:
memset(initialData, 0, sizeof(*initialData) * rows * columns);
分配行指针数组时,使用错误的类型计算大小。所以这个:
rowPointers = malloc(sizeof(float) * columns);
应该是:
rowPointers = malloc(sizeof(float *) * rows);
并且以下 memset 应更改为:
memset(rowPointers, 0, sizeof(float *) * rows);
此外,在createMatrix()
中,你应该free(initialData)
if你在函数中分配了它(即. 如果 NULL
通过了)。请记住,在释放 matrix
对象时,您需要循环 free()
每一行,然后是行数组,然后是实际的 matrix
结构——因此您可能希望为此写一个函数。
您还通过在 createMatrix
中动态分配 return 值 matrix
结构来泄漏内存 - 所以 malloc()
ed 结构被泄漏尽管为 return 复制了内容。要修复它,您应该 return 指向动态分配结构的指针,或者修改函数以使用本地 matrix
变量而不是动态分配的变量。要以对代码进行最少的更改来做到这一点,您可以使用:
matrix newMatrixStruct;
matrix *newMatrix = &newMatrixStruct;
而不是声明和 malloc()
s newMatrix
.
的行
经过大量修改代码后,我能够解决自己的问题。
在意识到必须通过 matrix.data[y][x]
而不是 matrix.data[x][y]
访问矩阵的元素后,我切换了行和列。我发现了一些列和行混淆的地方,但在 3x3 矩阵中,它不会有什么不同。
我改变了创建结构的整个方式。我不再使用 malloc 先分配它然后用数据填充它而是这样做的:
newMatrix {columns, rows, malloc(sizeof(float*) * columns)};
我之前使用 malloc 来分配结构,因为我在我的结构中为指针数组腾出空间,但是 malloc 会随机分配空间并给我指向它分配内存的位置的指针。我想我对指针和数组之间的界限感到困惑。
我还使用 newMatrix.data
来引用指针数组,而不是创建数组 rowData[rows]
,然后将指向行数据的指针存储在 newMatrix.data
中。我想我在那里又混淆了指针和数组。
因为我改变了行和列,所以数组 matrix.data
中的指针不再指向行数据的数组,而是现在指向列的数组。
matrix.h
修复后变成这样:
#pragma once
typedef struct matrix {
int columns;
int rows;
float **data;
} matrix;
matrix createMatrix(int columns, int rows, float initialData[]) {
//create struct struct
matrix newMatrix = {
columns,
rows,
malloc(sizeof(float*) * columns) //create array of pointers and store the pointer to it
};
if(newMatrix.data == NULL) puts("pointer array allocation failed");
memset(newMatrix.data, 0, sizeof(float*) * columns);
//create initial data if none is given
if(initialData == NULL) {
initialData = malloc(sizeof(float) * columns * rows);
if(initialData == NULL) puts("Array allocation for initial data failed");
memset(initialData, 0, sizeof(float) * columns * rows);
}
//get the elements of each column
float *columnData;
int i;
int j;
for(i = 0; i < columns; i++) {
printf("On column: %i\n", i + 1);
//allocate data to store column data
columnData = malloc(sizeof(float) * rows); //create array for column and record pointer
if(columnData == NULL) printf("Array allocation for matrix column %i failed", i + 1);
memset(columnData, 0, sizeof(float) * rows);
newMatrix.data[i] = columnData; //store pointer to column data
for(j = 0; j < rows; j++) {
columnData[j] = initialData[(j * columns) + i];
printf("%f ", newMatrix.data[i][j]);
}
printf("\n");
}
return newMatrix;
}
void printMatrix(matrix matrix) {
printf("Confirming pointer to array of pointers:\n%p\n", matrix.data);
int i;
puts("Confirming pointers to columns:");
for(i = 0; i < matrix.columns; i++) {
printf("%p\n", matrix.data[i]);
}
int j;
for(int i = 0; i < matrix.rows; i++) {
printf("On row: %i\n", i + 1);
for(int j = 0; j < matrix.columns; j++) {
printf("%f ", matrix.data[j][i]);
}
printf("\n");
}
}
请注意,如果传递 NULL
,我仍然没有解除分配矩阵并修复分配 initialData
时导致的内存泄漏,但这不是问题的一部分.
主文件中唯一更改的行是:
for(i = 0; i < myMatrix.rows; i++) {
改为:
for(i = 0; i < myMatrix.columns; i++) {
在记忆中,第 1 列与第 2 列的距离仍然比第 2 列与第 3 列的距离更远,我仍然不知道为什么,但它不影响我的代码。访问矩阵元素的问题只是让我混淆了数组和指针,并在我尝试修复它们时弄得一团糟。
编辑:代码已根据其中一个答案进行了更新,但仍然出现同样的问题。
我最近遇到了 C 中的多维数组并将它们作为参数传递的问题。我正在使用一个指针数组来模拟多维数组。数组中的每个指针都指向另一个包含行中值的数组。
我为矩阵创建了一个结构,其中包含指针数组以及行数和列数。指针数组实际上只是指向指针的指针。我发现您可以采用任何具有非 void 数据类型的指针并将其用作数组。
主 C 文件非常基本,实际上只是几个函数调用。
#include <stdio.h>
#include <stdlib.h>
#include "matrix.h"
int main() {
float myData[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
puts("going to create matrix");
matrix myMatrix = createMatrix(3, 3, myData);
puts("matrix created");
printf("Pointer to array of pointers:\n%p\n", myMatrix.data);
puts("Pointers to rows:");
int i;
for(i = 0; i < myMatrix.rows; i++) {
printf("%p\n", myMatrix.data[i]);
}
puts("going to print matrix");
printMatrix(myMatrix);
puts("printed matrix");
return 0;
}
实际的矩阵编程在头文件中:
//matrix.h
#pragma once
typedef struct matrix {
int columns;
int rows;
float **data;
} matrix;
matrix createMatrix(int columns, int rows, float initialData[]) {
//allocate struct
matrix *newMatrix = malloc(matrix);
if(newMatrix == NULL) puts("struct allocation failed");
memset(newMatrix, 0, sizeof(*newMatrix));
newMatrix -> columns = columns;
newMatrix -> rows = rows;
//create initial data if none is given
if(initialData == NULL) {
initialData = malloc(sizeof(float) * columns * rows);
if(initialData == NULL) puts("Array allocation for initial data failed");
memset(initialData, 0, sizeof(*initialData) * columns * rows);
}
//get the elements of each row
float **rowPointers;
rowPointers = malloc(sizeof(float) * rows);
if(rowPointers == NULL) puts("Array allocation for pointers failed");
memset(rowPointers, 0, sizeof(float) * rows);
float *rowData;
int i;
int j;
for(i = 0; i < rows; i++) {
printf("On row: %i\n", i + 1);
//allocate data to store row data
rowData = malloc(sizeof(*rowData) * columns); //create array for row and record pointer
if(rowData == NULL) printf("Array allocation for matrix row %i failed", i + 1);
memset(rowData, 0, sizeof(*rowData) * columns);
rowPointers[i] = rowData; //store pointer to row data
for(j = 0; j < columns; j++) {
rowData[j] = initialData[(i * columns) + j];
printf("%f ", rowPointers[i][j]);
}
printf("\n");
}
newMatrix -> data = rowPointers;
return *newMatrix;
}
void printMatrix(matrix matrix) {
printf("Confirming pointer to array of pointers:\n%p\n", matrix.data);
int i;
puts("Confirming pointers to rows:");
for(i = 0; i < matrix.rows; i++) {
printf("%p\n", matrix.data[i]);
}
int j;
for(int i = 0; i < matrix.rows; i++) {
printf("On row: %i\n", i + 1);
for(int j = 0; j < matrix.columns; j++) {
printf("%f ", matrix.data[i][j]);
}
printf("\n");
}
}
到目前为止,几乎一切正常。创建矩阵所涉及的一切都有效。我什至可以打印矩阵中的大部分数据。 大部分 的数据。运行代码给出输出:
going to create matrix
On row: 1
1.000000 2.000000 3.000000
On row: 2
4.000000 5.000000 6.000000
On row: 3
7.000000 8.000000 9.000000
matrix created
Pointer to array of pointers:
0x7f9a9ad00020
Pointers to rows:
0x7f9a9ad00030
0x7f9a9ad000e0
0x7f9a9ad000f0
going to print matrix
Confirming pointer to array of pointers:
0x7f9a9ad00020
Confirming pointers to rows:
0x7f9a9ad00030
0x7f9a9ad000e0
0x7f9a9ad000f0
On row: 1
-0.000000 0.000000 3.000000
On row: 2
4.000000 5.000000 6.000000
On row: 3
7.000000 8.000000 9.000000
printed matrix
如您所见,第 2 行和第 3 行中的所有内容都可以正确打印,甚至第 1 行中的第 3 列也可以正确打印。我觉得很奇怪,在第 1 行中,第 1 列和第 2 列不正确,但第 3 列正确。如果您查看指向行的指针,您会注意到在内存中第 1 行与第 2 行的距离比第 2 行与第 3 行的距离远得多。每次我运行它时都是如此。第 1 行始终与第 2 行相距 0x70,第 2 行始终与第 2 行相距 0x10。
不一致的是第 1 行第 1 列的数据。它并不总是 -0。有时它是一个非常大的数字,有时是一个非常小的数字。但是第 1 行第 2 列的数据始终为 0。
其他输出示例:
On row: 1
1704328922398720.000000 0.000000 3.000000
On row: 2
4.000000 5.000000 6.000000
On row: 3
7.000000 8.000000 9.000000
printed matrix
我一直无法解决这个问题,而且根据打印语句中的所有信息,我也不知道是什么原因造成的。为什么矩阵中的前两个元素打印错误,为什么第 1 行在内存中总是离第 2 行那么远?
A struct
可能包含成员之间的填充以保持内存对齐。这意味着 struct
的大小并不总是与其成员的大小之和相同。
因此,在 createMatrix()
中,这一行:
matrix *newMatrix = malloc((sizeof(int) * 2) + (sizeof(float*) * rows));
...应该是:
matrix *newMatrix = malloc(sizeof(matrix));
另请注意,您 float **
已经是 matrix
类型的一部分,并且
它指向的 float *
数组稍后动态分配,因此您不需要
为此处的行指针添加额外的 space。
在传递 NULL
时分配 initialData
后的 memset()
仅将第一行归零——应将其更改为:
memset(initialData, 0, sizeof(*initialData) * rows * columns);
分配行指针数组时,使用错误的类型计算大小。所以这个:
rowPointers = malloc(sizeof(float) * columns);
应该是:
rowPointers = malloc(sizeof(float *) * rows);
并且以下 memset 应更改为:
memset(rowPointers, 0, sizeof(float *) * rows);
此外,在createMatrix()
中,你应该free(initialData)
if你在函数中分配了它(即. 如果 NULL
通过了)。请记住,在释放 matrix
对象时,您需要循环 free()
每一行,然后是行数组,然后是实际的 matrix
结构——因此您可能希望为此写一个函数。
您还通过在 createMatrix
中动态分配 return 值 matrix
结构来泄漏内存 - 所以 malloc()
ed 结构被泄漏尽管为 return 复制了内容。要修复它,您应该 return 指向动态分配结构的指针,或者修改函数以使用本地 matrix
变量而不是动态分配的变量。要以对代码进行最少的更改来做到这一点,您可以使用:
matrix newMatrixStruct;
matrix *newMatrix = &newMatrixStruct;
而不是声明和 malloc()
s newMatrix
.
经过大量修改代码后,我能够解决自己的问题。
在意识到必须通过 matrix.data[y][x]
而不是 matrix.data[x][y]
访问矩阵的元素后,我切换了行和列。我发现了一些列和行混淆的地方,但在 3x3 矩阵中,它不会有什么不同。
我改变了创建结构的整个方式。我不再使用 malloc 先分配它然后用数据填充它而是这样做的:
newMatrix {columns, rows, malloc(sizeof(float*) * columns)};
我之前使用 malloc 来分配结构,因为我在我的结构中为指针数组腾出空间,但是 malloc 会随机分配空间并给我指向它分配内存的位置的指针。我想我对指针和数组之间的界限感到困惑。
我还使用 newMatrix.data
来引用指针数组,而不是创建数组 rowData[rows]
,然后将指向行数据的指针存储在 newMatrix.data
中。我想我在那里又混淆了指针和数组。
因为我改变了行和列,所以数组 matrix.data
中的指针不再指向行数据的数组,而是现在指向列的数组。
matrix.h
修复后变成这样:
#pragma once
typedef struct matrix {
int columns;
int rows;
float **data;
} matrix;
matrix createMatrix(int columns, int rows, float initialData[]) {
//create struct struct
matrix newMatrix = {
columns,
rows,
malloc(sizeof(float*) * columns) //create array of pointers and store the pointer to it
};
if(newMatrix.data == NULL) puts("pointer array allocation failed");
memset(newMatrix.data, 0, sizeof(float*) * columns);
//create initial data if none is given
if(initialData == NULL) {
initialData = malloc(sizeof(float) * columns * rows);
if(initialData == NULL) puts("Array allocation for initial data failed");
memset(initialData, 0, sizeof(float) * columns * rows);
}
//get the elements of each column
float *columnData;
int i;
int j;
for(i = 0; i < columns; i++) {
printf("On column: %i\n", i + 1);
//allocate data to store column data
columnData = malloc(sizeof(float) * rows); //create array for column and record pointer
if(columnData == NULL) printf("Array allocation for matrix column %i failed", i + 1);
memset(columnData, 0, sizeof(float) * rows);
newMatrix.data[i] = columnData; //store pointer to column data
for(j = 0; j < rows; j++) {
columnData[j] = initialData[(j * columns) + i];
printf("%f ", newMatrix.data[i][j]);
}
printf("\n");
}
return newMatrix;
}
void printMatrix(matrix matrix) {
printf("Confirming pointer to array of pointers:\n%p\n", matrix.data);
int i;
puts("Confirming pointers to columns:");
for(i = 0; i < matrix.columns; i++) {
printf("%p\n", matrix.data[i]);
}
int j;
for(int i = 0; i < matrix.rows; i++) {
printf("On row: %i\n", i + 1);
for(int j = 0; j < matrix.columns; j++) {
printf("%f ", matrix.data[j][i]);
}
printf("\n");
}
}
请注意,如果传递 NULL
,我仍然没有解除分配矩阵并修复分配 initialData
时导致的内存泄漏,但这不是问题的一部分.
主文件中唯一更改的行是:
for(i = 0; i < myMatrix.rows; i++) {
改为:
for(i = 0; i < myMatrix.columns; i++) {
在记忆中,第 1 列与第 2 列的距离仍然比第 2 列与第 3 列的距离更远,我仍然不知道为什么,但它不影响我的代码。访问矩阵元素的问题只是让我混淆了数组和指针,并在我尝试修复它们时弄得一团糟。