Подтвердить что ты не робот

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 from type' void *

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

4b9b3361

Ответ 1

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. */

Ответ 2

Здесь много typedef. Лично я против "сокрытия звездочки", т.е. typedef: включение типов указателей во что-то, что не похоже на указатель. В 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], чтобы указать на большой блок, конечно.

Ответ 3

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

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

Ответ 4

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

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

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