【问题标题】:Errors when allocating arrays dynamically. vfscanf.c: 1898动态分配数组时出错。 vfscanf.c: 1898
【发布时间】:2019-02-24 05:28:15
【问题描述】:

我正在尝试编写一个程序来判断数组是否是幻方。在创建最多 3x3 尺寸时效果很好。但是从 4x4 开始,他们的行为很糟糕。 5x5 或更高,我得到一个“分段失败(记录的核心图像)”错误,总是在同一点:mat [4] [0]。这是我的代码:

#include <stdio.h>
#include <stdlib.h>

int qm(int ** mat, int n){
    int sl = 0, sc = 0, sdP = 0, sdS = 0;
    int i, j;

    for(i = 0; i < n; i++){
        sl += mat[0][i];
        sc += mat[i][0];
        sdP += mat[i][i];
        sdS += mat[i][n-i-1];
    }


    if((sl != sc)||(sl != sdP) || (sl!= sdS)) return 0;
    else{
        for(i = 1; i < n; i++){
            int tempL = 0, tempC = 0;
            for(j = 1; j <= n; j++){
                tempC += mat[j - 1][i];
                tempL += mat[i][j - 1];
            }
            if((tempL != tempC) || (tempL != sl)) return 0;
        }
        return 1;
    }
}

int main(void){
    int ** mat, n, i, j;

    printf("\nINFORME O NUMERO N DE LINHAS E COLUNAS: ");
    scanf("%d", &n);

    mat = (int **) malloc(n * sizeof(int));
    for(i = 0; i < n; i++) {
        mat[i] = (int *) malloc(n * sizeof(int));
    }

    for(i = 0; i < n; i++){
        for(j = 0; j < n; j++){
            printf("\nINFORME MAT[%d][%d]: ", i, j);
            scanf("%d", &mat[i][j]);
        }
    }

    int test = qm(mat, n);

    for(i = 0; i < n; i++){
        free(mat[i]);
    }
    free(mat);


    if(test) printf("\nA MATRIZ É QUADRADO MÁGICO!\n");
    else{
        printf("\nA MATRIZ NÃO É QUADRADO MÁGICO!\n");
    }

    return 0;
}

下面是 gdb 的一些测试:

3x3 矩阵:

(gdb) run
Starting program: /home/.../

INFORME O NUMERO N DE LINHAS E COLUNAS: 3

INFORME MAT[0][0]: 1

INFORME MAT[0][1]: 1

INFORME MAT[0][2]: 1

INFORME MAT[1][0]: 1

INFORME MAT[1][1]: 1

INFORME MAT[1][2]: 1

INFORME MAT[2][0]: 1

INFORME MAT[2][1]: 1

INFORME MAT[2][2]: 1

A MATRIZ É QUADRADO MÁGICO!
[Inferior 1 (process 4804) exited normally]

4x4 矩阵:

(gdb) run
Starting program: /home/.../

INFORME O NUMERO N DE LINHAS E COLUNAS: 4

INFORME MAT[0][0]: 1

INFORME MAT[0][1]: 1

INFORME MAT[0][2]: 1

INFORME MAT[0][3]: 1

INFORME MAT[1][0]: 1

INFORME MAT[1][1]: 1

INFORME MAT[1][2]: 1

INFORME MAT[1][3]: 1

INFORME MAT[2][0]: 1

INFORME MAT[2][1]: 1

INFORME MAT[2][2]: 1

INFORME MAT[2][3]: 1

INFORME MAT[3][0]: 1

INFORME MAT[3][1]: 1

INFORME MAT[3][2]: 1

INFORME MAT[3][3]: 1
double free or corruption (out)

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51  ../sysdeps/unix/sysv/linux/raise.c:Arquivo ou diretório inexistente.

5x5:

(gdb) run
Starting program: /home/.../

INFORME O NUMERO N DE LINHAS E COLUNAS: 5

INFORME MAT[0][0]: 1

INFORME MAT[0][1]: 1

INFORME MAT[0][2]: 1

INFORME MAT[0][3]: 1

INFORME MAT[0][4]: 1

INFORME MAT[1][0]: 1

INFORME MAT[1][1]: 1

INFORME MAT[1][2]: 1

INFORME MAT[1][3]: 1

INFORME MAT[1][4]: 1

INFORME MAT[2][0]: 1

INFORME MAT[2][1]: 1

INFORME MAT[2][2]: 1

INFORME MAT[2][3]: 1 

INFORME MAT[2][4]: 1

INFORME MAT[3][0]: 1

INFORME MAT[3][1]: 1

INFORME MAT[3][2]: 1

INFORME MAT[3][3]: 1

INFORME MAT[3][4]: 1

INFORME MAT[4][0]: 1

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a538c2 in _IO_vfscanf_internal (s=<optimized out>, format <optimized out>, argptr=argptr@entry=0x7fffffffdc80, errp=errp@entry=0x0) at vfscanf.c:1898
1898    vfscanf.c: Arquivo ou diretório inexistente.

和 6x6:

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/lucas/Documentos/UFF/ProgEstruturada/EXERCICIOS/labs/test 

INFORME O NUMERO N DE LINHAS E COLUNAS: 6

INFORME MAT[0][0]: 1

INFORME MAT[0][1]: 1

INFORME MAT[0][2]: 1

INFORME MAT[0][3]: 1

INFORME MAT[0][4]: 1

INFORME MAT[0][5]: 1

INFORME MAT[1][0]: 1

INFORME MAT[1][1]: 1

INFORME MAT[1][2]: 1

INFORME MAT[1][3]: 1

INFORME MAT[1][4]: 1

INFORME MAT[1][5]: 1

INFORME MAT[2][0]: 1

INFORME MAT[2][1]: 1

INFORME MAT[2][2]: 1

INFORME MAT[2][3]: 1

INFORME MAT[2][4]: 1

INFORME MAT[2][5]: 1

INFORME MAT[3][0]: 1

INFORME MAT[3][1]: 1

INFORME MAT[3][2]: 1

INFORME MAT[3][3]: 1

INFORME MAT[3][4]: 1

INFORME MAT[3][5]: 1

INFORME MAT[4][0]: 1

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a538c2 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffdc80, errp=errp@entry=0x0) at vfscanf.c:1898
1898    vfscanf.c: Arquivo ou diretório inexistente.

然后我在 gdb 尝试了这个:

(gdb) bt
#0  0x00007ffff7a538c2 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffdc80, errp=errp@entry=0x0) at vfscanf.c:1898
#1  0x00007ffff7a5ffd8 in __isoc99_scanf (format=<optimized out>) at isoc99_scanf.c:37
#2  0x0000555555554a97 in main () at labII_exIV.c:44
(gdb) frame 0
#0  0x00007ffff7a538c2 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffdc80, errp=errp@entry=0x0) at vfscanf.c:1898
1898    in vfscanf.c
(gdb) list
1893    in vfscanf.c
(gdb) frame 1
#1  0x00007ffff7a5ffd8 in __isoc99_scanf (format=<optimized out>) at isoc99_scanf.c:37
37  isoc99_scanf.c: Arquivo ou diretório inexistente.
(gdb) list
32  in isoc99_scanf.c
(gdb) frame 2
#2  0x0000555555554a97 in main () at labII_exIV.c:44
warning: Source file is more recent than executable.
44              scanf("%d", &mat[i][j]);
(gdb) list
39      }
40  
41      for(i = 0; i < n; i++){
42          for(j = 0; j < n; j++){
43              printf("\nINFORME MAT[%d][%d]: ", i, j);
44              scanf("%d", &mat[i][j]);
45          }
46      }
47  
48      int test = qm(mat, n);

我使用这些命令是基于我对错误所做的搜索,我在这个网站上找到:“https://vinipsmaker.wordpress.com/2013/12/20/mug-favorito-de-cc-false-of-segmentacao/”。我在对scanf()的调用中看到了错误在第44行的警告,但是我不太明白这个问题。

我在 ubuntu 18.04 中使用 gcc 编译

【问题讨论】:

  • (int **) malloc(n * sizeof(int)); sizeof(int *)?
  • mat = (int **) malloc(n * sizeof(int)); --> 一种不易出错的代码分配方法是使用解引用指针的大小而不是其类型,这是 OP 错误的。使用mat = malloc(sizeof *mat * n);。更容易正确编码、审查和维护。代码中可能存在其他问题。
  • @immibis,是的,谢谢。因为它,我总是卡在 mat[4][0] 索引,对吧?

标签: c multidimensional-array memory-management


【解决方案1】:

问题出在这一行:

mat = (int **) malloc(n * sizeof(int));

由于mat 是指向int 的指针,它包含指向int 的指针。所以malloc 操作应该有sizeof 指向int 的指针。 将上面的内容改为:

mat = (int **) malloc(n * sizeof(int*));

在此更改之后,我对 4x4、5x5 和 6x6 矩阵进行了测试,并且它可以工作。

下面是 6X6 矩阵的输出。

INFORME O NUMERO N DE LINHAS E COLUNAS: 6

INFORME MAT[0][0]: 1

INFORME MAT[0][1]: 1

INFORME MAT[0][2]: 1

INFORME MAT[0][3]: 1

INFORME MAT[0][4]: 1

INFORME MAT[0][5]: 1

INFORME MAT[1][0]: 1

INFORME MAT[1][1]: 1

INFORME MAT[1][2]: 1

INFORME MAT[1][3]: 1

INFORME MAT[1][4]: 1

INFORME MAT[1][5]: 1

INFORME MAT[2][0]: 1

INFORME MAT[2][1]: 1

INFORME MAT[2][2]: 1

INFORME MAT[2][3]: 1

INFORME MAT[2][4]: 1

INFORME MAT[2][5]: 1

INFORME MAT[3][0]: 1

INFORME MAT[3][1]: 1

INFORME MAT[3][2]: 1

INFORME MAT[3][3]: 1

INFORME MAT[3][4]: 1

INFORME MAT[3][5]: 1

INFORME MAT[4][0]: 1

INFORME MAT[4][1]: 1

INFORME MAT[4][2]: 1

INFORME MAT[4][3]: 1

INFORME MAT[4][4]: 1

INFORME MAT[4][5]: 1

INFORME MAT[5][0]: 1

INFORME MAT[5][1]: 1

INFORME MAT[5][2]: 1

INFORME MAT[5][3]: 1

INFORME MAT[5][4]: 1

INFORME MAT[5][5]: 1

A MATRIZ É QUADRADO MÁGICO!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 2021-08-04
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多