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

时间:2018-09-15 23:40:20

标签: c arrays pointers dynamic allocation

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

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

当我尝试将数组定义为双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

在适当的步骤,第二行,第7列的值将获取输入的正确值

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

2 个答案:

答案 0 :(得分:1)

在分配指针之后,您无法为每一行分配足够的存储空间。 (您有一个幻数问题)

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

    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指针。从KAB[3]开始,您调用未定义行为(因为您已经使用了分配的3个指针),并且代码的定义操作已结束。

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

分配指针和存储值

使用 pointer-to-pointer-to-type 作为基本类型进行分配时,必须

  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的返回值,这是不必要的。请参阅:Do I cast the result of malloc?

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

将所有部分放在一起,您可以执行以下操作:

#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;
}

使用/输出示例

如何构建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

内存使用/错误检查

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

当务之急是使用一个内存错误检查程序来确保您不会尝试访问内存或在已分配的块的边界之外/之外进行写入,不要试图以未初始化的值读取或基于条件跳转,最后,以确认您释放了已分配的所有内存。

对于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)

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

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

答案 1 :(得分:0)

您没有正确执行malloc。

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

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

以下陈述与此类似

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

这里,您正在分配一个double *数组,它应该是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