简体   繁体   中英

How can I dynamically allocate memory for an array of int (not int*) in C?

I am trying to implement a stack in C using arrays. I want an array of integers, and each time I try to push an int I want to allocate some new memory. But my understanding of malloc() is that it returns a pointer to some memory it allocated somewhere, which would be fine if I had an array of int-pointers, but I don't. Here's where I allocate new memory, and I get a warning:

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

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

Is it possible to implement a stack using a dynamically allocated array of non-pointers? Or does malloc() lend itself to just using an array of pointers?

EDIT: I think I am trying to treat an array like a linked list? Seems when I want to allocate space for an array using malloc, it looks something like malloc(sizeof(int) * maxSize) . This will make a big chunk of memory somewhere. What I can't do is ask malloc to give me another piece of memory right at the end of that chunk, but I can expand that chunk. If I were implementing a stack using a linked list, it wouldn't matter WHERE malloc put the new space. I think I'm mixing some things up in my head.

So next question- if implementing a stack using arrays, do I HAVE to specify a maximum size of the stack?

The memory returned by malloc() could be used to store an int array of a certain size. One way to implement your data structure is to allocate a fixed size int array using malloc() . And then, you can insert elements into the array until you reach its maximum size. At this point, you can realloc() (See man page for more details) to resize the previously allocated block for more memory (You can double the previous size par example). Or another technique is to use a multi stage stack which means you add new stack frames to the stack bank whenever the previous stack runs out of space. One other possible way to avoid realloc() (It could fail if handling large sized memory blocks) is to swap the previous stack frame into disk whenever it is full & then use the same frame to insert new values.

An implementation of the realloc() stack :

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

You have to initialize your stack struct before calling insert() .
I wrote a demo on ideone.com (Saves file forever) that shows a complete implementation of the stack with an example of inserting 100 elements with an initial size of 25 elements.

Some people suggested to call realloc() for every new insertion. This method is extremely bad because it causes a horrible performance degradation (realloc() is a heavy duty function), especially when the insertion process happens so many times in a unit of time (Insertion overhead).

You have entirely misunderstood what malloc() does - it returns a pointer to a memory block; you can interpret that memory block how you wish - it is not an array of pointers - the pointer is how you reference the array.

To implement your stack dynamically using a contiguous memory block, you need to resize the allocation using realloc() ; however this can be terrifically inefficient since in most cases the existing allocation cannot simply be extended and will require a new larger allocation to be created than all the content of the existing allocation copied to it before deleting the previous allocation. One solution is to extend the stack in "chunks", where the chunk size is a proportion of the current capacity, so that the number of reallocation is adaptive to the usage.

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

The above solution can be adapted to also decrease the capacity dynamically in the pop() when the stack_index falls below a certain proportion of stack_size for example and further perhaps to allow multiple stacks. Some safety checks for the calloc() / realloc() calls could be included, but I have omitted for clarity.

when you declare small array in your main function it goes in the stack memory . Dynamically allocated memory goes into heap and you can allocate memory through pointer. first you declare pointer to int and allocate small memory though malloc and when it is needed you can reallocate memory through realloc() .like this

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

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

Always remember to check errors.

to understand better how a pointer works, let's see and compare two declaration:

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

The second one use pointers:

int *array = NULL;

The pointer "array" store the address in the memory of the first value of an int array. We have to 'manually' allocate some space in the memory, so our process can read and write in this region of memory. To do so let's see this code:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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