Why are increment statements a thing in for-loops in C++? To me it seems redundant, because you could simply put the increments inside the conditional code. Am I misunderstanding something important here?
To illustrate my question better, I'm including some pseudocode:
What is the difference between ->
for( int a = 10; a < 20; a = a + 1 )
{
cout << a << endl;
}
and
for( int a = 10; a < 20;)
{
a = a + 1
cout << a << endl;
}
It's more than mere convenience sometimes.
These are equivalent:
for (int a = 10; a < 20; a = a + 1) {
cout << a << endl;
}
for (int a = 10; a < 20; ) {
cout << a << endl;
a = a + 1;
}
But, these are not:
// this works ...
for (int a = 10; a < 20; a = a + 1) {
if (blah ...)
continue;
cout << a << endl;
}
// this doesn't
for (int a = 10; a < 20; ) {
if (blah ...)
continue;
cout << a << endl;
a = a + 1;
}
Since you're coming from python, an idiomatic for loop is like a python range, but much more powerful. Your C for loop, expressed in python would be:
for a in range(10,20,1)
It's more idiomatic to express this as:
for (a = 10; a < 20; a += 1)
Because the loop increment is 1, it's even more idiomatic to do this:
for (a = 10; a < 20; ++a)
But, for loops are:
for ([init_stmt]; [test_stmt]; [incr_stmt])
Where any of the *_stmt can be compound:
for (x = 0, y = 0; x < 10; ++x, y += 2)
Convenience.
However, your equivalent code should be:
for (int a = 10; a < 20;)
{
cout << a << endl;
a = a + 1;
}
It runs at the end of the loop body.
[ snips grumbling about quality of now deleted/ edited answers ;-) ]
This:
for (unsigned counter = 1; counter <= 10; ++counter) {
doStuff();
}
is largely equivalent to this:
unsigned counter = 1;
while (counter <= 10) {
doStuff();
++counter;
}
with the notable exception that, in the 1st case, you have the considerable benefit that counter is scoped only to within the for block and automatically goes out-of-scope as soon as it finishes - whereas with the latter, counter must remain in-scope after the loop, where it's potentially useless or even an obstacle.
(tangential: Note that C did not support within-for declaration, or any non-top-of-block declarations, until C99 - but barring extenuating circumstances, anyone not using at least C99 by now is making a questionable choice imho.)
edit: Craig also makes a very good point regarding continue - an oft-forgotten but certainly useful statement. I'm sure there are probably other differences we could conjure up.
for this example:
using namespace std;
int main(int argc, char** argv) {
for( int a = 10; a < 20;)
{
a = a + 1;
cout << a << endl;
}
return 0;
}
the output will be from 11-->20
the first example will be from 10-->19
your are putting the increment part outside the loop and this possible, but notice that the value 10 will not appear, because you are increment before printing the value of a
so in the 2nd example your printing the value and then increment, and at the end of the loop, you are quiting the loop without reaching 20, because the condition get you out the loop
executing code block before increment is the key for you, the for loop increment just after the code block is executed
Well it is not required, it is just for convenience.
In your second code, you made a little mistake which would make the code nonequivalent to the the first one.
Your increment should be at the end of loop in order to be equivalent to the first code
so it should rather be:
for( int a = 10; a < 20;)
{
cout << a << endl;
a = a + 1; //increment at the end of instructions
}
These little errors and also errors like forgetting to include your increment is why it is convenient to include the increment in the for loop.
Or you can use the while loop instead:
while (condition)
{//instructions here;}
Related
First of all, sorry for the mis-worded title. I couldn't imagine a better way to put it.
The problem I'm facing is as follows: In a part of my program, the program counts occurences of different a-zA-Z letters and then tells how many of each letters can be found in an array. The problem, however, is this:
If I have an array that consists of A;A;F;A;D or anything similar, the output will be this:
A - 3
A - 3
F - 1
A - 3
D - 1
But I am required to make it like this:
A - 3
F - 1
D - 1
I could solve the problem easily, however I can't use an additional array to check what values have been already echoed. I know why it happens, but I don't know a way to solve it without using an additional array.
This is the code snippet (the array simply consists of characters, not worthy of adding it to the snippet):
n is the size of array the user is asked to choose at the start of the program (not included in the snippet).
initburts is the current array member ID that is being compared against all other values.
burts is the counter that is being reset after the loop is done checking a letter and moves onto the next one.
do {
for (i = 0; i < n; i++) {
if (array[initburts] == array[i]) {
burts++;
}
}
cout << "\n\n" << array[initburts] << " - " << burts;
initburts++;
burts = 0;
if (initburts == n) {
isDone = true;
}
}
while (isDone == false);
Do your counting first, then loop over your counts printing the results.
std::map<decltype(array[0]), std::size_t> counts;
std::for_each(std::begin(array), std::end(array), [&counts](auto& item){ ++counts[item]; });
std::for_each(std::begin(counts), std::end(counts), [](auto& pair) { std::cout << "\n\n" << pair.first << " - " pair.second; });
for (i = 0; i < n; i++)
{
// first check if we printed this character already;
// this is the case if the same character occurred
// before the current one:
bool isNew = true;
for (j = 0; j < i; j++)
{
// you find out yourself, do you?
// do not forget to break the loop
// in case of having detected an equal value!
}
if(isNew)
{
// well, now we can count...
unsigned int count = 1;
for(int j = i + 1; j < n; ++j)
count += array[j] == array[i];
// appropriate output...
}
}
That would do the trick and retains the array as is, however is an O(n²) algorithm. More efficient (O(n*log(n))) is sorting the array in advance, then you can just iterate over the array once. Of course, original array sequence gets lost then:
std::sort(array, array + arrayLength);
auto start = array;
for(auto current = array + 1; current != array + arrayLength; ++current)
{
if(*current != *start)
{
auto char = *start;
auto count = current - start;
// output char and count appropriately
}
}
// now we yet lack the final character:
auto char = *start;
auto count = array + arrayLength - start;
// output char and count appropriately
Pointer arithmetic... Quite likely that your teacher gets suspicious if you just copy this code, but it should give you the necessary hints to make up your own variant (use indices instead of pointers...).
I would do it this way.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string s;
vector<int> capCount(26, 0), smallCount(26, 0);
cout << "Enter the string\n";
cin >> s;
for(int i = 0; i < s.length(); ++i)
{
char c = s.at(i);
if(c >= 'A' && c <= 'Z')
++capCount[(int)c - 65];
if(c >= 'a' && c <= 'z')
++smallCount[(int)c - 97];
}
for(int i = 0; i < 26; ++i)
{
if(capCount[i] > 0)
cout << (char) (i + 65) << ": " << capCount[i] << endl;
if(smallCount[i] > 0)
cout << (char) (i + 97) << ": " << smallCount[i] << endl;
}
}
Note: I have differentiated lower and upper case characters.
Here's is the sample output:
output
I currently have a C++ program which is supposed to generate every possible domain name up to a set number of digits. The code I have is current pretty verbose (this is fine) but also tediously slow once it starts generating past 4 digits. The loops where things really start to go wrong are shown here:
const char* chars[] = {"a","b","c","d","e","f","g","h","i","j","k",
"l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", "0", "1",
"2", "3", "4", "5", "6", "7", "8", "9", "-"};
int char_num = 1;
[...]
if(char_num == 5) {
for(int i = 0; i < 36; i++) {
for(int j = 0; j < 37; j++) {
for(int k = 0; k < 37; k++) {
for(int l = 0; l < 37; l++) {
for(int m = 0; m < 36; m++) {
cout << "adding " << chars[i] << chars[j] << chars[k] << chars[l] << chars[m] << ".com to list\n";
if(i == 35 && j == 36 && k == 36 && l == 36 && m == 35) {
char_num++;
cout << "Generating to " << char_num + 1 << " characters\n";
}
}
}
}
}
}
}
I am intending at least three or four additional if statements after this one, with incrementally more for loops in each. I'm also going to need to write the output to a file, and to use this file to do DNS lookups, so I need every drop of performance I can get so I'm not waiting weeks for the program to complete.
My main concern at present is that the program is evaluating the if statement on every single interation which I presume is having a significant effect on performance, given the number of nested loops. To stop this I tried moving the if statement into a separate function and having it return a value once it finished, but I noticed that when I do this I'm not able to log to the console from within the function, which makes things more complicated.
What is the correct process for doing this in C++ and are there any other ways to speed up the code? I did try writing the code in node.js before but it went berserk and threw a bunch of out of memory errors when I started writing to a file, and I figured C++ would probably be quicker anyway, hence I switched languages.
Your if statement seems to be checking for the end of the loop. There is a simple solution to avoid this: remove the if and put the code after the loop!
However, if you need to add more ifs that depend on loop variables, I don't really know how you can optimize it. Don't, however, put them in a function: the overhead of calling the function will slow your code (and an optimizing compiler will inline your function anyway).
Here are a few possibilities you can explore:
use multithreading/multiprocessing. If done well, this can divide the execution time by up to the number of CPU cores on your computer
enable compiler optimization (-O3 or -Ofast with g++)
One last thing: if the consumer program accepts data from the standard input, piping the output of your program into it will be twice as fast as generating the names then using them. EG instead of
producer > storage.txt
consumer < storage.txt
do
producer | consumer
Focus on code optimizations. In the statement you are constantly re accessing the same member of the char array every iteration wasting clock cycles.
`cout << "adding " << chars[i] << chars[j] << chars[k] << chars[l] << chars[m] << ".com to list\n";`
A way to optimize this is by adding temporary variables.
char tempI;
char tempJ;
char tempK;
char tempL;
if(char_num == 5) {
for(int i = 0; i < 36; i++) {
tempI = char[i];
for(int j = 0; j < 37; j++) {
tempJ = char[j];
for(int k = 0; k < 37; k++) {
tempK = char[k];
for(int l = 0; l < 37; l++) {
tempL = char[l];
for(int m = 0; m < 36; m++) {
cout << "adding " << tempI << tempJ << tempK << tempL <<
chars[m] << ".com to list\n";
if(i == 35 && j == 36 && k == 36 && l == 36 && m == 35) {
char_num++;
cout << "Generating to " << char_num + 1 << " characters\n";
}
}
}
}
}
}
}
There are things you can do that make your code faster in regards to temporal and spatial locality just by the way you write it.
Also use compiler optimizations -03 with g++, etc.
Or consider rewriting your algorithm, because there might be a better way altogether in regards to time complexity
EDIT: Posting everything, because it gets really weird.
using namespace std;
int main()
{
int doors = -1;
int jumper = 1;
bool isOpen[100];
string tf;
for(int i = 0 ; i < 100; i++){
isOpen[i] = false;
}
while(jumper < 100){
while(doors < 100){
if(isOpen[doors + jumper] == true){
isOpen[doors + jumper] = false;
}
else{
isOpen[doors + jumper] = true;
}
doors += jumper;
cout << doors << endl;
}
doors = -1;
jumper+=1;
}
for(int i = 0; i < 100; i++){
if(isOpen[i]){
tf = "open";
}
else{
tf = "closed.";
}
cout << "Door " << i << " is " << tf << endl;
}
return 0;
}
So I'm having a very odd problem with this piece of code.
It's supposed to go through an array of 100 items. 0 - 99 by ones then tows then threes, etc. However, after a = 10, it shoots up to 266.
Can anyone tell me why?
Edit:
This problem only happens when the for loop is commented out. When it is left in the code, it does the same thing, but it doesn't happen until 19.
If I comment out the "string tf;" as well, it continues to loop at 99.
This is all based on the doors count.
I'm unsure why either of these should be a factor to the loop that neither are connected to.
According to your description this is what you should do:
for(int adv = 1, i = 0; adv < 100;)
{
// i is array index (your b) -> use it somehow:
doSomething(arr[i]);
i += adv;
if(i >= 100)
{
i = 0;
adv++;
}
}
The (probable) reason you got weird behavior (including the 266 value) is that your code overruns the buffer. When b will be high enough (say 99), you'd write to isOpen[b + a] which will be 100 or higher (100 if a is 1, and that's just the first iteration, later iterations will go much further). If the compiler allocates isOpen before the ints you'll be overwriting them.
I'm trying to write a program for university. The goal of the program is to make a nurse schedule for a hospital. However, i'm really stuck for the moment. Below you can find one function of the program.
The input for the function is a roster which consists of the shift each nurse has to perform on each day. In this example, we have 32 rows (32 nurses) and 28 columns (representing 28 days). Each cell contains a number from 0 to 6, indicating a day off (0) or a certain shift (1 to 6).
The function should calculate for each day, how many nurses are scheduled for a certain shift. For example, on the first day, there are 8 nurses which perform shift 2, 6 shift 3 and so forth. The output of the function is a double vector.
I think the function is mostly correct but when I call it for different rosters the program always gives the first roster gave.
void calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
for (int i = 0; i < get_nbr_days(); i++)
{
vector<int> nurses_per_shift;
int nbr_nurses_free = 0;
int nbr_nurses_shift1 = 0;
int nbr_nurses_shift2 = 0;
int nbr_nurses_shift3 = 0;
int nbr_nurses_shift4 = 0;
int nbr_nurses_shift5 = 0;
int nbr_nurses_shift6 = 0;
for (int j = 0; j < get_nbr_nurses(); j++)
{
if (roster1[j][i] == 0)
nbr_nurses_free += 1;
if (roster1[j][i] == 1)
nbr_nurses_shift1 += 1;
if (roster1[j][i] == 2)
nbr_nurses_shift2 += 1;
if (roster1[j][i] == 3)
nbr_nurses_shift3 += 1;
if (roster1[j][i] == 4)
nbr_nurses_shift4 += 1;
if (roster1[j][i] == 5)
nbr_nurses_shift5 += 1;
if (roster1[j][i] == 6)
nbr_nurses_shift6 += 1;
}
nurses_per_shift.push_back(nbr_nurses_shift1);
nurses_per_shift.push_back(nbr_nurses_shift2);
nurses_per_shift.push_back(nbr_nurses_shift3);
nurses_per_shift.push_back(nbr_nurses_shift4);
nurses_per_shift.push_back(nbr_nurses_shift5);
nurses_per_shift.push_back(nbr_nurses_shift6);
nurses_per_shift.push_back(nbr_nurses_free);
nbr_nurses_per_shift_per_day.push_back(nurses_per_shift);
}
}
Here you can see the program:
Get_shift_assignment() and schedule_LD are other rosters.
void test_schedule_function()
{
calculate_nbr_nurses_per_shift(schedule_LD);
calculate_nbr_nurses_per_shift(get_shift_assignment());
calculate_coverage_deficit();
}
One more function you need to fully understand the problem is this one:
void calculate_coverage_deficit()
{
int deficit = 0;
for (int i = 0; i < get_nbr_days(); i++)
{
vector<int> deficit_day;
for (int j = 0; j < get_nbr_shifts(); j++)
{
deficit = get_staffing_requirements()[j] - nbr_nurses_per_shift_per_day[i][j];
deficit_day.push_back(deficit);
}
nurses_deficit.push_back(deficit_day);
}
cout << "Day 1, shift 1: there is a deficit of " << nurses_deficit[0][0] << " nurses." << endl;
cout << "Day 1, shift 2: there is a deficit of " << nurses_deficit[0][1] << " nurses." << endl;
cout << "Day 1, shift 3: there is a deficit of " << nurses_deficit[0][2] << " nurses." << endl;
cout << "Day 1, shift 4: there is a deficit of " << nurses_deficit[0][3] << " nurses." << endl;
}
So the problem is that each time I run this program it always gives me the deficits of the first roster. In this case, this is Schedule_LD. When I first run the function with input roster get_shift_assignment() than he gives me the deficits for that roster.
Apparently the nbr_nurses_per_shift_per_day[][] vector is not overwritten the second time I run the function and I don't know how to fix this... Any help would be greatly appreciated.
Let me try to summarize the comments:
By using global variables to return values from your functions it is very likely, that you forgot to remove older results from one or more of your global variables before calling functions again.
To get around this, return your results from the function instead.
Ex:
vector<vector<int>> calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
vector<int> nbr_nurses_per_shift_per_day; // Create the result vector
... // Do your calculations
return nbr_nurses_per_shift_per_day;
}
or if you do not want to return a vector:
void calculate_nbr_nurses_per_shift(vector<vector<int>> roster1, vector<vector<int>> nbr_nurses_per_shift_per_day)
{
... // Do your calculations
}
But clearly, the first variant is a lot less error-prone (in the second example you can forget to clear nbr_of_nurses again) and most compilers will optimize the return nbr_nurses_per_shift_per_day so the whole vector does not get copied.
The second possible issue is that ´get_nbr_days()´ might return numbers that are larger or smaller than the actual size of your vector. To work around this, use either the size() method of vector or use iterators instead.
Your first function would then look like this:
vector<vector<int>> calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
vector<vector<int>> nbr_nurses_per_shift_per_day;
for (vector<vector<int>>::iterator shiftsOnDay = roster1.begin(); shiftsOnDay != roster1.end(); ++shiftsOnDay)
{
vector<int> nurses_per_shift(6, 0); // Create vector with 6 elements initialized to 0
for (vector<int>::iterator shift = shiftsOnDay->begin(); shift != shiftsOnDay->end(); ++shift)
{
if (*shift == 0)
nurses_per_shift[5]++;
else
nurses_per_shift[*shift - 1]++; // This code relies on shift only containing meaningful values
}
nbr_nurses_per_shift_per_day.push_back(nurses_per_shift);
}
return nbr_nurses_per_shift_per_day;
}
For this code I created that outputs the ASCII characters corresponding to ints, I need to print out 16 ASCIIs per line. How would I go about doing so? I'm not sure how to approach these? Do I create another for loop inside?
int main()
{
int x = 0;
for (int i = 0; i <= 127; i++)
{
int x = i;
char y = (char) x;
cout << y;
}
return 0;
}
Or should I put the cout outside with 16 separate lines? I am trying to print 17 ASCIIs starting from 1 in a row.
Use another variable that counts up along with i. When it reaches 16, reset it and print a new line. Repeat until the loop terminates.
i.e.(I may be off by one here, I didn't think about it too deeply)
for (int i=0, j=1; i<=127; i++,j++)
{
int x = i;
char y = (char) x;
cout << y;
if (j == 16) {
j = 0;
cout << '\n';
}
}
Alternatively, you could just check if (i % 16 == 0)
You don't need another variable to track it. i is already an int.
so if i modulo 16 equals 0 then print a newline
else print (char)i
EDIT:
Note, using variables like i is ok for simple iteration but its always good practice to name them better.
So think about how changing i to ascii in your program improves the readability. It instantly makes it even more clear what is it that you are trying to do here.
int main()
{
int charsThisLine =0;
for (int currentChar=0; currentChar<128; currentChar++)
{
if(charsThisLine==16)
{
cout<<endl;
charsThisLine = 0;
}
else
{
cout<<(char)currentChar;
charsThisLine++;
}
}
}
How about:
#include <iostream>
int main()
{
for(int i = 0, j = 0; i < 128; ++i, ++j)
{
if(j == 16)
{
j = 0;
std::cout << std::endl;
}
std::cout << static_cast<char>(i);
}
return 0;
}
Every iteration, j increases by 1; after 16 iterations, j is reset to 0, and a newline is printed.
Alternatively, as #Sujoy points out, you could use:
if((i % 16) == 0)
std::cout << std::endl;
But this introduces the problem of printing an extra newline character at the beginning of the output.
Yes, you need a second loop inside the first. (I misunderstood what is being requested.)
You also need to clean up the code. The first x is unused; the second x isn't needed since you could perfectly well use char y = (char)i; (and the cast is optional). You should normally use a loop for (int i = 0; i < 128; i++) with a < condition rather than <=.
You will also need to generate a newline somewhere (cout << endl; or cout << '\n';). Will you be needing to deal with control characters such as '\n' and '\f'?
Finally, I'm not sure that 'asciis' is a term I've seen before; the normal term would be 'ASCII characters'.