malloc an array of struct pointers

Mam następującą strukturę:

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

I mam:

typedef struct _chess *Chess;

Teraz chcę utworzyć tablicę długości dynamicznej, aby przechowywać wskaźniki do struktury szachowej, więc wykonuję następujące czynności:

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

To daje mi błąd: invalid initializer.

A jeśli upuszczę [] i zrobię to:

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

Kompiluje się bez błędu, ale kiedy próbuję ustawić element tej tablicy na NULL, wykonując:

array[i]=NULL;

Podczas przypisywania do type 'struct pojawia się błąd: niekompatybilne typy _chess 'from type' void * '

Wiesz, co robię źle? Dzięki.
Author: MinaHany, 2012-05-30

4 answers

array to nazwa nieco myląca. Dla dynamicznie przydzielanej tablicy wskaźników, malloc zwróci wskaźnik do bloku pamięci. Musisz użyć Chess*, a nie Chess[], aby przytrzymać wskaźnik na tablicy.

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

I być może później:

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

/* set up its members */
array[i]->size = 0;
/* etc. */
 37
Author: CB Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-13 23:50:08

Dużo się tu dzieje. Osobiście jestem przeciwny "ukrywaniu gwiazdki", tzn. typedef: wpisywanie wskaźnika w coś, co nie wygląda jak wskaźnik. W C wskaźniki są dość ważne i naprawdę wpływają na kod, istnieje duża różnica między foo i foo *.

Myślę, że wiele odpowiedzi również jest zdezorientowanych.

Twój przydział tablicy Chess wartości, które są wskaźnikami do wartości typu chess (ponownie, a bardzo mylące nomenklatura, której naprawdę nie mogę polecić) powinna być taka:

Chess *array = malloc(n * sizeof *array);
Następnie musisz zainicjować rzeczywiste instancje, zapętlając:
for(i = 0; i < n; ++i)
  array[i] = NULL;

Zakłada to, że nie chcesz przydzielać żadnej pamięci dla instancji, po prostu chcesz tablicę wskaźników z wszystkimi wskaźnikami początkowo wskazującymi na nic.

Jeśli chcesz przydzielić przestrzeń, najprostszą formą będzie:

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

Zobacz, jak użycie sizeof jest w 100% spójne i nigdy nie zaczyna wymień jawne typy. użyj informacji o typie zawartych w zmiennych i pozwól kompilatorowi martwić się, który typ jest który. Nie powtarzaj się.

Oczywiście powyższe wywołania wykonują niepotrzebnie dużą liczbę wywołań do malloc(); w zależności od wzorców użycia może być możliwe wykonanie wszystkich powyższych przy użyciu tylko jednego wywołania do malloc(), po obliczeniu całkowitego wymaganego rozmiaru. Następnie trzeba jeszcze przejść i zainicjalizować array[i] wskaźniki, aby wskazać na duży blok, z oczywiście.

 21
Author: unwind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-30 07:48:16

Zgadzam się z @maverik powyżej, wolę nie ukrywać szczegółów za pomocą typedef. Zwłaszcza, gdy próbujesz zrozumieć, co się dzieje. Wolę też zobaczyć wszystko zamiast częściowego fragmentu kodu. Z tym powiedział, tutaj jest malloc i wolne od skomplikowanej struktury.

Kod wykorzystuje wykrywacz nieszczelności MS visual studio, dzięki czemu można eksperymentować z potencjalnymi wyciekami.

#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;
}
 1
Author: netskink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-14 16:03:14

IMHO, to wygląda lepiej:

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
Author: maverik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-30 07:09:19