I've been hacking away at C++ for a few months now, making simple console applications in Dev C++. However, after spending time in this forum and hearing more experienced programmers testify to Dev C++s inadequacies, I decided to make the switch to Visual C++.
But now my one working Dev C++ game won't compile. Actually, the game starts up so it might compile (?), but after the first move I get:
This is from previously working code I posted here a few weeks back and at least one other person compiled successfully. I use String class in the code. Could it have to do with the location of Visual C++ class libraries?
The error is just what the message says, you're having an out-of-bounds access somewhere.
Just because your code seems to be working most of the time doesn't mean it's correct.
Actually, the game starts up so it might compile
If it didn't compile, there wouldn't be anything to start.
Should be a big button near the top somewhere, in that ribbon of buttons. I seem to recall it looks like a little green arrowhead pointing to the right. Failing that, the "F5" key rings a bell in my memory.
ok, yeah, but that seems to have the same effect as what i've been doing all along from the Debug pulldown, then the program runs, but I get the "Assertion Failure" in the same place.
i can't see specifically which line is triggering it. is there a way to tell?
it's happening (i think) during the execution of this function:
1 2 3 4 5 6 7
int normalizeINPUT (string inp) {
int i, q;
string n;
for (int i=0;inp[i] != '\0';i++) n=n+inp[i];
q=atoi(n.c_str());
return q;
}
which i call from main() like this:
1 2 3 4 5 6 7
cout<<"Enter grid number ('Q' to Quit) : ";
getline (cin,inp);
if ((inp[0]=='q')||(inp[0]=='Q')) break;
g=normalizeINPUT(inp);
if ((g<1)||(g>4)) {cout<<"\nInvalid selection.\n\n";
system("PAUSE");turn--;continue;}
where inp is a string and g is an int. (i know system ("PAUSE") is bad)
i'm thoroughly baffled.
'3D Tic Tac Toe.exe': Loaded 'C:\Users\Erik\Documents\Visual Studio 2010\Projects\3D Tic Tac Toe\Debug\3D Tic Tac Toe.exe', Symbols loaded.
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\ntdll.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\kernel32.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\KernelBase.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\msvcp100d.dll', Symbols loaded.
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\msvcr100d.dll', Symbols loaded.
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\apphelp.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\user32.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\gdi32.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\lpk.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\usp10.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\msvcrt.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\imm32.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\msctf.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\advapi32.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\sechost.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\rpcrt4.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\uxtheme.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\dwmapi.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\ole32.dll', Cannot find or open the PDB file
'3D Tic Tac Toe.exe': Loaded 'C:\Windows\System32\cryptbase.dll', Cannot find or open the PDB file
3D Tic Tac Toe.exe has triggered a breakpoint
So am I.
Why didn't you just write string n=s; instead of that loop?
Or while we're at it, what purpose serves n anyway? Why not this?
1 2 3
int normalizeINPUT (string inp) {
return atoi(inp.c_str());
}
or rather:
1 2 3
int stringToInt (const string& str) {
return atoi(str.c_str());
}
If the problem is really caused by that function, it's likely because you're trying to access the element behind the actual string. While this is actually allowed for std::string, VC++ might decide to treat it as an error.
just realized i declared 'i' twice in normalizeINPUT, but fixing it hasn't helped my original problem.
All that happened there was that the i in the loop shadowed the outer i. It made no difference.
anyone know what all this stuff means?
Means you've got no debugging symbols for those files. As a general rule of thumb, the bug will be in your code rather than the libraries, so that's nothing to worry about.
When debugging, you really should be able to access the variables directly and interrogate them to see what values they have. Anyway, as Athar says, your code is far more complicated than it needs to be to turn a string into an int. I see nothing in your code above that looks like you would be stomping over memory that isn't yours, so if this is where the bug is expressed, it's not where it's caused.
Athar- you're right, though in partial defense that loop was a holdover from an earlier version of the program where i used a whitespace instead of a null as an exit condition.... at the time i think i was trying to handle someone entering a huge string of gobbledigoop with whitespaces.
But I just got rid of that function altogether and replaced each function call with
1 2 3 4 5 6 7
getline (cin,inp);
if ((inp[0]=='q')||(inp[0]=='Q')) break;
g=atoi(inp.c_str()); //this here where the function call was
if ((g<1)||(g>4)) {cout<<"\nInvalid selection.\n\n";
system("PAUSE");turn--;continue;}
and it appears to work. but i still don't understand why, or exactly what you mean by "accessing the element behind the string".
string a="42";
That string has length 2, so it has two elements - a[0] and a[1].
However, since neither of those are equal to '\0', your loop keeps going and accesses a[2] - which is out of bounds.
It's still okay, because the standard says that operator[] has to return a reference to a default-initialized instance of the underlying character type (char in this case, so '\0') when you access a[a.length()]. However, this wouldn't have worked if you had used at() instead, for instance.
The std::string type is actually a std::basic_string<char>. In a basic_string, the elements (of type char for a std::string) are stored contiguously in memory (just like an array), which is what allows us to happily use the [] notation to fetch individual characters. However, as Athar says, this is completely within the standard behaviour, and I think it very unlikely that the VS compiler has an issue.
What's definitely happening is that at some point, you're trying to read (or write) to part of the string that doesn't exist, and in debug mode there are things to keep you from doing that (so that you can then fix your code). For example, if you had a string of 4 characters, you'd see this error if you tried to access character -1 (or lower), or 4 (or greater).
Because of where the error was happning, it seemed likely that my problem was in that little function (normalizeINPUT). And this notion is reinforced by the program working with that function removed. The loop in that function is the only line that attempts to access inp.
Now I had thought that a String type was null-terminated like a char*[] array, and that seems to be what Athar is saying here:
It's still okay, because the standard says that operator[] has to return a reference to a default-initialized instance of the underlying character type (char in this case, so '\0') when you access a[a.length()]
The loop does check inp[inp.len()] for it's exit condition, but it doesn't modify it, and i don't see how it differs from this other code from C++ Without Fear:
This code demonstrates reading every character in a std::string, and then choosing to read beyond the size of the string. We find that it is indeed null-terminated. However, to find out, we had to read beyond the size of string. Your debug runtime is keeping track of the size of the array for you, and when you try to read beyond the size of the array, it stops you. This means that you cannot use the mechanism of finding the null-terminator in a std::string (under the debug runtime you're using), because to find it, you must read beyond the end of the array.
I suspect that the code below will not work on your setup; however, it should work fine if you don't use the debug runtime that does you the favour of checking your array access. A better way is to just read the size of the string, as below (for(int i=0; i<aString.size(); ++i) )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#include <string>
#include <iostream>
int main()
{
std::string aString("Eggs on toast");
std::cout << aString << std::endl;
std::cout << "Size of the string is " << aString.size() << std::endl;
for(int i=0; i<aString.size(); ++i)
{ std::cout << i << ":" << aString[i] << std::endl;
}
std::cout << "Value of size+1 element is " << (int)aString[aString.size()+1];
return 0;
}
i don't see how it differs from this other code from C++ Without Fear:
The difference that in that example, it's a C string and those are null-terminated by definition. That means "Hello!" is an array of 7 characters - 6 for Hello! and a final '\0'. That's not true for C++ strings. When you assign "Hello!" to a std::string, it will contain 6 characters, not 7.