在引用指针影响后发生意外的指针更改

时间:2016-02-06 18:09:38

标签: c pointers

我的一个指针在我尊重它之后被改变并影响它。我不明白为什么,特别是因为该函数中的代码多次运行但大部分时间都在运行。这是代码:

typedef struct          s_freeList
{
  int                   sSize;
  struct s_freeList     *next;
  struct s_freeList     *back;
  int                   *eSize;
}                       t_freeList;

void            *addNode(void *addr, size_t size)
{
  t_freeList    *freeList;

  // Working stuff
  freeList = (t_freeList *)addr;
  freeList->sSize = size * -1;
  freeList->next = ((t_freeList *)g_startAddr)->next;
  freeList->back = g_startAddr;
  ((t_freeList *)g_startAddr)->next->back = freeList;
  ((t_freeList *)g_startAddr)->next = freeList;

  // Not working stuff
  printf("addr = %p\nsize = %d\n", addr, (int)size);
  freeList->eSize = addr + size - 4;
  printf("freelist->esize = %p\n", freeList->eSize);
  *(freeList->eSize) = size * -1;
  printf("freelist->esize = %p\n\n", freeList->eSize);

  return (collapseNodes(addr));
}

以下是地址输出:

addr = 0x1647020
size = 32
freelist->esize = 0x164703c
freelist->esize = 0xffffffe00164703c

2 个答案:

答案 0 :(得分:5)

v输出中,您将在具有64位指针的平台上运行。每个指针都有大小,重要的是,8个字节的自然对齐,它给出了结构的以下布局(偏移量为十进制):

printf

您正在设置 00 sSize; 04 <padding> 08 *next; 16 *back; 24 *eSize; 32 <total size> ,其中freeList->eSize = addr + size - 4恰好与size = 32字段本身的较高部分重叠。

如果您要进行地址算术,请尽可能使用编译器提供的内省工具,例如eSizesizeof。它们可以减少此类错误的发生率,并使代码更具可读性和便携性。

(或者,更好的是,完全避免地址算术)。

答案 1 :(得分:3)

我没有尝试过代码,但这是我认为它发生的事情。以下几行为新节点分配值并将其插入列表中:

// Working stuff
freeList = (t_freeList *)addr;
freeList->sSize = size * -1;
freeList->next = ((t_freeList *)g_startAddr)->next;
freeList->back = g_startAddr;
((t_freeList *)g_startAddr)->next->back = freeList;
((t_freeList *)g_startAddr)->next = freeList;

显然,addr是指向新插入节点的指针。现在这是有趣的事情:

freeList->eSize = addr + size - 4;

假设size == sizeof(struct s_freeList)那么你基本上做的是为eSize分配自己的地址+4个字节!我认为这是因为sizeof(int *)碰巧是8个字节,而在内存中你的结构可能是这样的:

----------
|sSize   |    <-- addr
----------
|next    |
----------
|back;   |
----------
|eSize;  |    <-- addr + size - 4 probably because sizeof(int *) == 8 bytes.
----------

所以当你这样做时:

*(freeList->eSize) = size * -1;

您正在修改eSize的值,因为它指向自己!

编辑:我只是在重新编写代码并输出并且atzz说的是正确的时候,你可能正在运行一台64位机器,但是这个想法仍然是一样的,eSize正在覆盖自己......