【问题标题】:Using an array of strings to implement a symbol table in C使用字符串数组在 C 中实现符号表
【发布时间】:2020-07-17 01:23:58
【问题描述】:

我正在尝试使用结构数组来创建符号表。这是我到目前为止所拥有的,但是我在创建函数中分配内存时遇到了问题,到目前为止我所拥有的是否正确?

我想要这样的东西作为我对 arr 的最终结果 { {"sym1"; 1}, {"sym2"; 2}, {"sym3"; 3} }

struct str_id {
  char* s;
  int id;
}

struct symbol_table {
  int count;
  struct str_id** arr;
}

struct symbol_table *symbol_table_create(void) {
  struct symbol_table *stt = malloc(sizeof(struct symbol_table));
  stt->count = 1;
  stt->arr =  malloc(sizeof(struct str_id*) * stt->count);
  return stt;

}

【问题讨论】:

  • struct symbol_table { int count = 1; ... } 是非法的。您不能在 C 中的类型声明中初始化 struct 字段。
  • 是的,抱歉,我解决了这个问题。其余的都好吗?
  • 如果我在创建函数中将其设置为 1,它是如何未定义的
  • 哦,我明白你的意思了,我忘了做 stt->count。谢谢

标签: c symbol-table


【解决方案1】:
  • 对标识符使用描述性名称,而不是神秘的短名称(如sstr_id)。
  • Avoid Systems Hungarian Notation(即在标识符的类型或它们是什么而不是它们的意思之后命名或前缀标识符)。
    • 在你的情况下,我假设str_idstruct_id(或string_id)的缩写——这是一个坏名字,因为已经很明显它是struct(或包含一个字符串)。
    • 直到 1990 年代,当程序员开始使用功能更强大的编辑器和 IDE 来跟踪变量类型时,它才流行起来 - 现在已经不需要了。
    • *
  • 始终通过将callocmalloc 的返回值与NULL 进行比较来检查堆分配是成功还是失败。这可以通过if( some_pointer ) abort() 完成。
    • 不要使用assert( some_pointer ),因为断言仅在调试版本中启用,请改用abort,因为与exit相比,它表示程序异常终止。
  • 传递一个size_t 参数,以便消费者可以指定符号表的大小。
  • 内存中保存的对象数量应表示为size_t(例如数组索引器)。 Never use int for this!
  • 您需要在每个 struct 定义的末尾添加一个分号。
  • 您确定要array-of-pointers-to-structs 而不仅仅是array-of-structs?在这种情况下,您可以使用内联结构并为数组使用单个分配,而不是单独分配每个成员。
  • 因为您正在执行自定义分配,所以您还必须定义一个析构函数。
struct symbol_table_entry {
  char* symbolText;
  int   id;
};

struct symbol_table {
  size_t count;
  struct symbol_table_entry** entries;
};

struct symbol_table* create_symbol_table( size_t count ) {
    struct symbol_table* stt = malloc( sizeof(struct symbol_table) );
    if( !stt )
    {
        abort();
    }
    stt->count = count;
    stt->entries = calloc( count, sizeof(struct symbol_table_entry) );
    if( !stt->entries ) {
        free( stt );
        abort();
    }
    // Note that calloc will zero-initialize all entries of the array (which prevents debuggers showing garbage string contents) so we don't need to do it ourselves.
    return stt;
}

void destroy_symbol_table( struct symbol_table* stt, bool free_strings ) {
    if( stt->entries ) {
        if( free_strings ) {
            for( size_t i = 0; i < stt->count; i++ ) {
                free( stt->entries[i]->symbolText );
            }
        }
        free( stt->entries );
    }
    free( stt );
}

【讨论】:

  • stt-&gt;entries = calloc( count, sizeof(struct symbol_table_entry) ); 分配错误。建议stt-&gt;entries = calloc( count, sizeof stt-&gt;entries[0]); 避免输入错误。
  • @chux-ReinstateMonica 感谢您的改进,我已经移除了 free 周围的保护。至于sizeof,我认为在这种情况下使用sizeof( stt-&gt;entries[0] ) 而不是sizeof(struct symbol_table_entry) 并没有多大优势。
  • 戴,sizeof(struct symbol_table_entry)wrong sizesizeof(struct symbol_table_entry*) 本来是正确的。 sizeof( stt-&gt;entries[0] ) 更有可能被正确编码(它避免了错误类型的原始编码错误,因此具有优势),更易于查看和维护。
猜你喜欢
  • 2014-05-13
  • 1970-01-01
  • 2015-10-25
  • 1970-01-01
  • 2018-06-12
  • 1970-01-01
  • 2014-10-18
  • 2010-11-22
  • 1970-01-01
相关资源
最近更新 更多