1
int *p;
p = (int*) malloc(n*sizeof(int));

I know there is a similar post but I have not gotten the point. So here in the example, I have a pointer that is being assigned a new pointer with malloc. So now the address of the pointer has changed? Is it a new address with the exact space that we have given with malloc? Can someone explain what we are doing in an easy way? I am getting confused.

Tenko
  • 123
  • 5
  • By the "address of the pointer," do you mean the physical location of the pointer variable itself, or the value (address) that the pointer is storing? – Brian61354270 Dec 01 '21 at 23:14
  • by the adress I mean like the house of the pointer, for example when I debbug it the adress of the pointer is 0x047bfc8 – Tenko Dec 01 '21 at 23:17
  • You are assigning a value to `p`. Its address does not change, just its value. The value it now holds is the address of the newly allocated memory. – William Pursell Dec 01 '21 at 23:18
  • Pointer variables, like all variables in memory, have an *address* and their *contents*. What can be hard to think about at first is that a pointer variable's contents is *also* an address. So when you say something like `p = malloc(…)`, you are setting the *contents* of p, *not* its address! – Steve Summit Dec 01 '21 at 23:19
  • what about this: means that the pointer p is assigned the address of the first element of the dynamically allocated array with malloc(),which has allocated an int array consisting of n elements. – Tenko Dec 01 '21 at 23:21
  • When you say `int i; i = 5;`, you are changing `i`'s contents. Same as when you say `p = malloc(n * sizeof(int));`. The only different is that `i`'s contents is an `int`, and `p`'s contents is a pointer. – Steve Summit Dec 01 '21 at 23:23
  • Yes, but p is a pointer, what is inside of this pointer is *p not p, p is the adress – Tenko Dec 01 '21 at 23:25
  • When we say "`p`", depending on context, we are talking abut either "the variable `p`" or "the contents of the variable `p`" — and where "the contents" is "a pointer value". When we say "`*p`" we are talking about "the contents of the object pointed to by (the contents of) the pointer variable `p`". – Steve Summit Dec 01 '21 at 23:27
  • You said, "`p` is a pointer, what is inside of this pointer is `*p`". I disagree. What is "inside" the variable `p` is a pointer value, an address, that points somewhere. I would say that *what this pointer **points to*** is `*p`. – Steve Summit Dec 01 '21 at 23:30

2 Answers2

2

There are two ways to think about this — the "high level" way and the "low level" way.

High level: I like to use labeled boxes to represent variables and other objects. If I say

int i = 5;

then I have an int-shaped box, named i, containing the value 5:

    +-------+
 i: |   5   |
    +-------+

If I then say

int *p = &i;

then I have a pointer-shaped box, named p, containing a pointer that points at variable i:

    +-------+
 i: |   5   |
    +-------+
        ^
        |
     +--|----+
p:  /   *   /
   +-------+

If I then say

p = malloc(5 * sizeof(int));

and if malloc succeeds, then p now contains a pointer pointing at some new, unnamed memory which malloc gave me:

     +-------+
p:  /   *   /
   +----|--+
        |
        v
    +-------+
    |       |
    +-------+
    |       |
    +-------+
    |       |
    +-------+
    |       |
    +-------+
    |       |
    +-------+

That's the high-level way. For the low-level way, I'm going to think about pointers not as those pretty little arrows, but as actual, numeric memory addresses.

I typed in this program:

#include <stdio.h>

int main()
{
    int i = 5;
    printf("i: %p: %d\n", &i, i);
    int *p = &i;
    printf("p: %p: %p: %d\n", &p, p, *p);
}

When I ran it on my computer, I got this output:

i: 0x7ffee74ed9cc: 5
p: 0x7ffee74ed9c0: 0x7ffee74ed9cc: 5

So I can draw a different version of the box-and-arrow picture, showing actual addresses:

                +-----+
0x7ffee74ed9cc: |  5  |
                +-----+

                +--------------+
0x7ffee74ed9c0: | 7ffee74ed9cc |
                +--------------+

Now suppose I do

p = malloc(5 * sizeof(int));
p[0] = 11;
p[1] = 22;
p[2] = 33;
p[3] = 44;
p[4] = 55;
printf("p: %p: %p: %d %d %d\n", &p, p, *p, p[1], p[2]);

Now it prints

p: 0x7ffee74ed9c0: 0x7fbd11500000: 11 22 33

so I can draw this picture:

                +--------------+
0x7ffee74ed9c0: | 7fbd11500000 |
                +--------------+

                +------+
0x7fbd11500000: |  11  |
                +------+
0x7fbd11500004: |  22  |
                +------+
0x7fbd11500008: |  33  |
                +------+
0x7fbd1150000c: |  44  |
                +------+
0x7fbd11500010: |  55  |
                +------+
Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • Yes, so in my example p here is ip, but not *ip, In my example p is the box and *p what is inside the box – Tenko Dec 01 '21 at 23:36
  • @Tenko I changed the `ip`'s to `p`, to match. `*p` is what is inside the *pointed to* box. In my last picture, `p`'s address is `0x7ffee74ed9c0`, and what's inside that box is `0x7fbd11500000 `, which is a pointer, another address. – Steve Summit Dec 01 '21 at 23:49
  • +1 This question comes up often enough and this answer is one of the better explanations I've seen. I'm bookmarking it to be able to link to it in other similar questions in the future – Craig Estey Dec 02 '21 at 00:22
1

p is the pointer to int.

The assignment does not change its address only the value it holds. So &p will always be the same through its lifetime.

Casting to pointer to pointer does not change anything only the type of the pointer returned by the malloc

There is no need to cast the result of malloc. It is considered bad practice as it silences the warnings, leading to hard to find errors.

You should always assign pointers of the same type (void *) is the only exception.

It is a good practice to use objects instead of types in sizeof.

p = malloc(n*sizeof(*p));

If you change the type of p you do not need to change it in all sizeofs in your code. It also often leads to hard to find errors if you forget to change one.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0___________
  • 60,014
  • 4
  • 34
  • 74
  • @Tenko also edited the question — now the cast and assignment are self-consistent. The cast here should not have hidden an error; only if you are compiling with C89 — as opposed to C99 or later — can the cast hide errors. In C99 or later, `malloc()` must be declared before using it. In C89, it was not necessary to have a declaration for `malloc()` in scope, so things could go wrong with the cast converting a presumed `int` return value to a pointer. Things have improved in the world of C. And the explicit cast is necessary if the code is converted to (compiled with) C++. – Jonathan Leffler Dec 01 '21 at 23:26