2010-02-25 91 views
1

我已经在我的哈希表结构如下:将结构初始化为指针还是没有区别?

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结构分配内存的额外代码以及HashTable指针的声明?

我最近一直在编写一些数据结构,如堆栈,链表,二叉搜索树和现在的散列表。对于他们所有人,我一直使用替代方案2.但现在我想我是否可以使用替代方案1并简化代码,去除大部分全部都在使用的*&

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

问题2:正如你可以在结构代码中看到,HashKey是一个指针。但是,我没有使用strdupmalloc为该字符串分配空间。这是如何和为什么这样工作?这可以吗?在处理动态字符串时,我总是在适当的地方使用mallocstrdup,否则我会得到很多分段错误。但是这段代码并没有给我任何分段错误,我不明白为什么,如果我应该这样做。

回答

2

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

选择1:

你Hashtable是在主宣称,这意味着结构是某处调用堆栈。如果你离开示波器,结构将被破坏。注意:在你的情况下,由于声明是主要的,所以范围在流程退出时结束。

备选方案2:

你必须在调用堆栈哈希表*(指针),所以你需要分配内存的结构。要做到这一点,你使用malloc。

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

那够清楚了吗? :)

0

唯一的区别是内存来自何处 - 局部变量通常位于堆栈上,而mallocs通常来自堆栈。

+0

不完全正确。局部变量不是'malloc''。他们的内存取自堆栈。 – 2010-02-25 16:26:03

2

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

+0

顺便说一句 - 在这两个例子中,内存不是free'd – Ofir 2010-02-25 16:23:00

+0

我知道内存不是free'd,我仍然在构建它的过程中,这不是最终的代码。 – 2010-02-25 16:27:32

2

如前所述,两种方案的区别在于内存管理。在替代方案1中,您希望调用方在调用之前为表分配内存;而在替代方法2中,只需要一个指针声明来给你一个放置内存的地方,在你创建它之后。

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

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

1

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

实际上把“AAA”放在内存中的只读部分和char *键指向它,键指向的内容不能改变。

(*表) - >项目[0] .KEY [0] = 'A' 给出和错误

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

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