【问题标题】:malloc an array of struct pointersmalloc 结构指针数组
【发布时间】:2012-06-04 09:39:07
【问题描述】:

我有以下结构:

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”类型时,类型不兼容

知道我做错了什么吗? 谢谢。

【问题讨论】:

  • 为什么要对结构进行类型定义?它已经有了一个独特的类型。
  • @user82238 所以在使用类型的时候不用输入struct
  • 停止使用指针类型定义,你只会让自己感到困惑。 chess *array = malloc(size * sizeof *array);.
  • 另外,NULL 不能分配给 chess。唯一可以分配给结构的是同一类型的另一个结构。也许你的意思是:chess blank = { 0 }; array[i] = blank;

标签: c arrays pointers struct malloc


【解决方案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. */

【讨论】:

  • 谢谢!这为我修好了!您能解释一下为什么 Chess[] 不起作用吗?我现在很困惑,虽然 [] 和 * 是同一个东西。
  • @MinaHany [] 是一个数组,包含实际内容。 * 是指向内容的指针。访问和使用是一样的,但是内存表示完全不同。
【解决方案2】:

这里有很多typedef。我个人反对“隐藏星号”,即typedef: 将指针类型转换为看起来不像指针的东西。在 C 中,指针非常重要,并且确实会影响代码,foofoo * 之间存在很大差异。

我认为许多答案对此也感到困惑。

您分配的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] 指针以指向大块。

【讨论】:

  • hmm.. 我做了国际象棋 *array = malloc(size * sizeof(Chess));然后 for (i=0; i
  • 是的,没关系,如果您想要的只是一个指针数组,您稍后将其设置为您周围的一些实例。我修改为添加 NULL-init 作为默认情况。
【解决方案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));
}

【讨论】:

  • 如果我希望数组保存实际结构而不仅仅是指向它们的指针,我想我会使用它。对吗?
  • 在此代码中,数组包含指针,而不是对象。要制作结构数组,请使用struct _chess a[10]; //Array of ten structs _chess
【解决方案4】:

我同意上面的@maverik,我不想用 typedef 隐藏细节。尤其是当您试图了解正在发生的事情时。我也更喜欢查看所有内容而不是部分代码 sn-p。话虽如此,这是一个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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    • 2012-04-18
    • 2010-12-21
    • 1970-01-01
    • 2012-02-25
    相关资源
    最近更新 更多