2012-05-30 4 views
12

Ho la seguente struct:malloc un array di puntatori struct

typedef struct _chess { 
    int **array; 
    int size; 
    struct _chess *parent; 
} chess; 

e ho:

typedef struct _chess *Chess; 

Ora, voglio creare un array di lunghezza dinamica per memorizzare i puntatori a scacchi struct so fare così:

Chess array [] = malloc(size * sizeof(Chess)); 

Questo mi dà un errore: inizializzatore non valido.

E se lascio cadere il [] e fare questo:

Chess array = malloc(size * sizeof(Chess)); 

compila senza errori, ma quando provo a impostare un elemento di questo array a NULL facendo:

array[i]=NULL; 

I ottenere un errore: tipi incompatibili quando si assegna a tipo 'struct _chess' da tipo 'void *'

Qualche idea di cosa sto sbagliando? Grazie.

+0

Perché digitare la struttura? ha già un tipo unico. –

+1

@ user82238 Quindi non è necessario digitare 'struct' quando si utilizza il tipo. – Tyilo

+3

Smetti di usare typedef del puntatore, ti stai solo confondendo. 'chess * array = malloc (size * sizeof * array);'. –

risposta

33

array è un nome leggermente fuorviante. Per una matrice di puntatori allocata dinamicamente, malloc restituirà un puntatore a un blocco di memoria. È necessario utilizzare Chess* e non Chess[] per mantenere il puntatore sull'array.

Chess *array = malloc(size * sizeof(Chess)); 
array[i] = NULL; 

e forse più tardi:

/* create new struct chess */ 
array[i] = malloc(sizeof(struct chess)); 

/* set up its members */ 
array[i]->size = 0; 
/* etc. */ 
+0

Grazie! Questo l'ha risolto per me! Spiegheresti perché non funziona Chess []? Sono confuso ora che però [] e * sono la stessa cosa. – MinaHany

+0

@MinaHany '[]' è un array, contenente i contenuti effettivi. '*' è un puntatore ai contenuti. Accesso e utilizzo sono gli stessi, ma la rappresentazione della memoria è completamente diversa. – glglgl

0

IMHO, questo sembra migliore:

Chess *array = malloc(size * sizeof(Chess)); // array of pointers of size `size` 

for (int i =0; i < SOME_VALUE; ++i) 
{ 
    array[i] = (Chess) malloc(sizeof(Chess)); 
} 
+0

Penso che lo userei se voglio che la matrice tenga le strutture reali e non solo i puntatori a loro. È giusto? – MinaHany

+0

In questo array di codice contiene puntatori, non gli oggetti. Per fare una matrice di strutture usa 'struct _chess a [10]; // Matrice di dieci strutture _chess' – maverik

18

C'è un sacco di typedef succedendo qui. Personalmente sono contrario a "nascondere l'asterisco", ovvero typedef: ing dei tipi di puntatore in qualcosa che non assomiglia a un puntatore. In C, i puntatori sono abbastanza importanti e influenzano davvero il codice, c'è molta differenza tra foo e foo *.

Molte delle risposte sono anche confuse su questo, penso.

tuo assegnazione di una serie di Chess valori, che sono puntatori a valori di tipo chess (ancora una volta, un molto confusione nomenclatura che davvero non posso raccomandare) dovrebbe essere simile a questo:

Chess *array = malloc(n * sizeof *array); 

quindi, è necessario inizializzare le istanze effettive, dal looping:

for(i = 0; i < n; ++i) 
    array[i] = NULL; 

Questo presuppone che non si vuole allocare la memoria per le istanze, si vuole solo un array di puntatori w con tutti i puntatori che inizialmente non puntavano verso il nulla.

Se si voleva allocare lo spazio, la forma più semplice sarebbe:

for(i = 0; i < n; ++i) 
    array[i] = malloc(sizeof *array[i]); 

vedere come l'utilizzo sizeof è coerente al 100%, e mai inizia a parlare di tipi espliciti. Utilizzare le informazioni sul tipo inerenti alle variabili e lasciare che il compilatore si preoccupi di quale tipo è quale. Non ripeterti.

Ovviamente, quanto sopra fa una quantità inutilmente grande di chiamate a malloc(); a seconda dei modelli di utilizzo, potrebbe essere possibile eseguire tutto quanto sopra con una sola chiamata a malloc(), dopo aver calcolato la dimensione totale necessaria. Quindi devi ancora passare e inizializzare i puntatori array[i] per puntare nel blocco grande, ovviamente.

+7

+1 per 'contro "che nasconde l'asterisco" ". – glglgl

+0

hmm .. Ho fatto scacchi * array = malloc (size * sizeof (Chess)); e quindi per (i = 0; i MinaHany

+0

Sì, va bene, se tutto ciò che si desidera è una serie di puntatori che in seguito si imposta su alcune istanze che si trovano in giro. Ho modificato per aggiungere NULL-init come caso predefinito. – unwind

0

Sono d'accordo con @maverik sopra, preferisco non nascondere i dettagli con un typedef. Soprattutto quando stai cercando di capire cosa sta succedendo. Preferisco anche vedere tutto invece di uno snippet di codice parziale. Detto questo, ecco un malloc e privo di una struttura complessa.

Il codice utilizza il rilevatore di perdite Visual Studio in modo da poter sperimentare le potenziali perdite.

#include "stdafx.h" 

#include <string.h> 
#include "msc-lzw.h" 

#define _CRTDBG_MAP_ALLOC 
#include <stdlib.h> 
#include <crtdbg.h> 



// 32-bit version 
int hash_fun(unsigned int key, int try_num, int max) { 
    return (key + try_num) % max; // the hash fun returns a number bounded by the number of slots. 
} 


// this hash table has 
// key is int 
// value is char buffer 
struct key_value_pair { 
    int key; // use this field as the key 
    char *pValue; // use this field to store a variable length string 
}; 


struct hash_table { 
    int max; 
    int number_of_elements; 
    struct key_value_pair **elements; // This is an array of pointers to mystruct objects 
}; 


int hash_insert(struct key_value_pair *data, struct hash_table *hash_table) { 

    int try_num, hash; 
    int max_number_of_retries = hash_table->max; 


    if (hash_table->number_of_elements >= hash_table->max) { 
     return 0; // FULL 
    } 

    for (try_num = 0; try_num < max_number_of_retries; try_num++) { 

     hash = hash_fun(data->key, try_num, hash_table->max); 

     if (NULL == hash_table->elements[hash]) { // an unallocated slot 
      hash_table->elements[hash] = data; 
      hash_table->number_of_elements++; 
      return RC_OK; 
     } 
    } 
    return RC_ERROR; 
} 


// returns the corresponding key value pair struct 
// If a value is not found, it returns null 
// 
// 32-bit version 
struct key_value_pair *hash_retrieve(unsigned int key, struct hash_table *hash_table) { 

    unsigned int try_num, hash; 
    unsigned int max_number_of_retries = hash_table->max; 

    for (try_num = 0; try_num < max_number_of_retries; try_num++) { 

     hash = hash_fun(key, try_num, hash_table->max); 

     if (hash_table->elements[hash] == 0) { 
      return NULL; // Nothing found 
     } 

     if (hash_table->elements[hash]->key == key) { 
      return hash_table->elements[hash]; 
     } 
    } 
    return NULL; 
} 


// Returns the number of keys in the dictionary 
// The list of keys in the dictionary is returned as a parameter. It will need to be freed afterwards 
int keys(struct hash_table *pHashTable, int **ppKeys) { 

    int num_keys = 0; 

    *ppKeys = (int *) malloc(pHashTable->number_of_elements * sizeof(int)); 

    for (int i = 0; i < pHashTable->max; i++) { 
     if (NULL != pHashTable->elements[i]) { 
      (*ppKeys)[num_keys] = pHashTable->elements[i]->key; 
      num_keys++; 
     } 
    } 
    return num_keys; 
} 

// The dictionary will need to be freed afterwards 
int allocate_the_dictionary(struct hash_table *pHashTable) { 


    // Allocate the hash table slots 
    pHashTable->elements = (struct key_value_pair **) malloc(pHashTable->max * sizeof(struct key_value_pair)); // allocate max number of key_value_pair entries 
    for (int i = 0; i < pHashTable->max; i++) { 
     pHashTable->elements[i] = NULL; 
    } 



    // alloc all the slots 
    //struct key_value_pair *pa_slot; 
    //for (int i = 0; i < pHashTable->max; i++) { 
    // // all that he could see was babylon 
    // pa_slot = (struct key_value_pair *) malloc(sizeof(struct key_value_pair)); 
    // if (NULL == pa_slot) { 
    //  printf("alloc of slot failed\n"); 
    //  while (1); 
    // } 
    // pHashTable->elements[i] = pa_slot; 
    // pHashTable->elements[i]->key = 0; 
    //} 

    return RC_OK; 
} 


// This will make a dictionary entry where 
// o key is an int 
// o value is a character buffer 
// 
// The buffer in the key_value_pair will need to be freed afterwards 
int make_dict_entry(int a_key, char * buffer, struct key_value_pair *pMyStruct) { 

    // determine the len of the buffer assuming it is a string 
    int len = strlen(buffer); 

    // alloc the buffer to hold the string 
    pMyStruct->pValue = (char *) malloc(len + 1); // add one for the null terminator byte 
    if (NULL == pMyStruct->pValue) { 
     printf("Failed to allocate the buffer for the dictionary string value."); 
     return RC_ERROR; 
    } 
    strcpy(pMyStruct->pValue, buffer); 
    pMyStruct->key = a_key; 

    return RC_OK; 
} 


// Assumes the hash table has already been allocated. 
int add_key_val_pair_to_dict(struct hash_table *pHashTable, int key, char *pBuff) { 

    int rc; 
    struct key_value_pair *pKeyValuePair; 

    if (NULL == pHashTable) { 
     printf("Hash table is null.\n"); 
     return RC_ERROR; 
    } 

    // Allocate the dictionary key value pair struct 
    pKeyValuePair = (struct key_value_pair *) malloc(sizeof(struct key_value_pair)); 
    if (NULL == pKeyValuePair) { 
     printf("Failed to allocate key value pair struct.\n"); 
     return RC_ERROR; 
    } 


    rc = make_dict_entry(key, pBuff, pKeyValuePair); // a_hash_table[1221] = "abba" 
    if (RC_ERROR == rc) { 
     printf("Failed to add buff to key value pair struct.\n"); 
     return RC_ERROR; 
    } 


    rc = hash_insert(pKeyValuePair, pHashTable); 
    if (RC_ERROR == rc) { 
     printf("insert has failed!\n"); 
     return RC_ERROR; 
    } 

    return RC_OK; 
} 


void dump_hash_table(struct hash_table *pHashTable) { 

    // Iterate the dictionary by keys 
    char * pValue; 
    struct key_value_pair *pMyStruct; 
    int *pKeyList; 
    int num_keys; 

    printf("i\tKey\tValue\n"); 
    printf("-----------------------------\n"); 
    num_keys = keys(pHashTable, &pKeyList); 
    for (int i = 0; i < num_keys; i++) { 
     pMyStruct = hash_retrieve(pKeyList[i], pHashTable); 
     pValue = pMyStruct->pValue; 
     printf("%d\t%d\t%s\n", i, pKeyList[i], pValue); 
    } 

    // Free the key list 
    free(pKeyList); 

} 

int main(int argc, char *argv[]) { 

    int rc; 
    int i; 


    struct hash_table a_hash_table; 
    a_hash_table.max = 20; // The dictionary can hold at most 20 entries. 
    a_hash_table.number_of_elements = 0; // The intial dictionary has 0 entries. 
    allocate_the_dictionary(&a_hash_table); 

    rc = add_key_val_pair_to_dict(&a_hash_table, 1221, "abba"); 
    if (RC_ERROR == rc) { 
     printf("insert has failed!\n"); 
     return RC_ERROR; 
    } 
    rc = add_key_val_pair_to_dict(&a_hash_table, 2211, "bbaa"); 
    if (RC_ERROR == rc) { 
     printf("insert has failed!\n"); 
     return RC_ERROR; 
    } 
    rc = add_key_val_pair_to_dict(&a_hash_table, 1122, "aabb"); 
    if (RC_ERROR == rc) { 
     printf("insert has failed!\n"); 
     return RC_ERROR; 
    } 
    rc = add_key_val_pair_to_dict(&a_hash_table, 2112, "baab"); 
    if (RC_ERROR == rc) { 
     printf("insert has failed!\n"); 
     return RC_ERROR; 
    } 
    rc = add_key_val_pair_to_dict(&a_hash_table, 1212, "abab"); 
    if (RC_ERROR == rc) { 
     printf("insert has failed!\n"); 
     return RC_ERROR; 
    } 
    rc = add_key_val_pair_to_dict(&a_hash_table, 2121, "baba"); 
    if (RC_ERROR == rc) { 
     printf("insert has failed!\n"); 
     return RC_ERROR; 
    } 



    // Iterate the dictionary by keys 
    dump_hash_table(&a_hash_table); 

    // Free the individual slots 
    for (i = 0; i < a_hash_table.max; i++) { 
     // all that he could see was babylon 
     if (NULL != a_hash_table.elements[i]) { 
      free(a_hash_table.elements[i]->pValue); // free the buffer in the struct 
      free(a_hash_table.elements[i]); // free the key_value_pair entry 
      a_hash_table.elements[i] = NULL; 
     } 
    } 


    // Free the overall dictionary 
    free(a_hash_table.elements); 


    _CrtDumpMemoryLeaks(); 
    return 0; 
}