使用malloc的2-D矩阵无法分配正确的值

时间:2016-06-04 03:14:40

标签: c arrays malloc

抱歉,我是c的新手,我正在尝试使用malloc创建两个2-D阵列。有人告诉我,这种方法在计算上比通过for循环(对于大型数组)创建数组指针数组更有效。

int i, j;
double **PNow, **PNext, *Array2D1, *Array2D2;

//Allocate memory
PNow = (double**)malloc(3 * sizeof(double*));
PNext = (double**)malloc(3 * sizeof(double*));
Array2D1 = (double*)malloc(5 * sizeof(double));
Array2D2 = (double*)malloc(5 * sizeof(double));

//Create 2-Dimensionality
for(i = 0; i < 3; i++)
{
    PNow[i] = Array2D1 + i * 5;
    PNext[i] = Array2D2 + i * 5;
};


//Define Element Values
for(i = 0; i < 3; i++)
{
    for(j = 0; j < 5; j++)
    {
        PNow[i][j] = 10.*(i + j);
        PNext[i][j] = 1000.*(i + j);
    };
};


//Output two matrices side-by-side.
for(i = 0; i < 3; i++)
{
    for(j = 0; j < 5; j++)
    {

        printf("%6lg", PNow[i][j]);
        if(j == 4)
        {
            printf("|");
        };
    };
    for(j = 0; j < 5; j++)
    {

        printf("%6lg", PNext[i][j]);
        if(j == 4)
        {
            printf("\n");
        };
    };
};

我的问题是第一个矩阵(PNow)结果如我所料,但由于某种原因,PNext中的一半值是PNow的值,我不能为我的生活弄清楚为什么它是这样做?我显然错过了一些东西..而且我对“Array2D1 + i * 5”正在做什么以及如何使PNow成为二维数组并不过分清楚?

任何帮助都会非常感激。 谢谢。

P.S。这是我得到的输出,所以你可以看到我的意思:

 0    10    20    30    40|    20    30    40    50    20
10    20    30    40    50|    30    40    50    60  5000
20    30    40    50    60|  2000  3000  4000  5000  6000

2 个答案:

答案 0 :(得分:2)

在C中你没有强制转换mallocs的结果,所以你的malloc行应该是

PNow = malloc(3*sizeof(double*));

您的问题是,您实际上并未在Array2D1Array2D2中分配足够的内存。当您移过阵列中的第一个“行”时,您将超出分配的内存!所以你处于未定义的行为领域。在你的情况下,看起来你的两个矩阵相互重叠(虽然我的测试只是抛出一个错误)。您可以通过两种方式解决此问题:

在malloc中指定矩阵的完整大小,并按照以下方式执行:

Array2D1 = malloc(15*sizeof(double));
Array2D2 = malloc(15*sizeof(double)); 

或者在for循环中使用malloc:

for(i=0; i<3; i++){
    PNow[i] = malloc(5*sizeof(double));
    PNext[i] = malloc(5*sizeof(double));
}

编辑:关于每个例子中的释放主题

对于第一个例子,释放是直截了当的

free(PNow);
free(PNext);
free(Array2D1);
free(Array2D2);

对于第二个,您必须遍历每一行并单独释放

for (i = 0; i < 3; i++) {
    free(PNow[i]);
    free(PNext[i]);
}

Edit2:实际上,如果您要使用预处理器宏对行和列进行硬编码,那么就没有理由使用malloc。你可以这样做:

#define ROW 3
#define COL 5

double PNow[ROW][COL], PNext[ROW][COL];

Edit3:至于Array2D1 + i * 5正在做什么,PNow是一个指针数组,Array2D1是一个指针。通过添加i * 5,您将指针递增i * 5(即,说“给我一个指向i * 5的内存的指针,距Array2D1一倍。”所以,你正在为PNow填充指向行的适当大小的内存块的开头的指针。

答案 1 :(得分:0)

您的代码没有2D数组,也就是矩阵。你的指针也不能指向这样的对象。

可以指向2D数组的正确指针将声明为:

2016-06-03 21:00:14 > user1 has connected.
2016-06-03 21:00:22 > foobar disconnected.
2016-06-03 21:00:22 > foobar disconnected.
2016-06-03 21:00:29 > user2 has connected.
2016-06-03 21:00:29 > user2 has disconnected.
2016-06-03 21:00:30 > user2 has disconnected.
2016-06-03 21:00:30 > user2 has disconnected.

分配是直截了当的:

#define ROWS 4
#define COLS 5

double (*arr)[COLS];

删除类似内容:

arr = malloc(sizeof(*arr) * ROWS);

索引就像:

free(arr);

请注意相同的语法。语义不同。

没有必要也不需要手工制作的指针数组。

上面的代码显示了另一个重要规则:不要使用魔术值。请改用类似常量的宏。这些应该在代码的开头或配置部分arr[row][col] (通常位于文件顶部附近或不同的头文件)。所以,如果你稍后改变,例如维度的长度,您不必编辑您明确写入的所有位置,而只需更改宏一次。

虽然上面的代码使用常量,但您也可以使用维度的变量。这是标准C,称为可变长度数组(VLA)。如果将数组传递给其他函数,则必须将它们作为附加参数传递:

#defined

请记住,数组参数会衰减到指向第一个元素的指针,因此void f(size_t rows, size_t cols, double a[rows][cols]); 实际上与上面的a相同。最外层的尺寸可以省略,但是无论如何你都需要它,文档也可以指定它。