对于2D动态分配的数组的循环错误

问题描述 投票:1回答:2

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

据我所知,我已经正确分配了内存,我不相信我的迭代是关闭的。

当我尝试将数组定义为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
c arrays pointers dynamic allocation
2个回答
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]开始,您调用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的回报,这是不必要的。见: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)当它为no时可以释放它需要更久。

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

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

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

仔细看看,如果您有其他问题,请告诉我。


0
投票

你没有正确地做malloc。

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

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

以下陈述的情况类似

KAB[i] =(double *) malloc(3 *sizeof(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 
© www.soinside.com 2019 - 2024. All rights reserved.