使用realloc扩展和缩小数组

时间:2016-01-05 15:30:29

标签: c arrays pointers realloc

我正在尝试编写一个程序,该程序首先动态初始化100个int元素的队列数组。每当队列已满并且另一个元素应该排队时,原始数组应该加倍它的大小,以便可以插入新元素。如果元素出队,并且队列所包含的元素数量低于其实际大小的一半,则队列大小应该减半。但是,它的大小不应低于10。

我试图使用realloc扩展和缩小数组,但是我在理解其机制方面遇到了一些问题,特别是在返回新指针时。这是我的程序(由于printf原因有一些冗余的debugging):

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



void enqueue(int arr[], int* lastElementIdx, int *length, int element);
int dequeue (int arr[], int* lastElementIdx, int *length);
void printQueue(const int arr[], int lastElementIdx);
int expandArray(int *arr, int length);
int shrinkArray(int *arr, int length, bool min);


void test1(int *arr, int* lastElementIdx, int *length)
{
    int* temp = arr;
    printf("\nprintQueue #1:\n");                   //print queue, should be empty
    printQueue(temp, *lastElementIdx);

    for(int i = 1; i <= 100; i++)                   //insert elemnts to queue
        enqueue(temp, lastElementIdx, length, i);

    printf("\nprintQueue #2:\n");                   //print queue
    printQueue(temp,*lastElementIdx);

    printf("\nAusgabe von dequeue:\n");             // dequeue array
    while(*lastElementIdx > *length/4)
        printf("\naddress: %p\tElement: %d\n", temp, dequeue(temp, lastElementIdx, length));

    free(temp);

}


void test2(int *arr, int* lastElementIdx, int *length)
{
    int *temp = arr;
    printf("\n************\nEnqueue beyond queue[N-1]:\n");
    puts("Queue aufbauen...");
    for(int i = 1; i <= 150; i++)
        enqueue(temp, lastElementIdx, length, i);

    printf("\nprintQueue:\n");
    printQueue(temp,*lastElementIdx);

    printf("\nDequeue:\n");
    while(*lastElementIdx > *length/4)
        printf("\naddress: %p\tElement: %d\n", temp, dequeue(temp, lastElementIdx, length));

    free(temp);

}



int main(int argc, char const *argv[])
{
    int startingPoint = -1, *lastElementIdx = &startingPoint, N = 100, *length = &N;
    int *queue = (int*) calloc(*length, sizeof(*queue));

    test2(queue, lastElementIdx, length);
    queue = (int*) calloc(*length, sizeof(*queue));
    test1(queue, lastElementIdx, length);


    return 0;
}

int expandArray(int *arr, int length)
{
    /*function to double the array size*/

    length *= 2;
    int *temp;
    temp = (int*) realloc(arr, sizeof(*arr)*length);
    if (!temp) {
        free(temp);
    }
    else{
        if (arr != temp) {
            free(arr);
            arr = temp;
        }
        else{
            arr = temp;
        }
    }

    printf("EXPAND ARRAY: %p\n", arr);
    return length;
}

int shrinkArray(int *arr, int length, bool min)
{
    /*function that cuts array in half*/
    int *temp;

    if (min){
        length = 10;
    }
    else{
        length /= 2;
    }

    temp = (int*) realloc(arr,sizeof(*arr)*length);
    if (!temp) {
        free(temp);
    }
    else{
        arr = temp;
    }

    printf("SHRINK ARRAY: %p\n",arr);
    return length;
}

void enqueue(int arr[], int* lastElementIdx, int *length, int element)
{
    if ( *lastElementIdx < *length - 1){        //checks if there's space for another element
        arr[*lastElementIdx + 1] = element;     //if yes, insert element after lastElementIdx
        (*lastElementIdx)++;                    //increment lastElementIdx
    }
    else{
        *length = expandArray(arr, *length);    //if not, expand array
    }
}



int dequeue (int arr[], int* lastElementIdx, int *length)
{
    printf("address before:\t%p\tLast Element: %d\tLength: %d\n", arr,*lastElementIdx, *length);
    int *p = arr;
    if(*lastElementIdx > -1){               //Checks if there is an element in the queue
        if (*lastElementIdx + 2 < *length/2 and *lastElementIdx + 2 > 10) {
            bool min = false;
            *length = shrinkArray(arr, *length, min);
        }
        else if (*lastElementIdx + 2 < 10){
            bool min = true;
            *length = shrinkArray(arr, *length, min);
        }

        (*lastElementIdx)--;        //shift position of last element
        printf("address afterw:\t%p\tLast Element: %d\tLength: %d\n", arr, *lastElementIdx,*length);
        return *(p + *lastElementIdx + 1);
    }


    return 0;
}



void printQueue(const int arr[], int lastElementIdx)
{
    while( lastElementIdx > -1){
        printf("%d\t", *(arr + lastElementIdx));
        lastElementIdx--;   
    }   
}

但是我不断收到2个错误。第一个是:

if (arr != temp) {
            free(arr);
            arr = temp;
        }

error for object 0x1001013b0: pointer being freed was not allocated。 我首先实现了这一行,因为过了一段时间我发现有时重新分配的内存更改的指针地址。如果我删除了if statement我仍然会收到错误,这次是在这一行:

temp = (int*) realloc(arr, sizeof(*arr)*length);

消息为:malloc: *** error for object 0x100500000: pointer being realloc'd was not allocated

我还应该补充一点,在这两种情况下,有时程序执行没有任何问题。在后一种情况下,错误在expandArray中的realloc行与shrinkArray中的realloc行之间交替出现。 我不太明白为什么会发生这种情况,以及当realloc返回新的指针地址时如何处理这种情况。受到类似帖子的启发,我尝试了不同的方法,例如将int **arr而不是int *arr传递给expandArrayshrinkArray。我还尝试了不同的方法来释放realloc后的原始数组

temp = (int*) realloc(arr,sizeof(*arr)*length);
if (!temp) {
    free(temp);
}
else{
    free(arr);
    arr = temp;
}

始终使用相同的错误消息。我希望在每个测试函数之后释放内存并在调用第二个测试函数之前在main function中为队列数组分配新内存将解决问题,而事实上它并没有解决问题。

我真的很感激这方面的任何帮助。

3 个答案:

答案 0 :(得分:4)

realloc无法按预期工作。 realloc为你完成这份工作。它需要一个指向动态内存的指针改变动态内存的大小并返回指针,为此可能分配新内存,移动内存中的数据并释放旧内存。

像这样调整你的代码:

int expandArray(int **arr, int length)
                 // ^^ pointer to array input and output
{
    int newLength = length * 2;
    int *temp = realloc( *arr, sizeof(int) * newLength); 
    // If the function fails to allocate the requested block of memory,
    // a null pointer is returned,
    // and the memory block pointed to by argument ptr is not deallocated
    if ( temp != NULL ) {
        *arr = temp;
        length = newLength;
    }

    printf("EXPAND ARRAY: %p\n", *arr);
    return length;
}

int shrinkArray(int **arr, int length, int min)
                 // ^^ pointer to array input and output 
{
    int newLength;
    if (min){
        newLength= 10;
    }
    else{
        newLength = length / 2;
    }

    int *temp = realloc( *arr, sizeof(int) * newLength ); 
    // If the function fails to allocate the requested block of memory,
    // a null pointer is returned,
    // and the memory block pointed to by argument ptr is not deallocated
    if ( temp != NULL ) {
       *arr = temp;
        length = newLength;
    }

    printf("SHRINK ARRAY: %p\n",*arr);
    return length;
}

最后,您必须调整函数enqueuedequeue,类似于expandArrayshrinkArray

void enqueue(int **arr, int* lastElementIdx, int *length, int element);
              // ^^
int dequeue (int **arr, int* lastElementIdx, int *length);
              // ^^

void enqueue(int **arr, int* lastElementIdx, int *length, int element)
{
    if ( *lastElementIdx < *length - 1){        // checks if there's space for another element
        (*arr)[*lastElementIdx + 1] = element;  // if yes, insert element after lastElementIdx
        (*lastElementIdx)++;                    // increment lastElementIdx
    }
    else{
        *length = expandArray(arr, *length);    // if not, expand array
    }
}

int dequeue (int **arr, int* lastElementIdx, int *length)
{
    printf("address before:\t%p\tLast Element: %d\tLength: %d\n", arr,*lastElementIdx, *length);
    if( *lastElementIdx > -1 ){   // Checks if there is an element in the queue
        if ( *lastElementIdx + 2 < *length/2 && *lastElementIdx + 2 > 10) {
            *length = shrinkArray( arr, *length, 0 );
        }
        else if ( *lastElementIdx + 2 < 10 ){
            *length = shrinkArray( arr, *length, 1 );
        }
        (*lastElementIdx)--;   // shift position of last element
        printf("address afterw:\t%p\tLast Element: %d\tLength: %d\n", *arr, *lastElementIdx,*length);
        return *(*arr + *lastElementIdx + 1);
    }
    return 0;
}

答案 1 :(得分:2)

int foo(int *arr, ... ) {
  arr = ...
}

arr是一个函数参数。因此只是调用者中的一个副本。像函数内部一样更改它只会更改函数参数。调用者保留旧值。

你需要:

int foo(int **arr, ... ) {
  *arr = ...
}

祝贺。您刚刚解锁了 2星级程序员徽章

答案 2 :(得分:0)

 #include<stdio.h>
 #include<stdlib.h>
 int main(){
 int *a,*b,*a1;
 int n,i,k=0;
 scanf("%d",&n);
 a=(int *)malloc(n*sizeof(int));
 b=(int *)malloc(n*sizeof(int));
printf("Enter a");
for(i=0;i<n;i++){
    scanf("%d",&a[i]);
}
printf("Enter b");
for(i=0;i<n;i++){
    scanf("%d",&b[i]);
}
a1=(int*)realloc(a,(2*n)*sizeof(int));
for(i=n;i<(2*n);i++)
{
    a1[i]=b[k];
    k++;
}

for(i=0;i<(2*n);i++)
    printf("%d",a1[i]);
}