对于二维动态分配数组的循环错误

For loop error with 2D dynamically allocated array

我在将值写入动态分配的二维数组时遇到问题。它似乎在不应该的时候将值写入数组中的其他位置。

据我所知,我已经正确分配了内存,而且我不认为我的迭代已关闭。

当我尝试将数组定义为 double KAB[3][15]={0.0} 时,我没有遇到这个问题。

在这个例子中,显然,我使用了特定长度的数组,但我希望它们在用户定义时起作用。任何故障排除建议将不胜感激。

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>



int main( ) 
{

int ms=0,i=0,j=0,n=0;
double value=0;
    double **KAB;
    KAB = (double **) malloc(3 * sizeof(double **));//makes array of pointers
    for(i = 0; i < 15; i++)
    {
        KAB[i] =(double *) malloc(3 *sizeof(double*));//each pointer points to a certain number of doubles
    }

        for(i=0;i< 3;i++)
        {
            for(j=0;j< 15;j++)
            {
                KAB[i][j]=0.0;//each value is set to 0.
            }
        }

for(ms=0; ms < 3; ms++)
{   
    for(i=0; i<15;i++)
    {       
        value=0;
        for(n=0; n<5 ;n++)
        {
                value+=ms*1.0+1;    
        }
        KAB[ms][i]=value;

        printf("Step:%d MS:%d\n",i,ms);
        printf("KAB[0][7]=%lf KAB[1][7]=%lf KAB[2][7]=%lf\n",KAB[0][7],KAB[1][7],KAB[2][7]);
    }
    }

return 0;
}//ends main    

我已经包含了带有一些注释的相关输出。

MS:0 Step:0
KAB[0][7]=0.000000, KAB[1][7]=0.000000, KAB[2][7]=0.000000
MS:0 Step:1

一切都从 0 开始。第一个值放在正确的位置。

MS:0 Step:7
KAB[0][7]=5.000000, KAB[1][7]=0.000000, KAB[2][7]=0.000000

但是在 ms=0 循环结束之前,一些东西被写入数组的第二行

MS:0 Step:11
KAB[0][7]=5.000000, KAB[1][7]=5.000000, KAB[2][7]=0.000000

在 ms=1 循环的第三步中,第一行被覆盖

MS:1 Step:3
KAB[0][7]=10.000000, KAB[1][7]=5.000000, KAB[2][7]=0.000000

在适当的步骤中,第二行第七列的值得到输入的正确值

MS:1 Step:7
KAB[0][7]=10.000000, KAB[1][7]=10.000000, KAB[2][7]=0.000000

但在该行的其余部分完成之前,相同的值会被放入同一列的下一行。

MS:1 Step:11
KAB[0][7]=10.000000, KAB[1][7]=10.000000, KAB[2][7]=10.000000

第二行被替换为第三行的一些值

MS:2 Step:3
KAB[0][7]=10.000000, KAB[1][7]=15.000000, KAB[2][7]=10.000000

第三行得到了正确的值。这些值一直保留到最后,但显然第一行和第二行有一些不正确的值。

MS:2 Step:7
KAB[0][7]=10.000000, KAB[1][7]=15.000000, KAB[2][7]=15.000000

您没有正确执行 malloc。

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

这个语句是错误的,会分配一个double *数组,但你需要一个double *数组,因为KAB中的每个元素都应该是一个double *来指向一个double数组而不是一个double **

类似下面的语句

KAB[i] =(double *) malloc(3 *sizeof(double*));

在这里,您分配的是双精度数组 *,它应该是双精度数组。

以下代码可以正常工作。

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>



int main() 
{

    int ms=0,i=0,j=0,n=0;
    double value=0;
    double **KAB;
    KAB = (double **) malloc(3 * sizeof(double *));//makes array of type double pointers
    for(i = 0; i < 15; i++)
    {
      KAB[i] =(double *) malloc(3 *sizeof(double));//each element in KAB points to an array of doubles
    }

      for(i=0;i< 3;i++)
      {
        for(j=0;j< 15;j++)
        {
            KAB[i][j]=0.0;//each value is set to 0.
        }
      }

    for(ms=0; ms < 3; ms++)
    {   
        for(i=0; i<15;i++)
        {       
          value=0;
          for(n=0; n<5 ;n++)
          {
                  value+=ms*1.0+1;    
          }
          KAB[ms][i]=value;

          printf("Step:%d MS:%d\n",i,ms);
          printf("KAB[0][7]=%lf KAB[1][7]=%lf KAB[2][7]=%lf\n",KAB[0][7],KAB[1][7],KAB[2][7]);
        }
    }
    return 0;
}//ends main 

分配指针后,您未能为每一行分配足够的存储空间。 (你有一个 幻数 问题)

在解决分配问题之前,让我们先看一下有关在代码中使用 幻数 的一般问题。例如,在:

    KAB = (double **) malloc(3 * sizeof(double **));//makes array of pointers
    for(i = 0; i < 15; i++)

3 & 15 幻数 (这意味着如果有任何变化并且您需要调整分配或循环限制,您只能通过代码来查找每个分配和调整每个循环限制、每个声明大小等...

不要使用 幻数,例如

#define ROW     3   /* if you need a constant, #define one (or more) */
#define COL    15
#define NVAL    5
...
    for (int ms = 0; ms < ROW; ms++) {              /* for each row */

        kab[ms] = calloc (COL, sizeof *kab[ms]);    /* allocate storage */

在你的情况下,你的行分配中有错误的幻数,例如

for(i = 0; i < 15; i++)
{
    KAB[i] =(double *) malloc(3 *sizeof(double*));
}

您只分配了 3 个指针,但是您随后尝试分配和分配 3 double*15 个指针[=104] 的存储空间=].从 KAB[3] 开始,您调用 Undefined Behavior(因为您已经使用了 3 个分配的指针),代码的定义操作结束。

使用常量代替 幻数 有助于避免此问题。此外,如果有任何需要更改,您可以在源文件顶部的一个方便的地方进行更改。

为值分配指针和存储空间

当您使用指向类型的指针作为基类型进行分配时,您必须

  1. 分配一个指针来保存每一行的内存地址;和
  2. 为每一行分配存储空间以保存值

(您还必须 验证 每个分配,malloc, calloc & realloc 可以并且确实会在内存耗尽时失败)

接下来,由于您正在循环将 kab 行值归零为零,因此只需使用 calloc 进行分配,它既分配内存又将内存设置为零。

(不要使用 UPPPER 大小写变量名称(为常量和宏保留),并且不要使用 camelCaseMixedCase 变量 -(将那些留给 java 或 C++))

因此您对指针和行的分配可能类似于:

...
int main (void) {

    double **kab = NULL;

    /* calloc allocates and initializes memory all zero */
    kab = calloc (ROW, sizeof *kab);    /* use dereference pointer to
                                         * determine typesize */

    if (!kab) {     /* validate every allocation by checking the return */
        perror ("calloc-kab");  /* handle error */
        exit (EXIT_FAILURE);
    }

    for (int ms = 0; ms < ROW; ms++) {              /* for each row */

        kab[ms] = calloc (COL, sizeof *kab[ms]);    /* allocate storage */
        if (!kab[ms]) {                             /* validate allocation */
            perror ("calloc-kab[ms]");              /* handle error */
            exit (EXIT_FAILURE);
        }
...

(不需要投malloc的return,没必要。见:Do I cast the result of malloc?

您现在已经为您的行值分配了指针和存储空间,设置为零(通过使用 calloc)并且您可以使用二维索引符号自由地寻址和填充您的值。

把所有的部分放在一起,你可以做类似下面的事情:

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

#define ROW     3   /* if you need a constant, #define one (or more) */
#define COL    15
#define NVAL    5

int main (void) {

    double **kab = NULL;

    /* calloc allocates and initializes memory all zero */
    kab = calloc (ROW, sizeof *kab);    /* use dereference pointer to
                                         * determine typesize */

    if (!kab) {     /* validate every allocation by checking the return */
        perror ("calloc-kab");  /* handle error */
        exit (EXIT_FAILURE);
    }

    for (int ms = 0; ms < ROW; ms++) {              /* for each row */

        kab[ms] = calloc (COL, sizeof *kab[ms]);    /* allocate storage */
        if (!kab[ms]) {                             /* validate allocation */
            perror ("calloc-kab[ms]");              /* handle error */
            exit (EXIT_FAILURE);
        }

        for (int i = 0; i < COL; i++ ) {    /* for each column */
            double value = 0;

            for (int n = 0; n < NVAL; n++)  /* loop NVAL times */
                value += ms * 1.0 + 1;      /* build value */

            kab[ms][i] = value;             /* assign value to kab[ms][i] */
        }
    }

    for (int ms = 0; ms < ROW; ms++) {      /* for each row */
        for (int i = 0; i < COL; i++)       /* for each col */
            printf (" %4.1lf", kab[ms][i]); /* output value */
        putchar ('\n');     /* tidy up */
        free (kab[ms]);     /* free row */
    }
    free (kab);             /* free pointers */

    return 0;
}

例子Use/Output

如何构建 value 以存储在每一列中有点无趣,但对于示例而言它很好。

$./bin/arraydyn2d
  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0
 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0

内存Use/Error检查

在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。

对于Linux valgrind是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。

$ valgrind ./bin/arraydyn2d
==15774== Memcheck, a memory error detector
==15774== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15774== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==15774== Command: ./bin/arraydyn2d
==15774==
  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0  5.0
 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0 15.0
==15774==
==15774== HEAP SUMMARY:
==15774==     in use at exit: 0 bytes in 0 blocks
==15774==   total heap usage: 4 allocs, 4 frees, 384 bytes allocated
==15774==
==15774== All heap blocks were freed -- no leaks are possible
==15774==
==15774== For counts of detected and suppressed errors, rerun with: -v
==15774== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放所有分配的内存并且没有内存错误。

检查一下,如果您还有其他问题,请告诉我。