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

C++ strings and strchr()

P: n/a
I want to find the position of a character in a string and replace it another
if it is actually there, and I'd like the operation to be efficient. I'm
assuming the "standard" way to do this is something like

string s = "blah";
int i = s.find_first_of('a'); /* returns 2, I presume? */
s.replace(i,0,"e");

Right? Is this the best way (assuming I haven't made some stupid error)? Is
there a way to (easily!) get a character pointer from a C++ string so I can
just change that one character, like maybe

char *cp;

if( (cp=strchr(s.c_str(), 'a') != NULL)
*cp='e';

? If neither way is good, what's a better way?

(if this is a FAQ, I didn't see it...)

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Jul 19 '05 #1
Share this Question
Share on Google+
32 Replies


P: n/a

<at***@nospam.cyberspace.org> wrote in message news:bi**********@chessie.cirr.com...
string s = "blah"; int i = s.find_first_of('a'); /* returns 2, I presume? */
You need to check to see if the find succeeds (unless you are sure it won't fail).
It might return npos. You could also use s.find('a'). Since your match string is
only a single character they both do the same thing (I'm not sure that one would
be faster than the other).
s.replace(i,0,"e");


That's a no op. It says to replace zero chars. You want.
s.replace(i, 1, "e");
Actually, for a single character this would be just as good
s[i] = 'e';

Jul 19 '05 #2

P: n/a
Ron Natalie <ro*@sensor.com> broke the eternal silence and spoke thus:
Actually, for a single character this would be just as good
s[i] = 'e';


You can reference strings as though they were C-style char*'s?
--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Jul 19 '05 #3

P: n/a
at***@nospam.cyberspace.org:
I want to find the position of a character in a string and replace it another if it is actually there, and I'd like the operation to be efficient. I'm
assuming the "standard" way to do this is something like

string s = "blah";
int i = s.find_first_of('a'); /* returns 2, I presume? */
s.replace(i,0,"e");


#include<algorithm>
replace(s.begin(),s.end(),'a','e');

-X
Jul 19 '05 #4

P: n/a

<at***@nospam.cyberspace.org> wrote in message
news:bi**********@chessie.cirr.com...
Ron Natalie <ro*@sensor.com> broke the eternal silence and spoke thus:
Actually, for a single character this would be just as good
s[i] = 'e';


You can reference strings as though they were C-style char*'s?


Not entirely. E.g. 'strlen()' et al won't necessarily work
as you expect. But std::string does feature 'index'
operators '[]'. It also has other 'intuitive' operators,
such as '+' for concatenation.

Which C++ book(s) are you reading?

-Mike

Jul 19 '05 #5

P: n/a

Agent Mulder <mb*******************@home.nl> wrote in message
news:bi**********@news2.tilbu1.nb.home.nl...
at***@nospam.cyberspace.org:
I want to find the position of a character in a string and replace it

another
if it is actually there, and I'd like the operation to be efficient. I'm assuming the "standard" way to do this is something like

string s = "blah";
int i = s.find_first_of('a'); /* returns 2, I presume? */
s.replace(i,0,"e");


#include<algorithm>
replace(s.begin(),s.end(),'a','e');


Nearly all C++ literature I've read states that one
should usually prefer a member function over a 'free'
function, if it does what you need. This is because
a member function could be optimized to take advantage
of internal details not available to 'free' functions.

In OP's case, I'd use 'std::string::find()' followed
by access to the found element with 'std::string::operator[]()'.

$.02,
-Mike

Jul 19 '05 #6

P: n/a
MW> Nearly all C++ literature I've read states that one
MW> should usually prefer a member function over a 'free'
MW> function, if it does what you need. This is because
MW> a member function could be optimized to take advantage
MW> of internal details not available to 'free' functions.

You produced some very ugly code, Mike ;-)7

<mikes>
#include <iostream>
#include <string>

int main()
{
his();
std::string s("blah");
std::cout << s << '\n';
std::string::size_type i(s.find('a'));

if(i != std::string::npos)
s[i] = 'e';

std::cout << s << '\n';

return 0;
}
</mikes>

-X


Jul 19 '05 #7

P: n/a

<at***@nospam.cyberspace.org> wrote in message news:bi**********@chessie.cirr.com...
Ron Natalie <ro*@sensor.com> broke the eternal silence and spoke thus:
Actually, for a single character this would be just as good
s[i] = 'e';


You can reference strings as though they were C-style char*'s?


Well, not totally, but they do support operator[] as shown above.
Jul 19 '05 #8

P: n/a
Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
Which C++ book(s) are you reading?


"The C++ Programming Language" by Stroustrup (aka God?) - it's in there, but
the book is so big I overlooked it... sorry... but I do have a question
about how they're implemented. Why can't you effectively modify the char*
that c_str gives you? Wouldn't that make one's life easier?

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Jul 19 '05 #9

P: n/a
Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
Which C++ book(s) are you reading?


"The C++ Programming Language" by Stroustrup (aka God?) - it's in there, but
the book is so big I overlooked it... sorry... but I do have a question
about how they're implemented. Why can't you effectively modify the char*
that c_str gives you? Wouldn't that make one's life easier when dealing with
C-style string functions?

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Jul 19 '05 #10

P: n/a

"Mike Wahler" <mk******@mkwahler.net> wrote in message
news:l8*****************@newsread4.news.pas.earthl ink.net...

Agent Mulder <mb*******************@home.nl> wrote in message
news:bi**********@news2.tilbu1.nb.home.nl...
at***@nospam.cyberspace.org:
I want to find the position of a character in a string and replace it

another
if it is actually there, and I'd like the operation to be efficient. I'm assuming the "standard" way to do this is something like

string s = "blah";
int i = s.find_first_of('a'); /* returns 2, I presume? */
s.replace(i,0,"e");


#include<algorithm>
replace(s.begin(),s.end(),'a','e');


Nearly all C++ literature I've read states that one
should usually prefer a member function over a 'free'
function, if it does what you need. This is because
a member function could be optimized to take advantage
of internal details not available to 'free' functions.

In OP's case, I'd use 'std::string::find()' followed
by access to the found element with 'std::string::operator[]()'.


It would be useful to know the OP's intention here, as the two examples
aren't completely equivalent. One is intended to replace the first occurence
of 'a' with 'e' whilst the other will replace all instances of 'a' with 'e'.
For "blah" the effect is the same, of course.

Jul 19 '05 #11

P: n/a

Agent Mulder <mb*******************@home.nl> wrote in message
news:bi**********@news2.tilbu1.nb.home.nl...
MW> Nearly all C++ literature I've read states that one
MW> should usually prefer a member function over a 'free'
MW> function, if it does what you need. This is because
MW> a member function could be optimized to take advantage
MW> of internal details not available to 'free' functions.

You produced some very ugly code, Mike ;-)7


Why do you find it 'ugly'? What would you do instead
that you'd consider less 'ugly'?

-Mike

Jul 19 '05 #12

P: n/a
Bob Jacobs <ne****@robertjacobs.fsnet.co.uk> broke the eternal silence and spoke thus:
It would be useful to know the OP's intention here, as the two examples
aren't completely equivalent. One is intended to replace the first occurence
of 'a' with 'e' whilst the other will replace all instances of 'a' with 'e'.
For "blah" the effect is the same, of course.


My original (flawed!) intention was actually to replace a single character in
a string with a null terminator (a la C - guess what I took in college? ;)),
which of course wouldn't have worked... And then I realized that the strings
I wanted already existed in the code anyway, so the whole exercise was
pointless... but at least I learned something.

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Jul 19 '05 #13

P: n/a

<at***@nospam.cyberspace.org> wrote in message
news:bi**********@chessie.cirr.com...
Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
Which C++ book(s) are you reading?
"The C++ Programming Language" by Stroustrup (aka God?) - it's in there,

but the book is so big I overlooked it... sorry... but I do have a question
about how they're implemented. Why can't you effectively modify the char*
that c_str gives you? Wouldn't that make one's life easier when dealing with C-style string functions?
Why do you want to use those functions with std::string's?

AFAIK, std::string supports anything you can do with a 'C-style
string', and more, in a much safer way.

-Mike

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |

Jul 19 '05 #14

P: n/a
at***@nospam.cyberspace.org wrote:
Ron Natalie <ro*@sensor.com> broke the eternal silence and spoke thus:

Actually, for a single character this would be just as good
s[i] = 'e';

You can reference strings as though they were C-style char*'s?


You can't access the string directly as C-style char*'s,
but you _can_ access a copy that is a C-style string.
Look up the "c_str()" method:
string b("blah");
cout << strlen(b.c_str());

The std::string class has many of the functions that
are used on C-style strings. Look through the list
of std::string methods.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

Jul 19 '05 #15

P: n/a

"Mike Wahler" <mk******@mkwahler.net> wrote in message news:Tu81b.1985
2) Even if modifying this array were allowed, it is *not*
the characters of the string itself, only a copy.


Well, potentially not. In practice, it usually is.
Jul 19 '05 #16

P: n/a

<at***@nospam.cyberspace.org> wrote in message news:bi**********@chessie.cirr.com...
Bob Jacobs <ne****@robertjacobs.fsnet.co.uk> broke the eternal silence and spoke thus:
It would be useful to know the OP's intention here, as the two examples
aren't completely equivalent. One is intended to replace the first occurence
of 'a' with 'e' whilst the other will replace all instances of 'a' with 'e'.
For "blah" the effect is the same, of course.


My original (flawed!) intention was actually to replace a single character in
a string with a null terminator (a la C - guess what I took in college? ;)),
which of course wouldn't have worked... And then I realized that the strings
I wanted already existed in the code anyway, so the whole exercise was
pointless... but at least I learned something.


Did you really want to poke a null terminator there, or shorten the string.
Putting a null terminator in a C++ string doesn't make it any shorter.
Jul 19 '05 #17

P: n/a
Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
AFAIK, std::string supports anything you can do with a 'C-style
string', and more, in a much safer way.


I guess I'm still dwelling in pointer-land... oh well. Actually, did C++
come up with a better strtok()?

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Jul 19 '05 #18

P: n/a
Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
1) c_str() returns a pointer to an array of *const* characters.
2) Even if modifying this array were allowed, it is *not*
the characters of the string itself, only a copy.


Yes, but my question is why? Are they that afraid of someone actually getting
a char* with strchr() or something and modifying it? Or is it just to
discourage C-style thinking?

--
Christopher Benson-Manica | Jumonji giri, for honour.
ataru(at)cyberspace.org |
Jul 19 '05 #19

P: n/a

<at***@nospam.cyberspace.org> wrote in message news:bi**********@chessie.cirr.com...
Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
AFAIK, std::string supports anything you can do with a 'C-style
string', and more, in a much safer way.


I guess I'm still dwelling in pointer-land... oh well. Actually, did C++
come up with a better strtok()?

You can write one in a few lines. strtok bites because it maintains a
hidden internal state and that it modifies it's input.
Jul 19 '05 #20

P: n/a
at***@nospam.cyberspace.org wrote:

Ron Natalie <ro*@sensor.com> broke the eternal silence and spoke thus:
Actually, for a single character this would be just as good
s[i] = 'e';


You can reference strings as though they were C-style char*'s?

Yes. What book are you using?

Brian Rodenborn
Jul 19 '05 #21

P: n/a
Ron Natalie wrote:
<at***@nospam.cyberspace.org> wrote in message news:bi**********@chessie.cirr.com...
Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
I guess I'm still dwelling in pointer-land... oh well. Actually, did C++
come up with a better strtok()?


You can write one in a few lines. strtok bites because it maintains a
hidden internal state and that it modifies it's input.


IANALG (I am not a language guru), but I'd bet that your best bet is to write a
"Tokenizer" class. The advantage of that over "strtok" would be that (if done right)
each Tokenizer would have its own state, so you could have several different "parsings"
going on simultaneously, plus you wouldn't corrupt your original string.

Jul 19 '05 #22

P: n/a
AM> You produced some very ugly code, Mike ;-)7

MW> Why do you find it 'ugly'? What would you do instead
MW> that you'd consider less 'ugly'?

At least you took the effort to type code. That's good.

#include <iostream>
#include <algorithm>
#include <string>
int main(int argc,char**argv)
{
std::string s("Bach");
std::cout<<"\nBefore: "<<s.c_str();
std::replace(s.begin(),s.end(),'B','J');
std::replace(s.begin(),s.end(),'c','h');
std::replace(s.begin(),s.end(),'h','z');
std::cout<<"\nAfter: "<<s.c_str();
}
______
output
Before: Bach
After: Jazz

Jul 19 '05 #23

P: n/a
<at***@nospam.cyberspace.org> wrote in message
news:bi**********@chessie.cirr.com...
Ron Natalie <ro*@sensor.com> broke the eternal silence and spoke thus:
Did you really want to poke a null terminator there, or shorten the string. Putting a null terminator in a C++ string doesn't make it any shorter.
I know this now, which is why I said my original plan was flawed (because

I *did* want to shorten the string...) :)


#include <iostream>
#include <string>

int main()
{
std::string s("blah");
std::string::size_type pos(s.find('a'));

if(pos != std::string::npos)
s.erase(pos);

std::cout << s << '\n'; /* prints "bl" */
return 0;
}

Recommendation:
http://www.josuttis.com/libbook/index.html

-Mike

Jul 19 '05 #24

P: n/a

"red floyd" <no*****@here.dude> wrote in message news:G9*******************@newssvr21.news.prodigy. com...

IANALG (I am not a language guru), but I'd bet that your best bet is to write a
"Tokenizer" class. The advantage of that over "strtok" would be that (if done right)
each Tokenizer would have its own state, so you could have several different "parsings"
going on simultaneously, plus you wouldn't corrupt your original string.


Yep, and I believe if you google back a bit in this group for "stringtok" you'll find one has
been posted.
Jul 19 '05 #25

P: n/a
at***@nospam.cyberspace.org wrote:

Ron Natalie <ro*@sensor.com> broke the eternal silence and spoke thus:
Did you really want to poke a null terminator there, or shorten the string.
Putting a null terminator in a C++ string doesn't make it any shorter.


I know this now, which is why I said my original plan was flawed (because I
*did* want to shorten the string...) :)

If you want to use std::string, you need to sit and study them
thoroughly. Stop worrying about C-style strings.


Brian Rodenborn
Jul 19 '05 #26

P: n/a

Agent Mulder <mb*******************@home.nl> wrote in message
news:bi**********@news2.tilbu1.nb.home.nl...
AM> You produced some very ugly code, Mike ;-)7

MW> Why do you find it 'ugly'? What would you do instead
MW> that you'd consider less 'ugly'?

At least you took the effort to type code. That's good.

#include <iostream>
#include <algorithm>
#include <string>
int main(int argc,char**argv)
{
std::string s("Bach");
std::cout<<"\nBefore: "<<s.c_str();
std::replace(s.begin(),s.end(),'B','J');
std::replace(s.begin(),s.end(),'c','h');
std::replace(s.begin(),s.end(),'h','z');
std::cout<<"\nAfter: "<<s.c_str();
}


Why is my code 'uglier' than yours?

I find yours 'uglier' if for no other reason than
that you failed to indent. You also declared parameters
to main() which you never use. Yuck! :-)

Why do you make the unnecessary call to 'c_str()'
for output?

(My computer can beat up your computer! :-) )

-Mike

Jul 19 '05 #27

P: n/a
at***@nospam.cyberspace.org wrote:

Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
AFAIK, std::string supports anything you can do with a 'C-style
string', and more, in a much safer way.


I guess I'm still dwelling in pointer-land... oh well. Actually, did C++
come up with a better strtok()?

Nothing built-in. Here's a utility I wrote, it's not equivilent to
strtok() but rather ones like PHP explode():
#include <vector>
#include <string>

// breaks apart a string into substrings separated by a character string
// does not use a strtok() style list of separator characters
// returns a vector of std::strings

std::vector<std::string> Explode (const std::string &inString,
const std::string &separator)
{
std::vector<std::string> returnVector;
std::string::size_type start = 0;
std::string::size_type end = 0;

while ((end=inString.find (separator, start)) != std::string::npos)
{
returnVector.push_back (inString.substr (start, end-start));
start = end+separator.size();
}

returnVector.push_back (inString.substr (start));

return returnVector;
}

Brian Rodenborn
Jul 19 '05 #28

P: n/a
Default User <fi********@company.com> wrote in message
news:3F***************@company.com...
at***@nospam.cyberspace.org wrote:

Mike Wahler <mk******@mkwahler.net> broke the eternal silence and spoke thus:
AFAIK, std::string supports anything you can do with a 'C-style
string', and more, in a much safer way.


I guess I'm still dwelling in pointer-land... oh well. Actually, did C++ come up with a better strtok()?

Nothing built-in. Here's a utility I wrote, it's not equivilent to
strtok() but rather ones like PHP explode():
#include <vector>
#include <string>

// breaks apart a string into substrings separated by a character string
// does not use a strtok() style list of separator characters
// returns a vector of std::strings

std::vector<std::string> Explode (const std::string &inString,
const std::string &separator)
{
std::vector<std::string> returnVector;
std::string::size_type start = 0;
std::string::size_type end = 0;

while ((end=inString.find (separator, start)) != std::string::npos)
{
returnVector.push_back (inString.substr (start, end-start));
start = end+separator.size();
}

returnVector.push_back (inString.substr (start));

return returnVector;
}


I guess I'll throw mine away now. :-) I started to
hack one out, which was beginning to look very much
like this. :-)

Thanks.
-Mike

Jul 19 '05 #29

P: n/a
Duh, I forgot the return statement:

#include <string>
#include <iostream>
#include <algorithm>
static std::string s="Bach";
int main(int argc,char**argv)
{
std::cout<<"\nBefore: "<<s.c_str();
std::replace(s.begin(),s.end(),'B','J');
std::replace(s.begin(),s.end(),'c','h');
std::replace(s.begin(),s.end(),'h','z');
std::cout<<"\nAfter: "<<s.c_str();
return 0;
}
______
output
Before: Bach
After: Jazz


Jul 19 '05 #30

P: n/a
at***@nospam.cyberspace.org wrote:

Default User <fi********@company.com> broke the eternal silence and spoke thus:
Nothing built-in. Here's a utility I wrote, it's not equivilent to
strtok() but rather ones like PHP explode():


Explode? Oh, you mean like "get bigger" and not "make pretty exceptions all
over the place" ;)

Like bust it into pieces.

Brian Rodenborn
Jul 19 '05 #31

P: n/a
Mike Wahler wrote:
I guess I'll throw mine away now. :-) I started to
hack one out, which was beginning to look very much
like this. :-)

I had a project last year that required parsing long strings (flight
plans) with nested delimiters, first "\r\n", then "..", then ":",
finally ",".

Brian Rodenborn
Jul 19 '05 #32

P: n/a
at***@nospam.cyberspace.org wrote:

Default User <fi********@company.com> broke the eternal silence and spoke thus:
Nothing built-in. Here's a utility I wrote, it's not equivilent to
strtok() but rather ones like PHP explode():


Explode? Oh, you mean like "get bigger" and not "make pretty exceptions all
over the place" ;)
(code)


Cool, thank you...

One major difference between that code and strtok() (besides string
separators vs. character delimiters) is the behavior with adjacent
delimiters.

Example, the string "one,two,,three" gives the tokens:

one
two
three

When using strtok().

And:

one
two

three

With the Explode() routine. That's by design and desire, so that "empty"
fields are represented, not just ignored.

Brian Rodenborn
Jul 19 '05 #33

This discussion thread is closed

Replies have been disabled for this discussion.