2012-05-30 11 views
12

que tienen la siguiente estructura:malloc una matriz de punteros struct

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

y tengo:

typedef struct _chess *Chess; 

Ahora, quiero crear una matriz de longitud dinámica para almacenar punteros al ajedrez struct por lo que hago lo siguiente:

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

Esto me da un error: inicializador no válido.

Y si me cae el [] y hacer esto:

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

compila sin error pero cuando intento configurar un elemento de esta matriz a NULL haciendo:

array[i]=NULL; 

I Obtiene un error: tipos incompatibles cuando se asigna a escribir 'struct _chess' del tipo 'void *'

¿Alguna idea de qué estoy haciendo mal? Gracias.

+0

WHy typedef the struct? ya tiene un tipo único. –

+1

@ user82238 Así que no tiene que escribir 'struct' cuando usa el tipo. – Tyilo

+3

Deja de usar punteros typedefs, solo te estás confundiendo. 'ajedrez * array = malloc (tamaño * sizeof * array);'. –

Respuesta

33

array es un nombre ligeramente engañoso. Para una matriz de punteros dinamicamente asignados, malloc devolverá un puntero a un bloque de memoria. Debe usar Chess* y no Chess[] para mantener el puntero a su matriz.

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

y quizás más adelante:

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

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

¡Gracias! ¡Esto me lo arregló! ¿Podría explicar por qué no funciona Chess []? Ahora estoy confundido, aunque creo que [] y * son lo mismo. – MinaHany

+0

@MinaHany '[]' es una matriz que contiene los contenidos reales. '*' es un puntero a los contenidos. El acceso y el uso es el mismo, pero la representación de la memoria es completamente diferente. – glglgl

0

en mi humilde opinión, esto se ve mejor:

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

Creo que usaría esto si quiero que la matriz contenga estructuras reales y no solo punteros. ¿Está bien? – MinaHany

+0

En este código, la matriz contiene punteros, no los objetos. Para hacer una matriz de estructuras use 'struct _chess a [10]; // Matriz de diez estructuras _chess' – maverik

18

Hay una gran cantidad de typedef pasando aquí. Personalmente, estoy en contra de "ocultar el asterisco", es decir, typedef: insertar tipos de puntero en algo que no se parece a un puntero. En C, los indicadores son bastante importantes y realmente afectan el código, hay mucha diferencia entre foo y foo *.

Muchas de las respuestas también están confundidas sobre esto, creo.

Su asignación de un conjunto de valores Chess, que son punteros a valores de tipo chess (de nuevo, un muy confuso nomenclatura que realmente no puedo recomendar) debe ser como este:

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

entonces, es necesario inicializar los casos reales, haciendo un bucle:

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

Esto supone que no desea asignar ningún recuerdo de los casos, lo que desea es una matriz de punteros w con todos los indicadores inicialmente apuntando a la nada.

Si desea asignar el espacio, la forma más simple sería:

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

ver cómo el uso de sizeof es 100% constante, y nunca se empieza a hablar de tipos explícitos. Use la información de tipo inherente en sus variables, y deje que el compilador se preocupe por qué tipo es cuál. No te repitas.

Por supuesto, lo anterior hace una cantidad innecesariamente grande de llamadas a malloc(); Dependiendo de los patrones de uso, es posible hacer todo lo anterior con solo una llamada al malloc(), luego de calcular el tamaño total necesario. Entonces todavía necesitaría ir e inicializar los punteros array[i] para apuntar al bloque grande, por supuesto.

+7

+1 para 'contra' ocultar el asterisco ''. – glglgl

+0

hmm .. Hice Ajedrez * array = malloc (tamaño * sizeof (Ajedrez)); y luego para (i = 0; i MinaHany

+0

Sí, está bien, si lo único que quieres es una serie de indicadores que luego configuras en algunos casos que tienes por ahí. Modifiqué para agregar NULL-init como el caso predeterminado. – unwind

0

Estoy de acuerdo con @maverik anterior, prefiero no ocultar los detalles con un typedef. Especialmente cuando intentas entender lo que está pasando. También prefiero ver todo en lugar de un fragmento de código parcial. Dicho esto, aquí hay un malloc y sin una estructura compleja.

El código utiliza el detector de fugas ms studio studio para que pueda experimentar con las posibles fugas.

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