【问题标题】:What's the difference between intializating a struct as pointer or not?将结构初始化为指针有什么区别?
【发布时间】:2010-02-25 16:14:21
【问题描述】:

我的 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 结构分配内存的额外代码和HashTable 指针的声明之外,它们之间究竟有什么不同?

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

但我问这个问题是为了了解这两种方法之间的区别,以及是否以及为什么我应该使用 on 而不是另一种。

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

【问题讨论】:

    标签: c memory pointers hashtable structure


    【解决方案1】:

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

    备选方案 1:

    您的 HashTable 在 main 中声明,这意味着该结构位于调用堆栈中的某个位置。如果您离开范围,该结构将被破坏。注意:在您的情况下,这不可能发生,因为声明在 main 中,因此范围在进程退出时结束。

    备选方案 2:

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

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

    够清楚吗? :)

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 顺便说一句 - 在这两个例子中,内存都不是空闲的
      • 我知道内存没有被释放,我还在构建它的过程中,这不是最终代码。
      【解决方案3】:

      如前所述,两种选择之间的区别在于内存管理。在备选方案 1 中,您希望调用者在调用之前为表分配内存;而在备选方案 2 中,只需要一个指针声明即可在创建内存后为您提供放置内存的位置。

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

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

      【讨论】:

        【解决方案4】:

        对于问题 2: (*table)->items[0].key = "AAA";

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

        (*table)->items[0].key[0]='a' 给出和错误

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

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

        【讨论】:

          【解决方案5】:

          唯一的区别是内存的来源——局部变量通常在堆栈中,而 malloc 通常来自堆。

          【讨论】:

          • 不完全正确。局部变量不是malloc'ed。他们的内存取自堆栈。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-23
          • 2012-08-23
          • 1970-01-01
          相关资源
          最近更新 更多