我的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:正如您在结构代码中看到的那样,&
是一个指针。但是,我没有使用HashKey
或strdup
来为该字符串分配空间。这是如何以及为什么有效?这样可以吗?在处理动态字符串时,我总是使用malloc
或malloc
,否则我会遇到很多分段错误。但是这段代码没有给我任何分段错误,我不明白为什么以及我是否应该这样做。
答案 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'给出错误
在这里你可以找到关于它的进一步讨论。
答案 4 :(得分:0)
唯一的区别在于内存的来源 - 局部变量通常在堆栈上,而malloc通常来自堆。