【问题标题】:Why does this example of pointer dereferencing work?为什么这个指针取消引用的例子有效?
【发布时间】:2017-09-28 12:03:18
【问题描述】:

我有一些代码,它可以工作,但我不明白为什么。这里:

// This structure keeps the array and its bookkeeping details together.
typedef struct {
    void** headOfArray;
    size_t numberUsed;
    size_t currentSize;
} GrowingArray;

// This function malloc()'s an empty array and returns a struct containing it and its bookkeeping details.
GrowingArray createGrowingArray(int startingSize) { ... }

// Self-explanatory
void appendToGrowingArray(GrowingArray* growingArray, void* itemToAppend) { ... }

// This function realloc()'s an array, causing it to double in size.
void growGrowingArray(GrowingArray* arrayToGrow) { ... }

int main(int argc, char* argv[]) {
    GrowingArray testArray = createGrowingArray(5);

    int* testInteger = (int*) malloc(1);
    *testInteger = 4;

    int* anotherInteger = (int*) malloc(1);
    *anotherInteger = 6;

    appendToGrowingArray(&testArray, &testInteger);
    appendToGrowingArray(&testArray, &anotherInteger);

    printf("%llx\n", **(int**)(testArray.headOfArray[1]));

    return 0;
}

到目前为止,一切都按照我的意图进行。让我困惑的部分是这一行:

printf("%llx\n", **(int**)(testArray.headOfArray[1]));

据我了解, printf() 的第二个参数没有意义。我主要是通过反复试验来完成的。它读起来好像我在说结构中指针数组的第二个元素是指向 int 指针的指针。它不是。它只是一个指向 int 的指针。

对我来说有意义的是:

*(int*)(testArray.headOfArray[1])

据我了解,结构中包含的指针数组的第二个元素将由最后一个括号获取,然后我将其转换为指向整数的指针,然后取消引用该指针。

我的理解有什么问题?编译器是如何解释的?

【问题讨论】:

  • 你的设计是错误的。 headOfArray 应该是 void*。你也应该打电话给appendToGrowingArray(&testArray, testInteger); 而不是appendToGrowingArray(&testArray, &testInteger);
  • *testInteger = 4; 写入越界,您只分配了 1 个字节
  • **(int**)(testArray.headOfArray[1]) 可能是未定义的行为,而且您使用了错误的 printf 格式说明符。为了在发布 MCVE 后获得更好的答案,您未发布的代码中有很多未知因素会影响问题
  • 为什么你认为它是一个指向 int 的指针?您已将 &anotherInteger 添加到数组中。 anotherInteger 是指向整数的指针,因此 &anotherInteger 是指向 int 指针的指针。

标签: c arrays pointers struct casting


【解决方案1】:

我最好的猜测是你的appendToGrowingArray 看起来像这样:

void appendToGrowingArray(GrowingArray* growingArray, void* itemToAppend) {
    growingArray->headOfArray[growingArray->numberUsed++] = itemToAppend;
}

虽然显然有额外的逻辑来实际增长箭头。然而重点是itemToAppend 存储在headOfArray 指向的数组中。

但是,如果您查看您的 appendToGrowingArray 调用,您正在传递 testIntegeranotherInteger地址 -- 这些已经是指向整数的指针,因此您正在存储指向当您真正打算存储指向整数的指针时,指向 headOfArray 中的整数的指针。

所以,当您考虑testArray.headOfArray[1] 时,它的值是main 的变量anotherInteger 的堆栈上的地址。当您第一次取消引用它时,它现在指向您存储在anotherInteger 中的第二个malloc 调用返回的缓冲区地址。所以,只有当你第二次尊重它时,你才能到达该缓冲区的 contents,即数字 6。

你可能想写:

appendToGrowingArray(&testArray, testInteger);
appendToGrowingArray(&testArray, anotherInteger);

改为。

(如评论中所述,您还应该修复您的 malloc;这些天您需要超过 1 个字节来存储整数!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-28
    相关资源
    最近更新 更多