简体   繁体   English

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

[英]For loop error with 2D dynamically allocated array

I'm having an issue with writing values to my 2D array that I've dynamically allocated.我在将值写入我动态分配的二维数组时遇到问题。 It seems that it is writing values to other spots in the array when it should not be.似乎它不应该将值写入数组中的其他位置。

As far as I can tell I've allocated the memory correctly and I don't believe my iterations are off.据我所知,我已经正确分配了内存,而且我认为我的迭代没有关闭。

When I try defining an array as double KAB[3][15]={0.0} I do not have this problem.当我尝试将数组定义为 double KAB[3][15]={0.0}我没有这个问题。

In this example, obviously, I'm using specific lengths of the array, but I would like them to work when defined by the user.在这个例子中,显然,我使用了特定长度的数组,但我希望它们在用户定义时工作。 Any trouble shooting suggestions would be appreciated.任何故障排除建议将不胜感激。

#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    

I've included relevant output with some annotations.我已经包含了一些注释的相关输出。

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

Everything starts at 0. And the first value gets put in the right spot.一切都从 0 开始。第一个值放在正确的位置。

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

But Before the end of the ms=0 loop something is written to the second row of the array但是在 ms=0 循环结束之前,一些东西被写入数组的第二行

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

During the third step of the ms=1 loop the first row gets over written在 ms=1 循环的第三步中,第一行被覆盖

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

At the appropriate step, the second row, column seven value gets the correct value entered在适当的步骤中,第二行第七列的值获得输入的正确值

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

But before the rest of the row is finished the same value gets put into the next row in the same column.但是在该行的其余部分完成之前,相同的值会被放入同一列的下一行。

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

the second row gets replaced with some values from the third row第二行被第三行的一些值替换

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

The third row gets it's correct value.第三行得到它的正确值。 These values remain until the end, but clearly the first and second rows have some incorrect values.这些值一直保留到最后,但显然第一行和第二行有一些不正确的值。

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

You are failing to allocate sufficient storage for each row after allocating for your pointers.分配指针后,您未能为每一行分配足够的存储空间。 (you have a magic number problem) (你有一个幻数问题)

Before addressing the allocation issue, let's look a general issue regarding using magic numbers in your code.在解决分配问题之前,让我们先看看有关在代码中使用幻数的一般问题。 For example, in:例如,在:

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

3 & 15 are magic numbers (meaning if anything changes and you need to adjust allocation or loop limits, you are left picking through your code to find each allocation and adjust each loop limit, each declaration size, etc... 3 & 15幻数(意味着如果有任何变化并且您需要调整分配或循环限制,则需要通过代码来查找每个分配并调整每个循环限制、每个声明大小等...

Don't use magic numbers , eg不要使用幻数,例如

#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 */

In your case, you have the wrong magic number in your row allocation, eg在您的情况下,您的行分配中有错误的幻数,例如

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

You only allocate 3-pointers , but you then attempt to allocate and assign storage for 3 double* to 15-pointers .您只分配3-pointers ,但随后尝试为 3 个double*分配存储空间给15-pointers Beginning with KAB[3] you invoke Undefined Behavior (because you have already used your 3 allocated pointers), and the defined operation of your code is over.KAB[3]开始,您调用未定义行为(因为您已经使用了 3 个分配的指针),并且代码的定义操作结束了。

Using constants instead of magic numbers helps avoid this problem.使用常量而不是幻数有助于避免这个问题。 Further, you have one convenient place to make changes at the top of you source file if anything needs changing.此外,如果需要更改任何内容,您可以在源文件顶部有一个方便的位置进行更改。

Allocating Pointers and Storage for Values为值分配指针和存储

When you are allocating using a pointer-to-pointer-to-type as your base type, you must当您使用指向类型的指针作为基类型进行分配时,您必须

  1. allocate a pointer to hold the memory address for each row;分配一个指针来保存每一行的内存地址; and
  2. allocate storage for each row to hold the values为每一行分配存储空间以保存值

(you also must validate each allocation, malloc, calloc & realloc can and do fail on memory exhaustion) (您还必须验证每个分配, malloc, calloc & realloc可以并且确实在内存耗尽时失败)

Next, since you are looping to zero your kab row values to zero, just use calloc to allocate, it both allocates and set memory to zero.接下来,由于您要循环将kab行值归零,因此只需使用calloc进行分配,它既分配内存kab内存设置为零。

(don't use UPPPER case variable names (reserved for constants and macros), and don't use camelCase or MixedCase variable - (leave those for java or C++)) (不要使用UPPPER变量名(为常量和宏保留),不要使用camelCaseMixedCase变量 - (将那些留给 java 或 C++))

So your allocation for both pointers and rows could look something like:因此,您对指针和行的分配可能如下所示:

...
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);
        }
...

(There is no need to cast the return of malloc , it is unnecessary. See: Do I cast the result of malloc? ) (不需要malloc的返回值,没有必要。参见:我是否强制转换了 malloc 的结果?

You now have both pointers and storage for your row values allocated, set to zero (by virtue of using calloc ) and you are free to address and fill your values using 2D index notation.您现在为行值分配了指针和存储空间,设置为零(通过使用calloc ),您可以自由地使用 2D 索引符号寻址和填充您的值。

Putting all the pieces together, you could do something similar to the following:将所有部分放在一起,您可以执行类似以下操作:

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

Example Use/Output示例使用/输出

How you build the value to store in each column is a bit uninteresting, but for purposes of the example it is fine.你如何构建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

Memory Use/Error Check内存使用/错误检查

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.在你写的,可动态分配内存的任何代码,您有任何关于分配的内存任何块2个职责:(1)始终保持一个指针的起始地址的存储器中,以便块,(2),当它是没有它可以被释放不再需要。

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化值的条件跳转,最后,确认你释放了你分配的所有内存。

For Linux valgrind is the normal choice.对于 Linux valgrind是正常的选择。 There are similar memory checkers for every platform.每个平台都有类似的内存检查器。 They are all simple to use, just run your program through it.它们都易于使用,只需通过它运行您的程序即可。

$ 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)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.始终确认您已释放所有分配的内存并且没有内存错误。

Look things over and let me know if you have further questions.仔细检查一下,如果您还有其他问题,请告诉我。

You are not doing malloc properly.您没有正确执行 malloc。

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

This statement is wrong and will allocate an array of double * but you need an array of double * because each element inside KAB should be a double * to point to an array of doubles and not a double **这个语句是错误的,会分配一个 double * 的数组,但你需要一个 double * 的数组,因为 KAB 中的每个元素都应该是一个 double * 来指向一个 double 的数组而不是一个 double **

Similar is the case with the following statement以下语句的情况类似

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

Here, you are allocating an array of double * instead, it should be an arrray of doubles.在这里,您分配的是一个 double * 数组,它应该是一个 double 数组。

The following code would work correctly.以下代码将正常工作。

#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 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM