简体   繁体   English

在for循环的每次迭代中动态分配memory以制作动态数组

[英]Dynamic memory allocation in each iteration of for loop to make dynamic array

what's the problem with this code?这段代码有什么问题? i am trying to allocate 1 int size memory every time for loops run, but this code doesn't print anything我试图在每次循环运行时分配 1 个 int 大小 memory,但此代码不打印任何内容

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int *a;
    for(int i=0;i<5;i++)
    {
        a=(int *)malloc(1*sizeof(int));
        a[i]=i;
    }
    for(int i=0;i<5;i++)
    {
        printf("%d\n",a[i]);
    }
    free(a);

}

What you need to do is allocate memory for each integer separately, but you are not doing it.您需要做的是分别为每个 integer 分配 memory,但您没有这样做。

You are doing repeated allocation for same variable a , which is not the right way to do and also causes the memory leak because you are loosing the previous pointer values您正在对同一个变量a进行重复分配,这不是正确的做法,并且还会导致 memory 泄漏,因为您丢失了先前的指针值

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

int main()
{
    int *a[5] = {NULL};

    for(int i = 0; i < 5;i++)
    {
        a[i] = malloc(sizeof(int));
        if(a[i])
            *a[i] = i;
        else
            puts("cannot malloc");
    }
    
    for(int i = 0; i < 5; i++)
    {
        printf("addr = %p and value = %d\n",a[i],*a[i] );
        free(a[i]);
        a[i] = NULL;
    }
    return 0;
}

But if you just want to store 5 integers then the above method is a superfluous way, instead allocate memory for 5 integers at a time and use it as shown below.但是如果你只想存储 5 个整数,那么上面的方法是多余的,而是一次分配 memory 为 5 个整数并使用它,如下所示。

a = malloc(5 * sizeof(int));
for(int i = 0;i < 5; i++)
    a[i] = i;

and once you are done with it, you can say free(a); a = NULL;一旦你完成它,你可以说free(a); a = NULL; free(a); a = NULL;

if you wanna allocate 1-D array do this如果您想分配一维数组,请执行此操作

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int *a = (int*)malloc(5*sizeof(int)); // allocate 5 int-items on your array 'a'
    for(int i=0;i<5;i++)
    {
        a[i]=i;
    }
    for(int i=0;i<5;i++)
    {
        printf("%d\n",a[i]);
    }
    free(a);
}

you don't need to allocate each a[i] separately.您不需要分别分配每个 a[i] 。

And, i assume that you will be get some hard to make 2-D array.而且,我假设您将很难制作二维数组。

if you want do that.如果你想这样做。 try this尝试这个

#include<stdio.h>
#include<stdlib.h>
int main()
{ // make 5 * 5 array
    int **a = (int**)malloc(5*sizeof(int*));
    for(int i=0;i<5;i++)
    {
        a[i] = (int*)malloc(5*sizeof(int));
    }

    ... do some logics

    for(int i = 0; i < 5; i++) {
        free(a[i]); // you need to free each a[i] to prevent memory leak.
    }
    free(a); // finally, free a (int**)
}

If you already know the number of objects to allocate, you are not really dynamically resizing anything, you are simply allocating a block of memory to hold that number of objects.如果您已经知道要分配的对象数量,那么您实际上并没有动态调整任何东西的大小,您只是分配了一块 memory 来保存该数量的对象。

The distinction when allocating storage for objects instead of just creating an array is the storage duration for the collection of objects.为对象分配存储而不是仅仅创建数组时的区别在于对象集合的存储持续时间 Declaring a plain old array results in the array having automatic storage duration (valid lifetime of array is limited to the scope where it was declared).声明一个普通的旧数组会导致该数组具有自动存储持续时间(数组的有效生命周期仅限于声明它的 scope)。 A block of memory allocated with malloc , calloc or realloc has allocated storage duration (valid until freed or program exit) C11 Standard - 6.2.4 Storage durations of objects分配有malloccallocrealloc的 memory 块已分配存储持续时间(在释放或程序退出之前有效) C11 标准 - 6.2.4 对象的存储持续时间

When you allocate memory with malloc , calloc or realloc , the function reserves the number of bytes requested and returns the beginning address to the block of memory allocated on success, NULL on failure. When you allocate memory with malloc , calloc or realloc , the function reserves the number of bytes requested and returns the beginning address to the block of memory allocated on success, NULL on failure.

You have 2 responsibilities regarding the 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.对于分配的 memory 块,您有两个责任:(1)始终保留指向 memory 块的起始地址的指针,因此,(2)它可以在不再需要时释放 In your code you fail to do (1).在您的代码中,您没有执行 (1)。 When you place the allocation within your loop, eg当您将分配放在循环中时,例如

    a=(int *)malloc(1*sizeof(int));

You overwrite the address held by a as its value -- on each iteration.在每次迭代中,您都会覆盖a持有的地址作为其值。 By not preserving a pointer to each block of memory, you create a memory-leak each time you overwrite the address held by a , because the address to the previous block of memory is lost and you cannot free() the block of memory failing (2) above.通过不保留指向 memory 的每个块的指针,每次覆盖a持有的地址时都会造成内存泄漏,因为 memory 的前一个块的地址丢失并且您无法free() ZCD69BZB4957F06CD829D1 的块失败(9 2)以上。

( note: in C, there is no need to cast the return of malloc , it is unnecessary. See: Do I cast the result of malloc? ) 注:在C中, malloc的返回不需要投,没有必要。见:我投malloc的结果吗?

To fix your immediate problem, simply allocate before entering the loop, eg:要解决您的直接问题,只需在进入循环之前进行分配,例如:

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

#define NOBJ 5          /* if you need a constant, #define one or more */

int main (void) {
    
    int *a = malloc (NOBJ * sizeof *a);             /* allocate storage for n objects */
    
    if (a == NULL) {                                /* validate EVERY allocation */
        perror ("malloc-a");
        return 1;
    }
    
    for (int i = 0; i < NOBJ; i++)                  /* fill a */
        a[i] = i;
        
    for (int i = 0; i < NOBJ; i++)                  /* output a */
        printf ("a[%d]: %d\n", i, a[i]);

    free (a);                                       /* free allocated memory */
}

Example Use/Output示例使用/输出

$ ./bin/malloc-a
a[0]: 0
a[1]: 1
a[2]: 2
a[3]: 3
a[4]: 4

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

It is imperative that you use a memory error checking program to ensure 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.您必须使用 memory 错误检查程序,以确保您不会尝试访问 memory 或写入超出/超出分配块的边界,尝试读取或基于未初始化值的条件跳转,最后确认释放所有已分配的 memory。

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

$ valgrind ./bin/malloc-a
==5019== Memcheck, a memory error detector
==5019== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5019== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5019== Command: ./bin/malloc-a
==5019==
a[0]: 0
a[1]: 1
a[2]: 2
a[3]: 3
a[4]: 4
==5019==
==5019== HEAP SUMMARY:
==5019==     in use at exit: 0 bytes in 0 blocks
==5019==   total heap usage: 2 allocs, 2 frees, 1,044 bytes allocated
==5019==
==5019== All heap blocks were freed -- no leaks are possible
==5019==
==5019== For counts of detected and suppressed errors, rerun with: -v
==5019== 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.始终确认您已释放所有已分配的 memory 并且没有 memory 错误。

Dynamically Sizing Storage动态调整存储大小

When you have an unknown number of objects to store, then you must dynamically allocate storage.当您有未知数量的对象要存储时,您必须动态分配存储空间。 The approach is straight forward.该方法是直截了当的。 You initially allocate for some reasonably anticipated number of objects and keep two counters, one for the number of objects that can fit in the allocated memory currently available , and a second counter for the number of those allocated objects you have used .您最初为一些合理预期的对象数量分配并保留两个计数器,一个用于当前可用的已分配 memory 中可以容纳的对象数量,第二个计数器用于您已使用的那些已分配对象的数量。 When used == available* you must realloc` to resize your block of memory create more available storage space. used == available* you must重新分配来调整 memory 块的大小,从而创建更多可用存储空间。 Repeat until you have run out of objects to store.重复直到您用完要存储的对象。

When you call realloc() you always realloc() using a temporary pointer so if realloc() fails returning NULL , you don't overwrite the address to the currently allocated block with NULL creating a memory-leak.当您调用realloc()时,您始终使用临时指针 realloc( realloc() ,因此如果realloc()无法返回NULL ,您不会使用NULL将地址覆盖到当前分配的块中,从而造成内存泄漏。 For example never do:例如永远不要这样做:

        if (used == avail) {                        /* is reallocation needed? */
            a = realloc (a, 2 * avail * sizeof *a);

Instead do:而是这样做:

        if (used == avail) {                        /* is reallocation needed? */
            /* always realloc to a temporary pointer */
            void *tmp = realloc (a, 2 * avail * sizeof *a);
            if (!tmp) {                             /* validate EVERY reallocation */
                perror ("realloc-a");
                break;
            }
            a = tmp;                                /* assigned resized block to a */
            ...

That way when , (not if ), realloc() fails, you preserve a pointer to your original block of memory in a .这样,realloc() (不是if )失败时,您会a . It still points to the valid data stored in a immediately prior to the call to realloc() .它仍然指向在调用realloc()之前存储在a中的有效数据。

Below is a short example that initially allocates for 2 integer values and then generates a random number between 10 and 50 and fills that number of objects, reallocating storage as needed.下面是一个简短的示例,最初分配2 integer 值,然后生成1050之间的随机数并填充该数量的对象,根据需要重新分配存储。 For an additional bit of unknown, if the original number of random objects was odd , then another random number of values between 10 and 50 is added to the original number and filling and reallocation continues until all values are stored, eg对于未知的附加位,如果随机对象的原始数量是奇数,则将另一个介于1050之间的随机值添加到原始数字中,并且填充和重新分配继续进行,直到所有值都被存储,例如

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

#define AVAIL  2        /* if you need a constant, #define one or more */
#define OMAX  50        /* maximum no. of objects per-random increment */
#define OMIN  10        /* minimum no. of objects per-random increment */

int main (void) {
    
    size_t  used = 0,                               /* number of objects used */
            avail = AVAIL,                          /* number available */
            nrealloc = 0,                           /* number of reallocations */
            nobjects;                               /* random no. of objects to fill */
    int *a = malloc (avail * sizeof *a);            /* allocate storage for n objects */
    
    if (a == NULL) {                                /* validate EVERY allocation */
        perror ("malloc-a");
        return 1;
    }
    
    srand (time(NULL));                             /* seed random no. generator */
    nobjects = rand() % (OMAX - OMIN + 1) + OMIN;   /* random no 10 - 50 */
    
    while (used < nobjects) {                       /* loop until a contains nobjects */
        if (used == avail) {                        /* is reallocation needed? */
            /* always realloc to a temporary pointer */
            void *tmp = realloc (a, 2 * avail * sizeof *a);
            if (!tmp) {                             /* validate EVERY reallocation */
                perror ("realloc-a");
                break;
            }
            a = tmp;                                /* assigned resized block to a */
            avail *= 2;                             /* update available objects */
            nrealloc += 1;                          /* add to no. of reallocations */
        }
        a[used] = used;                             /* assign value */
        used++;                                     /* increment used count */
    }
    
    if (used & 1) {     /* if odd number used, add to nobjects */
        size_t group1 = nobjects;
        nobjects += rand() % (OMAX - OMIN + 1) + OMIN;
        printf ("\nnobjects increased from %zu - %zu\n\n", group1, nobjects);
    }
    
    while (used < nobjects) {                       /* loop until a contains nobjects */
        if (used == avail) {                        /* is reallocation needed? */
            /* always realloc to a temporary pointer */
            void *tmp = realloc (a, 2 * avail * sizeof *a);
            if (!tmp) {                             /* validate EVERY reallocation */
                perror ("realloc-a");
                break;
            }
            a = tmp;                                /* assigned resized block to a */
            avail *= 2;                             /* update available objects */
            nrealloc += 1;                          /* add to no. of reallocations */
        }
        a[used] = used;                             /* assign value */
        used++;                                     /* increment used count */
    }
    
    /* results */
    printf ("allocations   : 1\nreallocations : %zu\n\n", nrealloc);
    for (size_t i = 0; i < used; i++)               /* output a */
        printf ("a[%3zu]: %d\n", i, a[i]);

    free (a);                                       /* free allocated memory */
}

Example Use/Output示例使用/输出

( note: the original number of objects was 19 (odd) so the second random block of objects was allocated for and added to a ) 注意:对象的原始数量是19 (奇数),因此第二个随机对象块被分配并添加到a中)

$ ./bin/malloc-realloc-a

nobjects increased from 19 - 44

allocations   : 1
reallocations : 5

a[  0]: 0
a[  1]: 1
a[  2]: 2
a[  3]: 3
a[  4]: 4
a[  5]: 5
a[  6]: 6
a[  7]: 7
a[  8]: 8
a[  9]: 9
a[ 10]: 10
...
a[ 40]: 40
a[ 41]: 41
a[ 42]: 42
a[ 43]: 43

You can choose any number or factor of additional objects to allocate for when you realloc() , but doubling the current size is convenient and balances growing the storage against the number of times realloc() is needed reasonably well.您可以在realloc()时选择任何数量或因子的附加对象来分配,但是将当前大小加倍很方便,并且可以很好地平衡增加存储空间与需要realloc()的次数。 For example, you can grow from 2 initially allocated object to more than 2,000,000 in 20 reallocations.例如,您可以在 20 次重新分配中从最初分配的 2 个 object 增加到超过 2,000,000 个。 You can also call realloc() a final time with the total number used to shrink the total allocation to the exact size needed.您还可以最后一次调用realloc() ,并used总数将总分配缩小到所需的确切大小。

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

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

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