web-dev-qa-db-ja.com

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;

エラーが発生します:タイプ「void *」からタイプ「struct _chess」に割り当てると互換性のないタイプ

私は何が間違っているのでしょうか?ありがとう。

14
MinaHany

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. */
44
CB Bailey

ここでは多くのtypedefが行われています。個人的には、「アスタリスクを隠す」ことに反対しています。つまり、typedef ::ポインター型をポインターのように見えないものに変換します。 Cでは、ポインターは非常に重要であり、実際にコードに影響します。fooと_foo *_には多くの違いがあります。

答えの多くもこれについて混乱していると思います。

Chess型の値へのポインターであるchess値の配列の割り当て(繰り返しますが、very私が本当にお勧めできない紛らわしい命名法)次のようになります:

_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%一貫していること、およびneverが明示的な型について言及し始めていることを確認してください。 使用変数に固有の型情報。コンパイラにどの型がどの型であるかを心配させます。繰り返してはいけません。

もちろん、上記はmalloc()を不必要に大量に呼び出します。使用パターンによっては、必要な合計サイズを計算した後、malloc()を1回呼び出すだけで上記のすべてを実行できる場合があります。もちろん、大きなブロックを指すように_array[i]_ポインターを初期化する必要があります。

22
unwind

上記の@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;
}
1
netskink

私見、これは良く見える:

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
maverik