【问题标题】:Iterating over an array stored on heap迭代存储在堆上的数组
【发布时间】:2019-04-15 21:02:51
【问题描述】:

请考虑以下代码:

// Thing is a typedef struct
void f(Thing* things, int size) {
    for (int i = 0; i < size; i++) {
        Thing my_thing = things[i];
        my_thing.a = 10;
    }
}

things 指向的数组分配在堆上的某处。

然而 - my_thing 是一个“堆栈变量” - 分配在堆栈上。

那么幕后发生了什么? things[i] 复制到堆栈并存储在my_thing 中吗? my_thing.a = 10; 做了什么 - 它是修改原始的 things[i] 还是修改“堆栈副本”?

【问题讨论】:

  • 是的,things[i] 被逐个成员复制到堆栈中,进入my_thing,不,my_thing.a = 10; 不会修改 things[i]
  • 如果你真的想要一个数组,你应该请求一个数组而不是一个指针。 ptrdiff_t 也更适合作为数组大小。 void f(ptrdiff_t size, Thing things[size])
  • @CacahueteFrito,我不确定我是否跟随。理想情况下,它应该是size_t size,但如果元素的数量在int 的范围内,int 就足够了。使用ptrdiff_t 不会改变任何东西。
  • 我知道你会放弃int,我认为这没有必要或有益,@CacahueteFrito。就像我说的,我似乎没有说服你。没关系;你可以有自己的意见。我可能最终不得不与你发生很多矛盾,但有时这就是生活。

标签: c arrays pointers memory


【解决方案1】:

是否将 things[i] 复制到堆栈并存储在 my_thing 中?

是的,作为内存拷贝,不是深拷贝。

my_thing.a = 10; 是什么?做 - 它是修改原始的东西[i]还是修改“堆栈副本”?

它只修改堆栈副本。但是在处理指针时要小心,参见示例here

【讨论】:

    【解决方案2】:

    线

        Thing my_thing = things[i];
    

    会将整个结构从 things[i] 复制到堆栈上的本地 my_thing 。复制的数据量将是结构体的大小,所以如果结构体很大,那么它可以在那里复制大量数据。

    线

        my_thing.a = 10;
    

    仅影响堆栈上的本地 my_thing。原始的 things[i] 永远不会被修改。如果您将const 放在输入指针上,代码也将继续以相同的方式工作,如下所示:

    void f(const Thing * things, int size) {
        for (int i = 0; i < size; i++) {
            Thing my_thing = things[i];
            my_thing.a = 10;
        }
    }
    

    【讨论】:

      【解决方案3】:

      my_thingthings[i] 是内存中两个不同的对象。线

      Thing my_thing = things[i];
      

      创建一个新对象my_thing 并将things[i] 的内容复制到它。对my_thing 的任何进一步更改(例如my_thing.a = 10;)对things[i] 没有影响,无论是分配在堆栈还是堆上。

      在大多数实现中,“堆栈”和“堆”只是同一内存段内的不同地址范围 - 除了如何为这些区域内的对象进行簿记之外,它们之间没有真正的区别。 IOW,就将一个复制到另一个的机制而言,things[i] 在堆上而my_things 在堆栈上并不重要。

      【讨论】:

      • 支持“对象所在的位置与问题无关”。嘿,我无法解释我的投票?愚蠢的保姆。
      【解决方案4】:

      首先你是否尝试过这段代码是否有效,因为通常我会写Thing* my_thing = things + i 来获取数组中的每个事物。

      你给函数一个指向事物而不是事物数组的指针。这就是为什么things是第一件事的地址。

      要获得下一个,您必须将 i 添加到基指针以到达想要的地址。

      下一行的工作方式取决于 my_thing 的类型。

      如果它像我声明的那样是一个指针,它实际上会在堆上编辑数组的内容,并且只在 my_thing 中创建地址的副本。但是,该行应该是(*my_thing).a = 10;,以便您实际设置指针指向的地址中的值。

      如果是Thing my_thing = *(things + i),则将创建该值的本地副本,并且下一行将更改该副本而不是原始数组。

      我希望这个答案可以帮助您了解实际发生的情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-31
        • 1970-01-01
        • 1970-01-01
        • 2016-06-17
        • 2020-01-14
        • 2023-03-13
        • 2014-12-04
        • 1970-01-01
        相关资源
        最近更新 更多