将结构初始化为指针之间的区别是什么?

时间:2010-02-25 16:14:22

标签: c memory pointers hashtable structure

我的HashTable结构有以下内容:

typedef char *HashKey;
typedef int HashValue;

typedef struct sHashElement {
    HashKey key;
    HashValue value;
} HashElement;

typedef struct sHashTable {
    HashElement *items;
    float loadFactor;
} HashTable;

直到现在我才真正想过它,但我才意识到我有两种方法可以使用它:

备选方案1:

void hashInitialize(HashTable *table, int tabSize) {
    table->items = malloc(sizeof(HashElement) * tabSize);

    if(!table->items) {
        perror("malloc");
        exit(1);
    }

    table->items[0].key = "AAA";
    table->items[0].value = 45;
    table->items[1].key = "BBB";
    table->items[1].value = 82;

    table->loadFactor = (float)2 / tabSize;
}


int main(void) {
    HashTable t1;
    int i;

    hashInitialize(&t1, HASHSIZE);

    for(i = 0; i < HASHSIZE - 1; i++) {
        printf("PAIR(%d): %s, %d\n", i+1, t1.items[i].key, t1.items[i].value);
    }

    printf("LOAD FACTOR: %.2f\n", t1.loadFactor);

    return 0;
}

备选方案2:

void hashInitialize(HashTable **table, int tabSize) {
    *table = malloc(sizeof(HashTable));

    if(!*table) {
        perror("malloc");
        exit(1);
    }

    (*table)->items = malloc(sizeof(HashElement) * tabSize);

    if(!(*table)->items) {
        perror("malloc");
        exit(1);
    }

    (*table)->items[0].key = "AAA";
    (*table)->items[0].value = 45;
    (*table)->items[1].key = "BBB";
    (*table)->items[1].value = 82;

    (*table)->loadFactor = (float)2 / tabSize;
}


int main(void) {
    HashTable *t1 = NULL;
    int i;

    hashInitialize(&t1, HASHSIZE);

    for(i = 0; i < HASHSIZE - 1; i++) {
        printf("PAIR(%d): %s, %d\n", i+1, t1->items[i].key, t1->items[i].value);
    }

    printf("LOAD FACTOR: %.2f\n", t1->loadFactor);

    return 0;
}

问题1:他们似乎都产生了相同的结果。在main上,两个示例都打印了正确的键/值对。那么,除了语法更改(使用(*table)而不仅仅是table)之外,它们之间究竟有什么不同,为HashTable结构分配内存的额外代码和{{{}的声明1}}指针?

我最近一直在编写一些数据结构,比如堆栈,链表,二进制搜索树和现在的哈希表。对于他们所有人,我总是使用替代方案2.但是现在我在考虑是否可以使用备选方案1并简化代码,删除大多数HashTable*到处都是。

但我要问这个问题是为了理解这两种方法之间的差异,以及是否应该使用另一种方法,以及为什么。

问题2:正如您在结构代码中看到的那样,&是一个指针。但是,我没有使用HashKeystrdup来为该字符串分配空间。这是如何以及为什么有效?这样可以吗?在处理动态字符串时,我总是使用mallocmalloc,否则我会遇到很多分段错误。但是这段代码没有给我任何分段错误,我不明白为什么以及我是否应该这样做。

5 个答案:

答案 0 :(得分:2)

在备选方案1中,调用者将分配table,但您的函数将分配其内容,这在内存管理方面并不总是一个好主意。备选方案2将所有分配保留在同一位置。

答案 1 :(得分:2)

如前所述,两种选择之间的差异是内存管理。在备选方案1中,您希望调用者在调用之前为表分配内存;然而,在备选方案2中,只需要一个指针声明就可以在创建内存后给你一个放置内存的地方。

问题2,简单的答案是你要为字符串分配一个常量。根据以下站点,分配是在编译时设置的,而不是运行时。

http://publications.gbdirect.co.uk/c_book/chapter6/initialization.html

答案 2 :(得分:2)

首先,两种解决方案都是完全正确的!

备选方案1:

您的HashTable在main中声明,这意味着struct位于调用堆栈中的某个位置。如果离开范围,结构将被销毁。注意:在您的情况下,由于声明位于main中,因此范围在进程退出时结束。

备选方案2:

你在调用堆栈中有一个HashTable *(指针),因此你需要为struct分配内存。为此,请使用malloc。

在这两种情况下,您的结构都已正确分配。主要区别在于表演。在堆栈上分配的性能要高得多,但是你不能进行动态分配。为此,您需要使用malloc。 所以,有时候,你必须使用malloc,但如果你想做一个高性能的应用程序,尽量避免mallocing。

这是否足够清楚? :)

答案 3 :(得分:1)

问题2:     (* table) - &gt; items [0] .key =“AAA”;

实际上将“AAA”放入内存的只读部分,并将char *键指向它,不能更改密钥指向的内容。

(* table) - &gt; items [0] .key [0] ='a'给出错误

在这里你可以找到关于它的进一步讨论。

What is the difference between char s[] and char *s?

答案 4 :(得分:0)

唯一的区别在于内存的来源 - 局部变量通常在堆栈上,而malloc通常来自堆。