character arrays and strings

Atomical
Unregistered
 
Post: #1
I've run this through xcode's debugger and it's storing all the right values in host, getpath, and query, but for some reason when it returns to main the arrays are filled with junk characters.

Here are some screenshots of the debugger so you can see what's happening:
http://www.harddrivecaddy.com/temp/stringproblem/


Quote:int hostfromurl ( char *url, char *getpath ,int& port,char *host, char
*query, ostream &h) {

string s_url = reinterpret_cast<const char*>(url);

url_string foo(s_url);

if ( foo.get_scheme() != "http" )
return -1;

host = (char*)tochar(foo.get_net_path());

getpath = (char *)tochar(foo.get_absolute_path());

query = (char*)tochar(foo.get_query());
port = foo.get_port();



if ( ! port )
port = 80;


return 1;
}


char * tochar ( string s ) {
char *ret = strdup (s.c_str() );
return ret;
}
Quote this message in a reply
Moderator
Posts: 771
Joined: 2003.04
Post: #2
You'll have to use ** (pointer to pointers) if you want to modify a pointer passed as a parameter: since changing the value to which the local variable points to doesn't have any effect on the parameter. For instance:

Code:
void doSomething(char *text)
{
    char *otherText = "new thing\n";
    text = otherText;
}


won't do what you expect:
Code:
int main (int argc, char * const argv[])
{
    char *myText = "old thing\n";
    printf(myText);
    doSomething(myText);
    printf(myText);
    return 0;
}


Result:
Code:
old thing
old thing


Also, you can't use statically allocated strings, since they will be released once your function exits.
Quote this message in a reply
Atomical
Unregistered
 
Post: #3
I just got an email from someone suggesting that I use std::strings instead of character arrays in C++. Where is the pay off and is this how professional applications are programmed? If this is true it's kind of disappointing since I converted my application from strings to character arrays.
Quote this message in a reply
Atomical
Unregistered
 
Post: #4
I updated my program but it's still not returning it to main. I got the same result as last time with the debugger.

Quote:int hostfromurl ( char *url, char **getpath ,int& port,char **host, char **query) {

string s_url = reinterpret_cast<const char*>(url);

url_string foo(s_url);

if ( foo.get_scheme() != "http" )
return -1;


//alright, so it works inside this function
host = (char **)tochar(foo.get_net_path());

}

char ** tochar ( string s ) {
char **retptr;
retptr = (char **)malloc(sizeof(char)*2000);
char *t = strdup (s.c_str() );
*retptr = t;
return retptr;
}
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #5
Sorry, I can't get a handle on your main problem, but:

Atomical Wrote:I just got an email from someone suggesting that I use std::strings instead of character arrays in C++. Where is the pay off and is this how professional applications are programmed? If this is true it's kind of disappointing since I converted my application from strings to character arrays.
I did much the same thing a long time ago, because I mistakenly believed that std::string was less efficient than using char arrays and plain old C string functions. That may be the case in some circumstances (or if your compiler is very stupid), but usually it's fine and the benefits of using std::string outweigh the efficiency concern. I'm now switching all my code back to using std::string. Wink

There are plenty of reasons why you should use std::string: no buffer writing overruns (unless you go out of your way to break things), no need to specify the size of your array in advance, easy to transfer ownership to other parts of your program, easier to understand and use (string1 = string2 + string3).

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #6
You still have the same problem, plus other ones that you've introduced (your malloc logic is completely wrong, for example). The whole point for having a pointer of a pointer, is you change what the pointer points to on the first level, so on the second level you get what it now points to. This is what your code should look like:
Quote:int hostfromurl ( char *url, char **getpath ,int& port,char **host, char **query) {

string s_url = reinterpret_cast<const char*>(url);

url_string foo(s_url);

if ( foo.get_scheme() != "http" )
return -1;


//you need little more then this
*host = foo.get_net_path().c_str;
//return whatever you were going to
}
Don't forget to free the strings when you're done with them! (they're on the free store, remember) Also, don't forget that when you access host from the original call, you need to de-reference it before you can use it.
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #7
I'd just use std::string everywhere and have done with it. You may as well pass the strings by reference too, since that prevents the caller from doing something dumb like passing NULL:

Code:
int hostfromurl(std::string url, std::string &getpath, int &port, std::string &host, std::string &query)
{
    url_string foo(url);

    if(foo.get_scheme() != "http")
        return -1;

    host = foo.get_net_path();
    getpath = foo.get_absolute_path();
    query = foo.get_query();
    port = foo.get_port();

    if(port == 0)        // Don't use ! in this context, test for the value you're looking for
        port = 80;

    return 1;        // Are you sure you don't want a bool return value?
}

// ----

std::string path;
int port;
std::string host;
std::string query;

hostfromurl("http://localhost:8008/path?query", getpath, port, host, query);

akb825 Wrote:Don't forget to free the strings when you're done with them! (they're on the free store, remember)
Another compelling reason to use std::string....

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
Atomical
Unregistered
 
Post: #8
Quote:int hostfromurl ( char *url, char *getpath ,int& port,char **host, char *query) {

string s_url = reinterpret_cast<const char*>(url);

url_string foo(s_url);

if ( foo.get_scheme() != "http" )
return -1;
string sm = foo.get_net_path();
host = malloc(2000);
*host = strdup (sm.c_str());


I tried couting that in the main program and it outputted garbage. I tried derefrencing it with (*host).
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #9
Why don't you just do what I showed you? You're making the exact same you made the last 2 times: you're overwriting the double pointer you're using to keep track of the changes. Mad You leave host alone. You have it as a double pointer so the top level can stay the same and you can keep track of how the lower levels change. Furthermore, your call to malloc is completely unnecessary. It's basically saying "I want an array of 2000 strings." Not only that, it overwrites your copy of the double pointer so you can't keep track of the change. Your call to strdup is unnecessary: it already has to be on the free store when you call c_str or it wouldn't be able to return the string. So you have a memory leak. Once again, here is a copy of the code that will work:

Code:
int hostfromurl ( char *url, char **getpath ,int& port,char **host, char **query) {

string s_url = reinterpret_cast<const char*>(url);

url_string foo(s_url);

if ( foo.get_scheme() != "http" )
return -1;


//you need little more then this
*host = foo.get_net_path().c_str;
//return whatever you were going to
}

Edit: Oh, and don't forget to malloc a char ** for host before you make the hostformurl function call. (Oh, and just as a style suggestion: it's a bit more readable if you either use capitols (my preference) or underscores for the names. For example, hostFormURL or host_form_url)
Quote this message in a reply
Atomical
Unregistered
 
Post: #10
It's the host line that gives my compiler this error:
/Users/adam/Desktop/proxyproject/server/html.cpp:743: error: argument of type `const char*(std::basic_string<char, std::char_traits<char>, std::allocator<char> >:Smile() const' does not match `char*'

That's why I changed it around.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #11
I see, the problem is I forgot to put the parentheses after c_str. Sorry Rasp

The offending line should be:
Code:
*host = foo.get_net_path().c_str();
Quote this message in a reply
Atomical
Unregistered
 
Post: #12
/Users/adam/Desktop/proxyproject/server/html.cpp:742: warning: invalid conversion from `const char*' to `char*'


I tried putting it in strdup and that gave me a sigbus too.
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #13
You need to cast it to char * from const char *, then
Code:
*host = (char *)foo.get_net_path().c_str();
All these functions that return constant strings do is just cause more need for casting where it shouldn't need it, IMO. Mad
Quote this message in a reply
Moderator
Posts: 365
Joined: 2002.04
Post: #14
You shouldn't cast the result of .c_str() (or virtually anything else) to remove constness. It's const so that you don't accidentally trash the private string data.

Moreover, you're making a deadly mistake here. 'url_string foo' is local. You just took a pointer to an internal buffer in one of its members. When the function returns, foo is destroyed and the buffer no longer exists. Attempting to access the returned pointer may return garbage, and writing to the pointer will probably trash the stack.

Seriously, use std::string. If you really don't want to, just use standard C string functions everywhere so that you can get your constness right.

Neil Carter
Nether - Mac games and comic art
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #15
Ok, I thought that c_str created a copy of the string instead of just returning the buffer from the local variable. In that case, strdup is needed. As for casting the result, the only person you need to worry about screwing up is yourself. If you don't do anything with it that will cause troubles, and there is no other way to put that string into the variable (as in this case), I see no problem with it.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Diferences between array and pointer initialized strings in C ferum 16 6,737 Jan 4, 2006 11:38 PM
Last Post: kelvin
  efficient strings? fabien007 4 3,111 Dec 9, 2005 10:59 PM
Last Post: zKing