<gratuitous rant>
If this example is representative of the overall quality of the course materials available from the CPP Institute, then I very strongly suggest you look elsewhere for your education and/or certification.
Unless this example is titled "How To NOT Write Code That Uses Pointers" (in which case it is very effective), this code is awful. Not only is it confusing, it's chock full of bad practice and undefined behavior.
</gratuitous rant>
Let's start with the obvious problems:
float *t = 1 + (float *) malloc(sizeof(float) * sizeof(float));
This - I don't know what this is supposed to illustrate, except how to write really confusing code.
sizeof (float)
evaluates to the number of bytes in a float
, which on most modern platforms will be 4 bytes. Squaring that value means that you're setting aside enough space for N
objects where each object is N
bytes wide - IOW, if sizeof (float)
is 4, you get enough space for 4 objects, whereas if sizeof (float)
is 8, you get enough space for 8 objects.
That's an ... unusual way of specifying how many objects you want. Us boring people in the real world just write sizeof (float) * N
, where N
is the number of objects we want (actually, we write sizeof *t * N
).
Okay, so we allocate enough space for N objects and return the pointer - plus 1? Pointer arithmetic takes the size of the pointed-to type into account, so adding 1 to a pointer means "point to the next object of the pointed-to type" (the array subscript operator a[i]
is defined as *(a + i)
- given a starting address a
, compute the address of the i
'th object following a
and dereference the result).
So basically, t
starts out pointing to the second object in the dynamic buffer. Drawing it out, you get something like this:
+---+
| |
+---+
t -> | |
+---+
| |
+---+
| |
+---+
malloc
does not initialize the dynamic buffer - the contents of the buffer are indeterminate. There's no guarantee that the bit pattern resident in that memory area corresponds to a value of 0.00
. Since the object is uninitialized, attempting to access its value results in undefined behavior - the line
printf("%f\n", *t);
may result in output of 0.0000
, or it may result in some other random value, or you may get a runtime error, or...
The statement
t--;
subtracts 1 from the pointer, causing it to point to the first element in the buffer:
+---+
t -> | |
+---+
| |
+---+
| |
+---+
| |
+---+
*t = 8.0; //we dereference pointer t and assign literal
//8.0. This will be [0] position
printf("%f\n",*t); //8.00000
Correct, although it would be a bit clearer to write
t[0] = 8.0;
printf("%f\n", t[0]);
When dealing with something you're treating as an array, it's best to use array subscript notation.
t[1] = *t / 4.0;
This code hurts. Seriously, mixing array and pointer notation is guaranteed to cause heartburn. This would better have been written
t[1] = t[0] / 4.0;
The statement
t++;
adds 1 to the pointer, getting us back to the previous state where we're pointing at the second element of the array.
t[-1] = *t / 2.0;
And this code merits a paddlin'. Negative indices are bad juju. Since t
is pointing to the second element of the array now, this won't blow up, but it's just ... just ... don't do that. If anyone turned code like that into me for review, I'd kick it back so hard they'd feel it for a week. Seriously, don't do that.
Here's how that code should have been written:
#include <stdio.h>
#include <stdlib.h>
#define N 2 // assuming you only want 2 floats.
int main(void) {
/**
* Since the type of t is float *, the *expression* *t has
* type float - thus, sizeof *t == sizeof (float). Oh, and
* the cast on malloc is unnecessary, and under C89 will suppress
* a useful diagnostic if you forget to include stdlib.h.
*/
float *t = malloc( sizeof *t * N );
if ( t ) // ***ALWAYS*** check the result of malloc, calloc, or realloc
{
t[0] = 8.0;
printf( "%f\n", t[0] ); // 8.000
t[1] = t[0] / 4.0;
printf( "%f\n", t[1] ); //2.00000
t[0] = t[1] / 2.0;
printf( "%f\n", t[0]);
free(t); // release the memory
}
return 0;
}
Note that you can use calloc
instead of realloc
if you want the allocated memory to be initialized to all-bits-0:
float *t = calloc( N, sizeof *t );
Just be aware that all-bits-0 doesn't necessarily correspond to 0.000
.