【问题标题】:How can I dynamically allocate memory for an array of int (not int*) in C?如何在 C 中为 int 数组(不是 int*)动态分配内存?
【发布时间】:2018-03-05 16:09:33
【问题描述】:

我正在尝试使用数组在 C 中实现堆栈。我想要一个整数数组,每次尝试推送一个 int 时,我都想分配一些新内存。但我对malloc() 的理解是,它返回一个指向它在某处分配的内存的指针,如果我有一个int 指针数组,那会很好,但我没有。这是我分配新内存的地方,我收到警告:

int stack[] = {1};  // stack is allocated like this

stack[lasti + 1] = malloc(sizeof(int));  // assignment makes integer from pointer without a cast

是否可以使用动态分配的非指针数组来实现堆栈?或者malloc() 是否适合使用指针数组?

编辑:我想我正在尝试将数组视为链表?似乎当我想使用 malloc 为数组分配空间时,它看起来像malloc(sizeof(int) * maxSize)。这将在某处产生大量内存。我不能做的是要求 malloc 在该块的末尾给我另一块内存,但我可以扩展该块。如果我使用链表实现堆栈,那么 malloc 将新空间放在哪里都没关系。我想我在脑子里混淆了一些东西。

那么下一个问题 - 如果使用数组实现堆栈,我是否必须指定堆栈的最大大小?

【问题讨论】:

  • 像任何数据结构一样,整数数组只是一个没有语义的任意大小的内存块(它由您的程序定义,即您如何使用它)。 malloc() 允许分配内存块。
  • 使用realloc...
  • 请说明stack 的声明方式。而且没有指针的动态内存分配有些矛盾。
  • 你定义它的方式,stack 只有一个元素。 stack[lasti + 1] 无效。
  • 不,你显然不懂数组。这与malloc无关。

标签: c arrays pointers memory-management stack


【解决方案1】:

当您在主函数中声明小数组时,它会进入stack memory。动态分配的内存进入堆,您可以通过指针分配内存。首先你声明pointer to int并通过malloc分配小内存,当需要时你可以通过realloc()重新分配内存。像这样

 int* stack=malloc(sizeof(int));

 stack=realloc(stack,(size+1)*sizeof(int)); //size is the size of stack

永远记得检查错误。

【讨论】:

  • 你不需要投射realloc()。您应该将结果分配给不同的变量,以便检查错误。
  • 而且“栈内存”不是静态的。
  • 我的意思是别的......对不起@jens Gustedt
  • 这是个坏主意。
  • 是的,我也知道这是个坏主意@Karim 但这是一个微不足道的解决方案。
【解决方案2】:

malloc() 返回的内存可用于存储一定大小的int 数组。实现数据结构的一种方法是使用malloc() 分配固定大小的int 数组。然后,您可以将元素插入到数组中,直到达到其最大大小。此时,您可以realloc()(有关详细信息,请参阅手册页)调整先前分配的块的大小以获取更多内存(您可以将先前的大小翻倍示例)。或者另一种技术是使用多级堆栈,这意味着只要前一个堆栈空间不足,您就可以将新堆栈帧添加到堆栈组。避免realloc()(如果处理大型内存块可能会失败)的另一种可能的方法是在前一个堆栈帧已满时将其交换到磁盘中,然后使用同一帧插入新值。

realloc() 堆栈的实现:

#define SCALE_FACTOR 2  /*  Double stack size at each new realloc   */

typedef struct stack {

    int *array;
    int stack_size;     /* Maximum number of elements */
    int stack_pointer;

} Stack;


int insert(Stack *ptr, int value)
{
    if(ptr->stack_pointer >= ptr->stack_size) {
        int realloc_size = ptr->stack_size * SCALE_FACTOR;
        int *new_array = realloc(ptr->array, realloc_size * sizeof(int));

        if(!new_array)
            return -1;   /* Resizing failed */

        ptr->array = new_array;
        ptr->stack_size = realloc_size;     
    }

    ptr->array[ptr->stack_pointer++] = value;
    return ptr->stack_pointer;
}

您必须在调用 insert() 之前初始化您的堆栈结构。
我在 ideone.com(永久保存文件)上写了一个演示,展示了堆栈的完整实现,并以插入 100 个初始大小为 25 个元素的元素为例。

有些人建议为每个新插入致电realloc()。这种方法非常糟糕,因为它会导致可怕的性能下降(realloc() 是一个重型函数),尤其是当插入过程在单位时间内发生如此多次时(插入开销)。

【讨论】:

    【解决方案3】:

    你完全误解了malloc() 的作用——它返回一个指向内存块的指针;您可以按照自己的意愿解释该内存块 - 它不是 指针数组 - 指针是您引用数组的方式。

    要使用连续内存块动态实现堆栈,您需要使用realloc() 调整分配大小;然而,这可能非常低效,因为在大多数情况下,现有分配不能简单地扩展,并且需要创建一个新的更大的分配,而不是在删除之前的分配之前复制到它的现有分配的所有内容。一种解决方案是以“块”为单位扩展堆栈,其中块大小是当前容量的一个比例,以便重新分配的次数适应使用情况。

    #define INITIAL_STACK_SIZE 128
    #define STACK_GROWTH_FACTOR 8
    
    static int stack_size = INITIAL_STACK_SIZE ;
    static int* stack = 0 ;
    static int stack_index = 0 ;
    
    void create()
    {
        stack_size = STACK_GROWTH_FACTOR ;
        stack = calloc( stack_size, sizeof(int) ) ;
    }
    
    void destroy()
    {
        free( stack ) ;
        stack = 0 ;
        stack_index = 0 ;
        stack_size = 0 ;
    }
    
    void push( int i )
    {
        if( stack != 0 )
        {
            if( stack_index >= stack_size )
            {
                stack_size += stack_size / STACK_GROWTH_FACTOR ;
                stack = realloc( stack, stack_size * sizeof(int) ) ; 
            }
    
            stack[stack_index] = i ;
            stack_index++ ;
        }
    }
    
    int pop()
    {
        int i = 0 ;
        if( stack != 0 )
        {
            i = stack[stack_index] ;
            stack_index-- ;
        }
    
        return i ;
    }
    

    stack_index 低于stack_size 的某个比例时,上述解决方案还可以适应在pop() 中动态减少 容量并且可能进一步允许多个堆栈。可以包括对 calloc()/realloc() 调用的一些安全检查,但为了清楚起见,我省略了。

    【讨论】:

    • 建议stack_growth_factor --> 将STACK_GROWTH_FACTORstack = calloc( stack_size, sizeof (int) ) ; 推荐给stack = calloc( stack_size, sizeof *stack ) ;,以简化编码、审查和维护。
    • @chux :首先是一个错误——当我不得不处理其他事情时,我正在改变。我考虑的第二个,但考虑到对指针的明显混淆,决定在这个阶段这可能只是另一个混​​淆的来源。当我在电脑上而不是手机上时,稍后会编辑(除非你愿意这样做)。
    【解决方案4】:

    为了更好地理解指针的工作原理,让我们看看并比较两个声明:

    int array[10];//note that we know the size of the array
    

    第二种使用指针:

    int *array = NULL;
    

    指针“array”将地址存储在 int 数组的第一个值的内存中。 我们必须“手动”在内存中分配一些空间,以便我们的进程可以在这个内存区域中读写。 为此,让我们看看这段代码:

    #include <stdlib.h>
    #include <stdio.h>
    
    int *dynamic_int_array_allocation(int *array, int size){
    
      if(size == 0){
        // if the size specified by the size variable is 0 then allocate
        // memory for one int, the size of this int in the memory is 2 or 4 bytes
        // it depend on your platform
        // if you want to know how many bytes their was used, use the following:
        // printf("The size of int in this platform is %lu\n", sizeof(int));
        array = (int*)malloc(sizeof(int));
      }
      else if(size != 0){
        // else if the size specified by the size variable is not 0
        // then we have to realloc our integer array, to do so
        // we declare a temporary integer pointer here:
        int *t1;
        // we reallocate our previous pointer with the size variable
        t1 = realloc(array, size * sizeof(int));
        // if the request failed (realloc return null) we free our array
        // if the request succeed we assign to our array pointer the address of
        // the new area of memory returned by the realloc function
        if(array == NULL)
          free(array);
        else
          array = t1;
    
      }
      return array; // return the address of the array
    }
    
    //to test our function:
    int main(int argc, char const *argv[]) {
      // declaration of our array
      int *my_integer_array = NULL;
    
      // allocate a new area of memory to our array
      my_integer_array = dynamic_int_array_allocation(my_integer_array, 0);
      printf("This is the first address of our pointer is: %p\n", my_integer_array);
      // to test our function, we use here a for loop
      for (int i = 0; i < 10; i++) {
        // this realloc our tab at each iteraction
        // we use i+1 because "i" was at 0 and we want
        // the function to reallocate our array with 2 boxes at the beginning of this loop
        // at the end of the loop i will be 9 and we will have 10 boxes in our array
        // wich is ok
        my_integer_array = dynamic_int_array_allocation(my_integer_array, i+1);
        // we fill the boxes of our array with integers
        my_integer_array[i] = i;
        printf("The new address of our pointer is: %p\n", my_integer_array);
      }
      // What is in our array:
      for (int i = 0; i < 10; ++i)
      {
        printf("array[%d] = %d\n",i, my_integer_array[i] );
      }
    //don't forget to free the zone of allocated memory
      free(my_integer_array);
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      • 1970-01-01
      • 2013-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-12
      相关资源
      最近更新 更多