How to overcome null pointer initialisation error? (C/C++) - c++

I'm having a hard time figuring out why the initialisation at NULL of one pointer is bugging my program.
In order to not receive a compilation error, almost all the pointers in my code need to be initialise as nullptr like usual. Problem is, when I tried to use them afterwards, I get a whole bunch of errors telling me the null pointer is invalid. To overcome this error, the buggy pointers are now declare as an array. This way all my problems with this initialisation are gone. Everything seems to work fine until I realise one of my conditional branch was always returning false.
The full code is a bit too long and some parts use french words, so let's just paste what interest us...
struct Numero {
int num;
char client[50];
Message *listeMessage = nullptr;
Numero *suivant = nullptr;
int nbmsg = 0;
};
char buff_char[50];
number = new Numero;
file >> number->client; // getting the right char client[50] from the file
if (number->client == buff_char)
break;
I also tried if(*number->client == *buff_char) without success. I'm now thinking that the problem is probably the array of char, but because of my previous problem I can't really change that so I'm hoping somebody can figure out what's going on here.
Note: Don't suggest anything related to strings, I can't use them because it's part of the challenge here to practice with pointers.

number->client == buff_char
Both of these are arrays, which decay into pointers. They are two different arrays with two different addresses, so this will always return false.
*number->client == *buff_char
This would compare the first element in each array, which is also not what you want.
You can use a standard library function like strcmp.
If you can't use the standard library, loop over each array until one has a different element than the other (not equal), they both have '\0' (equal), or they both reach 50 (equal).

In If do a comparison instead of assignment
if (number->client == buff_char)

In C++ = is the assignment operator. You want == for equality. What your if statement does right now is sets client equal to buff_char and then evaluates based on the newly assigned value of client.

Related

two short questions about pointers and references

consider this code:
double *pi;
double j;
pi = &j;
pi[3] = 5;
I don't understand how is that possible that I can perform the last line here.
I set pi to the reference of j, which is a double variable, and not a double [] variable. so how is this possible that I can perform an array commands on it?
consider this code:
char *c = "abcdefg";
std::cout << &(c[3]) << endl;
the output is "defg". I expected that I will get a reference output because I used &, but instead I got the value of the char * from the cell position to the end. why is that?
You have two separate questions here.
A pointer is sometimes used to point to an array or buffer in memory. Therefore it supports the [] syntax. In this case, using pi[x] where x is not 0 is invalid as you are not pointing to an array or buffer.
Streams have an overload for char pointers to treat them as a C-style string, and not output their address. That is what is happening in your second case. Try std::cout << static_cast<const void *>(&(c[3])) << endl;
Pointers and arrays go hand in hand in C (sort of...)
pi[3] is the same as *(pi + 3). In your code however this leads to Undefined Behavior as you create a pointer outside an object bounds.
Also be careful as * and & are different operators depending on in which kind of expression the appear.
That is undefined behavior. C++ allows you to do things you ought not to.
There are special rules for char*, because it is often used as the beginning of a string. If pass a char* to cout, it will print whatever that points to as characters, and stop when it reaches a '\0'.
Ok, so a few main things here:
A pointer is what it is, it points to a location in the memory. So therefore, a pointer can be an array if you whish.
If you are working with pointers (dangerous at times), this complicates things. You are writing on p, which is a pointer to a memory location. So, even though you have not allocated the memory, you can access the memory as an array and write it. But this gives us the question you are asking. How can this be? well, the simple answer is that you are accessing a zone of memory where the variable you have created has absolutely no control, so you could possibly be stepping on another variable (if you have others) or simply just writting on memory that has not been used yet.
I dont't understand what you are asking in the second question, maybe you could explain a little more? Thanks.
The last line of this code...
double *pi;
double j;
pi = &j;
pi[3] = 5;
... is the syntactic equivalent to (pi + 3) = 5. There is no difference in how a compiler views a double[] variable and a double variable.
Although the above code will compile, it will cause a memory error. Here is safe code that illustrates the same concepts...
double *pi = new double[5]; // allocate 5 places of int in heap
double j;
pi[3] = 5; // give 4th place a value of 5
delete pi; // erase allocated memory
pi = &j; // now get pi to point to a different memory location
I don't understand how is that possible that I can perform the last
line here. I set pi to the reference of j
Actually, you're setting your pointer pi, to point to the memory address of j.
When you do pi[3], you're using a non-array variable as an array. While valid c++, it is inherently dangerous. You run the risk of overwriting the memory of other variables, or even access memory outside your process, which will result in the operating system killing your program.
When that's said, pi[3] means you're saying "give me the slot third down from the memory location of pi". So you're not touching pi itself, but an offset.
If you want to use arrays, declare them as such:
double pi[5]; //This means 5 doubles arrayed aside each other, hence the term "array".
Appropos arrays, in c++ it's usually better to not use raw arrays, instead use vectors(there are other types of containers):
vector<double> container;
container.push(5.25); //"push" means you add a variable to the vector.
Unlike raw arrays, a container such as a vector, will keep it's size internally, so if you've put 5 doubles in it, you can call container.size(), which will return 5. Useful in for loops and the like.
About your second question, you're effectively returning a reference to a substring of your "abcdefg" string.
&([3]) means "give me a string, starting from the d". Since c-style strings(which is what char* is called) add an extra NULL at the end, any piece of code that takes these as arguments(such as cout) will keep reading memory until they stumble upon the NULL(aka a 0). The NULL terminates the string, meaning it marks the end of the data.
Appropos, c-style strings are the only datatype that behaves like an array, without actually being one. This also means they are dangerous. Personally I've never had any need to use one. I recommend using modern strings instead. These newer, c++ specific variables are both safe to use, as well as easier to use. Like vectors, they are containers, they keep track of their size, and they resize automatically. Observe:
string test = "abcdefg";
cout<<test.size()<<endl;//prints 7, the number of characters in the array.
test.append("hijklmno");//appends the string, AND updates the size, so subsequent calls will now return 15.

Malloc error in std::string

I'm getting the error
malloc: *** error for object 0x101346a70: pointer being freed was not allocated
When using an std::string. Sometimes it occurs, sometimes it does not.
string1 += string2[i]
This is the statement which it breaks on (I've obviously changed the variable names)
I'm running Xcode 4.0.2 and using llvm.
I'm fairly certain that there isn't a bug with my code (although the error only occurs under a single function call). Is std::string even supposed to have errors like that?
Some googling returns this:
I haven't tried doing this however, as I use Macro's and the article is incredibly breif and not explanatory as to what macro causes this issue and why. I also found some other logs of mac developers complaining of similar errors, but have sofar found no other solutions.
Do I just have buggy code, or is this a problem with Xcode/LLVM/STL Implementation
-- Edit for source code and class explinations --
Explanations:
This function is for getting a c-string out of a class which is message,
primarily a string and some accompanied data. A printf style notation is used
for where the data should go in the message, ie %f means float.
MSIterator is just a typecast for an unsigned int.
I should point out that I wrote this a few years ago, so it doesn't have the best practises in terms
of naming and other practises.
Hopefully the variable names will be all thats needed to show what the variables are.
string MSMessage::getString()
{
string returnValue;
Uint stringElementIndex = 0;
Uint floatElementIndex = 0;
// Iterate through arguments
for(MSIterator messageIndex = 0; messageIndex < m_message.size();++messageIndex)
{
if(m_message[messageIndex] == '%')
{
// Check the next character
switch (m_message[++messageIndex])
{
case 's':
returnValue += string(m_stringArguments[stringElementIndex]);
++stringElementIndex;
break;
case 'f':
returnValue += StringServices::toString(m_floatArguments[floatElementIndex]);
++floatElementIndex;
break;
case '%':
returnValue+='%';
break;
default:
/* Otherwise, act as if its normal text */
returnValue+='%';
returnValue+=m_message[messageIndex];
break;
}
}
// Not a argument? Tack it on!
else
{
// Malloc Error is here, with one character in returnValue and another 50 or so in m_message,
// Message index is correctly equal to 1
returnValue += m_message[messageIndex];
}
}
return returnValue;
}
m_message is set to "The text object iterator given to GUITextLine::insertTextObject was not valid". ie, there is no
associated data, and no '%' characters to complicate things.
EDIT 2:
The function now returns an std::string (I've changed the source code as well), and still fails with the same error. I'm really confused.
EDIT 3:
This:
MSMessage x = MSMessage("The text object iterator given to
GUITextLine::insertTextObject was not valid", MSRegion_Systems,
MSZone_Object, MSType_Error_Orange, 0);
string y;
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
y = x.getString();
Doesn't seem to be causing any problems. Any thoughts?
returnValue is a local variable, so it automatically gets deleted when the function returns. This invalidates returnValue.c_str(). After returning to the calling function, the contents of the returned value will be undefined; and any attempt to free the pointer will corrupt the heap. This heap corruption may not be detected immediately; in fact it looks like it gets detected on a subsequent call of MSMessage::getCString().
Edited to add: As a quick fix, you can just change the last line to:
char* t = new char[returnValue.length() + 1] ;
strcpy (t, returnValue.c_str()) ;
return t ;
It is not good style to allocate something in a called function that must be freed by the calling function like this, but judging by your comment, it will save you a lot of work :-)
This kind of error is often caused by a memory corruption somewhere else in your program. The next call to one of the memory managment functions will then fail, because the heap is corrupt.
I believe the safest solution here would be to have the caller pass down the string that is currently declared as returnValue after having creating it using new(), have getString() (which might be better called stuffString()) stuff it and expect to caller to use it and free it using delete() when done with it. Any use of malloc() with a properly designed std class introduces un-necessary danger, since the class can only keep track of the storage it has allocated for itself and of course, that which was allocated by new(). I belive that once created, std:string should automatically allocate and track any space needed for any text added to it using its own methods and overloaded operators (if I'm being naive here, please correct me), so there should be no need to ever use malloc().
PS: The one exception I can see to this is the case where one wants to instantiate a C-style string with the contents of an existing std:string. Then one could write
char* new_C_string = malloc(strlen(old_CPP_string.c_str) + 1);
strcpy(new_c_string, old_CPP_string.c_str);
This would, of course, be a last resort to glue existing C code with existing C++ code. Tomas it right, this stuff can get very confusing.
return returnValue.c_str();
You may not do this. .c_str() necessarily returns a pointer to the string's internal storage, because there is no way to have it create a copy without there being a memory leak in general. (This is not C, where there is a culture of waving a magic documentation wand and thereafter freely expecting the caller to clean up the callee's messes.) Upon returning from the function, returnValue ceases to exist, and thus returnValue.c_str() is a dangling pointer, and any attempt to use it is undefined behaviour.
The normal way to approach the problem is to - drum roll - just return the string. Use the string class everywhere possible - why reject a real string type when you finally have it? The reason .c_str() is named that way is because it's for C interoperability. Accordingly, you use it at the point where actual interoperation with C code is required. For example, when passing the string to a C function.
Note that the C function may not legally modify the pointed-at data, because there is no way for the string object to know about the changes, so that would break the class invariants. If your C function requires a mutable char buffer, then you'll have to create one. One possible approach is to copy the characters into a std::vector<char> and pass a pointer to the internal storage of that. Of course, you still won't be able to capitalize on the vector's auto-resizing, because there is no way for the C code to interact with the vector's full interface. But then, most well-behaved C code doesn't assume it can "resize" strings "in-place" anyway. If you have something that expects a char** and the ability to replace the input "string", or something that attempts to realloc() a string, well... you may have to get a little creative, or better yet just abandon that C library.

STACK.peek function, having some trouble, C++

CARD& STACK::peek()
{
if(cards.size == 0)
{
CARD temp = CARD {-1, -1};
return temp;
}
return cards.back();
}
This is the function I am having trouble with.
CARD is just a struct with two int variables, called rank and suit.
STACK is a class that manages an std::vector<CARD>, that is called cards.
The function is supposed to return a reference to the card on top of the stack, or return the reference to a dummy card if the vector is empty.
First of all, I get a warning that says a reference to a local variable temp is returned. What is wrong with that? How will that effect the function? What do I do about it?
Second, I am trying to use this function with another function I created called cardToString
char* cardToString(CARD& c);
It is supposed to use the rank and suit variables in the passed CARD to look up string values in a table, concatenate the two strings together, and return a pointer to the new string.
So the end result looks like:
cout<<cardToString(deck.peek())<<"\n";
but this line of code will execute up to the cardToString function, then just stop for some reason. It is annoying the hell out of me because it just stops, there is no error message and there does not look like there is anything wrong to me.
Can somebody help me out?
Edit: here is the cardToString function
char *cardToString(const CARD& c)
{
if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
{
std::cout<<"returned null";
return NULL;
}
char *buffer = new char[32];
strcpy(buffer, RANKS[c.r]);
strcat(buffer, " of ");
return strcat(buffer, SUITS[c.s]);
}
I specifically want the function STACK.peek() to return the address of the CARD that already exists on the top of the STACK. It seems to make more sense to do that than to create a copy of the card that I want to return.
First of all, I get a warning that says a reference to a local variable temp is returned. What is wrong with that? How will that effect the function? What do i do about it?
A local variable, as it name implies, is local to the function it belongs to, so it's destroyed as the function returns; if you try to return a reference to it, you'll return a reference to something that will cease to exist at the very moment the function returns.
Although in some cases this may seem to work anyway, you're just being lucky because the stack hasn't been overwritten, just call some other function and you'll notice it will stop working.
You have two choices: first of all, you can return the CARD by value instead of reference; this, however, has the drawback of not allowing the caller to use the reference to modify the CARD as is stored in the vector (this may or may not be desirable).
Another approach is to have a static dummy CARD instance stored in the STACK class, that won't have these lifetime problems, and that can be returned when you don't have elements in the vector; however, you should find a method to "protect" its field, otherwise a "stupid" caller may change the values of your "singleton" dummy element, screwing up the logic of the class. A possibility is to change CARD in a class that will encapsulate its fields, and will deny write access to them if it's the dummy element.
As for the cardToString function, you're probably doing something wrong with the strings (and I'm almost sure you're trying to return a local also in this case), but without seeing the body of the function it's difficult to tell what.
By the way, to avoid many problems with strings I suggest you to use, instead of char *, the std::string class, which takes away most of the ugliness and of the low level memory management of the usual char *.
Also, I'd suggest you to change cardToString to take a const reference, because most probably it doesn't need to change the object passed as reference, and it's good practice to clearly mark this fact (the compiler will warn you if you try to change such reference).
Edit
The cardToString function should be working fine, as long as the RANKS and SUITS arrays are ok. But, if you used that function like you wrote, you're leaking memory, since for each call to cardToString you make an allocation with new that is never freed with delete; thus, you are losing 32 bytes of memory per call.
As stated before, my tip is to just use std::string and forget about these problems; your function becomes as simple as this:
std::string cardToString(const CARD& c)
{
if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
return "(invalid card)";
return std::string(RANKS[c.r]) + " of " + SUITS[c.s];
}
And you don't need to worry about memory leaks and memory allocations anymore.
For the reference/value thing: if the caller do not need to use the reference to modify the object stored in the vector, I strongly suggest passing it by value. The performance hit is negligible: two ints instead of one pointer means 8 vs 4 bytes on most 32 bit architectures, and 8 bytes vs 8 bytes on most 64 bit machines (and also accessing the fields via pointer has a small cost).
This kind of micro-optimization should be the last of your concerns. Your top priority is to write correct and working code, and the last thing you should do is to let micro-optimization get in the way of this aim.
Then, if you experience performance problems, you'll profile your application to find where the bottlenecks are and optimize those critical points.
You cannot return a reference to a local variable, because the local variable no longer exists when the function returns.
You need to return by-value, not by-reference (i.e. CARD STACK::peek() { ... }).

Large Dynamic MultiDimensional Array Not Working

My code that I have is quite large and complicated so I won't waste your time reading it, but you're going to have to make certain assumtions about variables in it as a result. I will tell you the values of the variables which I have confirmed in the debugger so you know with certainty. Know that I have omitted a lot of unrelated code in here so what you see isn't everything but I have included everything that is relevant.
// This is defined in a class:
char**** m_DataKeys;
// This is in a member function of the same class:
m_DataKeys = new char*** [m_iNumOfHeroes]; // m_iNumOfHeroes = 2
while ( pkvHero )
{
// iHeroNum = 0 and then 1 #define NUM_OF_ABILITIES 4
m_DataKeys[iHeroNum] = new char** [NUM_OF_ABILITIES];
for (int ability = 0; ability < NUM_OF_ABILITIES; ability++)
{
if (pkvExtraData) // only is true when iHeroNum == 1 and ability == 0
{
// iNumOfExtraData == 2
m_DataKeys[iHeroNum][ability] = new char* [iNumOfExtraData];
while ( pkvSubKey )
{
// iCurExtraDataNum increments from 0 to 2
m_DataKeys[iHeroNum][ability][iCurExtraDataNum] = new char [50];
I put a break point on the line
m_DataKeys[iHeroNum] = new char** [NUM_OF_ABILITIES];
Before the line is called and when iHeroNum == 0 the m_DataKeys array looks like:
m_DataKeys | 0x02072a60
pointer | 0xffeeffee
Error : expression cannot be evaluated
Which is expected. After the line gets called it looks like:
m_DataKeys | 0x02072a60
pointer | 0x02496b00
pointer | 0xffeeffee
Error : expression cannot be evaluated
Which seems to look correct. However, since I set a breakpoint there, I hit play and had it hit it on the next loop around, where iHeroNum == 1 now and ran the line and m_DataKeys then looked like this:
m_DataKeys | 0x02072a60
pointer | 0x02496b00
pointer | 0xffeeffee
Error : expression cannot be evaluated
Which is the exact same as before! The line didn't change the array.... At all!
For clarification, m_DataKeys is a 3 dimensional array of character pointers to character arrays of size 50.
I can't figure out why this is happening, it looks like my code is correct. Is it possible that the garbage collector is screwing me over here? Or maybe the new allocator?
Edit: A Symptom of a Larger Problem
Let me elaborate a little more on the structure of my code, because really, this is just a cheap solution to a bigger problem.
I already have structs as one of you wisely suggested:
struct HeroData
{
// Lots o data here
// ...
// .
//
AbilityData* Abilities[NUM_OF_ABILITIES];
}
struct AbilityData
{
// More data here
// ...
// .
CUtlMap<char*,int> ExtraData [MAX_ABILITY_LEVELS];
}
Now when it got complicated and I had to do this DataKeys arrays of pointers to arrays of pointers crap is only when the need arose to be loading in some data to a dynamic structure, where both the keys, the values, and the numbers of data are completely dynamic. So I thought to use a map of char arrays to ints, but the only problem is that I can't store the actual char array in my map, I have to use a char *. I tried defining the map as:
CUtlMap<char[50],int> ExtraData [MAX_ABILITY_LEVELS];
But that really didn't work and it seems sort of strange to me anyway. So, I had to find some place to stick all these ExtraDataKeys and for some reason I thought it cool to do it like this. How can I store char arrays in objects like arrays or maps?
Since you are using pointers as class members, my best guess is that you are violating The Rule Of Three. That is, you did not provide a copy constructor and a copy assignment operator for your class. That usually leads to strange data loss when passing objects of your class around.
Note that no sane C++ programmer would use char****. Here is my best attempt to fix your problem using vectors and strings, but there is probably a much better design for your specific problem:
#include <string>
#include <vector>
class Foo
{
int m_iNumOfHeroes;
std::vector<std::vector<std::vector<std::string> > > m_DataKeys;
enum { NUM_OF_ABILITIES = 4, iNumOfExtraData = 2 };
public:
explicit Foo(int iNumOfHeroes)
: m_iNumOfHeroes(iNumOfHeroes)
, m_DataKeys(m_iNumOfHeroes, std::vector<std::vector<std::string> >
(NUM_OF_ABILITIES, std::vector<std::string>(iNumOfExtraData)))
{
}
};
int main()
{
Foo x(2);
}
In case you have never seen that colon syntax in the constructor before, that is a member initializer list.
I really wish C++ had array bounds checking
std::vector and std::string do have bounds checking if you use the foo.at(i) syntax instead of foo[i]. In Debug mode, even foo[i] has bounds checking enabled in Visual C++, IIRC.
Though the code might be correct, I personally find that working with something like a char **** can get pretty confusing pretty fast.
This is just my personal preference, but I always try to organize things in the most clear and unambiguous way I can, so what I would do in your situation would be something like
struct Ability
{
char extraData[NUM_OF_EXTRA_DATA][50];
};
struct HeroData
{
Ability abilities[NUM_OF_ABILITIES];
};
class Foo
{
// here you can choose a
HeroData *heroArray;
// and then you would alloc it with "heroArray = new HeroData[m_iNumOfHeroes];"
// or you can more simply go with a
std::vector<HeroData> heroVector;
};
I think this makes things more clear, making it easier for you and other programmers working on that code to keep track of what is what inside your arrays.
I think you expect the wrong thing to happen (that the visual display in the debugger would change), even though your code seems correct.
Your debugger displays m_DataKeys, *m_DataKeys and **m_DataKeys, which is the same as m_DataKeys, m_DataKeys[0] and m_DataKeys[0][0]. When you change m_DataKeys[1], you are not going to notice it in your debugger output.
The following might help you: in my debugger (MS Visual Studio 2005), if you enter e.g. m_DataKeys,5 as your watch expression, you will see the first 5 elements of the array, that is, m_DataKeys[0], m_DataKeys[1], ..., m_DataKeys[4] - arranged in a neat table. If this syntax (with the ,5) doesn't work for you, just add m_DataKeys[1] into the debugger's watch window.
Not sure why this didn't occur to me last night, but I was pretty tired. Heres what I decided to do:
struct AbilityData
{
// Stuff
CUtlMap<char*,int> ExtraData [MAX_ABILITY_LEVELS];
char **DataKeys;
}
Thats what my abilityData struct now looks like, and it now works, but now I want to reorganize it to be like:
struct AbilityData
{
// Stuff
CUtlMap<char*,int[MAX_ABILITY_LEVELS]> ExtraData;
char **DataKeys;
}
Because it makes more sense that way, but then I run into the same problem that I had before with the char array. It almost seems like to me it might just be best to ditch the whole map idea and make it like:
struct AbilityData
{
// Stuff
int *ExtraData;
char **DataKeys;
}
Where ExtraData is now also a dynamically allocated array.
The only problem with that is that I now have to get my data via a function which will loop through all the DataKeys, find a matching key for my input string, then return the ExtraData associated with it.

C++ string.compare()

I'm building a comparator for an assignment, and I'm pulling my hair out because this seems to simple, but I can't figure it out.
This function is giving me trouble:
int compare(Word *a, Word *b)
{
string *aTerm = a->getString();
string *bTerm = b->getString();
return aTerm->compare(bTerm);
}
Word::getString returns a string*
Error:
In member function `virtual int CompWordByAlpha::compare(Word*, Word*)':
no matching function for call to...
...followed by a bunch of function definitions.
Any help?
You're comparing a string to a string pointer, and that's not valid. You want
return aTerm->compare(*bTerm);
You aren't getting the different uses of the * operator. The use of the * in "string* bTerm = b->getString()" means "bTerm is a pointer to a string". The use of the * inside of compare(*bTerm) means "take the value of the location pointed to by bTerm" instead of just using compare(bTerm) which simply attempts to compare the value of bTerm itself, which is a hex address.
This is also happening on the left side of that call:
aTerm->compare(*bTerm); //this statement
(*aTerm).compare(*bTerm); //is the same as this statement
The -> operator just reduces the amount of typing required.
P.S.: This kind of stuff you could have easily figured out from Google or your programming textbook. Although others may disagree, I don't feel that questions about completely basic syntax have any place on Stack Overflow.