Pointers Into Arrays: What You’re Really Dereferencing
This one falls under the heading of things you should definitely know as a C/C++ programmer, but which are easy to get wrong by accident. For me it was while working on an Sliding Discrete Fourier Transform (SDFT) implementation in C++ that I stumbled over this gotcha. When I got nonsense output from the algorithm I took a long, detailed look at all aspects of it until finally a friend pointed me at something which I had overlooked until then because my brain had been telling itself that it couldn’t possibly be something that simple.
First of all, a little bit of theory on arrays in C/C++: all they are is just a series (array) of bytes in memory of which you tell the compiler that it’s special. You also give it a type, which doesn’t do anything to the bytes, but just hints to the compiler how it should treat the array in certain operations. This type is usually char, but can be anything else as well, including int and float. The trick here is that the compiler will thus essentially know not only the type this array contains, but also how many bytes go into each unit of the array.
Now, arrays are usually allocated on the heap, which in C++ takes the following format:
char* pChar = new char;
This gives us a single pointer into the array, which we have told the compiler contains char types. The pointer we have is thus also of the type char. This is the entire clue we have to the next procedure where we attempt to read 32-bit floating point types (float) from the array. We therefore want to get 4 bytes at a time where the array is said to contain chars, which are a single byte each. The naive but wrong approach is the following:
float f = *pChar;
Here we hope that the compiler will be so kind as to deposit four bytes into our four-byte destination type from the array. Unfortunately compilers aren’t very nice and thus from our dereferenced char pointer we only get a single byte, namely the char value it was pointing at.
To actually obtain four bytes from the array in one go we need to talk a bit with the compiler. This is also called ‘casting’, whereby we tell the compiler that we want to stop to pretend that this blob of bits is a certain type and that we’d rather have the compiler treat it as something else. This is a common technique in many applications, whereby the by itself unusable void type is instrumental. Fortunately we don’t have to go that far here. All we want in this case is to let the compiler know that we want to have this array treated as a series of floats instead of chars now:
float f = *((float*) pChar);
What we do here via some delicious brackets magic to make things flow in the right order, is to first cast the char pointer we have into a float pointer, which means that it now points at four bytes instead of just one. When we thus dereference the result we are copying four bytes into the destination instead of one. Mission accomplished.
It is possible to go even fancier here than in the above example using C++’s myriad of fancy casting mechanisms, but for basic casting as we need here the C-style method suffices. It’s best to leave those for special cases anyway, as they tend to be significantly more specialized and unnecessary for casting of basic types.
Hopefully the above will be useful to someone, whether a beginner or a more advanced C/C++ user, even just as a quick reminder. I know I could have used it a few days ago 🙂