2016-01-05 22 views
1

我試圖寫一個程序,其第一動態初始化爲100個INT元件隊列陣列收縮陣列。每當隊列已滿並且另一個元素應該排隊時,原始數組應該是其大小的兩倍,以便可以插入新元素。在元素出隊的情況下,隊列所包含的元素數量低於其實際大小的一半時,隊列大小應該減半。然而,它的規模應該不會低於10擴展和使用的realloc

我試圖擴大和縮小與realloc的數組,但我在理解其機制的一些問題,返回新的指針時尤其如此。下面是我的程序(有一些冗餘printfdebugging原因):

#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。 我實現了擺在首位這一行,因爲過了一段時間我有時想通了的重新分配內存的變化指針的地址。在這兩種情況下,有時執行程序malloc: *** error for object 0x100500000: pointer being realloc'd was not allocated

我也應該補充,如果我刪除if statement我仍然不斷收到錯誤,這一次在這條線是:

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

消息之中沒有任何問題。在後一種情況下,錯誤在expandArray中的重新分配行與shrinkArray中的重新分配行之間交替。 我真的不明白爲什麼會這樣,以及如何處理這種情況時realloc返回新的指針地址。受類似帖子的啓發,我嘗試了不同的方法,例如將int **arr而不是int *arr傳遞給expandArrayshrinkArray。我也嘗試了不同的方法來釋放後的realloc原始數組一樣

temp = (int*) realloc(arr,sizeof(*arr)*length); 
if (!temp) { 
    free(temp); 
} 
else{ 
    free(arr); 
    arr = temp; 
} 
具有相同的錯誤消息

始終。我希望在每個測試函數之後釋放內存,並在調用第二個測試函數之前在隊列數組中分配新內存以解決問題,但事實上並不如此。

我真的很感激任何形式的這一幫助。

+1

評論:使用''標題是很不尋常的。目光觀察代碼,我發現'&和'代替'&&'的一個實例。我想知道這是否是一個優勢。這在技術上不是錯誤的;不過,這很不尋常。 –

+0

好的謝謝。其實我更喜歡玩它,因爲幾天前我讀到了它。這也是我第一次也是唯一一次使用它。 –

+1

注意:1)'realloc()'可能在內存不足的情況下返回'NULL',如'realloc(arr,sizeof(* arr)* length);',如果長度爲0。所以不是'if(!temp){free(temp);'use'if(!temp && length!= 0){free(temp);'更好的是,事先檢測if(length <= 0)只需調用'free(arr)'。 2)最好使用'size_t長度'。 – chux

回答

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; 
} 
+0

謝謝。我一直在調整我的代碼給你。我仍然遇到同樣的問題。即使使用以前的版本,在編輯它之前。它仍然有時運行沒有錯誤,但大部分時間它告訴我'指針被重新分配'沒有被分配。我會繼續嘗試,也許我的其他功能稱爲這兩個功能有問題。 –

+0

嗯,沒有。根據輸出,長度永遠不會低於10.另外,'shrinkArray' realloc期間的錯誤總是在第一次調用時發生,更確切地說,在這種情況下,從200和100收縮的時刻。如果程序成功,它會成功所有其他剩餘的減少也是如此。第一個測試函數被終止,第二個被調用。但是一旦調用'expandArray',它就會停止工作。在第一次通話時再次正確。因此,似乎每個功能中的第一個「realloc」調用至關重要 –

+1

是的!我喜歡你!我一直在努力,直到我看到您的評論。該代碼現在完美工作。我一直坐在這最後2天,在我終於放棄並決定在這裏發佈之前,試圖自己找出解決方法。你,先生,讓我的一天! –

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

arr是函數參數。因此只是來電者的副本。在函數內部改變它只會改變函數參數。來電者保留舊的價值。

您需要:

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

祝賀。您剛剛解鎖了2星級程序員徽章

+0

然後如何工作'memset'例如?它的第一個參數是'void *',而不是'void **'。 – stek29

+0

@ stek29 memset不會更改指針的值。它改變指針指向的內存的內容。 – bolov

+1

@reinka:爲了理解'2星級程序員'徽章,您還需要了解[三星程序員](http://c2.com/cgi/wiki?ThreeStarProgrammer)不是一個好評的名詞,一般來說(不像成爲'三星將軍',但他們通常不是程序員)。在C中使用兩顆星是完全可以接受的,有時也是必需的三顆星更經常表明可能存在問題。 –