C 中带有双指针的转置矩阵



用户输入一个二维矩阵,预期的打印输出是一个转置矩阵。对我来说,只有当我输入方阵时,比如说 2 x 2、3 x 3...... 对于"正常"矩阵,它不起作用。 有什么帮助吗?

这是我的代码:

#include<stdio.h>
#include<stdlib.h>
void Trans(int **, int, int);
int main()
{
int n, m;
int **p;
printf("Number of rows: n");
scanf("%d", &n);
printf("Nuber of columns: n");
scanf("%d", &m);
p = malloc(n * sizeof(int *));
for (int i = 0; i < n; i++)
{
p[i] = malloc(m * sizeof(int));
}
printf("Elements of matrix: n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("P[%d][%d] = ", i, j);
scanf("%d", (*(p+i)+j));
}
}
Trans(p, n, m);
return 0;
}
void Trans(int **p, int n, int m)
{
int **a;
a = malloc(m * sizeof(int *));
for (int i = 0; i < m; i++)
{
a[i] = malloc(n * sizeof(int));
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (i == j)
a[i][j] = *(*(p+i)+j);
else
a[j][i] = *(*(p+i)+j);
}
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
printf ("%d ", *(*(a+i)+j));
}
puts("");
}
return 0;
}

我看到这段代码的最大问题是它太神秘了;你的变量不是描述性的,在数组上使用指针数学而不是数组数学只会让它更难阅读。

肯定有一些地方,一个字母的变量是可以的,甚至是优越的,可以理解正在发生的事情,但是如果我不得不调试别人的代码,我宁愿他们在冗长和具体性方面犯错。

为了明确这一点,我:

  • 使变量名称具有描述性
  • 将所有指针数学更改为数组索引(通常(总是?)相同的代码生成)
  • 添加了变量以在转置函数中保存转置数组的本机范围

为了方便起见,我在代码中使用了文字值,以方便测试而不是用户输入。

以下是有助于发现此问题的主要更改:

main()

为源数组分配名称更清晰的范围变量

int num_rows, num_cols;
int** elems;
elems = (int**) malloc(num_rows * sizeof(int*));
for (int i = 0; i < num_rows; i++)
elems[i] = (int*) malloc(num_cols * sizeof(int));

转置称为

transpose_matrix(elems, num_rows, num_cols);

transpose_matrix

具有更清晰命名的范围变量的转置函数

void transpose_matrix(int* elems[], int orig_num_rows, int orig_num_cols)
{
// use variables that explicitly reference the new matrix
int num_rows = orig_num_cols;
int num_cols = orig_num_rows;

**使用目标扩展数据块分配转置的阵列 **

int** transposed_elems;
transposed_elems = (int**) malloc(num_rows * sizeof(int*));

for (int new_col_index = 0; new_col_index < num_rows; new_col_index++)
transposed_elems[new_col_index] = (int *) malloc(num_cols * sizeof(int));

将源矩阵复制到转置矩阵

for (int row_index = 0; row_index < num_rows; row_index++)
for (int col_index = 0; col_index < num_cols; col_index++)
if (row_index == col_index)
transposed_elems[row_index][col_index] = elems[row_index][col_index];
else
transposed_elems[col_index][row_index] = elems[row_index][col_index];
}

当我运行清理后的代码时,我收到异常:

"Exception thrown at 0x00007FF6AE8B193B in ConsoleApplication1.exe:
0xC0000005: Access violation writing location 0x000001E1FDFDFDFD."

访问冲突告诉您正在写入不应写入的内存。因此,首先应该考虑的是您的索引不正确。使用更具描述性的代码,很容易弄清楚发生了什么。

transposed_elems的大小为[num_rows][num_cols]我们在顶部将其定义为源矩阵的旧orig_num_cols和旧orig_num_rows

elems的大小为[orig_num_cols][orig_num_rows]相当于[num_cols][num_rows]

异常发生在以下行:

// this is trying to copy the matrix element when col_index != row_index
transposed_elems[col_index][row_index] = elems[row_index][col_index];

所以,让我们再看一行:你正在分配给transposed_elems[col_index][row_index].由于这是一个行优先数组,因此您将列索引用于行索引,将行索引用于列索引。您尝试复制的元素elems[row_index][col_index]。这应该相反,因为您正在访问非转置数组,列在第一位,行在第二位。所以,这就是为什么如果你有方阵以外的任何东西,你将写入你没有分配的内存,你不打算。

还有另一个错误不会导致异常,因此如果您依赖它进行调试,则更难找到。当两个索引相等时,您将分配给[row_index][col_index]并从[row_index][col_index]复制。

// this is trying to copy the matrix element when col_index == row_index
transposed_elems[row_index][col_index] = elems[row_index][col_index]`

因为你只在它们彼此相等时才这样做(你有理由试图检查它吗?),它不会写入未分配的内存,但它确实错误地分配了东西。只需查看变量的含义,您就可以看到转置矩阵被正确索引,但原始矩阵的索引颠倒了。

要制作转置副本,您只需要循环中的一个语句来复制它们:始终分配给[row_index][col_index]并始终从[col_index][row_index]复制。

for (int row_index = 0; row_index < num_rows; row_index++)
for (int col_index = 0; col_index < num_cols; col_index++)
transposed_elems[row_index][col_index] = elems[col_index][row_index];

一旦我做出改变,一切就会正常。这是输出

矩阵的元素: P[0][0] = P[0][1] = P[0][2] = P[0][3] =

P[0][4] = P[1][0] = P[1][1] = P[1][2] = P[1][3] = P[1][4] = P[2][0] = P[2][1] = P[2][2] = P[2][3] = P[2][4] = P[3][0] = P[3][1] = P[3][2] = P[3][3] = P[3][4] = P[4][0] = P[4][1] = P[4][2] = P[4][3] = P[4][4] = P[5][0] = P[5][1] = P[5][2] = P[5][3] = P[5][4] = P[6][0] = P[6][1] = P[6][2] = P[6][3] = P[6][4] = P[7][0] = P[7][1] = P[7][2] = P[7][3] = P[7][4] = P[8][0] = P[8][1] = P[8][2] = P[8][3] = P[8][4] = P[9][0] = P[9][1] = P[9][2] = P[9][3] = P[9][4] = 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 11 3 4 5 6 7 8 9 10 11 12 4 5 6 7 8 9 10 11 12 13

因此,要使用原始代码回答:

您需要更改执行赋值的循环以分配给正确的索引,并删除不需要执行的相等检查。

// remember: [m][n] is the size of the new matrix, and `[n][m]` of the original
// so `[j][i]` is used to index the new one, and `[i][j]` the old one
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
a[j][i] = p[i][j];

开发软件的一部分是在代码中尽可能多地记录含义,而不会使其变得难以忍受的冗长。您不限于短变量名称。如果必须,您应该使用注释进行记录,但这并不那么有用,并且仍然很难遵循。

只需让代码实际说些什么,就很容易找到错误。捷径只是让它难以遵循。使它具有描述性意味着阅读它并查看它是否有意义变得简单。

这就是你的答案。


为了完整起见,以下是我在清理代码时所做的完整版本:

#include<stdio.h>
#include<stdlib.h>
void transpose_matrix(int* elements[], int orig_rows, int orig_cols);
int main()
{
int num_rows, num_cols;
int** elems;
//printf("Number of rows: n");
//scanf("%d", &num_rows);
//printf("Nuber of columns: n");
//scanf("%d", &num_cols);
num_rows = 10;
num_cols = 5;
elems = (int**) malloc(num_rows * sizeof(int*));
for (int i = 0; i < num_rows; i++)
{
elems[i] = (int*) malloc(num_cols * sizeof(int));
}
printf("Elements of matrix: n");
for (int row_index = 0; row_index < num_rows; row_index++)
{
for (int col_index = 0; col_index < num_cols; col_index++)
{
printf("P[%d][%d] = ", row_index, col_index);
//scanf("%d", elems[row_index][col_index]);
elems[row_index][col_index] = row_index + col_index;
}
}
transpose_matrix(elems, num_rows, num_cols);
return 0;
}
void transpose_matrix(int* elems[], int orig_num_rows, int orig_num_cols)
{
int num_rows = orig_num_cols;
int num_cols = orig_num_rows;
int** transposed_elems;
transposed_elems = (int**) malloc(num_rows * sizeof(int*));

for (int new_col_index = 0; new_col_index < num_rows; new_col_index++)
transposed_elems[new_col_index] = (int *) malloc(num_cols * sizeof(int));
for (int row_index = 0; row_index < num_rows; row_index++)
{
for (int col_index = 0; col_index < num_cols; col_index++)
{
if (row_index == col_index)
transposed_elems[row_index][col_index] = elems[row_index][col_index];
else
transposed_elems[col_index][row_index] = elems[row_index][col_index];
}
}
for (int row_index = 0; row_index < num_rows; row_index++)
{
for (int col_index = 0; col_index < num_cols; col_index++)
{
printf("%d ", transposed_elems[row_index][col_index]);
}
puts("");
}
}

相关内容

  • 没有找到相关文章

最新更新