2014-01-09 36 views
3

我想創建一個基於動態數組的動態集合抽象數據類型。不過,我得到一個編譯器警告和錯誤,當我嘗試添加的數據陣列,它們是:虛空指針的動態數組

警告:提領「無效*」指針[默認啓用]

錯誤:無效使用無效的表達

我的代碼如下,我已加評論

struct SET 
{ 
//general dynamic array 
void *data; 
int elements; //number of elements 
int allocated; // size of array 
}; 

struct SET create() 
{ 
//create a new empty set 

struct SET s; 
s.data = NULL; 
s.elements = 0; 
s.allocated = 0; //allocations will be made when items are added to the set  
puts("Set created\n"); 
return s; 
} 

struct SET add(struct SET s, void *item) 
{ 
//add item to set s 

if(is_element_of(item, s) == 0) //only do this if element is not in set 
{ 
    if(s.elements == s.allocated) //check whether the array needs to be expanded 
    { 
     s.allocated = 1 + (s.allocated * 2); //if out of space, double allocations 
     void *temp = realloc(s.data, (s.allocated * sizeof(s))); //reallocate memory according to size of the set 

     if(!temp) //if temp is null 
     { 
      fprintf(stderr, "ERROR: Couldn't realloc memory!\n"); 
      return s; 
     } 

     s.data = temp; 
    } 

    s.data[s.elements] = item; //the error is here 
    s.elements = s.elements + 1; 
    puts("Item added to set\n"); 

    return s; 
} 

else 
{ 
    fprintf(stdout, "Element is already in set, not added\n"); 
    return s; 
} 
} 

我已經做了研究空指針問題的行,但很明顯,我在這裏失去了一些東西。我會很感激我能得到的任何幫助。感謝閱讀並希望回答!

+0

你應該把所有的函數定義在這裏..它似乎是成員數據應該是無效的**? – michaeltang

+0

爲什麼會這樣? –

回答

4

首先,我想你打算在你的結構中有一個通用指針數組(void *),因爲你的項目是void *,並且你想存儲它們作爲一個數組。也就是說,你想要的void *動態數組,因此,你應該使用void **

struct SET { 
    void **data; 
    int elements; 
    int allocated; 
}; 

當然,你的add功能需要更新:

struct SET add(struct SET s, void *item) {  
     if (is_element_of(item, s) == 0) { 
      if (s.elements == s.allocated) { 
       s.allocated = 1 + (s.allocated * 2); 
       void **temp = realloc(s.data, (s.allocated * sizeof(*s.data))); 
       if (!temp) { 
        fprintf(stderr, "ERROR: Couldn't realloc memory!\n"); 
        return s; 
       } 

      s.data = temp; 
     } 
     s.data[s.elements] = item; 
     s.elements = s.elements + 1; 
     puts("Item added to set\n"); 
     return s; 
    } 

    else { 
     fprintf(stdout, "Element is already in set, not added\n"); 
     return s; 
    } 
} 

注意realloc行改爲:你不想重新分配到s.allocated * sizeof(s),你想要s.allocated*sizeof(*s.data),因爲你將存儲void *類型的元素(*s.data的類型是void *,我沒有明確寫入void *到m更容易適應未來可能的變化)。另外,我相信你應該改變你的函數來接收和返回指向struct SET的指針,否則,你總是會在結構上覆制(記住值是通過複製傳遞的)。

+0

非常感謝! –

+2

@MattGrima不客氣。動態數組背後的想法總是相同的。當你想在一個動態數組中存儲'T'類型的元素時,你必須聲明一個指向T的指針。在這種情況下,你想將'void *'存儲在一個動態數組中,所以你需要一個指向'void *'的指針,即'void **'。如果你遵循這一思路,你將永遠不會再犯這個錯誤:) –

+0

但請記住,當你從集合中彈出這些元素時,接收它們的函數必須知道它們的類型,如果你想解引用指針。 –

0

您需要在解除引用前指定void *指針。

((some_type *)(s.data))[s.elements] = *(some_type *)item;

+0

我把它轉換成char *,然後編譯,但是我有點擔心這會破壞數組的目的。如果它像這樣工作,那麼爲什麼不讓數組爲字符串定義? –

1

您要使用的數據作爲數組,但已宣佈它爲void *。編譯器無法確定是否打算將數據類型存儲到此數組中。

如果您知道要存儲在「數據」中的數據類型,您應該爲其聲明一種類型。 (如char *數據或int *數據)

+0

我不確定我關注..數組背後的想法是它可以存儲任何類型的數據。 –

+0

然後,您需要根據您存儲在其中的數據類型進行適當的轉換。 – Kiran

1

我一直在努力解決同樣的問題。我已經將我們被教導的想法分解爲混亂,void** ptr是一個二維數組。也許它也是一個二維數組,但是對於大多數我們想要使用單個指針數組和語法的部分來說,只是混淆了這個問題。使用整數例如:

int a; 

a是指存儲器的集團,其保持一個int的變量的名稱。

int* aPtr; 

aPtr是指存儲器的集團,其保持size_t類型的變量的名稱。所有指針都是size_t類型,就像所有int都是int類型一樣,float也是float類型。它保存的size_t將被分配一個地址(aPtr = &aaPtr = malloc(sizeof(int)))。因爲這是一個int指針,所分配的地址將是一個int的大小,並且它將存儲一個int。因此,您將地址分配給aPtr。您分配一個值到這個地址,記憶集團aPtr點,提領*aPtr = 10;你讀的INT值提領int val = *aPtr;

int** pPtr; 

PPTR是一個變量是指一個集團的名義指出,保存size_t的內存。存儲在這個size_t中的地址是另一個size_t存儲塊,即一個指針的地址。第二個size_t塊是保存整數地址的指針。因此你有:

int a = 10; 
int* aPtr = &a; 
int* bPtr = malloc(sizeof(int)); 
*bPtr = 20; 
int** pPtr = malloc(2 * sizeof(int*)); 
pPtr[0] = aPtr; 
*(pPtr + 1) = bPtr; 

printf("a is %d, aPtr address is %d, aPtr points to %d, bPtr points to %d.\n", a, aPtr, *aPtr, *bPtr); 
printf("pPtr[0] points to aPtr which points to %d. Which is to say, qwe dereference pPtr to get to aPtr and dereference aPtr to get to its value.\n", *(pPtr)[0]); 
printf("Which can be handled with different syntax illustrated by pPtr[1] to give %d\n", *(*(pPtr + 1))); 

pPtr需要取消引用訪問它指向的指針。具體而言,我們希望指向的指針爲bPtr,數組中的第二個元素如*(pPtr + 1)。但是,我們希望值bPtr點,不bPtr的地址,以便我們已經取消引用*(pPtr + 1)因此*(*(pPtr + 1))

空指針可正是如此包括:

void** vPtr = malloc(2 * sizeof(void*)); 
*(vPtr + 0) = aPtr; 
*(vPtr + 1) = bPtr; 

printf("vPtr[1] is %d\n", *((int*)*(vPtr + 1))); 

正如一些評論家已經指出的無效指針必須轉換爲類型。因此aPtrbPtr被存儲在數組中作爲void指針需要被轉換回int指針:(int *)*(vPtr + 1)