473,413 Members | 1,755 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,413 software developers and data experts.

C++ Primer ex 3.14

i have solved it. any suggestions for improving the code:

/* C++ Primer - 4/e
* chapter 3

* exercise 3.14

* STATEMENT
read some text into a vector,storing each word as an elelment in
the vector. transform each word into the uppercase letter. print the
transofrmed elelments from the vector as eight words per line.

*/

#include <iostream>
#include <vector>
#include <string>

int main()
{
std::cout << "please enter some words seperated by newlines" <<
std::endl;

std::string a_word;
std::vector<std::stringsvec;
while(std::cin >a_word)
{
svec.push_back(a_word);
}

for(std::vector<std::string>::iterator iter=svec.begin(); iter !=
svec.end(); ++iter)
{
for(std::string::size_type ix=0; ix != (*iter).size(); ++ix)
{
((*iter)[ix]) = toupper((*iter)[ix]);

/* i call it the MESSY solution.
isn't there anything better ? */
}
}

int counter = 0;
for(std::vector<std::string>::const_iterator iter=svec.begin(); iter !=
svec.end(); ++iter)
{
if(counter == 7)
{
std::cout << *iter << std::endl;
counter = 0;
}
else
{
std::cout << *iter << " ";
++counter;
}
}

std::cout << std::endl;

return 0;
}
======= OUTPUT ===========
[arnuld@arch cpp ]% g++ -ansi -pedantic -Wall -Wextra ex_03-14.cpp
[arnuld@arch cpp ]% ./a.out
please enter some words seperated by newlines
aRnUld
Fraser
was fallING
out OFF his TraCKL from some MONTHS but NOW hE iS bAcK

ARNULD FRASER WAS FALLING OUT OFF HIS TRACKL
FROM SOME MONTHS BUT NOW HE IS BACK

[arnuld@arch cpp ]%

--
-- http://arnuld.blogspot.com

Jul 19 '07 #1
8 2175
arnuld wrote:
[..]
for(std::vector<std::string>::iterator iter=svec.begin(); iter !=
svec.end(); ++iter)
{
for(std::string::size_type ix=0; ix != (*iter).size(); ++ix)
{
((*iter)[ix]) = toupper((*iter)[ix]);

/* i call it the MESSY solution.
isn't there anything better ? */
You mean, like writing a functor which will call 'transform' and
then calling 'for_each' here?
}
}
[..]
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jul 19 '07 #2
On Thu, 19 Jul 2007 08:39:28 -0400, Victor Bazarov wrote:
arnuld wrote:
>[..]
for(std::vector<std::string>::iterator iter=svec.begin(); iter !=
svec.end(); ++iter)
{
for(std::string::size_type ix=0; ix != (*iter).size(); ++ix)
{
((*iter)[ix]) = toupper((*iter)[ix]);

/* i call it the MESSY solution.
isn't there anything better ? */
You mean, like writing a functor which will call 'transform' and
then calling 'for_each' here?
i am still chapter 3 of C++ Primer 4/e yet but i have read soem parts of
Stroustrup some months ago, so IIRC, "for_each" is a Standard Library
Algorithm.

BTW, i will stop here because i think the author have introduced some
basic features only, so within those "basic features", withing those
constraints, my programme is ok. thanks Victor for reminding me that :)

--
-- http://arnuld.blogspot.com

Jul 19 '07 #3
On Jul 19, 2:35 pm, arnuld <geek.arn...@gmail.comwrote:
i have solved it.
No you haven't, but you've run into a very subtle issue.
any suggestions for improving the code:
/* C++ Primer - 4/e
* chapter 3
* exercise 3.14

* STATEMENT
read some text into a vector,storing each word as an elelment in
the vector. transform each word into the uppercase letter. print the
transofrmed elelments from the vector as eight words per line.
*/
#include <iostream>
#include <vector>
#include <string>
You're missing at least one include.
int main()
{
std::cout << "please enter some words seperated by newlines" <<
std::endl;
std::string a_word;
std::vector<std::stringsvec;
while(std::cin >a_word)
{
svec.push_back(a_word);
}
for(std::vector<std::string>::iterator iter=svec.begin(); iter !=
svec.end(); ++iter)
{
for(std::string::size_type ix=0; ix != (*iter).size(); ++ix)
{
((*iter)[ix]) = toupper((*iter)[ix]);
/* i call it the MESSY solution.
isn't there anything better ? */
I call it a wrong solution. On my system, if the user enters an
accented character, it passes a negative value to "toupper".
For the one argument version of toupper (declared in <ctype.h>),
"the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of
the macro EOF." This is a pre-condition; violating it results
in undefined behavior. At the very least, you need to write:

(*iter)[ ix ] = toupper( static_cast< unsigned char >( (*iter)
[ ix ] ) ;

(In practice, of course, I'd recommend using string iterators
for the inner loop as well. It's more C++'ish.)

As you can see by the name of the header, the single argument
version of toupper is in fact a C function (included by
reference in C++). The C++ variants are in <locale(and have
been designed to be particularly complicated to use:-)). In
C++, there is a convenience function, std::toupper, but most of
the time, you'll probably want to obtain a ctype facet, and work
with that:

std::ctype< char const& ctype
= std::use_facet< std::ctype< char ( std::locale() ) ;

There's a ctype::toupper which works on strings, but only on
char[] strings. (Don't ask me how they justify that.) So once
again, you're stuck with a loop. Or you embed the call in a
functional object, and use std::transform; this occurs so often
in my own code that I have such functional objects in my
toolbox, and would simply write:

std::transform( iter->begin(), iter->end(),
iter->begin(),
CTypeToUpper() ) ;

Writing a robust version of such a functional object is trickier
than it looks, because you have to be concerned with the
lifetime of the facet (e.g. if the locale is a temporary, or if
someone changes it during the lifetime of the functional
object); something sufficient for a program like yours (and most
programs, in fact), however, shouldn't be that difficult, and
would serve as an interesting introduction to <locale>.
(Implementing one which uses the <ctype.hone argument form of
toupper is even easier. Just don't forget the coversion to
unsigned char.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jul 20 '07 #4
James Kanze <ja*********@gmail.comwrites:
I call it a wrong solution. On my system, if the user enters an
accented character, it passes a negative value to "toupper".
For the one argument version of toupper (declared in <ctype.h>),
"the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of
the macro EOF." This is a pre-condition; violating it results
in undefined behavior. At the very least, you need to write:

(*iter)[ ix ] = toupper( static_cast< unsigned char >( (*iter)
[ ix ] ) ;

(In practice, of course, I'd recommend using string iterators
for the inner loop as well. It's more C++'ish.)
i tried that but it does not work, i get a compile-time error:

for(std::string::iterator siter=(*iter).begin();
siter !=(*iter).end(); ++siter)
{
((*iter)(*siter)) = toupper(static_cast<unsigned char>((*iter)(*siter)));
}

{arnuld@arch cpp }% g++ -ansi -pedantic -ggdb -Wall -Wextra test.cpp
test.cpp: In function ‘int main()’:
test.cpp:32: error: no match for call to ‘(std::basic_string<char, std::char_traits<char>, std::allocator<char) (char&)’
test.cpp:32: error: no match for call to ‘(std::basic_string<char, std::char_traits<char>, std::allocator<char) (char&)’
{arnuld@arch cpp }%

Jul 20 '07 #5

arnuld <ge*********@gmail.comwrote in message...
>
i tried that but it does not work, i get a compile-time error:

for(std::string::iterator siter=(*iter).begin();
siter !=(*iter).end(); ++siter){
((*iter)(*siter)) = toupper(static_cast<unsigned
char>((*iter)(*siter)));

Did you try:
(*siter) = toupper(static_cast<unsigned char>(*siter) );
}
Forget the iterators for a minute. Let's look at straight indexing.

std::vector<std::stringsvec;
// fill with strings

for( std::size_t iter(0); iter < svec.size(); ++iter){
for( std::size_t ix(0); ix < svec.at(iter).size(); ++ix){
svec.at(iter).at(ix) // this is char ix of string in svec iter

// What you did above with your iterators is:
// svec.at(iter).at(iter).at(ix)
// int main()
{
std::vector<std::stringsvec;
svec.push_back("Skunk");
svec.push_back("Snail");
svec.push_back("Slug");
for(std::vector<std::string>::iterator iter( svec.begin() );
iter != svec.end(); ++iter){
for( std::string::iterator siter( (*iter).begin() );
siter != (*iter).end(); ++siter){
// ((*iter)(*siter)) = toupper(static_cast<unsigned
char>((*iter)(*siter)));

(*siter) = std::toupper(static_cast<unsigned
char>( (*siter) ) );

} // for(string)
} // for(svec)

std::copy( svec.begin(), svec.end(),
std::ostream_iterator<std::string>( std::cout, "\n") );
cout<<std::endl;
// return 0;
}
/* - output -
SKUNK
SNAIL
SLUG
*/

--
Bob R
POVrookie
Jul 21 '07 #6
"BobR" <re***********@worldnet.att.netwrites:
>arnuld <ge*********@gmail.comwrote in message...
i tried that but it does not work, i get a compile-time error:

for(std::string::iterator siter=(*iter).begin();
siter !=(*iter).end(); ++siter){
((*iter)(*siter)) = toupper(static_cast<unsigned
char>((*iter)(*siter)));
Did you try:
(*siter) = toupper(static_cast<unsigned char>(*siter) );
yes, it works :-) i got the logic of it, as (*iter) will remain
pointing to one place till we finish through the test conditon of
inner for loop.
Forget the iterators for a minute. Let's look at straight indexing.

std::vector<std::stringsvec;
// fill with strings

for( std::size_t iter(0); iter < svec.size(); ++iter){
for( std::size_t ix(0); ix < svec.at(iter).size(); ++ix){
svec.at(iter).at(ix) // this is char ix of string in svec iter

// What you did above with your iterators is:
// svec.at(iter).at(iter).at(ix)
i know that and did write this code earlier, my code was different in
the initialisation phase. i used:

std::vector<int>::size_type ix= svec.begin()

subscriptiing is uch easier but as authors of C++ Primer put it
subscripting is not vailable for every "Class Template" or
Std. Lib. Container but iterators are available for every
container/Class-Template, since, most of the time, i will be writing
C++ code using the Standard Library (e.g. Vectors & Strings rather than
Arrays and Pointers) i try to learn more about the use and behaviour
of iterators. this exercise was my one attempt.

// int main()
{
std::vector<std::stringsvec;
svec.push_back("Skunk");
svec.push_back("Snail");
svec.push_back("Slug");
for(std::vector<std::string>::iterator iter( svec.begin() );
iter != svec.end(); ++iter){
for( std::string::iterator siter( (*iter).begin() );
siter != (*iter).end(); ++siter){
// ((*iter)(*siter)) = toupper(static_cast<unsigned
char>((*iter)(*siter)));

(*siter) = std::toupper(static_cast<unsigned
char>( (*siter) ) );

} // for(string)
} // for(svec)

yes, this is what you changed and it runs :-)
std::copy( svec.begin(), svec.end(),
std::ostream_iterator<std::string>( std::cout, "\n") );
cout<<std::endl;
// return 0;
}
i have included "algorithm" header but this piece of code does not
run.i get an error:

{arnuld@arch cpp }% g++ -ansi -pedantic -Wall -Wextra test.cpp
test.cpp: In function ‘int main()’:
test.cpp:43: error: ‘ostream_iterator’ is not a member of ‘std’
test.cpp:43: error: expected primary-expression before ‘>’ token
test.cpp:43: warning: left-hand operand of comma has no effect
i even tried to remove the "std::" scope operator but then it says,
"ostream_iterator was not declared in this scope".

Jul 22 '07 #7

arnuld <ge*********@gmail.comwrote in message...
"BobR" <re***********@worldnet.att.netwrites:
Did you try:
(*siter) = toupper(static_cast<unsigned char>(*siter) );

yes, it works :-) i got the logic of it, as (*iter) will remain
pointing to one place till we finish through the test conditon of
inner for loop.
Forget the iterators for a minute. Let's look at straight indexing.

std::vector<std::stringsvec;
// fill with strings
for( std::size_t iter(0); iter < svec.size(); ++iter){
for( std::size_t ix(0); ix < svec.at(iter).size(); ++ix){
svec.at(iter).at(ix) // this is char ix of string in svec iter

// What you did above with your iterators is:
// svec.at(iter).at(iter).at(ix)

i know that and did write this code earlier, my code was different in
the initialisation phase. i used:

std::vector<int>::size_type ix= svec.begin()
Did that work? It shouldn't. '.begin()' returns an iterator, not a size_type
(usually an 'size_t').
BTW,
sometype mine( 0 );
and
sometype mine = 0;
do the same thing in the end. I prefer the first, while many prefer the
second(they like to *see* the assignment (=)).
>
subscriptiing is uch easier but as authors of C++ Primer put it
subscripting is not vailable for every "Class Template" or
Std. Lib. Container but iterators are available for every
container/Class-Template, since, most of the time, i will be writing
C++ code using the Standard Library (e.g. Vectors & Strings rather than
Arrays and Pointers) i try to learn more about the use and behaviour
of iterators. this exercise was my one attempt.
I was just using 'indexing' to illustrate your mistake. Definately learn
both.
>
// int main()
{
std::vector<std::stringsvec;
svec.push_back("Skunk");
svec.push_back("Snail");
svec.push_back("Slug");
for(std::vector<std::string>::iterator iter( svec.begin() );
iter != svec.end(); ++iter){
for( std::string::iterator siter( (*iter).begin() );
siter != (*iter).end(); ++siter){
// ((*iter)(*siter)) = toupper(static_cast<unsigned
char>((*iter)(*siter)));

(*siter) = std::toupper(static_cast<unsigned
char>( (*siter) ) );

} // for(string)
} // for(svec)

yes, this is what you changed and it runs :-)
std::copy( svec.begin(), svec.end(),
std::ostream_iterator<std::string>( std::cout, "\n") );
cout<<std::endl;
// return 0;
}

i have included "algorithm" header but this piece of code does not
run.i get an error:

{arnuld@arch cpp }% g++ -ansi -pedantic -Wall -Wextra test.cpp
test.cpp: In function â?~int main()â?T:
test.cpp:43: error: â?~ostream_iteratorâ?T is not a member of â?~stdâ?T
test.cpp:43: error: expected primary-expression before â?~>â?T token
test.cpp:43: warning: left-hand operand of comma has no effect

i even tried to remove the "std::" scope operator but then it says,
"ostream_iterator was not declared in this scope".
My 'TestBench' probably pulls in every header in the system, either through
the many 'tests' in it(I need to clean it up), or through 'wxWidgets'. I'm
sorry for not noticing a missed one.
'std::copy' should be in <algorithm>.
You may need <iteratorbesides <iostream>(, <ostream>) for the
'ostream::iterator'.

Try that. Re-post if you still have trouble, and I'll track it down.

--
Bob R
POVrookie
Jul 22 '07 #8
On Jul 20, 9:28 pm, arnuld <geek.arn...@gmail.comwrote:
James Kanze <james.ka...@gmail.comwrites:
I call it a wrong solution. On my system, if the user enters an
accented character, it passes a negative value to "toupper".
For the one argument version of toupper (declared in <ctype.h>),
"the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of
the macro EOF." This is a pre-condition; violating it results
in undefined behavior. At the very least, you need to write:
(*iter)[ ix ] = toupper( static_cast< unsigned char >( (*iter)
[ ix ] ) ;
(In practice, of course, I'd recommend using string iterators
for the inner loop as well. It's more C++'ish.)
i tried that but it does not work, i get a compile-time error:
for(std::string::iterator siter=(*iter).begin();
siter !=(*iter).end(); ++siter)
Using iter->begin() and iter->end() instead of (*iter).begin(),
(*iter).end() is perhaps more idiomatic.
{
((*iter)(*siter)) = toupper(static_cast<unsigned char>((*iter)(*siter)));
What on earth is "(*iter)(*siter)" supposed to mean? With
siter, you're iterating through a string, so just:

*siter = toupper( static_cast< unsigned char >( *siter ) ;

should be all you need. And whatever you need, you can't just
juxtapose two iterator dereferences---regardless of the types,
there is no place in C++ where you can simply juxtapose two
value expressions without an operator.
}
{arnuld@arch cpp }% g++ -ansi -pedantic -ggdb -Wall -Wextra test.cpp
test.cpp: In function ?int main()?:
test.cpp:32: error: no match for call to ?(std::basic_string<char, std::char_traits<char>, std::allocator<char) (char&)?
test.cpp:32: error: no match for call to ?(std::basic_string<char, std::char_traits<char>, std::allocator<char) (char&)?
{arnuld@arch cpp }%
Apparently, the compiler is interpreting (*iter)(...) as a
function call (which it could be, if *iter returned a pointer to
a function or a class which implemented operator()()), and
complaining because you're trying to call a function on
something which doesn't support the operator()().

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jul 22 '07 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Sandman | last post by:
Could anyone give me a tip about a good primer on object oriented php programming - why I should use it, the benefits, the drawbacks, the bugs, the glory? And, should I upgrade to php5 before...
1
by: Charles L | last post by:
Does anyone know where I can find errata for Stan Lippman's 'C++ Primer 2nd Edition'? Charles Leng
1
by: hugo | last post by:
what is L&L ,people or book?
5
by: hajime | last post by:
I purchased this book: C++ Primer, 4th Edition ISBN: 0201721481 in Australia. The right side of the last three lines on page 231 are not legible. A stain shows a piece of paper was on that part...
7
by: Lycan. Mao.. | last post by:
Hello, I am a newbie in C++ and I'm in trouble in choosing books, I hope some one who can give me some tips. I'm already know C and a little about Scheme, C#, Python, Lua and so on, and now I want...
2
by: W. Watson | last post by:
Is there a primer out there on these two items? I have the Python tutorial, but would like either a Tkinter tutorial/primer to supplement it, or a primer/tutorial that addresses both. Maybe there's...
20
by: arnuld | last post by:
I get an error, can't find what is the problem: /* C++ Primer - 4/e * * Chapter 8, exercise 8.3 * STATEMENT * write a function that takes and returns an istream&. the function should read...
2
by: xianwei | last post by:
First, typedef struct pair { Node *parent; Node *child; } Pair; static Pair SeekItem(cosnt Item *pI, const Tree *pTree) { Pair look;
1
by: Kveldulv | last post by:
Hi all, here is the code: http://pastebin.com/m6e74d36b I'm stuck at highfink constructor, last line before #endif. As parameters, I have reference to one parent class and int member of another...
0
by: cincerite | last post by:
Hello , guys , I'm reading C++ Primer 3rd edition recently.I tried to download the errata of it from Stan Lippman's Home Page:http:// staff.develop.com/slip/ ,but it says:We're Sorry, we could not...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.