Need Help to understand the do while loop in details - c++

Please do not try to modify the code. This code works fine.I took it from a book.I just need some help to understand the behavior of the code.
#include <iostream>
#include <ctime>
using namespace std;
void suffle2(int[][13]);
int main(){
int deck[4][13] = { 0 };
srand(time(0));
suffle2(deck);
return 0;
}
void suffle2(int d[4][13])
{
int row, column;
for (int card = 1; card <= 20; card++)
{
do{
row = rand() % 4;
column = rand() % 13;
cout << "d[" << row << "]" << "[" << column << "]" << "=" << d[row][column]<<endl;
} while (d[row][column] != 0);
d[row][column] = card;
cout << "d[" << row << "]" << "[" << column << "]" << "=" << d[row][column] <<endl;
}
}
Both cout << "d[" << row << "]" << "[" << column << "]" << "=" << d[row][column] <<endl;
I code to understand the behavior.My question is:
deck[4][13] has initialized to 0.So the while loop should not work cause it should always
find d[row][column] == 0 but it is not..it is working fine.
second question is,suppose the output is following:
d[0][4]=0
d[0][4]=1
d[2][4]=0
d[2][4]=2
d[1][12]=0
d[1][12]=3--------duplicate
d[3][11]=0
d[3][11]=4
d[0][6]=0
d[0][6]=5
d[1][12]=3--------duplicate
d[1][11]=0
d[1][11]=6
d[0][7]=0
d[0][7]=7<--------------------duplicate
d[1][6]=0
d[1][6]=8
d[0][6]=5
d[0][11]=0
d[0][11]=9
d[2][11]=0
d[2][11]=10
d[3][11]=4
d[3][2]=0
d[3][2]=11
d[2][11]=10
d[1][10]=0
d[1][10]=12
d[1][6]=8
d[0][9]=0
d[0][9]=13
d[0][1]=0
d[0][1]=14
d[3][4]=0
d[3][4]=15
d[0][7]=7 <---------------------duplicate
d[0][2]=0
d[0][2]=16
d[0][3]=0
d[0][3]=17
d[2][11]=10
d[0][5]=0
d[0][5]=18
d[0][9]=13
d[0][10]=0
d[0][10]=19
d[1][6]=8
d[1][7]=0
d[1][7]=20
Press any key to continue . . .
In the for loop the card value is incremental but when the duplicate card value is found for the same index of array, it is taking the very first value for that index.Why it is not changing the increment value?Please help me to understand the code.

You are right, all values of deck are 0 at the beginning and the loop works because the do{}while(condition); is executing at least once before checking condition. The loop is looking here for the first uninitialized card.
Duplicate output is just what the loop is currently checking, it finds an initialized card so it keeps looking for an uninitialized one (this is the first cout).

Related

Randomize distinct cout statements (like getting 4 possible answers for a quiz)

This code is outputting 1 correct answer - which is always the one associated with 'random_number', so the first cout statement is always true. But who wants this kind of a quiz?
srand((int)time(0));
int random_number = rand() % max_event_number;
std::cout <<"\n" << final_years[random_number] << std::endl;
std::cout << "\n" << final_years[1 + random_number] << std::endl;
std::cout << "\n" << final_years[2 + random_number] << std::endl;
std::cout << "\n" << final_years[3 + random_number] << std::endl;
std::cout << "\n" << "Please type the correct year : " << std::endl;
Yes..., I can generate some random answers from the entire array, but they won't necessarily include the correct answer.
I don't want to change the way the correct answer is generated by the first 'random_number', because it takes only one line of code to check if the answer is true or not...
If only I could shuffle every time those 4 cout statement...
How would you do it?
Maybe not the best solution, but it works:
#include <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
std::vector<std::string> possible_answers = { final_years[random_number], final_years[1 + random_number], final_years[2 + random_number], final_years[3 + random_number] };
// I initialized a vector like an array with all the 4 answers, including the correct one (since C++11)
std::vector<std::string>::iterator it;
it = possible_answers.begin();
std::random_shuffle(possible_answers.begin(), possible_answers.end()); //shuffled its contents
for (it = possible_answers.begin(); it < possible_answers.end(); it++) //some tinkering to output vector's content
std::cout <<"\n" << *it;
Now the randomly generated numbers are displayed in a random order on the screen, but the correct answer is always the first generated number.

Mean and Mode of vector array - How can I make a smaller improvement in the function

Doing an exercise to find the mean and mode of a list of numbers input by a user. I have written the program and it works, but I'm wondering if my function 'calcMode' is too large for this program. I've just started looking into functions which is a first attempt. Would it be better to write smaller functions? and if so what parts can I split? Im pretty new to C++ and also looking if I can improve this code. Is there any changes I can make to make this run more efficient?
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int calcMean(vector<int> numberList)
{
int originNumber = numberList[0];
int nextNumber;
int count = 0;
int highestCount = 0;
int mean = 0;
for (unsigned int i = 0; i <= numberList.size() - 1; i++)
{
nextNumber = numberList[i];
if (nextNumber == originNumber)
count++;
else
{
cout << "The Number " << originNumber << " appears " << count << " times." << endl;
count = 1;
originNumber = nextNumber;
}
}
if (count > highestCount)
{
highestCount = count;
mean = originNumber;
}
cout << "The Number " << originNumber << " appears " << count << " times." << endl;
return mean;
}
int main()
{
vector<int> v;
int userNumber;
cout << "Please type a list of numbers so we can arrange them and find the mean: "<<endl;
while (cin >> userNumber) v.push_back(userNumber);
sort(v.begin(), v.end());
for (int x : v) cout << x << " | ";
cout << endl;
cout<<calcMean(v)<<" is the mean"<<endl;
return 0;
}
One thing to watch out for is copying vectors when you don't need to.
The function signature
int calcMode(vector<int> numberList)
means the numberList will get copied.
int calcMode(const & vector<int> numberList)
will avoid the copy. Scott Meyer's Effective C++ talks about this.
As an aside, calling is a numberList is misleading - it isn't a list.
There are a couple of points that are worth being aware of in the for loop:
for (unsigned int i = 0; i <= numberList.size()-1; i++)
First, this might calculate the size() every time. An optimiser might get rid of this for you, but some people will write
for (unsigned int i = 0, size=numberList.size(); i <= size-1; i++)
The size is found once this way, instead of potentially each time.
They might even change the i++ to ++i. There used to a potential overhead here, since the post-increment might involve an extra temporary value
One question - are you *sure this gives the right answer?
The comparison nextNumber == originNumber is looking at the first number to begin with.
Try it with 1, 2, 2.
One final point. If this is general purpose, what happens if the list is empty?
Would it be better to write smaller functions?
Yes, you can make do the same job using std::map<>; which could be
a much appropriate way to count the repetition of the array elements.
Secondly, it would be much safer to know, what is the size of the
array. Therefore I suggest the following:
std::cout << "Enter the size of the array: " << std::endl;
std::cin >> arraySize;
In the calcMode(), you can easily const reference, so that array
will not be copied to the function.
Here is the updated code with above mentioned manner which you can refer:
#include <iostream>
#include <algorithm>
#include <map>
int calcMode(const std::map<int,int>& Map)
{
int currentRepetition = 0;
int mode = 0;
for(const auto& number: Map)
{
std::cout << "The Number " << number.first << " appears " << number.second << " times." << std::endl;
if(currentRepetition < number.second )
{
mode = number.first; // the number
currentRepetition = number.second; // the repetition of the that number
}
}
return mode;
}
int main()
{
int arraySize;
int userNumber;
std::map<int,int> Map;
std::cout << "Enter the size of the array: " << std::endl;
std::cin >> arraySize;
std::cout << "Please type a list of numbers so we can arrange them and find the mean: " << std::endl;
while (arraySize--)
{
std::cin >> userNumber;
Map[userNumber]++;
}
std::cout << calcMode(Map)<<" is the mode" << std::endl;
return 0;
}
Update: After posting this answer, I have found that you have edited your function with mean instead of mode. I really didn't get it.
Regarding mean & mode: I recommend you to read more. Because in general, a data set can have multiple modes and only one mean.
I personally wouldn't split this code up in smaller blocks, only if i'd want to reuse some code in other methods. But just for this method it's more readable like this.
The order of excecution is aroun O(n) for calc which is quite oke if you ask me

My application is crashing using Do/While loop to parse table

I have 2 QCheckbox tables, each contains 11 elements.
I declare them as following in my class :
QCheckBox *sectionTable[10];
QCheckBox *postTable[10];
For each QCheckBox, I do this
QCheckBox* checkboxA = new QCheckBox("A");
sectionTable[0] = checkboxA;
Through my test method, I would like to return the content of each element of my QCheckbox tables.
To do so, I've done this test :
/** TEST() **/
void VGCCC::test()
{
sectionTable[0]->setText("A");
sectionTable[1]->setText("B");
sectionTable[2]->setText("C");
sectionTable[3]->setText("D");
postTable[0]->setText("E");
postTable[1]->setText("F");
postTable[2]->setText("G");
postTable[3]->setText("H");
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
}
My application is compiling, and also running. But when I call the test function, my application crash.
How can we explain this problem ?
I would like to notify that I get a result in my console. It seems my test is half working, but is crashing at the end of the 1st do/while loop, when I get out of my condition.
With regard to the 11 elements: QCheckBox *sectionTable[10]; defines only 10 slots (0 through 9) for elements.
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
Has the potential to reach past ten or eleven elements. Unless the terminating condition is found earlier, there is nothing to stop sectionTable[i] from trying to read sectionTable[11] to call its text method. If it manages to survive the call to the out-of-range sectionTable[11]->text(), it will then try calling sectionTable[11]->text().isNull(). Possibly this will be survivable as well and not be NULL. In this case sectionTable[12] will be tested. This will continue until the program hits really bad memory and crashes, a null is found, or pigs become the terror of the airways we all know they truly wish to be.
Note that i is not set back to 0 after this loop, so the first postTable to be inspected in the next loop will be at the same index as the last sectionTable.
So if sectionTable[5]->text().isNull() was NULL, postTable[5] will be the first postTable indexed and inspected.
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
This loop has the same error in the exit condition as the sectionTable loop.
I find out how to solve the problem. As said in the answer before (#user4581301), I didn't set back my iterator i to 0.
Also, to avoid the "out of range" crash, I put a second condition which is i<sizeof(sectionTable[i]);
This is my fonctional test function :
/** TEST() **/
void VGCCC::test()
{
int i = 0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << m_materialMap[sectionTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull() && i<sizeof(sectionTable[i]));
i = 0;
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
std::cout << "POST TABLE " << m_materialMap[postTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty() && i<sizeof(postTable[i]));
}

Trying to make an ASCII table in C++, cannot get the "special characters" to display properly

I'm working on an assignment where I need to print out the ASCII table in the table format exactly like the picture below.
http://i.gyazo.com/f1a8625aad1d55585df20f4dba920830.png
I currently can't get the special words/symbols to display (8, 9, 10, 13, 27, 32, 127).
Here it is running:
http://i.gyazo.com/80c8ad48ef2993e93ef9b8feb30e53af.png
Here is my current code:
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
cout<<"ASCII TABLE:"<<endl;
cout<<endl;
for (int i = 0; i < 128; i++)
{
if (i <= 32)
cout << "|" << setw(2)
<<i
<< setw(3)
<< "^" << char (64+i) <<"|";
if (i >= 33)
cout << "|" << setw(3)
<<i
<< setw(3)
<<char (i) << "|";
if((i+1)%8 == 0) cout << endl;
}
return 0;
}
8 Back Space
9 Horizontal Tab
10 New Line
13 carriage return
27 Escape (Esc)
32 Space
127 Del
As Above these ASCII characters doesn't display any visible or printed character. That's why you might be thinking you are not getting these values.
I'm no sure what's your real problem there, but you didn't get an answer yet about how to print the special codes.
Running your programme I see that you have some minor alignment problems. If that's the problem, note that setw(3) only applies to the next element:
cout << setw(3) << "^" << char (64+i); // prints " ^A" instead of " ^A".
If you try to correct into
cout << setw(3) << "^"+ char (64+i); // ouch !!!!
you'll get undefined behaviour (garbage) because "^" is a pointer to a string and adding char(64+i) is understood as adding an offset of 64+i to this pointer. As this is a rather random address, you'll get garbage. Use a std::string instead.
The other difference I see between your programme's output and the expected result is that you don't print the code of the special chars. If that's the problem, either use a switch statement (very repetitive here), or a lot of if/else or use an associative map.
Here an alternative proposal putting all this together:
map<char, string>special{ { 8, "BS " }, { 9, "\\t " }, { 10, "\\n " }, { 13, "CR " }, { 27, "ESC" }, { 32, "SP " }, { 127, "DEL" } };
cout << "ASCII TABLE:" << endl << endl;
for (int i = 0; i < 128; i++) {
cout << "|" << setw(3)<<i<<setw(4); // setw() only applies to next
if (iscntrl(i) || isspace(i)) { // if its a control char or a space
auto it = special.find(i); // look if there's a special translation
if (it != special.end()) // if yes, use it
cout << it->second;
else cout << string("^") + char(64 + i)+ string(" "); // if not, ^x, using strings
}
else if (isprint(i)) // Sorry I'm paranoïd: but I always imagine that there could be a non printable ctrl ;-)
cout << char(i)+string(" ") ; // print normal char
cout << "|";
if ((i + 1) % 8 == 0) cout << endl;
}
Now some additional advices:
take the effort to indent
instead of manual categorization of chars, use iscntrl(), isspace(), isprint(). As long as you only use ascii, it's manageable to do like you did. But as soons as you move to internationalisation and wide chars it becomes increasinlgy cumbersome to do that whereas there are easy wide equivalents like iswcntrl(), iswspace(), iswprint().
also be rigorous on two consecutive if: If you know that only one of the two should apply, make the effort to write if ... else if these four additional lettes can save you hours of debugging later.

Is there a limit on the size of std::set::iterator?

I have a std::set of strings and I want to iterate over them, but the iterator is behaving differently for different sizes of set. Given below is the code snippet that I'm working on:
int test(set<string> &KeywordsDictionary){
int keyword_len = 0;
string word;
set<string>::iterator iter;
cout << "total words in the database : " << KeywordsDictionary.size() << endl;
for(iter=KeywordsDictionary.begin();iter != KeywordsDictionary.end();iter++) {
cout << *iter;
word = *iter;
keyword_len = word.size();
if(keyword_len>0)
Dosomething();
else
cout << "Length of keyword is <= 0" << endl;
}
cout << "exiting test program" << endl;
}
The code is working properly & *iter is being dereferenced & assigned to word until the size of KeywordsDictionary is around 15000. However when the size of KeywordsDictionary increases beyond 15000,
the print statement cout << *iter; is printing all the contents of KeywordsDictionary correctly.
but the pointer to the iterator *iter is not being dereferenced & not being assigned to word. word is just being an empty string.
EDIT: And the output of the program is :
total words in the database : 22771
�z���AAAADAAIIABABBABLEABNABOUTACACCEPTEDACCESSACCOUNT...
Length of keyword is <= 0
exiting test program
So basically, I'm guessing the loop is executing only once.
Try to declare keyword_len as
std::string::size_type keyword_len = 0;
instead of
int keyword_len = 0;