While Loop in For Loop - c++

I'm trying to count the cats and dogs in a string. So,
for example:
if the string is "cc+dd-cd",:
I want to count 2 positive cats, 2 positive dogs, 1 negative cat, 1 negative dog (yes I know this is a weird way to count, but it's part of my assignment).
I thought about doing a for loop where I iterated over the string, then nested inside the for loop, I'd have a while loop that would run until a '-', then run until a '+' or the end. I started the code, and without even getting that far into it, it created an infinite loop.
Question: How can I fix it?
Thanks!
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
while (k != '-'){
pdc = pdc + 1; //positive dog count
pcc = pcc + 1; //positive cat count
}
while (k != '+') {
ndc = ndc + 1;
ncc = ncc + 1;
}
}

The immediate issue is that the while loops check k's value, but don't modify it. So once you entered one of them you'll be stuck there infinitely as k doesn't change inside the loop's body.
I wouldn't bother with nested loops - I'd just go over the entire string in one loop, and evaluate each character in its turn. A neat way to accomplish this is to keep a state of whether you're adding or subtracting (according to whether you last encountered a + or a - sign:
bool positive = true;
string animalparkString = "cc+dd-cd";
for (int k = 0; k < animalparkString.size(); k++) {
char ch = animalparkString[k];
switch (ch) {
case '+':
positive = true;
break;
case '-':
positive = false;
break;
case 'c':
if (positive) {
pcc++;
} else {
ncc++
}
break;
case 'd':
if (positive) {
pdc++;
} else {
ndc++
}
break;
}
}

This post describes iterating all characters is a string.
This is a simple solution using modern C++:
int sign = 1;
int dogs_count = 0, cats_count = 0;
std::string animalparkString = "-cccccc+dddd-cd";
for (const char& ch : animalparkString)
{
switch (ch) {
case '+':
sign = 1;
continue;
case '-':
sign = -1;
continue;
case 'c':
cats_count += sign;
continue;
case 'd':
dogs_count += sign;
continue;
}
}
std::cout <<"dogs: " << dogs_count << " cats: " <<cats_count;
A couple of suggestions to help you get started:
1. Use online c++ compilers to quickly test code
2. If your code doesn't behave as expected, use step-by-step debugging in your IDE or print our variables as you go using std::cout
3. Explicitly stating namespace is considered good practice. i.e:
// preferable:
std::string myString;
// avoid:
using namespace std;
string myString

To make your code work without too many changes , you can simply replace the while() condition with an if(). Moreover, instead of checking the iterator value k, you should compare the kth string element animalparkString[k].
Then you might start wondering if the code you wrote is actually doing what you expect. Possible questions you could try to answer is "how do I distinguish between positive or negative counts" and, then, "how do I distinguish between cats and dogs "? You will probably need to check also for cs and ds, not only for the operation sign!
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
if(animalparkStrink[k] != '-'){
// Now you know, there will be a pos count. Dog or Cat?
}
if(animalparkString[k] != '+') {
// Now you know, there will be a neg count. Dog or Cat?
}
}
Note that if you write while( k != '-'), it will always evaluate true and, therefore, you will be stuck there. If it is the first time working with for-loops, consider printing the iterator value, to understand when and where you are stuck.
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
std::cout << "for-loop iteration number: " << k << std::endl;
if(animalparkStrink[k] != '-'){
// Now you know, there will be a pos count. Dog or Cat?
}
if(animalparkString[k] != '+') {
// Now you know, there will be a neg count. Dog or Cat?
}
}

for and while together approach is unnecessarily complicated. Here's a simpler solution:
#include <concepts>
#include <iostream>
int main() {
auto const& str{"cc+dd-cd"};
std::boolean auto isPositive = 1;
std::integral auto pdc{0}, pcc{0}, ndc{0}, ncc{0};
for (char const ch : str) {
switch (ch) {
case 'c': {
pcc += isPositive;
ncc += !isPositive;
break;
}
case 'd': {
pdc += isPositive;
ndc += !isPositive;
break;
}
case '+': {
isPositive = true;
break;
}
case '-': {
isPositive = false;
break;
}
}
}
std::cout << "pcc: " << pcc << '\n'
<< "ncc: " << ncc << '\n'
<< "pdc: " << pdc << '\n'
<< "ndc: " << ndc << '\n';
}
LIVE

Related

Basic program to convert Roman number Arabic form?

I am wanting some help in answering these two questions. The first one is this:
I am trying to write a program that converts a single Roman number in the range I (1) to IX (9) to Arabic form. The
program should read a single string from standard input and print the corresponding value to standard output.
I then want to Extend the program so that it works correctly when the input consists of either lower case or upper case Roman letters.
The simplest approach is to convert each character in the input word into uppercase before trying to find a match. Run a
loop over the characters in the string using the index operator ([]) to access each character and use the toupper
function (you will need to include the cctype header file) to get the corresponding uppercase value.
For the second question this is what it wants me to do next:
Extend the program so that it can deal with single digit numbers of any value. A single digit number is one that consists
only of thousands, hundreds, tens, or units. Thus LXX (70) and CD (400) are single digit numbers, but XIV (14) and
MC (1100) are not. Use the same approach as for units digits, but with 4 different arrays, one each for the thousands,
hundreds, tens, and units digits. Try looking for thousands digits first, then for hundreds, and so on. When you find a
match in one of the arrays, print the corresponding value and stop.
Modify the program so that it reads and converts all input numbers until end of file (eof) on standard input. You will
probably be able to do this by simply adding an appropriate reading loop around the code that reads a single line.
Currently this is what i have to start but am unsure how to write a program like this:
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;
class RomanNumeral
{
public:
const static int M = 1000;
const static int D = 500;
const static int C = 100;
const static int L = 50;
const static int X = 10;
const static int V = 5;
const static int I = 1;
RomanNumeral( const int arabic ) :
m_roman( "" ),
m_arabic( ((arabic > 0) ? arabic : 0) )
{
if( arabic > 0 )
{
int i = arabic;
while( i > 0 )
{
if( ( i - M ) >= 0 )
{
m_roman += "M";
i -= M;
continue;
}
if( ( i - D ) >= 0 )
{
m_roman += "D";
i -= D;
continue;
}
if( ( i - C ) >= 0 )
{
m_roman += "C";
i -= C;
continue;
}
if( ( i - L ) >= 0 )
{
m_roman += "L";
i -= L;
continue;
}
if( ( i - X ) >= 0 )
{
m_roman += "X";
i -= X;
continue;
}
if( ( i - V ) >= 0 )
{
m_roman += "V";
i -= V;
continue;
}
if( ( i - I ) >= 0 )
{
m_roman += "I";
i -= I;
continue;
}
}
}
else
{
m_roman = "0";
}
}
RomanNumeral( const std::string& string ) :
m_roman( ((string.size() > 0 ) ? string : "0" ) ),
m_arabic( 0 )
{
int i = 0;
while( i < (int)string.size() )
{
char c = string[i++];
switch( c )
{
case 'M':
case 'm':
m_arabic += M;
break;
case 'D':
case 'd':
m_arabic += D;
break;
case 'C':
case 'c':
m_arabic += C;
break;
case 'L':
case 'l':
m_arabic += L;
break;
case 'X':
case 'x':
m_arabic += X;
break;
case 'V':
case 'v':
m_arabic += V;
break;
case 'I':
case 'i':
m_arabic += I;
break;
default:
throw new std::out_of_range( "Not a valid Roman numeral!" );
break;
}
}
}
int getArabic()
{
return m_arabic;
}
void setArabic( const int arabic );
const std::string& getRoman()
{
return m_roman;
}
protected:
std::string m_roman;
int m_arabic;
};
int main()
{
std::string roman;
cin >> roman;
try
{
RomanNumeral rn( roman );
cout << rn.getArabic() << endl;
}
catch( exception* ex )
{
cout << roman << " " << ex->what() << endl;
}
return 0;
}
Have been doing some tutorials on it but came across this question on a website the other day but I can't find the solution to this to see how its done. Could you demonstrate how to write a program like this by any chance?
Whenever you're stuck on a problem, try to decompose it into steps and implementing the things you can.
Step one is reading a single word:
std::string word;
std::cin >> word;
Step two is converting the word into a number:
int convert_to_number(const std::string& w) {
if (w == "I") return 1;
if (w == "II") return 2;
// and so on.
}
Step three is doing the conversion and printing the result:
std::cout << convert_to_number(word) << std::endl;
Instead of writing large amounts of if statements, you may want to try using an std::map<std::string, int> or std::unordered_hash<std::string, int> for a constant-time lookup.

Sorting given text alphabetically w/o additional library

My homework was to write an application that sorts given text in alphabetically order. To do so, I was allowed only to use 'vector', 'string' and 'iostream' library.
I succeed but now struggling with strange problem - while I'm trying to sort a short text, everything works well but with longer inputs program seems to get into infinity loop or efficiency problem. Eg in text
"Albert Einstein 14 March 1879 – 18 April 1955 was a German-born theoretical physicist who developed the theory of relativity one of the two pillars of modern physics alongside quantum mechanics His work is also known[...]"
everything works great until "mechanics" phrase. After adding this, or any other word, program is running eternally like I mentioned before.
I'm afraid that I have to paste whole code in this case (please forgive).
#include <iostream>
#include <string>
#include <vector>
int compare(std::string first, std::string second){
int flag = 1;
int i;
if (first.size() <= second.size()){
for (i = 0; i<first.size(); ++i ){
if (first[i] == second[i]){
continue;}
else if (first[i] > second[i]){
flag = 0;
break;}
else {
break;}}}
else {
for (i = 0; i<second.size(); ++i ){
if (first[i] == second[i]) {
continue;}
else if (first[i] > second[i]){
flag = 0;
break;}
else {
break;}
}
int m = second.size() - 1;
if (first[m] == second[m]){
flag = 0;}}
return flag;}
int main() {
std::vector<std::string> text;
std::string word;
std::string tmp;
while(std::cin >> word){
text.push_back(word);}
int mistakes, m = 1;
while(m) {
mistakes = 0;
for (int index = 1; index < text.size() ; ++index){
if (!(compare(text[index-1], text[index]))){
tmp = text[index];
text[index] = text[index-1];
text[index-1] = tmp;
mistakes += 1;}}
m = mistakes;}
for (auto element: text){
std::cout << element << " ";}}
I would love to hear how to fix it and why exactly this problem appears - at least time of execution doesn't grow with lenght of input, but more like "work/doesn't work", what is unlike to efficency issues.
You had missed some conditions because of which your while loop running infinitely. For example:
Your mistakes variable on whose value your while loop executes never becomes 0, if the very first pair of words are in wrong order. Negative test case would be : "ball apple". In this case your code runs infinitely.
In your compare method because of following line of code test case like this "Apple ball" were giving wrong answers. Here first[m] = second[m] = l , thus according to your condition it will return false and swap them. It will swap "Apple" with "Ball" which is wrong.
int m = second.size() - 1;
if (first[m] == second[m]){
flag = 0;
}
You also need to handle the cases where there will be comparison between upper and lower case words. For example: "Month also". In this case answer should be "also Month". So before comparing two string you should bring them to same case and then compare.
Number comparison case where 1874 should come after 18. (you can add this)
Following is the corrected code.
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
int compare(std::string first, std::string second){
// this is to handle the comparison of two words with mixed case(upper/lower) of letters.
// earlier solution failed for comparison between 'Month' and 'a'
for(int i=0;i<first.size();i++){
first[i] = tolower(first[i]);
}
for(int i=0;i<second.size();i++){
second[i] = tolower(second[i]);
}
int flag = 1;
int i;
if (first.size() <= second.size()){
for (i = 0; i<first.size(); ++i ){
if (first[i] == second[i]){
continue;}
else if (first[i] > second[i]){
flag = 0;
break;}
else {
break;}}}
else {
for (i = 0; i<second.size(); ++i ){
if (first[i] == second[i]) {
continue;}
else if (first[i] > second[i]){
flag = 0;
break;}
else {
break;}
}
}
return flag;}
int main() {
std::vector<std::string> text;
std::string word;
std::string tmp;
while(std::cin >> word){
text.push_back(word);}
// bubble short
for(int i=0;i<(text.size()-1);i++){
for(int j=0;j<(text.size()-1-i);j++){
if (!(compare(text[j], text[j+1]))){
tmp = text[j];
text[j] = text[j+1];
text[j+1] = tmp;
}
}
}
for (auto element: text){
std::cout << element << " ";}}

How to find first set?

I am trying to list the First set of a given grammar with this function:
Note:
char c - the character to find the first set;
first_set - store elements of the corresponding first set;
q1, q2 - the previous position;
rule- store all the grammar rule line by line listed below;
for the first time the parameters are ('S', 0, 0).
void findfirst(char c, int q1, int q2){
if(!(isupper(c)) || c=='$'){
first_set[n++] = c;
}
for(int j=0;j<rule_number;j++){
if(rule[j][0]==c){
if(rule[j][2]==';'){
if(rule[q1][q2]=='\0')
first_set[n++] = ';';
else if(rule[q1][q2]!='\0' &&(q1!=0||q2!=0))
findfirst(rule[q1][q2], q1, (q2+1));
else
first_set[n++] = ';';
}
else if(!isupper(rule[j][2]) || rule[j][2]=='$')
first_set[n++] = rule[j][2];
else
findfirst(rule[j][2],j,3);
}
}
}
But found that if the given grammar looks like this:
S AC$
C c
C ;
A aBCd
A BQ
B bB
B ;
Q q
Q ;
(which the left hand side or any capital letters in the right hand side are non-terminal, and any small case letters are terminal)
the function couldn't correctly output the first set for S, since it will stop at finding the first set of Q and store ';' to the first set and won't go on to find C's first set.
Does anyone have a clue? Thanks in advance.
It is extremely inefficient to compute FIRST sets one at a time, since they are interdependent. For example, in order to compute the FIRST set of A , you need to also compute the FIRST set of B, and then because B can derive the emoty string, you need the FIRST set of Q.
Most algorithms compute all of them in parallel, using some variation of a transitive closure algorithm. You can do this with a depth-first search, which seems to be what you are attempting, but it might be easier to implement the least fixed point algorithm described in the Dragon book (and Wikipedia.
Either way, you will probably find it easier to first compute NULLABLE (that is, which non-terminals derive the empty set). There is a simple linear-time algorithm for that (linear in the size of the grammar), which again is easy to find.
If you are doing this work as part of a class, you'll probably find the relevant algorithms in your course materials. Alternatively, you can look for a copy of the Dragon book or other similar text books.
You could do like the following code:
used[i] means the rule[i] is used or not
The method is Depth-first search, see https://en.wikipedia.org/wiki/Depth-first_search
#include <iostream>
#define MAX_SIZE 1024
char rule[][10] = {
"S AC$",
"C c",
"C ;",
"A aBCd",
"A BQ",
"B bB",
"B ;",
"Q q",
"Q ;"
};
constexpr int rule_number = sizeof(rule) / sizeof(rule[0]);
char first_set[MAX_SIZE];
bool findfirst(int row, int col, int *n, bool* used) {
for (;;) {
char ch = rule[row][col];
if (ch == '$' || ch == ';' || ch == '\0') {
first_set[*n] = '\0';
break;
}
if (islower(ch)) {
first_set[(*n)++] = ch;
++col;
continue;
}
int i;
for (i = 0; i != rule_number; ++i) {
if (used[i] == true || rule[i][0] != ch)
continue;
used[i] = true;
int k = *n;
if (findfirst(i, 2, n, used) == true)
break;
used[i] = false;
*n = k;
}
if (i == rule_number)
return false;
++col;
}
return true;
}
int main() {
bool used[rule_number];
int n = 0;
for (int i = 2; rule[0][i] != '$' && rule[0][i] != '\0'; ++i) {
for (int j = 0; j != rule_number; ++j)
used[j] = false;
used[0] = true;
findfirst(0, i, &n, used);
}
std::cout << first_set << std::endl;
return 0;
}

How would I cycle through all of the various possibilities in this situation?

I saw a programming assignment that I decided to try, and it's basically where the user inputs something like "123456789=120", and the program has to insert a '+' or '-' at different positions to make the statement true. For example, in this case, it could do 123+4-5+6-7+8-9 = 120. There are only 3^8 possible combinations, so I think it would be okay to brute force it, but I don't know exactly in what order I could go in/how to actually implement that. More specifically, I don't know what order I would go in in inserting the '+' and '-'. Here is what I have:
#include <iostream>
#include <cmath>
using namespace std;
int string_to_integer(string);
int main()
{
string input, result_string;
int result, possibilities;
getline(cin, input);
//remove spaces
for(int i = 0; i < input.size(); i++)
{
if(input[i] == ' ')
{
input.erase(i, 1);
}
}
result_string = input.substr(input.find('=') + 1, input.length() - input.find('='));
result = string_to_integer(result_string);
input.erase(input.find('='), input.length() - input.find('='));
possibilities = pow(3, input.length() - 1);
cout << possibilities;
}
int string_to_integer(string substring)
{
int total = 0;
int power = 1;
for(int i = substring.length() - 1; i >= 0; i--)
{
total += (power * (substring[i] - 48));
power *= 10;
}
return total;
}
The basic idea: generate all the possible variations of +, - operators (including the case where the operator is missing), then parse the string and obtain the sum.
The approach: combinatorially, it is easy to show that we can do this by associating the operators (or the absence thereof) with the base-3 digits. So we can just iterate over every 8-digit ternary number, but instead of printing 0, 1 and 2, we will append a "+", a "-" or nothing before the next digit in the string.
Note that we do not actually need a string for this; one could use digits and operators etc. directly as well, computing the result on the fly. I only took the string-based approach because it's simple to explain, trivial to implement, and additionally, it gives us some visual feedback, which helps understanding the solution.
Now that we have constructed our string, we can just parse it; the simplest solution is to use the C standard library function strtol() for this purpose, which will take signs into account and it will return a signed integer. Because of this, we can just sum all the signed integers in a simple loop and we are done.
Code:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
int main()
{
const char *ops = " +-";
// 3 ^ 8 = 6561
for (int i = 0; i < 6561; i++) {
// first, generate the line
int k = i;
std::string line = "1";
for (int j = 0; j < 8; j++) {
if (k % 3)
line += ops[k % 3];
k /= 3;
line += (char)('2' + j);
}
// now parse it
int result = 0;
const char *s = line.c_str();
char *p;
while (*s) {
int num = strtol(s, &p, 10);
result += num;
s = p;
}
// output
std::cout << line << " = " << result << (result == 120 ? " MATCH" : "") << std::endl;
}
return 0;
}
Result:
h2co3-macbook:~ h2co3$ ./quirk | grep MATCH
12-3-45+67+89 = 120 MATCH
1+2-34-5+67+89 = 120 MATCH
12-3+4+5+6+7+89 = 120 MATCH
1-23+4+56-7+89 = 120 MATCH
1+2+34-5+6-7+89 = 120 MATCH
123+4+5-6-7-8+9 = 120 MATCH
1+2-3+45+6+78-9 = 120 MATCH
12-3+45+67+8-9 = 120 MATCH
123+4-5+6-7+8-9 = 120 MATCH
123-4+5+6+7-8-9 = 120 MATCH
h2co3-macbook:~ h2co3$
The following bool advance(string& s) function will give you all combinations of '+', '-' and ' ' strings of arbitrary length except one and return false if no more are available.
char advance(char c)
{
switch (c)
{
case ' ': return '+';
case '+': return '-';
default: case '-': return ' ';
}
}
bool advance(string& s)
{
for (int i = 0; i < s.size(); ++i)
if ((s[i] = advance(s[i])) != ' ')
return true;
return false;
}
You have to first feed it with a string containing only spaces having desired length and then repeat 'advancing' it. Usage:
string s = " ";
while (advance(s))
cout << '"' << s << '"' << endl;
The above code will print
"+ "
"- "
" + "
"++ "
"-+ "
" - "
.
.
.
" ---"
"+---"
"----"
Note that the 'first' combination with just 4 spaces is not printed.
You can interleave those combinations with your lhs, skipping spaces, to produce expressions.
Another very similar approach, in plain C OK, in C++ if you really want it that way ;) and a bit more configurable
The same base 3 number trick is used to enumerate the combinations of void, + and - operators.
The string is handled as a list of positive or negative values that are added together.
The other contribution is very compact and elegant, but uses some C tricks to shorten the code.
This one is hopefully a bit more detailled, albeit not as beautiful.
#include <iostream>
#include <string>
using namespace std;
#include <string.h>
#include <math.h>
void solver (const char * str, int result)
{
int op_max = pow(3, strlen(str)); // number of operator permutations
// loop through all possible operator combinations
for (int o = 0 ; o != op_max ; o++)
{
int res = 0; // computed operation result
int sign = 1; // sign of the current value
int val = str[0]-'0'; // read 1st digit
string litteral; // litteral display of the current operation
// parse remaining digits
int op;
for (unsigned i=1, op=o ; i != strlen (str) ; i++, op/=3)
{
// get current digit
int c = str[i]-'0';
// get current operator
int oper = op % 3;
// apply operator
if (oper == 0) val = 10*val + c;
else
{
// add previous value
litteral += sign*val;
res += sign*val;
// store next sign
sign = oper == 1 ? 1 : -1;
// start a new value
val = c;
}
}
// add last value
litteral += sign*val;
res += sign*val;
// check result
if (res == result)
{
cout << litteral << " = " << result << endl;
}
}
}
int main(void)
{
solver ("123456789", 120);
}
Note: I used std::strings out of laziness, though they are notoriously slow.

C++ Accepting a command-line argument with parameters

I've got a program that needs to accept multiple command line arguments. I've gotten to a stage where I need to set it up to accept argument n, which specifies the max and min lengths of the string that will eventually be printed. Basically input could look like this:
-a -n7,7 -i // with -a and -i being other arguments
I'm fine with picking out arguments on their own, but I'm not sure how to pluck out those max and min values too. I've had a go (see below), but whenever I try and use variables minimum and maximum, I just get a run time error. Cheers guys.
int c;
while ((c = getopt(argc, argv, ":wpsaevin")) != -1) {
switch (c) {
case 'w': // pattern matches whole word
mode = WHOLE;
break;
case 'p': // pattern matches prefix
mode = PREFIX;
break;
case 'a': // pattern matches anywhere
mode = ANYWHERE;
break;
case 's': // pattern matches suffix
mode = SUFFIX;
break;
case 'e': // pattern matches anywhere
mode = EMBEDDED;
break;
case 'v': // reverse sense of match
reverse_match = true;
break;
case 'i': // ignore case of pattern
ignore_case = true;
break;
case 'n': //Specifies word length
length_spec = true;
cin >> minimum >> maximum;
if (minimum == 0 && maximum == 0) { //no word limit
length_spec = false;
} else if (maximum == 0) {
maximum = 100;
}
break;
}
}
argc -= optind;
argv += optind;
From this page:
This variable is set by getopt to point at the value of the option
argument, for those options that accept arguments.
case 'n': //Specifies word length
length_spec = true;
char *cvalue = optarg;
// TODO: Split cvalue by delimiter
// to obtain minimum and maximum
if (minimum == 0 && maximum == 0) { //no word limit
length_spec = false;
} else if (maximum == 0) {
maximum = 100;
}
break;
And an example of splitting a string:
#include <iostream>
#include <string>
#include <algorithm>
int
main()
{
const char* test = "1000,2000";
std::string str = std::string(test);
auto find = std::find(str.begin(), str.end(), ',');
std::string first = std::string(str.begin(), find);
std::string second = std::string(find+1,str.end());
std::cout << first << " " << second;
// 1000 2000
}
EDIT
Reference link
If you're able to use C++11, consider using std::stoi, like so:
int first_int = std::stoi( first );
int second_int = std::stoi ( second );
If not, try this:
std::replace(str.begin(), str.end(), ',', ' ');
std::istringstream ss(str);
ss >> first_int;
ss >> second_int;
std::cout << first_int << " " << second_int << std::endl;
I would use atoi as a last resort.
A naive implementation might look like this (use at your own risk):
int convert(std::string s)
{
int size = s.size();
int exp = size - 1;
int result = 0;
for (int i = 0; i < size; i++)
{
char c = s[i];
result += (int)(c - '0') * std::pow(10, exp--);
}
return result;
}
You can use Boost Library Program Options, as #aaronman suggested above.