Skip to main content
gamedev.net
🔒 Locked

String manipulation

Started by BloodLust666 19 replies 2k views
Original Post
BloodLust666
BloodLust666
Ok, i have 10 char* pointers i need to add to a map<> template (it is the key type). I go through a loop. // 10 Items for (char i=0, char*ch; i < 10 ; i++) { sprintf(ch, "Item%d", i); MapList.Add(SomeItem, ch); } but then when i check the map for that same item, it returns an error saying it's not there... MapList.GetItem("Item0") <-- returns NULL what's wrong?
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
BloodLust666
BloodLust666
it is really just that, i have a template.

template
Type* tMapList::GetItem(char *RefName)
{
map ::iterator Iter;
Iter = m_MapList.find(RefName);

if (Iter != m_MapList.end())
return Iter->second;
else {
cError::Write("tMapList::GetItem(char*) No such item as:");
cError::Write(RefName);
return NULL;
}
}

GetItem("Item0") is passed into that. and i get a NULL pointer saying it was never stored... but in my for loop, i clearly did!

// 10 Items
for (char i=0, char*ch; i < 10 ; i++)
{
sprintf(ch, "Item%d", i);
MapList.Add(SomeItem, ch);
}
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
xeddiex
xeddiex
Quote:
Original post by EvilKnuckles666
Ok, i have 10 char* pointers i need to add to a map<> template (it is the key type). I go through a loop.

// 10 Items
for (char i=0, char*ch; i < 10 ; i++)
{
sprintf(ch, "Item%d", i);
MapList.Add(SomeItem, ch);
}

but then when i check the map for that same item, it returns an error saying it's not there...

MapList.GetItem("Item0") <-- returns NULL

what's wrong?


I see one problem here:
sprintf(ch, "Item%d", i);


In your for loop. 'ch' is being declared. The problem is you're not allocating memory for 'ch' (malloc, realloc etc..) You're writing into an uninitialized-unknown memory space. Which is bad.

[edit: I see you're using C++. substitute malloc/relloac with the C++ equivalents]
one..
BloodLust666
BloodLust666
yes i am. it's in the beginning line in the for loop.

for (char i=0, char* ch; i<10 ; i++)
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
Telastyn
Telastyn
++ for eddie.

Also, though it might depend on your setup, the map was not declared to do string comparesson on the key. It's just comparing pointers, which even if you malloc the key properly, the string literal you're checking against won't have the same pointer. Thus the map will not consider it equal, even though the text is the same.

Here at the top is example code to setup the map [the 3rd template parameter to it to be specific] to do what you want. Though eddie is correct, and proper memory management with char*'s will also be a problem.

And further:
sprintf(ch,"Item%d",i);


is non-sense.

i is a char, not a ?double? which is what %d is looking for, meaning 0 is not what will be at the end of that string, meaning it won't match anyways.

std::string, and stringstream are your friends. Even if you use char*'s correctly, it's a pain to remember niggling details like memory management and what %code is a certain type in *printf functions. Especially when busy trying to learn other stuff.

[edit: correcting...]
Mercury
Mercury
Quote:
Original post by EvilKnuckles666
yes i am. it's in the beginning line in the for loop.

for (char i=0, char* ch; i<10 ; i++)

char *ch will create a character pointer, but it won't be pointing to anything unless you new or malloc it. Right now, it's pointing to something random. Probably something you don't want to overwrite.

To do what you think you're doing now, do either of these:
char *ch = new char[256]; // or however long you want it
char ch[256]; // or however long you want it

After doing that, you can use sprintf on the strings.
xeddiex
xeddiex
Quote:
Original post by EvilKnuckles666
yes i am. it's in the beginning line in the for loop.

for (char i=0, char* ch; i<10 ; i++)


No you did not.

You forgot, or don't know, that, pointers need to be intialized with memory first in order to store something in the pointer variable.

Example:

In C:
ch = malloc(10 * sizeof(char));


In C++ .. something like this:
ch = new[10];
one..
Telastyn
Telastyn
Here's some code that should work. [edit: for the map problems.]

Note that the struct "bar" does not need to do manual deletion of the copied keys, and that "foo" will.

#include <map>#include <stdio.h>#include <stdlib.h>#include <iostream>#include <string>#include <sstream>#include <utility>#define bzero(p, l) memset(p, 0, l)using namespace std;struct ltstr{  bool operator()(const char* s1, const char* s2) const  {    return strcmp(s1, s2) < 0;  }};struct  foo{        map<char *, int, ltstr>         foomap;        void    add(char *k, int v){                //                //                //                char    *kcopy=0;                kcopy=(char *)malloc(strlen(k)+1);                strcpy(kcopy,k);                foomap.insert(make_pair(kcopy,v));        }        int     fetch(char *k){                //                //                //                map<char *,int, ltstr>::iterator        it;                it=foomap.find(k);                if(it!=foomap.end()){                        return(it->second);                }else{                        return(0);                }        }};struct  bar{        map<string, int>                barmap;        void    add(char *k, int v){                //                //                //                barmap.insert(make_pair(k,v));        }        int     fetch(char *k){                //                //                //                map<string,int>::iterator        it;                it=barmap.find(k);                if(it!=barmap.end()){                        return(it->second);                }else{                        return(0);                }        }};int     main(){//////foo     f;bar     b;f.add("cow",1);f.add("duck",2);cout << "cow: " << f.fetch("cow") << "\n";cout << "duck: " << f.fetch("duck") << "\n";b.add("moose",42);b.add("goat",-5);cout << "moose: " << b.fetch("moose") << "\n";cout << "goat: " << b.fetch("goat") << "\n";}

output
> ./testcow: 1duck: 2moose: 42goat: -5


[edit2: And here's the code for the sprintf issues. Note, the char* in "bar" was changed to const char * to make this work nicer.]
int     x;char    *buf;buf=(char *)malloc(50);bzero(buf,50);for(x=3; x<8; x++){        sprintf(buf,"Item%i",x);        f.add(buf,x*x);}free(buf);cout << "Item 5 (5*5): " << f.fetch("Item5") << "\n";string  ss;for(x=3;x<8;x++){        ss="Item"+x;        b.add(ss.c_str(),x*9);}cout << "Item 6 (6*9): " << b.fetch("Item6") << "\n";
Glak
Glak
in conclusion: if you had used the standard string type you would not have had two bugs in three lines of code.
BloodLust666
BloodLust666
soo all would i have to do is add that struct at the top of my code and put:
map
as my map declaration?

edit: Or would i have to change things around? (hopefully not...)
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
BloodLust666
BloodLust666
hmmm, now i'm thinking of just going with:
map

think that would be better/easier?
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
Drew_Benton
Drew_Benton
Quote:
Original post by EvilKnuckles666
hmmm, now i'm thinking of just going with:
map


When you are using the standard C++ library, you might as well try to use all the provided components if they fit your needs. If you are in need of using a string data type for the key, choose std::string over char*. It just makes life better for you.
BloodLust666
BloodLust666
geez... now it can't see they're the same again...

for (char i=0 ; i < 10 ; i++)
{
string str;
str = "Level_1_Enemy_" + i;
MapList.Add(Item, str);
}

GetItem("Level_1_Enemy_0")
yet again returns NULL...

edit: and now my map is map
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
Drew_Benton
Drew_Benton
When you want to do what you just did, you will need to use the stringstream to build a string.
#include <sstream>...for ( int i = 0; i < 10; i++ ){   stringstream ss;   ss << "Level_1_Enemy_" << i;   MapList.Add( Item, ss.str() );}


If that does not work right, check over your Add function. Perhaps there is a logic error there that makes the problem happen.

Oh and as to why I used ints over char's here's what your code is doing:
Level_1_Enemy_Level_1_Enemy_☺Level_1_Enemy_☻Level_1_Enemy_♥Level_1_Enemy_♦Level_1_Enemy_♣Level_1_Enemy_♠Level_1_Enemy_Level_1_Enemy_Level_1_Enemy_


You should have had:
for ( char i = '0'; i <= '9'; i++ )
BloodLust666
BloodLust666
i did what you said and this came up:

ss.str() = "Level_1_Enemy_0ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ"

what's all that stuff after it..
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
Drew_Benton
Drew_Benton
Quote:
Original post by EvilKnuckles666
i did what you said and this came up:

ss.str() = "Level_1_Enemy_0ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþ"

what's all that stuff after it..


Are you debugging? If you are, don't worry about it, it's just there, I see it too. I just made this program
#include <sstream>#include <string>#include <iostream>#include <map>using namespace std;void main(){	for ( int i = 0; i < 10; i++ )	{		stringstream ss;		ss << "Level_1_Enemy_" << i;		cout << ss.str() << endl;	}}


With this output
Level_1_Enemy_0Level_1_Enemy_1Level_1_Enemy_2Level_1_Enemy_3Level_1_Enemy_4Level_1_Enemy_5Level_1_Enemy_6Level_1_Enemy_7Level_1_Enemy_8Level_1_Enemy_9Press any key to continue

So nothings wrong with the values.
BloodLust666
BloodLust666
yea, it's what came up in the locals in debug mode
-------------------------Unless specified otherwise, my questions pertain:Windows Platform (with the mindset to keep things multi-platform as possible)C++Visual Studio 2008OpenGL with SFML
me22
me22
If you look at the contents of a std::string with a debugger, odds are good that you'll see extra characters because std::string keeps track of its own length so it doesn't have to be null terminated, which will confuse a debugger looking for a null terminator.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.