(C)realloc数组按项目修改数据_pointed_

时间:2012-12-14 17:42:25

标签: c arrays pointers realloc

(C)realloc数组按项目

修改数据指向

您好,

我想分享一个很奇怪的错误;​​-)需要一些初步的解释:

首先,我有一种字符串PString,它们保持它们的大小(和一个哈希值),然后是一个带有字节的灵活数组成员。下面是构造函数的类型和种类(最后的printfl语句是debug):

typedef struct {
   size_t   size;
   uint     hash;
   char     bytes[];
} PString;

// offset from start of pstring struct to start of data bytes:
static const size_t PSTRING_OFFSET = sizeof(size_t) + sizeof(uint);

PString * pstring_struct (string str, size_t size, uint hash) {
   // memory zone
   char *mem = malloc(PSTRING_OFFSET + size * sizeof(char));
   check_mem(mem);

   // string data bytes:
   memcpy(mem + PSTRING_OFFSET, str, size);
   mem[PSTRING_OFFSET + size] = NUL;

   // pstring struct:
   PString * pstr = (PString *) mem;
   pstr->size = size;
   pstr->hash = hash;

   printfl("*** str:'%s' (%u) --> pstr:'%s' (%u) 0x%X",
   str, size, pstr->bytes, pstr->size, pstr);   ///////////////////////
   return pstr;
}

[对这个建筑欢迎的任何评论:我不确定在这里做正确的事情。这是我第一次使用灵活的数组成员,我找不到在分配的结构中使用它们的例子。]

其次,这些pstrings存储在字符串池中,这意味着一个实现为哈希表的集合。像往常一样,用于冲突的“桶”(在散列和模数之后)是单元的纯链接列表,每个单元包含pstring 指针和指向下一个单元的指针。唯一特殊的细节是单元格本身存储在一个数组中,而不是在堆上的任何地方分配[1]。希望图片清晰。以下是Cell

的定义
typedef struct SCell {
   PString        * pstr;
   struct SCell   * next;
} Cell;

一切似乎都运转正常,包括对游泳池本身的一系列测试。现在,在测试pstring例程(搜索)时,我注意到一个字符串发生了变化。经过一些研究,我终于猜到这个问题与池的增长有关,并且最终可以在细胞阵列的增长过程中完全减少问题(因此,在将细胞重新分配到列表之前)。这是围绕这种增长的调试打印线,其中show_pool例程的副本产生输出(只显示字符串),输出本身:

static void pool_grow (StringPool * pool, uint n_new) {
    ...
   // Grow arrays:
   show_pool(pool);  /////////////////////
   pool->cells = realloc(pool->cells, pool->n_cells * sizeof(Cell));
   check_mem(pool->cells);
   show_pool(pool);  ////////////////////
   ...

static void show_pool (StringPool * pool) {
   if (pool->n == 0) {
      printfl("{}");
      return;
   }

   printf("pool          : {\"%s\"", pool->cells[0].pstr->bytes);

   PString * pstr;
   uint i;
   for (i = 1; i < pool->n; i++) {
      pstr = pool->cells[i].pstr;
      printf(", \"%s\"", pstr->bytes);
   }

   printl("}");
}

// output:
pool          : {"", "abc", "b", "abcXXXabcXXX"}
pool          : {"", "abc", "b", "abcXXXabcXXXI"}

如您所见,存储的最后一个字符串有一个额外的字节'I'。因为在此期间我只是调用realloc,我发现自己有一点阻止进一步调试;并且努力思考并没有帮助揭开这个神秘面纱。 (请注意,单元格只保存pstring 指针,那么如何增长单元格数组会改变字符串字节?)另外,我被大肆宣传的事实似乎是一个非常方便的NUL神秘的'我',因为printf停在那里。

谢谢。 你能帮忙吗?

[1]这里没有特别的理由,使用字符串池。我通常这样做是为了免费获得有序的集合或地图,以及参考的地方。 (唯一的开销是除了桶数组之外,单元格数组必须增长,但是可以通过预定义来减少增长的数量。)

1 个答案:

答案 0 :(得分:2)

由于size不包含空终止符,

   mem[PSTRING_OFFSET + size] = NUL;

无效。其他每一个问题都源于此。

相关问题