【问题标题】:Multiple one line assignments with malloc in c在c中使用malloc进行多行赋值
【发布时间】:2016-11-16 03:48:30
【问题描述】:

假设以下语句:

int *numbers, *inverse;
numbers = inverse = (int *)malloc(n * sizeof(int));

我很想知道这里发生了什么——我知道它是从右到左的,所以首先分配了inverse 的内存。然后我设置numbers等于inverse,是不是意味着numbers的内存位置会和inverse一样?还是在&numbers&inverse 位置分配相同数量的内存?

例如,如果我执行inverse[i] = 5 之类的操作,是否意味着numbers[i] == 5

【问题讨论】:

标签: c memory variable-assignment assignment-operator


【解决方案1】:

你有:

int *numbers, *inverse;
numbers = inverse = (int *)malloc(n * sizeof(int));

这和写的一样:

int *inverse = (int *)malloc(n * sizeof(int));
int *numbers = inverse;

变量numbers 只是拥有inverse 中指针的副本——它指向同一个地方。但是,您可能要使用一个指针遍历数组,同时从函数返回另一个指针,这可能是拥有两个副本的一个很好的理由。

只有一个内存分配;需要一次调用free() 来释放分配的内存。传递给free() 的值将与分配给inversenumbers 的原始值相同。

你还问:

如果我执行inverse[i] = 5 之类的操作,是否意味着numbers[i] == 5

如果您没有更改存储在inversenumbers 中的值,并且如果i0 .. (n-1) 范围内,那么在赋值之后,等式将成立。指针是相同的(相同的类型,相同的值),因此对它们进行索引会产生相同的结果。当然,这也意味着inverse[i] == numbers[i]

【讨论】:

    【解决方案2】:

    第一项工作是删除多余的 (int*) 演员表(如果类型不是内置的,这样的方案甚至可能是有害的)。这是 C 和 C++ 的区别之一。

    malloc(n * sizeof(int)); 返回一个 void* 类型的指针。

    该指针被分配给inverse

    表达式 inverse = malloc(n * sizeof(int)) 的类型为int*。因此,这可以有效地分配给numbers

    很清楚,malloc 只被调用一次,因此您应该只调用一次free

    【讨论】:

      【解决方案3】:

      TL;DR,是的,inversenumbers 都指向同一个内存。


      长答案:为什么部分,引用C11,第 §6.5.16 章,赋值运算符 (强调我的)

      [...] 一个 赋值表达式有赋值后左操作数的值,但不是 一个左值。赋值表达式的类型是左操作数的类型 左值转换后

      所以,正如您正确提到的,for right-to-left associativity of the assignment operator =,评估看起来像

      numbers = ( inverse = (int *)malloc(n * sizeof(int)) );
      

      所以,一旦inverse = (int *)malloc(n * sizeof(int)) 被评估,

      • 这个表达式的值为inverse赋值后的值
      • 另外,类型与inverse的类型相同

      (两者都是有效的) 因此,下一个评估与

      相同
       numbers = inverse;
      

      所以,(如果你愿意),你可以分解如下语句

      if ( (inverse = malloc(n * sizeof*inverse )) )  //error check, just saying
            numbers = inverse;
      

      and finally, if you're wondering why I removed the cast, see this discussion for more info on this.

      【讨论】:

        【解决方案4】:

        只分配了一块内存,inversenumbers 都指向同一个块。

        我们可以通过实验验证这一点。

        #include <assert>
        
        int main() {
            int n = 100;
            int *numbers, *inverse;
            numbers = inverse = (int *)malloc(n * sizeof(int));
        
            numbers[0] = 10;
            inverse[0] = 20;
        
            // If numbers and inverse point to the same memory, then we would expect
            // that numbers[0] is now 20.
            assert(inverse[0] == 20);
            assert(numbers[0] == 20);
        }
        

        【讨论】:

          【解决方案5】:

          是的,您正在分配单个内存块。这就是指针的魔力!

          【讨论】:

          • 这不是特定于指针的! int i,k; i = k = 1; 完全一样!
          • 不,不是。您的代码声明了两个 int 变量并将它们设置为相同的值。这与声明两个指向 int 的指针并将它们指向内存中的同一个 int 字段不同。
          • 指针不是引用!两个 sn-ps 都将内部分配的 LHS 的 value 分配给下一个外部分配的左值!值的语义完全不相关。
          • 当您说值的语义与赋值运算符的功能无关时,您是正确的。这不是OP所关心的。问题是关于实际效果。
          • 常识真的减少了那么多吗?这是一个简单的注入:a-&gt;b-&gt;c =&gt; a-&gt;c
          【解决方案6】:

          在这里,您分配了一个内存块并将地址存储在两个指针中。所以两个指针都会指向同一个地址

          【讨论】:

            【解决方案7】:

            在 C 中,赋值 (=, +=, ...) 是像 +- 等这样的运算符。它产生运算符左侧的值。见标准6.5.16p3他们是右联想,求值顺序是:

            numbers = ( inverse = malloc(n * sizeof(int)) );
            

            (一般不要将malloc & friends 或void * 的结果转换为指针。C 中不需要它并且可能有害。)

            所以number 获得与inverse 相同的。这是malloc 为正确分配返回的任何内容。

            强调:这与指针无关:

            int i, k;
            i = k = 4;
            

            原理完全一样。

            编辑:

            明确地说(再一次):赋值的右侧对于每个运算符都被精确地评估一次。您也不会期望 f(x) + g(x) + h(x) 会调用两次 h

            对于指针:malloc 返回一个指向内存块的指针,两个指针具有相同的值,因此它们指向同一个内存块。由于两者具有相同的类型,您可以同时使用它们来访问内存块。

            【讨论】:

            • 原理相同,用泡沫飞镖枪射击某人与用 AK-47 射击他们的原理相同。在实践中,它们具有非常不同的效果。
            • @RobertColumbia:请详细说明!效果完全一样:内部赋值的 LHS 的值用作下一个的 RHS。
            • OP 的问题是关于他的代码的结果是创建两个内存块还是一个。赋值运算符在指针上从右到左的工作方式与在 int 上的工作方式相同,但指针不是 int。如果将一个指针设置为等于另一个指针,则最终会得到两个指向同一位置的指针。改变一个指向的值将(根据定义)改变另一个指向的值。如果将一个 int 设置为等于另一个 int,则最终会得到两个具有相同值的 int。改变一个不会影响另一个。
            • 应该清楚效果是什么,因为我明确指出number 获得与inverse 相同的值。您将语义与运算符混淆了。不要试图让这两个不同,否则下次OP会询问i = k = f(x);是否不同并调用f两次。
            猜你喜欢
            • 2016-12-01
            • 2015-03-07
            • 1970-01-01
            • 1970-01-01
            • 2012-05-09
            • 2010-12-18
            • 1970-01-01
            • 2012-11-11
            • 2011-01-21
            相关资源
            最近更新 更多