malloc – массив структурных указателей

У меня есть следующая структура:

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

и я имею:

 typedef struct _chess *Chess; 

Теперь я хочу создать массив динамической длины для хранения указателей на шахматную структуру, поэтому я делаю следующее:

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

Это дает мне ошибку: недействительный инициализатор.

И если я уронил [] и сделаю это:

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

он компилируется без ошибок, но когда я пытаюсь установить элемент этого массива в NULL, выполните:

 array[i]=NULL; 

Я получаю сообщение об ошибке: несовместимые типы при назначении типа ‘struct _chess’ из типа ‘void *’

Любая идея, что я делаю неправильно? Благодарю.

array – немного вводящее в заблуждение имя. Для динамически выделенного массива указателей malloc вернет указатель на блок памяти. Вам нужно использовать Chess* а не Chess[] чтобы удерживать указатель на ваш массив.

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

и, возможно, позже:

 /* create new struct chess */ array[i] = malloc(sizeof(struct chess)); /* set up its members */ array[i]->size = 0; /* etc. */ 

Здесь много typedef . Лично я против «сокрытия звездочки», т. typedef : ing типов указателей во что-то, что не похоже на указатель. В C указатели очень важны и действительно влияют на код, между foo и foo * существует большая разница.

Думаю, многие из ответов тоже смущены.

Ваше выделение массива Chess значений, которые являются указателями на значения типов chess (опять же, очень запутанная номенклатура, которую я действительно не могу рекомендовать), должна быть такой:

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

Затем вам нужно инициализировать фактические экземпляры путем циклизации:

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

Это предполагает, что вы не хотите выделять какую-либо память для экземпляров, вы просто хотите, чтобы массив указателей со всеми указателями изначально указывал ни на что.

Если вы хотите выделить пространство, простейшей формой будет:

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

Посмотрите, как sizeof использования на 100% соответствует, и никогда не упоминает явные типы. Используйте информацию о типе, присущую вашим переменным, и пусть компилятор беспокоится о том, какой тип есть. Не повторяйте себя.

Конечно, вышесказанное делает бесполезно большое количество вызовов для malloc() ; в зависимости от шаблонов использования можно было бы сделать все вышеперечисленное только одним вызовом malloc() после вычисления необходимого размера. Тогда вам все равно нужно пройти и инициализировать указатели array[i] чтобы указать на большой блок, конечно.

Я согласен с @maverik выше, я предпочитаю не скрывать детали с typedef. Особенно, когда вы пытаетесь понять, что происходит. Я также предпочитаю видеть все вместо частичного fragmentа кода. С учетом сказанного здесь находится malloc и свободен от сложной структуры.

В коде используется детектор течей ms visual studio, поэтому вы можете поэкспериментировать с потенциальными утечками.

 #include "stdafx.h" #include  #include "msc-lzw.h" #define _CRTDBG_MAP_ALLOC #include  #include  // 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; } 

ИМХО, это выглядит лучше:

 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)); }