I am stumped when it comes to what the actual effect of the malloc is
The malloc
call allocates the space for your array. When you initially declare ptr
, it's not initialized to point to a valid memory location:
+---+
ptr: | | ----> ???
+---+
Attempting to read or write through ptr
at this time will lead to undefined behavior; your code may crash outright, or it may corrupt storage somehow, or it may appear to run without any issues.
The malloc
call allocates space from the heap (a.k.a., a dynamic memory pool) and assigns the address of the first element of that space to ptr
:
+---+
ptr: | | ---+
+---+ |
... |
+------+
|
V
+---+
| | ptr[0]
+---+
| | ptr[1]
+---+
...
Please note that the (int *)
cast on the malloc
call has not been necessary since the 1989 standard, and is actually considered bad practice (under C89, it could mask a bug). IMO, the best way to write a malloc
call is
T *p = malloc( N * sizeof *p );
where T
is any type, and N
is the number of elements of type T
you want to allocate. Since the expression *p
has type T
, sizeof *p
is equivalent to sizeof (T)
.
and what all of the *(ptr + i) actually does.
*(ptr + i)
is equivalent to ptr[i]
, so
*ptr = 'x';
*(ptr + 1) = 'x';
are equivalent to writing
ptr[0] = 'x';
ptr[1] = 'x';
Please note that
*(ptr +99) = 'x';
is outside the range of the array you've allocated; you only set aside enough space for 25 integers. Again, this operation (and any operation *(ptr + i) = 'x';
where i
is greater than 24) will lead to undefined behavior, and your code may crash, corrupt data, or otherwise.
Pointer arithmetic takes the pointed-to type into account; ptr + 1
yields the address of the next integer object following the one at ptr
. Thus, if ptr
is 0x8000
and sizeof (int)
is 4, then ptr + 1
yields 0x8004
, not 0x8001
.