我正在尝试使用2d数组模拟矩阵。但是我陷入了运行时错误。我确定它是在打印功能上发生的,但是我根本找不到解决方法。
obtn_matrix 是我用来创建矩阵数组的函数。我没有共享填充函数,该函数用于获取矩阵数组元素的int值,因此打印出的值将是内存中的内容。但是,问题是,我根本无法打印这些值。 obtn_matrix 之后,程序崩溃。
int main()
{
int**matrix,m,n;
obtn_matrix(matrix,m,n);
prnt_matrix(matrix,m,n);
getch();
}
void prnt_matrix(int** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",matrix[i][j]);
}
printf("\n");
}
}
void obtn_matrix(int** matrix,int m,int n)
{
printf("Please enter the column number: ");
fflush(stdin);
scanf("%d",&m);
printf("Please enter the row number: ");
fflush(stdin);
scanf("%d",&n);
matrix=create_matrix(m,n);
}
预期结果如下:
4542 64 274 4234
765 53 3523 5345
5145 154 545 545
5435 543 545 14
我将处理格式(%4d等)。预先感谢。
答案 0 :(得分:1)
obtn_matrix
中的在 main 中看不到 matrix,m 和 n 的赋值,您需要使用指向他们。
例如,使用int *
数组,因为在编译时尺寸未知:
#include <stdio.h>
#include <stdlib.h>
void prnt_matrix(int ** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",matrix[i][j]);
}
printf("\n");
}
}
int ** create_matrix(int m, int n)
{
int ** ma = calloc(m, sizeof(int*));
if (ma != NULL) {
int i, j;
for (i = 0; i != m; ++i) {
if ((ma[i] = malloc(n*sizeof(int))) == NULL)
return NULL;
for (j = 0; j != n; ++j) {
ma[i][j] = i*n + j;
}
}
}
return ma;
}
void obtn_matrix(int *** matrix,int * m,int * n)
{
printf("Please enter the row number: ");
fflush(stdin);
scanf("%d",m);
printf("Please enter the column number: ");
fflush(stdin);
scanf("%d",n);
*matrix=create_matrix(*m,*n);
}
void free_matrix(int ** matrix,int m,int n)
{
for(int i=0;i<m;i++)
{
if (matrix[i] == NULL)
/* matrix creation was aborted */
break;
free(matrix[i]);
}
free(matrix);
}
int main()
{
int ** matrix,m,n;
obtn_matrix(&matrix,&m,&n);
if (matrix != NULL) {
prnt_matrix(matrix,m,n);
free_matrix(matrix,m,n);
}
}
编译和执行:
pi@raspberrypi:~ $ gcc -pedantic -Wextra m.c
pi@raspberrypi:~ $ ./a.out
Please enter the row number: 3
Please enter the column number: 2
0 1
2 3
4 5
在 valgrind
下执行pi@raspberrypi:~ $ valgrind ./a.out
==10436== Memcheck, a memory error detector
==10436== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10436== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10436== Command: ./a.out
==10436==
Please enter the row number: 3
Please enter the column number: 2
0 1
2 3
4 5
==10436==
==10436== HEAP SUMMARY:
==10436== in use at exit: 0 bytes in 0 blocks
==10436== total heap usage: 6 allocs, 6 frees, 2,084 bytes allocated
==10436==
==10436== All heap blocks were freed -- no leaks are possible
==10436==
==10436== For counts of detected and suppressed errors, rerun with: -v
==10436== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
请注意,也可以只分配一个数组 m * n int ,但是在这种情况下,您不必执行m[i][j]
{1}}
答案 1 :(得分:0)
如果您还没有完全解决所遇到的基本问题,那就是问题,C会通过值将参数传递给函数。这意味着传递参数时,该函数会收到一个可以自由更改的变量的副本,但是当函数返回时,所有更改都将丢失。
对此的一个警告是,传递了 分配的指针 。尽管它仍按值传递,并且指针将具有与原始地址非常不同的地址,但由于其值而持有的内存地址仍将指向与调用方相同的地址。这与分配int a = 5;
然后传递a
作为参数没什么不同,该函数接收变量的副本,但是它仍然包含5
。
但是,如果您尝试分配或重新分配以使指针的 地址发生更改,则函数中所做的任何更改都会在返回时丢失,而不会在呼叫者中可见。
您如何处理?
您有两个选择(1)传递指针的 地址 ,因此对地址的任何更改都可以分配给已取消引用的指针(即原始指针地址) ),或(2)将返回类型从void
更改为需要返回的指针类型,并返回新分配/重新分配的指针,以在调用方中分配。
例如,对于您而言,根本不需要将matrix
作为参数传递给obtn_matrix()
。您可以简单地使用上面的选项(2),最后将obtn_matrix()
的返回类型更改为int **
和return create_matrix (*m, *n);
,例如
int **create_matrix (int m, int n)
{
int **matrix = malloc (m * sizeof *matrix);
if (matrix == NULL) {
perror ("malloc-matrix");
return NULL;
}
for (int i = 0; i < m; i++)
/* use calloc to initialize values zero */
if ((matrix[i] = calloc (n, sizeof **matrix)) == NULL) {
perror ("malloc-matrix[n]");
return NULL;
}
return matrix;
}
/* use pointers as parameters so the updated values of m, n are
* available back in the caller after the function returns. return
* int** for assignment back in the caller. avoids becomming a
* 3-Star Programmer (not a compliment). return NULL on failure.
*/
int **obtn_matrix (int *m, int *n)
{
fputs ("enter number of rows: ", stdout);
if (scanf ("%d", m) != 1) { /* validate ALL user-input */
fputs ("error: invalid number of rows.\n", stderr);
return NULL;
}
fputs ("enter number of cols: ", stdout);
if (scanf ("%d", n) != 1) {
fputs ("error: invalid number of cols.\n", stderr);
return NULL;
}
return create_matrix (*m, *n);
}
现在全部说明,并注意@bruno解释了为什么必须通过 m, n
的 地址(例如{{1} })到&m, &n
(上面的选项(1)),这样obtn_matrix
的更新值就可以在m & n
(这里的调用者)中使用了,您可以执行以下操作:
main()
由于您#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int **create_matrix (int m, int n)
{
int **matrix = malloc (m * sizeof *matrix);
if (matrix == NULL) {
perror ("malloc-matrix");
return NULL;
}
for (int i = 0; i < m; i++)
/* use calloc to initialize values zero */
if ((matrix[i] = calloc (n, sizeof **matrix)) == NULL) {
perror ("malloc-matrix[n]");
return NULL;
}
return matrix;
}
/* use pointers as parameters so the updated values of m, n are
* available back in the caller after the function returns. return
* int** for assignment back in the caller. avoids becomming a
* 3-Star Programmer (not a compliment). return NULL on failure.
*/
int **obtn_matrix (int *m, int *n)
{
fputs ("enter number of rows: ", stdout);
if (scanf ("%d", m) != 1) { /* validate ALL user-input */
fputs ("error: invalid number of rows.\n", stderr);
return NULL;
}
fputs ("enter number of cols: ", stdout);
if (scanf ("%d", n) != 1) {
fputs ("error: invalid number of cols.\n", stderr);
return NULL;
}
return create_matrix (*m, *n);
}
void prnt_matrix (int **matrix, int m, int n)
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
printf (" %4d", matrix[i][j]);
putchar ('\n');
}
}
void free_matrix (int **matrix, int m)
{
for (int i = 0; i < m; i++)
free (matrix[i]); /* free integers */
free (matrix); /* free pointers */
}
int main (void) {
int **matrix, m = 0, n = 0;
if ((matrix = obtn_matrix (&m, &n)) == NULL)
return 1;
prnt_matrix (matrix, m, n);
free_matrix (matrix, m);
return 0;
}
,上面的代码通过使用"didn't share the filler function"
而不是row
为每个calloc
分配整数来简单地将所有整数值归零,这在工作时是个好主意模拟数组,这样,如果您无意中未能初始化整数之一,则在尝试遍历所有元素时都不会出现SegFault,例如malloc
等...
使用/输出示例
prnt_matrix
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于任何分配的内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)当不再需要它时可以释放。
当务之急是使用一个内存错误检查程序来确保您不会尝试访问内存或在已分配的块的边界之外/之外进行写入,不要试图以未初始化的值读取或基于条件跳转,最后,以确认您释放了已分配的所有内存。
对于Linux,$ ./bin/matrix_cr_obtn
enter number of rows: 5
enter number of cols: 3
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。
valgrind
始终确认已释放已分配的所有内存,并且没有内存错误。
仔细检查一下,如果还有其他问题,请告诉我。
答案 2 :(得分:-1)
如果要向函数发送2D数组,则代码会与所有指针混淆在一起。
void obtn_matrix(int matrix[][n],int m,int n)
// or equivalently: void obtn_matrix(int (*matrix)[n], int m, int n )
{
...
}
[假设您在将n传递给函数之前先为其分配了一个值(也可以给它分配一个随机值,然后使用malloc为它添加空间)]
因为int **不代表2D数组-它应该是指向指针的指针数组。