Jump to content
  • Advertisement
Sign in to follow this  
dphoenix

Having a problem with a vector iterator

This topic is 3558 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Good afternoon, I'm at my wits end. I'm keeping track of a vector of 2 IP addresses. I do a function to send them all a message via TCP. Then when I go back and check right after I send the message, the first element of the vector is changed to the second, and they are both the same! This is where I iterate and send message to all the addresses:
vector<const char*>::battleList;
vector<const char*>::iterator it;

        for(it = battleList.begin(); it !=battleList.end(); it++)
        {
            Message m;
            cout<<"IP: "<<*it<<endl;
            messenger.sendMessage(m, *it);
        }
Here's the messenger function:
void Messenger::sendMessage(Message m, const char* host)
{
    int n, sockfd;
    struct sockaddr_in serv_addr;
    struct hostent *server = gethostbyname(host);

    string m1 = string(m.code) + "#";
    string m2 = m.message;
    string m3 = m1 + m2;

    const char* buffer1 = m3.c_str();

    char buffer[256];
    memcpy(buffer, buffer1, sizeof(buffer1));

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        cout<<"ERROR opening socket"<<endl;
        int t;
        cin>>t;
        if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
        }
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr,
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(9000);

    if (connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
        cout<<"ERROR connecting"<<endl;

    n = write(sockfd,buffer,strlen(buffer));
    n = send(sockfd, buffer, strlen(buffer), 0);
    if (n < 0)
         cout<<"ERROR writing to socket"<<endl;

}
As you can see, nowhere in the messaging code did I change the host address. In fact, if I put in a cout statement in the for loop, right after the message is sent, it says that the address has not been changed. But if I do:
cout<<battleList[0]<<endl;
cout<<battleList[1]<<endl;
immediately after the for loop, the first address has changed. I called that same bit of code right before the for loop to see if there was a difference. What on earth can the problem be? No one else is accessing these pointer values. If I take the sendMessage function out of the for loop, and just output the address, there is no problem. But I don't see the problem in sendMessage, and in fact, if I cout the host address right at the end of that function, it still is correct. The problem seems to occur in the handoff back to my for loop.

Share this post


Link to post
Share on other sites
Advertisement
I'm not entirely sure, but why on earth are you keeping a vector of char*'s? Where is that allocated? If it's from a std::string::c_str() call, or a string on the stack, you're likely not copying the string out, just storing thr pointer. I suspect you really want to store a vector of std::strings, unless you're storing pointers to arbitrary chunks of memory.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
I'm not entirely sure, but why on earth are you keeping a vector of char*'s? Where is that allocated? If it's from a std::string::c_str() call, or a string on the stack, you're likely not copying the string out, just storing thr pointer. I suspect you really want to store a vector of std::strings, unless you're storing pointers to arbitrary chunks of memory.



The vector of char*s is because the TCP protocol stuff takes addresses in that format, rather than a string. It's just easier than having to convert back and forth.

Share this post


Link to post
Share on other sites
Quote:
Original post by dphoenix
Quote:
Original post by Evil Steve
I'm not entirely sure, but why on earth are you keeping a vector of char*'s? Where is that allocated? If it's from a std::string::c_str() call, or a string on the stack, you're likely not copying the string out, just storing thr pointer. I suspect you really want to store a vector of std::strings, unless you're storing pointers to arbitrary chunks of memory.



The vector of char*s is because the TCP protocol stuff takes addresses in that format, rather than a string. It's just easier than having to convert back and forth.
So how are you filling the vector? If you're doing something like this:

char szBuff[256];
sprintf(szBuff, "123.123.123.123");
battleList.push_back(szBuff);
sprintf(szBuff, "0.0.0.0");
battleList.push_back(szBuff);


Then battleList will just store the szBuff pointer both times, which is a random varaiable on the stack. Only the pointer is copied, not the contents. If you were storing a vector of std::strings, then push_back() would implicitly convert the char* to a std::string, and would copy the data (not the pointer).

If the value changes depending on calling a function, that usually means that the function is changing the stack (Which isn't a problem), and that's affecting what your code does.

Basically - How are you adding elements to the vector [smile]?

Share this post


Link to post
Share on other sites
Hi again :)

I am doing push_back. So when I enter combat with an enemy, I take my IP address and theirs and add it like so:


const char* myIP; //initialized to whatever
const char* theirIP;

battleList.push_back(myIP);
battleList.push_back(theirIP);


If I do a check to confirm the IP addresses immediately after this part, they display as they should.

Share this post


Link to post
Share on other sites
Quote:
Original post by dphoenix

const char* myIP; //initialized to whatever
const char* theirIP;
Define "whatever". You need to allocate space for the pointer to point at at some point, and if both pointers end up pointing at the same space or similar you could quite easily get the problem you're describing.

Share this post


Link to post
Share on other sites
I think it's a pointer issue.

struct hostent *server = gethostbyname(host);

I'm not sure what "gethostbyname" does, but are you setting "server" to the same address location as "host"

bcopy will overlay memory if the two areas overlap.

From http://www.opengroup.org/onlinepubs/000095399/functions/bcopy.html
The bcopy() function shall copy n bytes from the area pointed to by s1 to the area pointed to by s2.

The bytes are copied correctly even if the area pointed to by s1 overlaps the area pointed to by s2.

Share this post


Link to post
Share on other sites
Quote:
Original post by Cranny76
I think it's a pointer issue.

struct hostent *server = gethostbyname(host);

I'm not sure what "gethostbyname" does, but are you setting "server" to the same address location as "host"

bcopy will overlay memory if the two areas overlap.

From http://www.opengroup.org/onlinepubs/000095399/functions/bcopy.html
The bcopy() function shall copy n bytes from the area pointed to by s1 to the area pointed to by s2.

The bytes are copied correctly even if the area pointed to by s1 overlaps the area pointed to by s2.
gethostbyname() stores a static hostent struct internally, and returns that. I presume at least, it allocates the storage space anyway and doesn't require you to free it.

Another thing the OP could try is setting a data breakpoint (After checking that there's different data being stored and not two copies of the same pointer or something). That'll break to the debugger when the specified memory changes.

Share this post


Link to post
Share on other sites
This is the function to get myIP:



const char* Messenger::getMyIP()
{
hostent* localInfo = gethostbyname(""); // get the local host name
struct in_addr addr;
memcpy(&addr,localInfo->h_addr_list[0],sizeof(struct in_addr));
const char* localIP = inet_ntoa(addr);
return localIP;
}




I've confirmed that that part works.

Also, whenever another player sends me a message, the message automatically has their IP address attached by the TCP listener that gets the message:




string mymessage(buffer);
size_t found = mymessage.find("#");
if((found != string::npos) && (found > 0))
//found # delimiter
{
Message m;
int pos = int(found);
string codeSub = mymessage.substr(0, pos);
m.code = codeSub;
m.message = mymessage.substr(pos+1);
m.sender = host;
messageList.push_back(m);
//cout<<"Message in queue."<<endl;
}


The preceding code is in the TCP listener, when it gets a message from another player. Each message has a code and the content, all delineated by the # sign. So that's what m.code and m.message are. Each message also has a space for the sender address, which is initially uninitialized when its sent (this was before I knew how to get my own IP address). m.sender is also a const char*,


class Message
{
public:
Message();
Message(string c, string m);

public:
string code;
string message;
const char* sender;
};

Message::Message()
{}

Message::Message(string c, string m):code(c),message(m)
{}





That's what it looks like. I hope I didn't post too much irrelevant code, but I want to make sure I'm providing enough info because I am absolutely at my wit's end and ready to cry right now lol...

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
Quote:
Original post by Cranny76
I think it's a pointer issue.

struct hostent *server = gethostbyname(host);

I'm not sure what "gethostbyname" does, but are you setting "server" to the same address location as "host"

bcopy will overlay memory if the two areas overlap.

From http://www.opengroup.org/onlinepubs/000095399/functions/bcopy.html
The bcopy() function shall copy n bytes from the area pointed to by s1 to the area pointed to by s2.

The bytes are copied correctly even if the area pointed to by s1 overlaps the area pointed to by s2.
gethostbyname() stores a static hostent struct internally, and returns that. I presume at least, it allocates the storage space anyway and doesn't require you to free it.

Another thing the OP could try is setting a data breakpoint (After checking that there's different data being stored and not two copies of the same pointer or something). That'll break to the debugger when the specified memory changes.


How do I set a data breakpoint? I'm using Code::Blocks because this is crossplatform and needs cygwin. Otherwise I'd be using the Visual Studio debugger to trace the data changes.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!