Trouble w/vector and while

I am going through C++ Primer (Lippman) and am in chapter 3. Exercise 3.17 reads as follows:

Read a sequence of words from cin and store the values in a vector. After you've read all the words, process the vector and change each word to uppercase. Print the transformed elements, eight words to a line.

Two things:
1. I don't think the while loop is storing the words in the vector bc whenever I've tried to access the elements in text nothing prints out.
2. Since I've added toupper(), the compiler says there

At this point I’ve spent over three hours on this one question and I can’t help but feel like I’m missing something simple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>
#include <vector>
#include <cctype>

using namespace std;
using std::string;
using std::vector;

int main() {
string word;
vector<string> text;
while (cin >> word) {
text.push_back(word);
for (auto &i : text)
i = toupper(i);
}
}
Last edited on
'text' is your vector<string>, not an individual string.
Therefore each 'i' in text in your for-each loop is a string, but toupper needs to be passed an individual character -- it does not know what a string is.

To access the string you just push_back'd, you can do text.back().

So you could do,
1
2
for (auto &ch : text.back())
    ch = toupper(ch);



Alternatively, you could write a helper function, something like:
1
2
3
4
5
6
7
void toupper(std::string& str)
{
    for (auto& ch : str)
    {
        ch = toupper(ch);
    }
}
Last edited on
You really need to work on using a consistent indent style, it'll make your cod much easier to read.

Next the code you supplied shouldn't even compile, so it shouldn't print anything.

Here is your code with a more consistent indent style.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
#include <vector>
#include <cctype>

using namespace std;
using std::string;
using std::vector;

int main()
{
    string word;
    vector<string> text;
    while(cin >> word)
    {
        text.push_back(word);
        for(auto &i : text)
            i = toupper(i);
    }
}


Next: Your instructions say:


Read a sequence of words from cin and store the values in a vector. After you've read all the words, process the vector and change each word to uppercase.


You are presently trying to do both of these steps in the same loop, they should be separated into different loops.

Also your for() loop is processing the vector not a string. Which means that you're trying to call toupper() on a string not a single character (which is why your program should not compile). The toupper() function works on single characters, not strings.

Hm. I just assumed they were supposed to be done in the same loop.

If I do separate loops, how would I exit the while loop?

I tried using a nested if and a break to do that, but I didn’t work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <vector>
#include <string>
#include <iostream>
#include <cctype>

int main()
{
	std::vector<std::string> vs;

	for (std::string line; std::cout << "Enter word <CR> to terminate: " && std::getline(std::cin, line) && !line.empty(); vs.push_back(line));

	for (auto& s : vs)
		for (auto& c : s)
			c = std::toupper(c);

		for (int c = 1; const auto & s : vs)
			std::cout << s << (c++ % 8 ? ' ' : '\n');
}


NB requires C++20 for initialisation within a range-for. If your compiler doesn't yet support this, move the int c = 1; outside of the for loop.


Enter word <CR> to terminate: qwe
Enter word <CR> to terminate: asd
Enter word <CR> to terminate: zxc
Enter word <CR> to terminate: tyyu
Enter word <CR> to terminate: gh
Enter word <CR> to terminate: uuii
Enter word <CR> to terminate: hggff
Enter word <CR> to terminate: wee
Enter word <CR> to terminate: ggh
Enter word <CR> to terminate: kjhh
Enter word <CR> to terminate:
QWE ASD ZXC TYYU GH UUII HGGFF WEE
GGH KJHH

Last edited on
Hello Walkup,

Given your instructions:

Read a sequence of words from cin and store the values in a vector. After you've read all the words, process the vector and change each word to uppercase. Print the transformed elements, eight words to a line.



You need to look at them in a different way.

 1. Read a sequence of words from cin and store the values in a vector.

 2. After you've read all the words, process the vector and change each word to uppercase.

 3. Print the transformed elements, eight words to a line.


Complete each step 1 at a time.

First input words and create the vector.

Step 2. Now that you have a vector of strings where eace element of the vector is an individual string you can process each string and shange it to uppercase.

Step 3 is to print the vector.

It is much easier to do 1 part at a time than to try and work on the whole at 1 time.

As you work on each compile often and test as needed.

Andy

Edit:
Last edited on
Change your while loop to this if you don't want to cram everything into the while:
14
15
16
17
   while (std::getline(std::cin, word) && !(word.empty()))
   {
      text.push_back(word);
   }

When the user hits just ENTER the while loop is terminated.
Hello Walkup,

1
2
3
4
using namespace std;

using std::string;
using std::vector;

Pick 1 or the other, but not both. The using namespace std; should be avoided. The 2 using statements that follow are slightly better, but still should be avoided. Either is not helping you.

As I started to work with your program I first noticed that the while loop is an endless loop with no way out.

Using formatted input, std::cin >> word there is no way to cause "cin" to fail and it will not accept just the enter key. So what you have is an endless loop with no way out.

With the input from Furry Guy I ended up with this:
1
2
3
4
5
6
7
while (std::cout<<" Enter a word (Enter to quit): " && std::getline(std::cin, word)  && !(word.empty()))
{
    //if (!(word.size()))  // <--- An Alternative to the big while condition.
    //    break;

    text.push_back(word);
}

The commented code in the loop is if you do not want to use the last "&&", but i would suggest keeping it.

The "cout" at the beginning of the while condition is needed otherwise you end up staring at a blank screen wondering what to do. Or even wondering if the program
is running.

That is something to get you started..

Andy
Last edited on
Using formatted input, std::cin >> word there is no way to cause "cin" to fail and it will not accept just the enter key. So what you have is an endless loop with no way out.


ctrl-z keyboard input will cause 'cin' to fail for Windows. But I prefer getline() as per my previous post.
Last edited on
@seeplus,

You got me there. I forgot about the ctrl-z, but then I very rarely use it.

I was think more about a normal user and a beginner programmer. Neither of them may not know about ctrl-z.

Then again I thought that this was the "Beginners" forum, but apparently not.

Andy
jlb wrote:
it'll make your cod much easier to read.

I'm not sure this is the right plaice for that kind of comment...

;)
Topic archived. No new replies allowed.