By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,168 Members | 1,036 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,168 IT Pros & Developers. It's quick & easy.

Bizarre char* problem

P: n/a
Okay, this one has me totally baffled. I have a function,
getParsedKey(char* key, char* returnString). I pass in the key I want,
it retrieves it from a data structure and puts the value in
returnString. The problem is that returnString points to the correct
value in the function, but after the function has finished, the string
that it points to is empty.

.....
char* radioList = NULL;
ini->getParsedKey("Radio",radioList);
.....

bool iniparser::getParsedKey(char *key, char *returnString)
{
//for all the keys in the section
for (int i = 0; i < numKeysInSection; i++)
{
//returnString takes the value of the current key
returnString = strtok(iniSection[i],"=");
//if the current key is the desired key
if ((strcmp(returnString,key) == 0))
{
//then returnString takes on the key's value
returnString = strtok(NULL,"\n");
MessageBox(NULL,returnString,"returnString in
getParsedKey(2)",NULL);
//return the key's value
return true;
}
}

MessageBox(NULL,"KEY NOT FOUND","OK",NULL);
//if the key isn't found, return NULL
return false;
}

So, to clarify, radiolist gets passed to getParsedKey, which finds the
key "Radio" and puts the value assosciated with radio in the pointer.
While it's in the function, the pointer (returnString) points, as it
should, to the value. After the function has finished, however, the
pointer radioList points to an empty string. This has me totally
baffled. I'm hoping I've made a noob mistake somewhere in the code and
that someone can kindly point it out to me, because I've been staring
at this and poking at it for many, many hours now, to no avail.

Any suggestions?

Cheers,
Aaron Brown

P.S: I'm working in the Visual Studio 2005 IDE

Jun 15 '06 #1
Share this Question
Share on Google+
26 Replies


P: n/a
th*********@gmail.com wrote:
Okay, this one has me totally baffled. I have a function,
getParsedKey(char* key, char* returnString). I pass in the key I
want, it retrieves it from a data structure and puts the value in
returnString. The problem is that returnString points to the correct
value in the function, but after the function has finished, the string
that it points to is empty.

....
char* radioList = NULL;
ini->getParsedKey("Radio",radioList);
....

bool iniparser::getParsedKey(char *key, char *returnString)
{
//for all the keys in the section
for (int i = 0; i < numKeysInSection; i++)
{
//returnString takes the value of the current key
returnString = strtok(iniSection[i],"=");
You change the *local* pointer here. This action has nothing to do
with the variable that you passed in.
//if the current key is the desired key
if ((strcmp(returnString,key) == 0))
{
//then returnString takes on the key's value
returnString = strtok(NULL,"\n");
Again...
MessageBox(NULL,returnString,"returnString in
getParsedKey(2)",NULL);
You have 'newline' in a literal here...
//return the key's value
return true;
}
}

MessageBox(NULL,"KEY NOT FOUND","OK",NULL);
//if the key isn't found, return NULL
return false;
}

So, to clarify, radiolist gets passed to getParsedKey, which finds the
key "Radio" and puts the value assosciated with radio in the pointer.
While it's in the function, the pointer (returnString) points, as it
should, to the value. After the function has finished, however, the
pointer radioList points to an empty string. This has me totally
baffled.
How about this:

foo(char const * blah)
{
blah = "DEF";
}

#include <stdio.h>
int main()
{
const char * blah = "ABC";
printf(blah);
}

? Confusing as well?
I'm hoping I've made a noob mistake somewhere in the code
and that someone can kindly point it out to me, because I've been
staring at this and poking at it for many, many hours now, to no
avail.

Any suggestions?
Don't use plain pointers. Or pass the second argument by reference.

Cheers,
Aaron Brown

P.S: I'm working in the Visual Studio 2005 IDE


If you need a VC++-specific solution, you might want to post to
'microsoft.public.vc.language' newsgroup.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 15 '06 #2

P: n/a
th*********@gmail.com wrote:
Okay, this one has me totally baffled. I have a function,
getParsedKey(char* key, char* returnString). I pass in the key I
want, it retrieves it from a data structure and puts the value in
returnString. The problem is that returnString points to the correct
value in the function, but after the function has finished, the string
that it points to is empty.

Look at the follow program. What do you think the value of i in main()
will be after the call to func()?

void func(int n)
{
n = 3;
}
int main()
{
int i = 0;

func(i);

return 0;
}

Brian
Jun 15 '06 #3

P: n/a
<th*********@gmail.com> wrote:
... I have a function,
getParsedKey(char* key, char* returnString). I pass in the key I want,
it retrieves it from a data structure and puts the value in
returnString. The problem is that returnString points to the correct
value in the function, but after the function has finished, the string
that it points to is empty.
...
bool iniparser::getParsedKey(char *key, char *returnString)
{
...
returnString = strtok(NULL,"\n");
...
}
...
Any suggestions?


You are modifying only a local copy of returnString.
Jun 15 '06 #4

P: n/a

Default User wrote:
th*********@gmail.com wrote:
Okay, this one has me totally baffled. I have a function,
getParsedKey(char* key, char* returnString). I pass in the key I
want, it retrieves it from a data structure and puts the value in
returnString. The problem is that returnString points to the correct
value in the function, but after the function has finished, the string
that it points to is empty.

Look at the follow program. What do you think the value of i in main()
will be after the call to func()?

void func(int n)
{
n = 3;
}
int main()
{
int i = 0;

func(i);

return 0;
}


5?

Jun 15 '06 #5

P: n/a
You're all quite correct. I modified it so that, instead of passing in
a pointer by value I had it return a pointer to the correct string.
This, unfortunately, didn't solve the problem.

....
char* radioList = ini->getParsedKey("Radio");
....

char* iniparser::getParsedKey(char* keyName)
{
char* tempString = new char[MAX_INI_LINE_LENGTH];
for(int i = 0; i < strlen(keyName); i++)
{
tolower(keyName[i]);
}

//for all the keys in the section
for (int i = 0; i < numKeysInSection; i++)
{
//tempString takes the value of the current key
tempString = strtok(iniSection[i],"=");
//if the current key is the desired key
if ((strcmp(tempString,keyName) == 0))
{
//then tempString takes on the key's value
tempString = strtok(NULL,"\n");
//return the key's value
return tempString;
}
}

MessageBox(NULL,"KEY NOT FOUND","OK",NULL);
//if the key isn't found, return NULL
return NULL;
}

Now, correct me if I'm wrong, but that should fix the pass-by-value
problem of the previous version of this function, right? I mean, I'm
passing back an address to a character string. That character string
exists inside the function, but disappears once the function has
returned the pointer.
Roberto Waltman wrote:
<th*********@gmail.com> wrote:
... I have a function,
getParsedKey(char* key, char* returnString). I pass in the key I want,
it retrieves it from a data structure and puts the value in
returnString. The problem is that returnString points to the correct
value in the function, but after the function has finished, the string
that it points to is empty.
...
bool iniparser::getParsedKey(char *key, char *returnString)
{
...
returnString = strtok(NULL,"\n");
...
}
...
Any suggestions?


You are modifying only a local copy of returnString.


Jun 15 '06 #6

P: n/a
Noah Roberts wrote:

Default User wrote:

Look at the follow program. What do you think the value of i in
main() will be after the call to func()?

void func(int n)
{
n = 3;
}
int main()
{
int i = 0;

func(i);

return 0;
}


5?

You may want to look into another occupation. ;)


Brian
Jun 15 '06 #7

P: n/a
th*********@gmail.com wrote:
You're all quite correct. I modified it so that, instead of passing
in a pointer by value I had it return a pointer to the correct string.
This, unfortunately, didn't solve the problem.
Don't top-post. Your replies belong following or interspersed with
trimmed quotes.

...
char* radioList = ini->getParsedKey("Radio");
...

char* iniparser::getParsedKey(char* keyName)
{
char* tempString = new char[MAX_INI_LINE_LENGTH];
for(int i = 0; i < strlen(keyName); i++)
{
tolower(keyName[i]);
}


You are attempting to modify a string literal. That causes undefined
behavior.

Is there a reason you aren't using std::string?


Brian
Jun 15 '06 #8

P: n/a
just change function prototype to

char* iniparser::getParsedKey(char[] keyName) ;

This will solve your problem

Regards
mangesh

Jun 16 '06 #9

P: n/a
mangesh schrieb:
just change function prototype to

char* iniparser::getParsedKey(char[] keyName) ;

This will solve your problem


Please quote what yuo are referring to.

The original prototype is
char* iniparser::getParsedKey(char* keyName);


So what problem will the char[] solve? Its functionally equal.

Thomas
Jun 16 '06 #10

P: n/a
Thomas J. Gritzan wrote:
mangesh schrieb:
just change function prototype to

char* iniparser::getParsedKey(char[] keyName) ;

This will solve your problem


Please quote what yuo are referring to.

The original prototype is
char* iniparser::getParsedKey(char* keyName);


So what problem will the char[] solve? Its functionally equal.


Actually, "char[] keyName" is a syntax error. It can't really
be "functionally equal". I am guessing you're both Java people
(no offense) and actually meant to write

char* iniparser::getParsedKey(char keyName[])

which *is* functionally equal.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 16 '06 #11

P: n/a

when u write
char *name ;
name is pointer to constant .( it is treated so by compiler , vc and
gcc)
In given code u r trying to modify constant , that result in undefined
behaviout .

in char name[]
name is constant pointer . but what it is pointing to is not constant .
so it will work

Regards
Mangesh

Jun 17 '06 #12

P: n/a
mangesh <ma************@walla.com> wrote:
when u write
char *name ;
name is pointer to constant .( it is treated so by compiler , vc and
gcc)
No. 'name' is a pointer to a *non-constant* char. The fact that you
can assign a string literal (which is constant) to a char* stems from C
and should be avoided. It does not change the fact that "char* name" is
a pointer to non-const char.
In given code u r trying to modify constant , that result in undefined
behaviout .
Right, because you assigned a string literal (const) to a 'char*'
and modified the characters thru that 'char*'.
in char name[]
name is constant pointer . but what it is pointing to is not constant
. so it will work


No. Neither the pointer, nor what is pointed to is const. You can
assign to both (ie. the pointer and the chars pointed to). In other
words, 'char name[]' will not work in the original code either, as 'char
name[]' and 'char* name' are the same (in the context of function
arguments).

regards
--
jb

(reply address in rot13, unscramble first)
Jun 17 '06 #13

P: n/a
Thanks for all your input, everyone, it's been most informative. So
question: If all of you were going to rewrite this function, how would
you do it? What type(s) of string would you use? Would you use an
"out" variable or have the function return the string? What kinds of
best-practices do you all use that might apply in this situation?

Cheers,
Aaron Brown

Jun 19 '06 #14

P: n/a
th*********@gmail.com wrote:
Thanks for all your input, everyone, it's been most informative. So
question: If all of you were going to rewrite this function, how would
you do it? What type(s) of string would you use? Would you use an
"out" variable or have the function return the string? What kinds of
best-practices do you all use that might apply in this situation?


Well, your spec of what this thing is supposed to do is not very
clear. It's always a good idea to write your spec down in as clear
and explicit a manner as you can. It *appears* to be some kind
of translation thing. You want a value from a keyword. If that is
true, then write it down as a table, for example. Or a table with
conditions. This keyword gives that value, in these conditions.

I'd do that using a class. The class would have some sort of
container (or maybe containers) (vector maybe, or maybe list,
or maybe map, depending on the context) that held the keywords
that were legal and the value to proffer up when that keyword
was sent. The data would most probably be stored as
std:string objects. Depending on how many of these things
there were I might want them in some sort of sorted container,
or might just have two vectors, keyword in this one and
values in that one in the same order.

The class would have a member function that accepted the
keyword, most probably as a std::string, and returned
an std::string with the result. Unless these thing were
getting very long, I'd just do that by value.

The class would have a member function that accepted
pairs of keywords and corresponding values, and packed
them into the container. That way, there could be different
translation tables for different contexts. Again, all in
std::string objects.
Socks

Jun 19 '06 #15

P: n/a
Thanks, that design makes a lot of sense.
Well, your spec of what this thing is supposed to do is not very
clear. It's always a good idea to write your spec down in as clear
and explicit a manner as you can.
Sorry about the lack of context for the function. What I've done is
created a class which parses and stores one section of a larger
initialization file. The section is, as you rightly inferred, a bunch
of key=value entries.
The class would have a member function that accepted the
keyword, most probably as a std::string, and returned
an std::string with the result. Unless these thing were
getting very long, I'd just do that by value.


What are the advantages of using std::string over C-style, char-based
strings? Quite a few of the functions and libraries I've run across
have been built around char* and const char* for strings.

Thanks again for all your information and advice. It's always
interesting to be able grill people who are more experienced with the
language than I am.

Cheers,
Aaron Brown

Jun 19 '06 #16

P: n/a
<th*********@gmail.com> wrote in message
news:11*********************@g10g2000cwb.googlegro ups.com...
Thanks, that design makes a lot of sense.
Well, your spec of what this thing is supposed to do is not very
clear. It's always a good idea to write your spec down in as clear
and explicit a manner as you can.


Sorry about the lack of context for the function. What I've done is
created a class which parses and stores one section of a larger
initialization file. The section is, as you rightly inferred, a bunch
of key=value entries.
The class would have a member function that accepted the
keyword, most probably as a std::string, and returned
an std::string with the result. Unless these thing were
getting very long, I'd just do that by value.


What are the advantages of using std::string over C-style, char-based
strings? Quite a few of the functions and libraries I've run across
have been built around char* and const char* for strings.

Thanks again for all your information and advice. It's always
interesting to be able grill people who are more experienced with the
language than I am.


There are many advantages of using std::string over char arrays.

1. You don't have to give a size. std::string is dynamic and will grow as
needed.
2. Comparisons are a lot easier. == works to compare strings, as does
..compare() for substrings
3. You don't have to worry about buffer over and underruns
4. You don't have to worry about setting the null terminator
5. You can use + to add strings together which you can't with substrings
6. If you do have to pass a c style string from a std::string you can simply
use .c_str()

Many others.
Jun 20 '06 #17

P: n/a
Jim Langston wrote:
<th*********@gmail.com> wrote in message
news:11*********************@g10g2000cwb.googlegro ups.com...
Thanks, that design makes a lot of sense.
Well, your spec of what this thing is supposed to do is not very
clear. It's always a good idea to write your spec down in as clear
and explicit a manner as you can.

Sorry about the lack of context for the function. What I've done is
created a class which parses and stores one section of a larger
initialization file. The section is, as you rightly inferred, a bunch
of key=value entries.
The class would have a member function that accepted the
keyword, most probably as a std::string, and returned
an std::string with the result. Unless these thing were
getting very long, I'd just do that by value.

What are the advantages of using std::string over C-style, char-based
strings? Quite a few of the functions and libraries I've run across
have been built around char* and const char* for strings.

Thanks again for all your information and advice. It's always
interesting to be able grill people who are more experienced with the
language than I am.


There are many advantages of using std::string over char arrays.

1. You don't have to give a size. std::string is dynamic and will grow as
needed.
2. Comparisons are a lot easier. == works to compare strings, as does
.compare() for substrings
3. You don't have to worry about buffer over and underruns
4. You don't have to worry about setting the null terminator
5. You can use + to add strings together which you can't with substrings
6. If you do have to pass a c style string from a std::string you can simply
use .c_str()

Many others.


If you've ever built a house, imagine replacing your claw hammer with a
nail gun. For the STL in general, I have become an evangelical nut
about c++ thanks to its existence.
Jun 20 '06 #18

P: n/a
Sgt. York wrote:
[snip]
If you've ever built a house, imagine replacing your claw hammer with a
nail gun. For the STL in general, I have become an evangelical nut
about c++ thanks to its existence.


That's a very nice comparison. I like it. It may show up in my posts.

Your experience mirrors my own. When I first encountered the STL
I was resistant. At least part of this was due to the implementation
I had not being particularly compliant or stable. But as I got used to
it, and as books appeared giving tutorial explanation and examples
of use, and higher level books appeared giving the rules for when to
choose various options, I also became evangelical for it.

I suppose we could push the hammer/nailgun analogy a bit. A guy
building a house is not going to give up his claw hammer just
because he has a nail gun. Sometimes you have to do some
picky little job that just does not accomodate the nail gun. Like
around windows or something. So too, the C-style char array
strings will hang around for those tasks that have some good
reason for them. Mostly handling legacy code I expect.
Socks

Jun 20 '06 #19

P: n/a
Puppet_Sock wrote:
Sgt. York wrote:
[snip]
If you've ever built a house, imagine replacing your claw hammer with a
nail gun. For the STL in general, I have become an evangelical nut
about c++ thanks to its existence.


That's a very nice comparison. I like it. It may show up in my posts.

Your experience mirrors my own. When I first encountered the STL
I was resistant. At least part of this was due to the implementation
I had not being particularly compliant or stable. But as I got used to
it, and as books appeared giving tutorial explanation and examples
of use, and higher level books appeared giving the rules for when to
choose various options, I also became evangelical for it.


At the risk of the obvious:

[AOL]
ME TOO!!!
[/AOL]

When I first saw STL stuff, I didn't really understand it or the
advantages... Later as I started reading and playing with it, I got
"religion", and my thoughts were simply, "this is f---ing BRILLIANT!!!".

Jun 20 '06 #20

P: n/a
Cool, I'll definitely look into them. Thanks for taking the time to
justify their existence for me.
If you've ever built a house, imagine replacing your claw hammer with a
nail gun. For the STL in general, I have become an evangelical nut
about c++ thanks to its existence.


Now that's an analogy I can appreciate - I spent several summers while
I was in school doing various kinds of contract work, including
building houses. Maybe it IS time I considered trading my proverbial
clawhammer in for a nailgun.

Cheers,
Aaron Brown

P.S: I still haven't figured out the problem (been working on a couple
of other modules that don't require the wonky function), so maybe I'll
just bite the bullet, take a few hours, and re-write the bitch. I'm
sick of tinkering with it to no avail.

Jun 20 '06 #21

P: n/a
Default User <de***********@yahoo.com> wrote:
th*********@gmail.com wrote:
...
char* radioList = ini->getParsedKey("Radio");
...

char* iniparser::getParsedKey(char* keyName)
{
char* tempString = new char[MAX_INI_LINE_LENGTH];
for(int i = 0; i < strlen(keyName); i++)
{
tolower(keyName[i]);
}

You are attempting to modify a string literal. That causes undefined
behavior.


Are you sure? Afaik, tolower accepts the character by value and
returns the lower-case value.

regards
--
jb

(reply address in rot13, unscramble first)
Jun 21 '06 #22

P: n/a
th*********@gmail.com wrote:
...
char* radioList = ini->getParsedKey("Radio");
...

char* iniparser::getParsedKey(char* keyName)
'keyName' should be a const char, given the way you call this
function.

char* iniparser::getParsedKey (char const* keyName) {
char* tempString = new char[MAX_INI_LINE_LENGTH];
for(int i = 0; i < strlen(keyName); i++)
{
tolower(keyName[i]);
This does not do anything. 'tolower' returns the lower-case value
and you are throwing it away.
}

//for all the keys in the section
for (int i = 0; i < numKeysInSection; i++)
{
//tempString takes the value of the current key
tempString = strtok(iniSection[i],"=");
Above you assigned a newly allocated char array to 'tempString' and
here you assign a new pointer to this variable. That is, you overwrite
the pointer value and the pointer to the allocated memory is gone ..
//if the current key is the desired key
if ((strcmp(tempString,keyName) == 0))
You are trying to compare the passed 'key' with the key name stored
in the ini without regard to case, correct? In that case you should
probably write yourself a function doing this compare:

bool equal (char const* str1, char const* str2, size_t sz)
{
while (*str1 != '\0' && *str2 != '\0' && sz > 0)
{
// different chars -> return false
if (tolower (*str1) != tolower (*str2))
return false;

++ str1;
++ str2;
-- sz;
}

// only equal if both strings are of equal length
// or 'sz' number of chars have been compared
return sz == 0 || (*str1 == 0 && *str2 == 0);
}
{
//then tempString takes on the key's value
tempString = strtok(NULL,"\n");
//return the key's value
return tempString;
}
}

MessageBox(NULL,"KEY NOT FOUND","OK",NULL);
//if the key isn't found, return NULL
return NULL;
}


All in all, you have:

char const* iniparser::getParsedKey (char const* keyName)
{
for (int i = 0; i < numKeysInSection; ++ i)
{
char const* inikey = strchr (iniSection [i], '=');
if (inikey)
{
char const* inivalue = inikey + 1;
size_t inikeylen = iniSection[i] - inikey;

if (equal (tmp, keyName, inikeylen))
{
return inivalue;
}
}
else
{
// malformed ini?
}
}

return 0;
}

You might want to add some handling so that "key = value" is also
parsed correctly (note the spaces). Now I have just typed this out of
the back of my head, so there might be errors in the code. But you
should be able to figure them out, if there are.

hth
--
jb

(reply address in rot13, unscramble first)
Jun 21 '06 #23

P: n/a
Jakob Bieling wrote:
Default User <de***********@yahoo.com> wrote:
th*********@gmail.com wrote:

...
char* radioList = ini->getParsedKey("Radio");
...

char* iniparser::getParsedKey(char* keyName)
{
char* tempString = new char[MAX_INI_LINE_LENGTH];
for(int i = 0; i < strlen(keyName); i++)
{
tolower(keyName[i]);
}

You are attempting to modify a string literal. That causes undefined
behavior.


Are you sure? Afaik, tolower accepts the character by value and
returns the lower-case value.


That was a case of over-aggressive snippage on my part. The full code
was:

char* iniparser::getParsedKey(char* keyName)
{
char* tempString = new char[MAX_INI_LINE_LENGTH];
for(int i = 0; i < strlen(keyName); i++)
{
tolower(keyName[i]);
}

//for all the keys in the section
for (int i = 0; i < numKeysInSection; i++)
{
//tempString takes the value of the current key
tempString = strtok(iniSection[i],"=");
//if the current key is the desired key
if ((strcmp(tempString,keyName) == 0))
{
//then tempString takes on the key's value
tempString = strtok(NULL,"\n");
//return the key's value
return tempString;
}
}
The strtok() call is the one that modifies the string literal.


Brian
Jun 21 '06 #24

P: n/a
Jakob Bieling wrote:
Default User <de***********@yahoo.com> wrote:
th*********@gmail.com wrote:

...
char* radioList = ini->getParsedKey("Radio");
...

char* iniparser::getParsedKey(char* keyName)
{
char* tempString = new char[MAX_INI_LINE_LENGTH];
for(int i = 0; i < strlen(keyName); i++)
{
tolower(keyName[i]);
}

You are attempting to modify a string literal. That causes undefined
behavior.


Are you sure? Afaik, tolower accepts the character by value and
returns the lower-case value.


There's nothing wrong there. I'm not entirely sure what I was objecting
to, perhaps the strtok() that I cut out, but I'm not sure that's even a
problem. It was a while ago.

Brian
Jun 21 '06 #25

P: n/a
Well, on the recommendation of some of the people in this thread, I
rewrote that function and a couple of the modules that use it to be
based around std::string, rather than char*. Problem is solved, thank
you all very much!

My one question is: what's the best way to tokenize a std::string. I
didn't see any standard tokenization functions with them. Do I need to
drum one up myself?

Thanks,
Aaron

Jun 21 '06 #26

P: n/a
th*********@gmail.com wrote:
Well, on the recommendation of some of the people in this thread, I
rewrote that function and a couple of the modules that use it to be
based around std::string, rather than char*. Problem is solved, thank
you all very much!

My one question is: what's the best way to tokenize a std::string. I
didn't see any standard tokenization functions with them. Do I need to
drum one up myself?

Thanks,
Aaron


Boost has some code to handle this nicely.

www.boost.org
Jun 21 '06 #27

This discussion thread is closed

Replies have been disabled for this discussion.