how to convert an for loop to while loop c++ - c++

I'm trying to convert a for loop to while loop in c++ and do some checking for duplicates in a random number generator for generating lotto numbers so far all the stuff i'm trying seems to make the compiler very unhappy and I could really use a few pointers. It's the for loop in the Harray() function that feeds the Balls[] array
that i want to convert to a while loop.
#include<iostream>
#include<cstdlib> // to call rand and srand.
#include<ctime> // to make rand a bit more random with srand(time(0)) as first call.
#include<iomanip> // to manipulate the output with leading 0 where neccesary.
using namespace std;
// Hrand() function create and return a random number.
int Hrand()
{
int num = rand()%45+1; // make and store a random number change 45 for more or less Balls.
return num; // return the random number.
}
// Harray() function create and fill an array with random numbers and some formatting.
void Harray()
{
int Balls[6]; // change the number in Balls[6] and in the for loop for more or less nrs. a row.
for(int x=0; x<=6; x++) //the loop to fill array with random numbers.
{
int a; // made to pass the Balls[x] data into so i can format output.
int m = Hrand(); // calling the Hrand() function and passing it's value in int m.
Balls[x] = m; // throwing it into the array tought i did this because of an error.
a = Balls[x]; // throwing it into int a because of an type error.
cout<<"["<<setfill('0')<<setw(02)<<a<<"]"; //format output with leading 0 if neccesary.
}
cout<<endl; // start new row on new line.
}
// Main function do the thing if compiler swallows the junk.
int main() // start the program.
{
int h; // int to store user cchoice.
srand(time(0)); // make rand more random.
cout<<"How many rows do you want to generate?"<<endl; // ask how many rows?
cin>>h; // store user input.
for(int i=h; h>0; h--) // produce rows from user input choice.
{
Harray(); // calling Harray function into action.
}
return 0; // return zero keep the comipler happy.
}
I would like to always have six diffrent numbers in a row but i don't see how to get there with the for loops i think the while loop is way to go but am open to any suggestion that will work. I'm just starting with c++ i might have overlooked some options.

int x=0;
while(x<6)
{
int a;format output.
int m = Hrand();value in int m.
Balls[x] = m; because of an error.
a = Balls[x];
cout<<"["<<setfill('0')<<setw(02)<<a<<"]";
x++;
}
Here, I also fixed a bug. Since Balls has 6 elements, the last element will be 5. Thus you want x<6 instead of x<=6. That goes for the for loop too.
One drawback of while loops is that you cannot declare local variables with them.

First of all, you should realize that the difference between a for loop and a while loop is mostly syntactic--anything you can do with one, you can also do with the other.
In this case, given what you've stated as your desired output, what you probably really want is something like this:
std::vector<int> numbers;
std::set<int> dupe_tracker;
while (dupe_tracker.size() < 6) {
int i = Hrand();
if (dupe_tracker.insert(i).second)
numbers.push_back(i);
}
The basic idea here is that dupe_tracker keeps a copy of each number you've generated. So, you generate a number, and insert it into the set. That will fail (and return false in retval.second) if the number is already in the set. So, we only add the number to the result vector if it was not already in the set (i.e., if it's unique).

How convert for-loop to while-loop
#include <iostream>
class T545_t
{
// private data attributes
int j;
public:
int exec()
{
// A for-loop has 3 parameters, authors often fill 2 of them with magic
// numbers. (magic numbers are usually discouraged, but are expected
// in for-loops)
// Here, I create names for these 3 for-loop parameters
const int StartNum = 2;
const int EndNum = 7;
const int StrideNum = 2;
std::cout << std::endl << " ";
for (int i = StartNum; i < EndNum; i += StrideNum ) {
std::cout << i << " " << std::flush;
}
std::cout << std::flush;
// A while-loop must use / provide each of these 3 items also, but
// because of the increased code-layout flexibility (compared to
// for-loop), the use of magic numbers should be discouraged.
std::cout << std::endl << " ";
j = StartNum;
do {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
} while(true);
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(true) {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(j < EndNum) {
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::endl;
return 0;
}
}; // class T545_t
int main(int , char** )
{
T545_t t545;
return(t545.exec());
}
Ask me where 'j' is declared?
This code is marked as C++, so in this case, I have declared 'j' in the private data attribute 'section' of this class definition. That is where you'd look for it, right?
If your c++ code does not have class, what's the point?

Related

C++ reversing a string

I'm trying to reverse a string in my C++ code line below revStr.at(j) = str.at(size);
But it doesn't change any of the elements in revStr.
Is there another way to do it without using any libraries.
#include <iostream>
#include<sstream>
#include <iterator>
using namespace std;
int main() {
ostringstream d;
long long c = 123456789;
d << c;
//cout << c << endl;
string str = d.str();
//cout << str.at(0) << endl;
int size = str.size() - 1;
//cout << size << endl;
ostringstream e;
e << str;
string revStr = e.str();
for (int i = size; size==0; size--) {
//cout << str.at(size);
int j = 0;
revStr.at(j) = str.at(size);
j++;
} // End For
cout << "Original String is :" << str << endl;
cout << "Reversed String is :" << revStr << endl;
}
Use std::reverse:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string test{"Hello"};
std::cout << "Original string: " << test << std::endl;
std::reverse(test.begin(), test.end());
std::cout << "Reversed string: " << test << std::endl;
return 0;
}
Output:
Original string: Hello
Reversed string: olleH
If you just want to reverse a string, you should use std::reverse, as described by Tyler Lewis. It is the best option.
If you want to learn C++, then writing your own version is good practice.
The line
for (int i = size; size==0; size--)
means “Create a new int called i and set it to size initially. Then, while size is zero, do the following and then decrement size”.
There are three problems with this:
Size is not zero unless you entered a one-character string
Since you never use i, there’s no point in declaring it
Inside the loop you use j which is set to zero each time.
You can fix the first by changing the middle part of the for loop to size >= 0 (but be careful—if you later change it so that size is an unsigned type, because it doesn’t make sense for it to be negative, that code won’t work; it’s generally better to increment going up instead). You can fix the second by using i everywhere in the loop statement, and not changing size. You can fix the third by using i in the loop body, and not declaring a new variable inside the loop.
I noticed you used std::string so I used std function swap and string. Depending on if you consider this as a 'library'. There are several definitions of 'reverse'. You could reverse the word order in a string, or a pure char to char reversal like I wrote. Reversal could also mean changing character case, etc... but this is simply swap first and last. Then swap the 2nd and 2nd to last, then swap the 3rd and 3rd to last, etc...
So some points from your code. You only need to loop half the string length. The swap is from the ith and the ith to last. So the last is numCharacters - 1, thus the ith to last would be Last - i or numCharacters - 1 - i. I believe this is what you intended by using a farLeft(i) and a farRight(j) index.
#include <iostream>
void reverseStringInPlace(std::string &stringToReverse)
{
int numCharacters = stringToReverse.length();
for (int i=0; i<numCharacters/2; i++)
{ std::swap(stringToReverse[i], stringToReverse[numCharacters-i-1]); }
}
int main()
{
std::string stringToReverse = "reversing a string";
std::cout << stringToReverse << std::endl;
reverseStringInPlace(stringToReverse);
std::cout << stringToReverse << std::endl;
return 0;
}
Output:
reversing a string
gnirts a gnisrever
Changes made to the piece of code in question, it works.
for (unsigned int i = size; size >= 0; size--) {
revStr[j] = str[size];
j++;
}

Working with vectors and loops

sorry to post a student question here. I'm not looking for a quick solution, I'm looking to understand. Comments in my code will explain the same, but here's a plain text version:
This is the beginning of a "LoShu Magic Square", I'm not to the addition of all parts of the matrix I'm making, I'm stuck at trying to verify that the same number has not been put into the rows before. My idea was to use one vector to "test" numbers that had been entered so far, so it does not need to be multi-dimensional (none of them are, but I don't care about the limit on the tester).
As-is the code will take the first number into the test vector, go to the check function, realize that number is there (which it should, haven't hashed out where to add the initial value), and after that initial check it will take ANY other value between 1-9, including repeats, which is bad. Help please? Why does it stop recognizing values inside the test vector after the initial round?
Separate link to code if it's maybe easier to read there: http://ideone.com/Dzh4mJ
#include<iostream> // This is the beginning of a "LoShu magic square" program for class, currently my
#include <vector> // goal is simply getting vectors to check whether or not a number has already been
using namespace std; // entered, and if so to go back and ask for another one. As-is it does not work
// through the first iteration. It recognizes the first number, says it's already in
bool theCheckening(vector<int>, int ); // and proceeds to take ANY numbers afterwards, repeats and all.
int main () {
int tester;
vector<int> loShu1; // Rows 1-3 of a "square"
vector<int> loShu2;
vector<int> loShu3;
vector<int> testCaseOut(1,0); // Test vector to iterate inside check function
do {
do{
cout << "Enter 1-9: "; // Working as intended, makes sure no number besides 1-9 is entered
cin >> tester;
} while (tester < 1 || tester > 9);
// Put initial value into test Vector
if (theCheckening(testCaseOut, tester)){ // If check function returns true, add value to row 1
loShu1.push_back(tester);
testCaseOut.push_back(tester);
cout << "It worked?!";
}
} while (loShu1.size() <= 2); // shooting for size of 3, working as intended
for (int var : loShu1) // Debug to see rows before maths and adding them (to come)
cout << var << " ";
cout << "\n";
for (int var : loShu2)
cout << var << " ";
cout << "\n";
for (int var : loShu3)
cout << var << " ";
return 0;
}
bool theCheckening(vector<int> testCaseInc, int testInt) {
int count;
vector<int> testCase(testCaseInc); // Initialize vector inside check function to current test numbers
for (int var : testCase)
cout << var << " ";
for (count = 0;count<=testCase.size();count++) { // for all the numbers inside the testing vector
if (testCase[count]!=testInt){ // if current position of test vector is ! in vector already,
cout << "ADDED!"; // add it to row back in main()
return true;
for (int var : testCase)
cout << var << " ";
}
cout << "ALREADY ENTERED!"; // Debug
cout << testCase.size();
return false; // otherwise, ignore and ask for another number
}
}
i think you have a logical error in your theCheckening function.
As far as i understand you want your function to return TRUE if the value is NOT in in the vector and FALSE if it IS in your vector.
Now to the problem:
Imagine someone has tipped in the following values to your code:
1 2 5 8
This values will be added to your vector and the vector will also contain:
1 2 5 8
Now let's say you tipp one more time the 2. Your Function will now start with value 1 of the vector and compare it to the 2. This is of course FALSE.
Look at your code:
if (testCase[count]!=testInt)
return true;
Your code says you can now return true. Which will cause your function to end and return true to the caller.
You didn't check the following values of the vector.
Your function theCheckening should look like this:
// user const vector<int> &, which will not cause to copy the
// vector
bool theCheckening(const vector<int> & testCase, int testInt) {
// use size_t which represents a integer datatype which
// is as big as arrays can be in the current bit setting
// 32 bit => size_t = unsigned int
// 64 bit => size_t = unsigned long long
for(size_t count = 0; count <= testCase.size(); count++) {
if(testCase[i] == testInt)
return false;
}
return true;
}
I hope this works and i understood this qestion correctly.

C++ Passing values to 2D char array in a function

I am trying to use a function to sort through a char array full of words. The current issue I am having is that in my sortNames function I am getting the error, "expression must be a modifiable lvalue" at the part below
hold = nameArr[ii];
nameArr[ii] = nameArr[jj];
nameArr[jj] = hold;
I am guessing that its because I am trying to pass values through an array for some reason. I am struggling with understanding references and pointers and the such, and I imagine that is hurting me here as well. Any help with this would be fantastic, thank you in advance.
Here is my current code...
#include <iostream>
#include <string>
using namespace std;
char nameArr[20][15]; // array to store the 20 values
int val = 0; // variable to pass values to the array
int x = 0; // loop counter outside functions
//Function prototypes
void getNames(char (&nameArr)[20][15], int &val);
void sortNames( char(&nameArr)[20][15]);
//getNames Function
void getNames(char (&nameArr)[20][15], int &val)
{
int i = 0; // loop counter
cout << "Awesome, now lets input those names...\n" << endl;
for (i = 0; i < val; i++)
{
cout << "\nNAME " << i+1 << ": " << ' ';
cin >> nameArr[i];
}
cout << "\n\n\nThese are the names that you inserted:\n" << endl;
for (i = 0; i < val; i++)
{
cout << nameArr[i] << "\n" << endl;
}
}
// sortNames function
void sortNames( char(&nameArr)[20][15])
{
int n = 15; // max length of word
int ii = 0; // loop counter
int jj = 0; // other counter
string hold; // holding array
for (int ii = 0 ; ii < n ; ii++)
{
for (int jj = ii + 1; jj < n; jj++)
{
if (nameArr[ii] > nameArr[jj])
{
hold = nameArr[ii];
nameArr[ii] = nameArr[jj];
nameArr[jj] = hold;
}
}
}
}
int main()
{
cout << "NAME SORTER!\n\nPlease enter in the amount of names you wish to enter: " << ' ';
cin >> val;
getNames(nameArr, val);
cout << "\n\n\nAlright, lets sort now..." << endl;
sortNames(nameArr);
cout << "\nHere are the results:\n" << endl;
for (x = 0; x < val; x++)
{
cout << nameArr[x] << "\n" << endl;
}
system("pause");
}
Your main problem here is that you are trying to use an assignment operator on two fixed sized arrays, which isn't legal. Consider the following code:
int a[2] = {0, 0};
int b[2] = {1, 1};
a = b;
This gives the same error you are getting. On the lines you mentioned, you are doing the same thing with char[15] arrays.
To fix your problems, you either need to allocate your char array dynamically/work with the pointers, or a simpler solution would be to just change your char[][] array to a string[] array.
That being said, there are a lot of things you can clean up here:
You have a few variables declared globally that can just be defined in main or lower
You can declare loop counters inside the for loop instead of beforehand, as you do in the sortNames function
In sortNames you are declaring a few variables twice
I'll add a few things to dwcanilla's answer.
You will want to change your function prototypes and headers to something more like this:
void getNames(char ** & arr, int val);
void sortNames(char ** & arr);
What this means is that the function accepts a reference to an array of c-strings; that is, when you work with the array within the function you are modifying the actual array you passed and not just a copy. Also I think you'd be fine just passing the integer by value for getNames.
Second, global variables are generally a bad idea. Since you can pass the array reference directly to your functions you may want to declare nameArr and your other global variables inside main instead.
Third, in getNames you won't be able to use cin to assign your c-strings directly.
EDIT: This is a better way --
getting console input for Cstrings
Finally, the < operator doesn't work on c-strings the way you're using it in your sort function. Use strcmp() instead (and be sure to include the cstring header):
if(strcmp(arr[ii], arr[jj]) > 0)

How Can I Speed My C++ Program Up?

Basically I am relearning C++ and decided to create a lotto number generator.
The code creates the ticket and if that ticket does not already exist, it is added to a vector to store every possible combination.
The program works, but its just far too slow, adding an entry roughly every second, and It will get slower as it finds it more difficult to add unique combinations out of over 13 million possible combinations.
Anyway here is my code, any optimization tips would appreciated:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
vector<string> lottoCombos;
const int NUMBERS_PER_TICKET = 6;
const int NUMBERS = 49;
const int POSSIBLE_COMBOS = 13983816;
string createTicket();
void startUp();
void getAllCombinations();
int main()
{
lottoCombos.reserve(POSSIBLE_COMBOS);
cout<< "Random Ticket: "<< createTicket()<< endl;
getAllCombinations();
for (int i = 0; i < POSSIBLE_COMBOS; i++)
{
cout << endl << lottoCombos[i];
}
system("PAUSE");
return 0;
}
string createTicket()
{
srand(static_cast<unsigned int>(time(0)));
vector<int> ticket;
vector<int> numbers;
vector<int>::iterator numberIterator;
//ADD AVAILABLE NUMBERS TO VECTOR
for (int i = 0; i < NUMBERS; i++)
{
numbers.push_back(i + 1);
}
for (int j = 0; j < NUMBERS_PER_TICKET; j++)
{
int ticketNumber = rand() % numbers.size();
numberIterator = numbers.begin()+ ticketNumber;
int nm = *numberIterator;
numbers.erase(numberIterator);
ticket.push_back(nm);
}
sort(ticket.begin(), ticket.end());
string result;
ostringstream convert;
convert << ticket[0] << ", " << ticket[1] << ", " << ticket[2] << ", " << ticket[3] << ", " << ticket[4] << ", " << ticket[5];
result = convert.str();
return result;
}
void getAllCombinations()
{
int i = 0;
cout << "Max Vector Size: " << lottoCombos.max_size() << endl;
cout << "Creating Entries" << endl;
while ( i != POSSIBLE_COMBOS )
{
bool matchFound = true;
string newNumbers = createTicket();
for (int j = 0; j < lottoCombos.size(); j++)
{
if ( newNumbers == lottoCombos[j] )
{
matchFound = false;
break;
}
}
if (matchFound != false)
{
lottoCombos.push_back(createTicket());
i++;
cout << "Entries: "<< i << endl;
}
}
sort(lottoCombos.begin(), lottoCombos.end());
cout << "\nCombination generation complete!!!\n\n";
}
The reason each lottery ticket is taking a second to generate is because you are misusing srand(). By calling srand(time(0)) every time createTicket() is called, you ensure that createTicket() returns the same numbers every time it is called, until the next time the value returned by time() changes, i.e. once per second. So your reject-duplicates algorithm will almost always find a duplicate until the next second goes by. You should move your srand(time(0)) call to the top of main() instead.
That said, there are perhaps larger issues to confront here: my first question would be, is it really necessary to generate and store every possible lottery ticket? (and if so, why?) IIRC real lotteries don't do that when issuing a ticket; they just generate some random numbers and print them out (and if there are multiple winning tickets printed with the same numbers, the owners of those tickets share the prize money).
Assuming you do need to generate every possible lottery ticket for some reason, there are better ways to do it than randomly. If you've ever watched the odometer increment while driving a car, you'll get the idea for how to do it linearly; just imagine an odometer with 6 wheels, where each wheel has 49 different possible positions it can be in (rather than the traditional 10).
Finally, a vector has O(N) lookup time, and if you are doing a lookup in the vector for every value you generate, then your algorithm has O(N^2) time, which is to say, it's going to get really slow really quickly as you generate more tickets. So if you have to store all known tickets in a data structure, you should definitely use a data structure with quicker lookup times, for example a std::map or a std::unordered_set, or even a std::bitset as suggested by #RedAlert.

Method problems: Deleting duplicate chars in an array

So I am trying to delete duplicate chars in a partially filled array. The array is populated from a file located on my PC. My array population method is working fine; however, my duplicate deleting method is not. Here is my method:
void deleteRepeated(char array[], int* numberUsed)
{
for (int x = 0; x < *numberUsed ; x++)
{
cout << "Positions used: " << *numberUsed << endl;
for (int y = x+1; y < *numberUsed; y++ )
{
cout << "Positions used: " << *numberUsed << endl;
if (array[y] == array[x])
{
cout << "Positions used: " << *numberUsed << endl;
for (int z = y; z < *numberUsed; z++)
array[z] = array[z+1];
y--;
*numberUsed--;
cout << "Positions used: " << *numberUsed << endl;
}
}
}
}
I am passing the entire array, and the number of indices used in that array. The array length is 10, and my tests, I am using 6 out of those 10 with the chars: {'g', 'g', 'n', 'o', 'r', 'e'}. What am I doing wrong?
NOTE: "cout << "Positions used: " << *numberUsed << endl" is being used to check if the method is correctly deleting or not. In the most inner loop where index is z, is where the method starts to go bonkers.
Any help would be much appreciated.
(I wrote the first part of this answer before I read your comment about STL not being allowed, but I'll leave it anyways because I think it's rather neat code.)
You could use the functionality that the C++ standard library makes available to you. Use std::string instead of char arrays (that's nearly always a good idea), then you can do the following (note: C++11 only because of unordered_set and std::begin):
#include <string>
#include <unordered_set>
#include <iostream>
#include <iterator>
std::string uniquechars(const std::string& s) {
std::unordered_set<char> uniquechars(std::begin(s), std::end(s));
std::string newstring(std::begin(uniquechars), std::end(uniquechars));
return newstring;
}
int main() {
std::string teststr("thisisanexamplesentence");
std::cout << "The unique characters of " << teststr << " are " << uniquechars(teststr) << std::endl;
}
Note that it doesn't keep the original order of the characters though, so if that's needed this does not work.
If you have to work without the standard library, you have to dig a bit deeper. #TimChild above already made a good start diagnosing what's wrong with your program, but there are more efficient solutions, for example keeping some kind of record of which characters you have already seen. As you're working with chars, I would consider a bit-field that can hold markers (extra overhead of 256/8=32 bytes) or if that's not too much, just a plain array of bools (extra overhead 256 bytes). As the latter is easier to implement and the code is more legible:
void deleteRepeated(char array[], int *numused) {
bool seenthischar[256] = {false};
char *readpointer = &array[0];
char *writepointer = &array[0];
int length = *numused;
for ( ;readpointer <= &array[0] + length; readpointer++) {
if (seenthischar[((unsigned char) *readpointer)]) {
*numused--;
} else {
seenthischar[((unsigned char) *readpointer)] = true;
*writepointer = *readpointer;
writepointer++;
}
}
}
This only has one loop, so it only has to go through the array once, i.e. its time complexity is linear in the length of the input array.
Every time you find a dup you reduce the number chars used
*numberUsed--;
but remember this controlling the first loop index
for (int x = 0; x < *numberUsed ; x++)
so try this
int count =*numberUsed;
for (int x = 0; x < count ; x++)
this way you visit all the original chars in the array.