简体   繁体   English

malloc一个struct指针数组

[英]malloc an array of struct pointers

I have the following struct: 我有以下结构:

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

and I have: 我有:

typedef struct _chess *Chess;

Now, I want to create an array of dynamic length to store pointers to the chess struct so I do the following: 现在,我想创建一个动态长度数组来存储指向ARCH结构的指针,所以我执行以下操作:

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

This gives me an error: invalid initializer. 这给了我一个错误:初始化程序无效。

And if I drop the [] and do this: 如果我放弃[]并执行此操作:

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

it compiles without error but when I try to set an element of this array to NULL by doing: 它编译没有错误,但当我尝试通过执行以下操作将此数组的元素设置为NULL:

array[i]=NULL;

I get an error: incompatible types when assigning to type 'struct _chess' from type 'void *' 我收到一个错误:从类型'void *'分配类型'struct _chess'时出现不兼容的类型

Any idea what am I doing wrong? 知道我做错了什么吗? Thanks. 谢谢。

array is a slightly misleading name. array是一个有点误导性的名字。 For a dynamically allocated array of pointers, malloc will return a pointer to a block of memory. 对于动态分配的指针数组, malloc将返回指向内存块的指针。 You need to use Chess* and not Chess[] to hold the pointer to your array. 你需要使用Chess*而不是Chess[]来保存指向你的数组的指针。

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

and perhaps later: 也许后来:

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

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

There's a lot of typedef going on here. 这里有很多typedef Personally I'm against "hiding the asterisk", ie typedef :ing pointer types into something that doesn't look like a pointer. 就个人而言,我反对“隐藏星号”,即将typedef :指针类型转换为看起来不像指针的东西。 In C, pointers are quite important and really affect the code, there's a lot of difference between foo and foo * . 在C中,指针非常重要并且真正影响代码, foofoo *之间存在很多差异。

Many of the answers are also confused about this, I think. 我认为,许多答案也对此感到困惑。

Your allocation of an array of Chess values, which are pointers to values of type chess (again, a very confusing nomenclature that I really can't recommend) should be like this: 你分配的一组Chess值,它们是chess类型值的指针(同样,一个我真的不能推荐的非常令人困惑的命名法)应该是这样的:

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

Then, you need to initialize the actual instances, by looping: 然后,您需要通过循环初始化实际实例:

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

This assumes you don't want to allocate any memory for the instances, you just want an array of pointers with all pointers initially pointing at nothing. 这假设你不想为实例分配任何内存,你只需要一个指针数组,所有指针最初都指向什么。

If you wanted to allocate space, the simplest form would be: 如果你想分配空间,最简单的形式是:

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

See how the sizeof usage is 100% consistent, and never starts to mention explicit types. 了解sizeof使用情况如何100%一致,并且永远不会开始提及显式类型。 Use the type information inherent in your variables, and let the compiler worry about which type is which. 使用变量中固有的类型信息,让编译器担心哪种类型。 Don't repeat yourself. 不要重复自己。

Of course, the above does a needlessly large amount of calls to malloc() ; 当然,上面对malloc()了不必要的大量调用; depending on usage patterns it might be possible to do all of the above with just one call to malloc() , after computing the total size needed. 根据使用模式,在计算所需的总大小之后,只需调用一次malloc()就可以完成上述所有操作。 Then you'd still need to go through and initialize the array[i] pointers to point into the large block, of course. 然后你仍然需要通过并初始化array[i]指针指向大块,当然。

I agree with @maverik above, I prefer not to hide the details with a typedef. 我同意上面的@maverik,我不想用typedef隐藏细节。 Especially when you are trying to understand what is going on. 特别是当你想要了解正在发生的事情时。 I also prefer to see everything instead of a partial code snippet. 我也更喜欢看一切而不是部分代码片段。 With that said, here is a malloc and free of a complex structure. 话虽如此,这里是一个malloc,没有复杂的结构。

The code uses the ms visual studio leak detector so you can experiment with the potential leaks. 该代码使用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;
}

IMHO, this looks better: 恕我直言,这看起来更好:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM