1

Suppose the below statement:

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

I am curious to know what is going on here - I know it is right to left, so first the memory for inverse is being allocated. Then I set numbers equal to inverse, will that mean that the memory location of numbers will be the same as inverse? Or does it allocate the same amount of memory at locations &numbers and &inverse?

For example, if I do something like inverse[i] = 5 will that mean that numbers[i] == 5?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Adjit
  • 10,134
  • 12
  • 53
  • 98
  • 2
    [Please see this discussion on why not to cast the return value of `malloc()` and family in `C`.](http://stackoverflow.com/q/605845/2173917). – Sourav Ghosh Jul 13 '16 at 13:54

7 Answers7

9

You have:

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

That's the same as writing:

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

The variable numbers simply has a copy of the pointer that is in inverse — it points to the same place. However, you might be about to iterate through the array with one pointer while returning the other from the function, which could be a good reason for having the two copies.

There's a single memory allocation; there will need to be a single call to free() to release the allocated memory. The value passed to free() will be the same as the original value assigned to either inverse or numbers.

You also ask:

If I do something like inverse[i] = 5 will that mean that numbers[i] == 5?

If you've not changed the value stored in either inverse or numbers, and if i is in the range 0 .. (n-1), then after the assignment, the equality will hold. The pointers are the same (same type, same value), so indexing them produces the same result. It also means inverse[i] == numbers[i] of course.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
4

The first job is to drop the (int*) cast which is superfluous (and such a scheme can even be harmful if the type is not built-in). This is one of the differences between C and C++.

malloc(n * sizeof(int)); returns a pointer of type void*.

That pointer is assigned to inverse.

But the expression inverse = malloc(n * sizeof(int)) has type int*. This therefore can then be validly assigned to numbers.

To be very clear, malloc is called exactly once, and therefore you should call free exactly once.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
4

TL;DR, yes, both inverse and numbers point to same memory.


Long answer: On why part, quoting C11, chapter §6.5.16, Assignment operators (emphasis mine)

[...] An assignment expression has the value of the left operand after the assignment, but is not an lvalue. The type of an assignment expression is the type the left operand would have after lvalue conversion.

So, as you have mentioned correctly, for right-to-left associativity of the assignment operator =, the evaluation looks like

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

so, once inverse = (int *)malloc(n * sizeof(int)) is evaluated,

  • The value of this expression is the value of inverse after the assignment
  • Also, the type is as of the same type of inverse

(and both are valid) thus, the next evaluation is the same as

 numbers = inverse;

So, (if you want), you can break down the statements like

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.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
3

Only one chunk of memory has been allocated, and both inverse and numbers point to the same chunk.

We can verify this experimentally.

#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);
}
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
1

Yes, you are allocating a single block of memory. That's the magic of pointers!

Robert Columbia
  • 6,313
  • 15
  • 32
  • 40
  • That's not a bit specific to pointers! `int i,k; i = k = 1;` is exactly the same! – too honest for this site Jul 13 '16 at 13:55
  • 1
    No it's not. Your code declares two int variables and sets them equal to the same value. That's not the same thing as declaring two pointers to int and pointing them at the same int field in memory. – Robert Columbia Jul 13 '16 at 14:00
  • A pointer is not a reference! Both snippets assign the **value** of the LHS of the inner assignment to the lvalue of the next-outer assignment! The semantics of the values is completely unrelated. – too honest for this site Jul 13 '16 at 14:07
  • You are correct when you say that the semantics of the values are not relevant to the functionality of the assignment operator. That's not what the OP is concerned about. The question was about the practical effect. – Robert Columbia Jul 13 '16 at 14:11
  • Has common sense really diminished that much? It is a simple injection: `a->b->c => a->c` – too honest for this site Jul 13 '16 at 14:24
0

Here you are allocating a single block of memory And storing the address in two pointers. So both the pointers will point to the same address

Twinkle
  • 514
  • 3
  • 8
-1

In C, an assignment (=, +=, ...) is an operator like +, -, etc. It yields the value of the left hand side of the operator. See the standard 6.5.16p3 They are right associative, evaluation order is:

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

(Don't cast the result of malloc & friends or void * in general to pointers. It is not required in C and potentially harmful.)

So number gets the same value as inverse. Which is whatever the malloc returned for the right assignment.

To emphasise: this is no way related to pointers:

int i, k;
i = k = 4;

is exactly the same principle.

Edit:

To state it clear (once more): The right hand side of an assignment as for every operator is evaluated exactly once. You would not expect f(x) + g(x) + h(x) to have h called twice either.

For the pointers: malloc returns a pointer to a memory block, both pointers have the same value, thus they point to the same memory block. As both have the same type, you may use both to access the memory block.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • 4
    It is the same principle in the sense that shooting someone with a foam dart gun is the same principle as shooting them with an AK-47. In practice they have very different effects. – Robert Columbia Jul 13 '16 at 14:02
  • @RobertColumbia: Please elaborate! The effect is exactly the same: the value from the LHS of the inner assignement is used as RHS of the next. – too honest for this site Jul 13 '16 at 14:04
  • 1
    The OP's question was about whether the result of his code would be the creation of two memory blocks or one. The assignment operator works from right to left on pointers in the same way that it works on ints, but a pointer is not an int. If you set a pointer equal to another pointer, you end up with two pointers pointing to the same location. Changing the value pointed to by one will (by definition) change the value pointed to by the other one. If you set an int equal to another int, you end up with two ints that have the same value. Changing one will have no effect on the other. – Robert Columbia Jul 13 '16 at 14:09
  • It should be clear what the effect is,a s I clearly state that `number` gets the same value as `inverse`. You confuse the semantics with the operator. Don't try to make these two different, otherwise next time OP will ask if `i = k = f(x);` is different and call `f` twice. – too honest for this site Jul 13 '16 at 14:12