Your immediate problem is the following line:
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char));
This is wrong because it allocates enough space for n
characters. Instead, it should be:
signed char** myPtr = (signed char**)malloc(n*sizeof(signed char*));
// ^
// char POINTER
The size of a char
is generally less than the size of a pointer but, even if it weren't, you should be using the right type. In fact, I tend to prefer the following form so that I don't have to repeat the type (repetition has the possibility that I may change one in the future, forgetting the other):
signed char** myPtr = (signed char**) malloc (n * sizeof (*myPtr));
Beyond that, you should consider which language you're actually coding for. While C and C++ share quite a bit of basic stuff, they are in no way the same language, and how you write your code depends on which one you're targeting.
Let's cover C first. In that language, you shouldn't cast the return value from malloc
because it can hide certain subtle errors that are not fun to debug. Dropping the cast gives you:
signed char **myPtr = malloc (n * sizeof (*myPtr));
Additionally, since sizeof (char)
(naked, signed and unsigned) is always one, whenever you see yourself multiplying by that, it's easier to just drop the multiplication. Combining that with the previous guideline allows you to turn:
myPtr[i] = (signed char*)malloc(k*sizeof(signed char));
into the much more readable:
myPtr[i] = malloc (k);
Now, if you're coding for C++, there are additional things to look into.
In C++, it's more acceptable to use the new
and delete
aspects of the language rather than the legacy C stuff like malloc
and free
. The guidelines you've already mentioned (ensuring you have a delete
for each new
) still hold, but there's the added complication of ensuring you use delete[]
when freeing arrays of items.
That's not to say malloc
and free
won't work; they're still very much part of the C++ language specification. It's just that the C++ way of doing things can be much more powerful in that it can both allocate and initialise objects in one hit, and raise exceptions on out-of-memory, meaning you don't have to pepper your code with NULL
checks.
In addition, C++ provides, in its standard library, a great many collections which make handling groups of things a lot easier than the use of raw arrays. One of these is a vector
, basically a resizable array, and you should consider using it in situation where you may have previously used arrays.
The code you've shown would be much easier to implement as a vector of strings (C++ strings, not those puny C ones). And, in fact, I'd consider going one step further and actually encapsulating the entire data structure into its own class, hiding the fact that it uses vectors at all.
If you do that, and provide all the setter/getter methods that you need, you can later replace the entire underlying data structure without affecting the code that uses it.