Using curly braces to separate code in C++ - c++

One thing I really like about IDEs is the ability to "minimize" sections of code, so that:
while(conditions){
// Really long code...
}
Can become:
while(conditions){ // The rest is hidden
My question is whether or not something like this would be acceptable formatting
// Code
{
// More code
}
// Code
I understand that anything done inside the brackets would have that limited scope, but I can also edit variables in the outer scope as well.
So, for a short, unnecessary example
int x = 1;
{ // Create new variable, add and output
int y = 2;
cout << x + y;
}
Would become:
int x = 1;
{ // Create new variable, add and output (The rest of the code is hidden)
So would this be acceptable, or shunned?
Here is a real example of something I would want to just hide.
/// Add line to msg vector
// Check to see if each side X is needed
if(uniqueSide && line == 1){
// Create stringstream to hold string and int (e.g. "Message " + 1 + " - Side " + 1
stringstream tempString;
// Add full line to stringstream. validMessages.length() + 1 will make Message X be incremental
tempString << "Message " << (validMessages.length() + 1) << " - Side " << numSide;
// Then append full string (e.g. "Message 1 - Side 1") to msg
msg.append(tempString.str());
}
// Else just add Message X using same method as above
else if(line == 1){
stringstream tempString;
tempString << "Message " << (validMessages.length() + 1);
}
// Add each line to msg vector with double space indent and (width) before each line
stringstream tempString;
tempString << setprecision(5) // Makes width be output as 10.325 or 100.33
<< " (" << width << ") " << tempInput
msg.append(tempString.str());
Thanks.

At least in my opinion, if you need (or even want) this very much, you're probably not structuring your code very well.
An interest in hiding code tends to indicate that you may have too much code shoved together that might be better off being separated into more meaningful functions or (usually even better) generic algorithms.
I'd like to go into more detail and give more specific advice about how some code could be improved, but it's hard to do that when the question is so general, and the little code it contains lacks any context, so it's almost impossible to guess what it represents, which is the first thing you need to do to improve it much.
That said: I'd say as a general rule, adding a block without it being controlled by an flow control statement is perfectly reasonable -- but it's usually done to control object lifetimes -- if you want something created and destroyed, use an RAII object and put it in a block, so when execution exits the block, it'll be destroyed automatically.
Edit: At least to me, your sample looks ripe (overdue?) for some serious refactoring.
/// Add line to msg vector
// Check to see if each side X is needed
if(uniqueSide && line == 1){
// Create stringstream to hold string and int (e.g. "Message " + 1 + " - Side " + 1
stringstream tempString;
// Add full line to stringstream. validMessages.length() + 1 will make Message X be incremental
tempString << "Message " << (validMessages.length() + 1) << " - Side " << numSide;
// Then append full string (e.g. "Message 1 - Side 1") to msg
msg.append(tempString.str());
}
// Else just add Message X using same method as above
else if(line == 1){
stringstream tempString;
tempString << "Message " << (validMessages.length() + 1);
}
Right now, your else clause isn't really doing anything (puts something in tempString, but that's local, so it disappears upon exit from the block. Let's assume the comment is correct, so the else should have:
msg.append(tempString.str());
before it exits. In this case, the two legs of the code are similar enough that they should probably be (mostly) merged:
stringstream tempString;
tempString << Message << validMesssages.length()+1;
if (uniqueSide && line == 1)
tempString << " - Side " << numSide;
msg.append(tempString.str());
Then, since the last part of that is executed unconditionally, we can merge the rest of the code with the preceding (and in the process, eliminate quite a bit so we end up with something like this:
stringstream tempString;
if (line == 1) {
tempString << "Message " << validMesssages.length()+1;
if (uniqueSide) tempString << " - Side " << numSide;
}
tempString << setprecision(5) << " ( " << width << " ) " << tempInput;
msg.append(tempString.str());
From there, the question is whether it makes sense to turn that into a function or functor, so the calling code would end up something like:
msg.append(msg(line, validMessages, uniqueSide, numSide, width, tempInput));
Whether you want to do that, only you can probably say. Personally, I think it would depend on whether you were writing similar code in a number of places. If this is the only place with code like that, I'd probably leave it, but if you need the same code in two (or more) places, a function starts to make a lot more sense.

Related

How does increment work in this scenario C++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
I did not write this code.
i'm on my 3rd day of coding in C++ and i'm having a hard time understanding how incremnent works in general.
int main()
{
int antal_ord {};
double medellangd {};
string kort_ord;
string langt_ord;
int min_length {100};
int max_length {};
string S;
cout << "Mata in en text:\n" << endl;
while (cin >> S)
{
if (S.length() > max_length)
{
max_length = S.length();
langt_ord = S;
}
if (S.length() < min_length)
{
min_length = S.length();
kort_ord = S;
}
medellangd+=S.length();
antal_ord++;
}
if (antal_ord == 0)
{
cout << "Inga ord matades in." << endl;
}
else {
medellangd = (medellangd / antal_ord);
round(medellangd);
cout << "Texten innehöll " << antal_ord << " ord." << endl;
cout << "Det kortaste ordet var " << '"' << kort_ord << '"' << " med "
<< kort_ord.length() << " tecken." << endl;
cout << "Det längsta ordet var " << '"' << langt_ord << '"' << " med "
<< langt_ord.length() << " tecken." << endl;
cout << "Medelordlängden var "<< fixed << setprecision(1) << medellangd << " tecken.";
}
return 0;
}
antal_ord is the variable for the amount of words written in this scenario.
In the line where it says "cout << "Texten innehöll " << antal_ord << " ord." << endl;" how does it know how many words have been written? The only time this variable is used before this line is when the variable gets incremented, but how does that let the variable know how many words have been written in total?
and also the .length command, does it basically just count the amount of letters written?
There's really nothing special going on here. Every time you read one word with cin >> S, you increment antal_ord by one. Since you started with zero words written and antal_ord==0, at the end antal_ord will equal the number of words read from cin.
Similarly, S.length() returns the number of letters currently in S. In your case, that is exactly the number of letters read from cin since you didn't chance S after reading. But if you did S += " some extra letters, then S.length() will of course change.
When you'll learn about most programming languages, you'll start off with basics: syntax, data types, declarations (vars + funcs as well as other possible concepts), loops, calls, math operations and other code-control techniques relevant to each programming language.
What you'll see about most (and I;ll try to "rewind" from the generalization I started with and back down to C/C++) is that you have the following type of math operation variations when it comes to addition (let's focus on this, as it's more on point with the question).
result in a separate variable, in our case b: b = a + 1;
result in the same variable: a += 1;
incrementing the value of the variable: a++;
Expanding on it:
In the first case, b will have its value overwritten and is dependent on a different values (in this case the value of a and 1). What you need to focus on here is that a is NOT changed.
In this case, a receives a new value and is incremented by the right-side-value, in our case 1. a is changed by adding one (not incrementing)
In our case, similar to #2, the value of 8a* is updated, but the incrementation is done by 1.
Apart from syntactic sugar or code style preference, the difference between each is also in the way the variables are assigned their values (more formally said, in the assembly code "underneath"). This topic is a lot more complicated for someone that started programming, but focusing on the question, the answer is simply that ++ increments the value by 1.
Also note that there is a difference in certain coding flows between ++a and a++. Mainly in loops. For ++a the value is set before executing the code, using the already incremented value in the code, while a++ uses the current value of a first, then increments it.
Try it like this:
int i = 0;
while (++i < 100)
{
std::cout << i << std::endl;
}
... versus...
int i = 0;
while (i++ < 100)
{
std::cout << i << std::endl;
}
Then count how many lines each case wrote.
There is also a small caveat you should be aware of, it's a bit more advanced, so it's just a little "FYI" for you. There are two C++ techniques called "function overloading" and "operator (re)definition". Let's focus on the second one. You could build your own data type (for example a struct or class) and implement your own operators that do something other than what their arithmetic counterparts do. You'll see this in iterator definitions. In that case ++ is not "actual value incrementation" (so it's not a math calculation), but rather switching to the next item in a list. Once you reach std::vector lessons you'll encounter that.

While loop in C++ (using break)

I'm currently working through the book C++ Primer (recommended on SO book list). An exercise was given that was essentially read through some strings, check if any strings were repeated twice in succession, if a string was repeated print which word and break out of the loop. If no word was repeated, print that. Here is my solution, I'm wondering a) if it's not a good solution and b) is my test condition for no repeated words ok? Because I had to add 1 to the variable to get it to work as expected. Here is my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<string> words = {"Cow", "Cat", "Dog", "Dog", "Bird"};
string tempWord;
unsigned int i = 0;
while (i != words.size())
{
if (words[i] == tempWord)
{
cout << "Loop exited as the word " << tempWord << " was repeated.";
break;
}
else
{
tempWord = words[i];
}
// add 1 to i to test equality as i starts at 0
if (i + 1 == words.size())
cout << "No word was repeated.";
++i;
}
return 0;
}
The definition of "good solution" will somewhat depend on the requirements - the most important will always be "does it work" - but then there may be speed and memory requirements on top.
Yours seems to work (unless you have the first string being blank, in which case it'll break); so it's certainly not that bad.
The only suggestion I could make is that you could have a go at writing a version that doesn't keep a copy of one of the strings, because what if they're really really big / lots of them and copying them will be an expensive process?
I would move the test condition outside of the loop, as it seems unnecessary to perform it at every step. For readability I would add a bool:
string tempWord;
unsigned int i = 0;
bool exited = false;
while (i != words.size())
{
if (words[i] == tempWord)
{
cout << "Loop exited as the word " << tempWord << " was repeated.";
exited = true;
break;
}
else
{
tempWord = words[i];
}
++i;
}
// Doing the check afterwards instead
if (!exited)
{
cout << "No word was repeated.";
}
a) if it's not a good solution
For the input specified it is a good solution (it works). However, tempWord is not initialized, so the first time the loop runs it will test against an empty string. Because the input does not contain an empty string, it works. But if your input started with an empty string it would falsely find as repeating.
b) is my test condition for no repeated words ok? Because I had to add 1 to the variable to get it to work as expected.
Yes, and it is simply because the indexing of the array starts from zero, and you are testing it against the count of items in the array. So for example an array with count of 1 will have only one element which will be indexed as zero. So you were right to add 1 to i.
As an answer for the training task your code (after some fixes suggested in other answers) look good. However, if this was a real world problem (and therefore it didn't contain strange restrictions like "use a for loop and break"), then its writer should also consider ways of improving readability.
Usage of default STL algorithm is almost always better than reinventing the wheel, so I would write this code as follows:
auto equal = std::find_adjacent(words.begin(), words.end());
if (equal == words.end())
{
cout << "No word was repeated" << endl;
}
else
{
cout << "Word " << *equal << " was repeated" << endl;
}

Change string by index

I am a beginner in C++ and I am currently working with strings.
My question is why when compiling the code I'm providing below, I can get the string's characters when I use index notation, but cannot get the string itself using cout?
This is the code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string original; // original message
string altered; // message with letter-shift
original = "abc";
cout << "Original : " << original << endl; // display the original message
for(int i = 0; i<original.size(); i++)
altered[i] = original[i] + 5;
// display altered message
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
cout << "altered : " << altered << endl;
return 0;
}
When I run this, the characters in the string altered are displayed correctly with this line:
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
But the string itself is not displayed with this line:
cout << "altered : " << altered << endl;
I would like to know why this happens.
You have not resized your altered string to fit the length of the original string before the loop, thus your code exhibits undefined behavior:
altered[i] = original[i] + 5; // UB - altered is empty
To fix this, resize altered before the loop:
altered.resize(original.size());
Or use std::string::operator+= or similar to append to altered:
altered += original[i] + 5;
This way, it can be empty before the loop, it will automatically resize itself to contain appended characters.
Explanation
The way UB is happening here, is that you're succeeding in writing the data in the static array, which std::string uses for short string optimization (std::string::operator[] does no checks if you're accessing this array past the std::string::size()), but std::string::size() remains 0, as well as std::string::begin() == std::string::end().
That's why you can access the data individually (again, with UB):
cout << altered[0] << " " << altered[1] << " " << altered[2] << endl;
but cout << aligned does not print anything, considering simplified operator<< definition for std::string looks functionally like this:
std::ostream &operator<<(std::ostream &os, std::string const& str)
{
for(auto it = str.begin(); it != str.end(); ++it) // this loop does not run
os << *it;
return os;
}
In one sentence, std::string is not aware of what you did to its underlying array and that you meant the string to grow in length.
To conclude, <algoritm> way of doing this transformation:
std::transform(original.begin(), original.end(),
std::back_inserter(altered), // or altered.begin() if altered was resized to original's length
[](char c)
{
return c + 5;
}
(required headers: <algorithm>, <iterator>)
In your program string altered is empty. It has no elements.
Thus you may not use the subscript operator to access non-existent elements of the string as you are doing
altered[i] = original[i] + 5;
So you can append the string with new characters. There are several ways to do this. For example
altered.push_back( original[i] + 5 );
or
altered.append( 1, original[i] + 5 );
or
altered += original[i] + 5;
As you may not apply the subscript operator for an empty string to assign a value then it is better to use the range-based for loop because the index itself in fact is not used. For example
for ( char c : original ) altered += c + 5;
The size of altered is always zero - by using indexes you are trying to copy values from original to altered at indexes altered does not have. As LogicStuff has said, this is undefined behaviour - it doesn't generate an error because when we use indexes with std::string we are in fact calling an operator on a std::string to access the data field of a string. Using [] operator is defined in the C++ Standard as having no range check - that's why no error was thrown. The safe way to access indexes is to use the at(i) method: altered.at(i) will instead throw a range error if altered.size() <= i
However, I'm going to give this as my solution because it's a "Modern C++" approach (plus shorter and complete).
This is the alternative I would do to what has been given above:
string original = "abc";
string altered = original;
for (auto& c : altered) c += 5; // ranged for-loop - for each element in original, increase its value by 5
cout << altered << endl;
Note the significant reduction in code :-)
Even if I were doing it LogicStuff's way, I would still do it like this:
string original = "abc"
string altered = ""; // this is actually what an empty string should be initialised to.
for (auto c : original) altered += (c+5);
However, I actually don't recommend this approach, because of the way push_back() and string appending / string concatenation work. It's fine in this small example, but what if original was a string holding the first 10 pages of a book to be parsed? Or what if it's a raw input of a million characters? Then every time the data field for altered reaches its limit it needs to be re-allocated via a system call and the contents of altered are copied and the prior allocation for the data field is freed. This is a significant performance impediment which grows relative to the size of original -- it's just bad practice. It would always be more efficient to do a complete copy and then iterate, making the necessary adjustments on the copied string. The same applies to std::vector.

How to break out of this for loop: `for (; cin >> A;);`

for (cout << "\nEnter the Sentence now:";
cin >> Ascii;
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
Probably the best advice is don't be clever. Not only do you make it hard for anyone else* to read, understand, and modify your code, you run a real risk of outsmarting yourself.
Thus, don't try to do weird and clever things to implement your loop. Just do things naturally. If they don't naturally fit into how for or while or do ... while statements are structured, then just write a generic loop and use break statements to deal with leaving the loop. e.g.
while (true) {
// Some stuff
if (i_should_break_out_of_the_loop) {
break;
}
// Some more stuff
}
This is pretty much always better than doing things like torturing the for statement in the way you have.
Once you have a clear, easily comprehensible loop, it should be relatively easy to modify it to suit your needs. (or to ask a clearer and more focused question)
*: "anyone else" also includes you three weeks from now, after you've had time for it leave your short term memory.
I strongly advise you to turn this loop into a while loop. However the following is true whether or not you do:
Just enter an EOF, then the loop will terminate.
How an EOF is input will depend on your OS (and possibly also on your terminal settings). On Linux (under default terminal settings) you get an EOF pressing Ctrl+D at the beginning of the line. On Windows, I think it's Ctrl+Z. On Mac I have no idea.
Of course you could also redirect stdin for your program to come from a file (in which case EOF is — as you would guess — generated at the end of file), or from a pipe (in which case EOF is generated as soon as the writing program closes the pipe).
If the variable Ascii is not of type char or string, you may also enter something that cannot be parsed as that variable's data type (e.g. if reading an int, anything other than a number will cause the stream to report failure and thus the loop to terminate).
You also might want to add another end condition then in the loop body (which in your for loop is currently just an empty statement). For example, you might decide that a percent sign should terminate your loop; then you could write (I'm still assuming the type of Ascii which you didn't provide is char):
cout << "\nEnter the Sentence now:";
while(cin >> Ascii)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
if (Ascii == '%')
break;
}
However note that normally operator<< skips whitespace; I guess you don't want whitespace skipped. Therefore you probably shouldn't use operator<< but get; this will also allow you to use the end of line as end condition:
cout << "\nEnter the Sentence now:";
while(std::cin.get(Ascii) && Ascii != '\n')
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
}
However in that case, it's better to read the line in one step and then iterate through it:
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (std::string::iterator it = line.begin; it != line.end(); ++it)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)*it + RandomNumberSubtract << endl;
}
Note that in C++11, you can simplify this into
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (auto ch: line)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)ch + RandomNumberSubtract << endl;
}

Do-while loop running twice when it should run only once (C++)

friends. I have a problem.
Problem: the computer must pick randomly one string out of an array of 36 strings. If by any chance it picks strings #34 or #35 (the two last ones), it has to draw two more random strings from the same array. I tried a do-while solution, and it "almost" works (see code below).
The randomization works fine - called srand inside main(). There is a forced "x2" draw (for testing reasons), so the computer draws two more strings. These two new random picks are NOT "x2", but still the loop kicks again - but just one more time! This time the computer picks two more "chits", which aren't "x2" either, so, as expected, it returns the "The chits have been drawn" sentence and the function is terminated. Why is the same code running twice with the same results but different if/else behavior? Thank you very much in advance.
string mortalityCalc ()
{
string mortalityChits[36] = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","-","-","-","-","x2","x2"};
int mortalityResult;
// mortalityResult = rand() %36;
mortalityResult = 35; // for testing only. Delete afterwards.
string drawnChit = mortalityChits[mortalityResult];
string drawnChit1;
string drawnChit2;
if (drawnChit != "-" && drawnChit != "x2")
{
string returnText = string("The computer has drawn the chit '") + drawnChit + "'.";
return returnText;
}
else if (drawnChit == "-")
{
string returnText = string("The computer has drawn the chit '") + drawnChit + "'. No senators died this year.";
return returnText;
}
do
{
cout << "The computer has drawn the 'x2' chit." << endl;
cout << "Two more chits will be drawn.\n" << endl;
mortalityResult = rand() %36;
drawnChit1 = mortalityChits[mortalityResult];
cout << "The first draw is the chit '" << drawnChit1 << "'. ";
mortalityResult = rand() %36;
drawnChit2 = mortalityChits[mortalityResult];
cout << "The second draw is the chit '" << drawnChit2 << "'." << endl;
} while (drawnChit1 == "x2" || drawnChit2 == "x2");
return "The mortality chits have been drawn. The corresponding senators are dead.";
}
UPDATE: Tried running this code isolated from the rest of the program and it behave as expected. So I guess it's important to post what comes before it:
cout << "If you are a lazy bastard, the computer can pick one senator randomly for you.\nAre you a lazy bastard? [y/n]" << endl;
string lazyBastard;
cin >> lazyBastard;
cout << endl;
if (lazyBastard == "y" || lazyBastard == "Y" || lazyBastard == "yes" || lazyBastard == "YES" || lazyBastard == "Yes")
{
mortalityCalc ();
cout << mortalityCalc () << endl;
cout << "Very well. Now, imminent wars become active (Only one of each match)." << endl;
cout << "Get ready for the next phase." << endl;
My guess, from reading some other questions here, is that somehow the cin is messing with the loop behavior, even though they are not related and there's no user input whatsoever in the loop's statements or conditions. Is that possible? If so, why and how to remedy it?
Thank you again.
In the first loop you are forcing an 'x2' so your are entering the do-while loop. The result of the two calls for 'rand())%36' is always 19 and a number between 30 and 34. The point is that the random number generator generates always the same sequence of numbers, if you don't give him a seed 'srand(...)'.
do {
// ...
cout << rand()%36;
// ...
} while( /*...*/ )
See http://ideone.com/zl8ggH
You have to create random numbers and your code does what you expect.
Finally! I thought it would be a stupid thing! I just realized that I called the mortalityCalc() function twice! That's why it was looping twice!
Thanks to all who tried to help!