character arrays and strings
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/
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;
}
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:
won't do what you expect:
Result:
Also, you can't use statically allocated strings, since they will be released once your function exits.
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 thingAlso, you can't use statically allocated strings, since they will be released once your function exits.
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 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;
}
Sorry, I can't get a handle on your main problem, but:

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).
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.

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).
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) {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.
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
}
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....
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).
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.
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:
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)
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)
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> >:
() const' does not match `char*'
That's why I changed it around.
/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> >:
() const' does not match `char*'That's why I changed it around.
I see, the problem is I forgot to put the parentheses after c_str. Sorry 
The offending line should be:

The offending line should be:
Code:
*host = foo.get_net_path().c_str();
/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.
I tried putting it in strdup and that gave me a sigbus too.
You need to cast it to char * from const char *, then
All these functions that return constant strings do is just cause more need for casting where it shouldn't need it, IMO.
Code:
*host = (char *)foo.get_net_path().c_str();
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.
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.
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.
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Diferences between array and pointer initialized strings in C | ferum | 16 | 6,193 |
Jan 4, 2006 11:38 PM Last Post: kelvin |
|
| efficient strings? | fabien007 | 4 | 2,805 |
Dec 9, 2005 10:59 PM Last Post: zKing |
|

