When I define a string, the program stops working properly - c++

I am new in programming and now I'm learning from a book written by Bjarne Stroustrup ("2014 Programming Principles And Practice Using C++"). Anyway, the problem I am encountering is about the fact that when I define a string, the program stop working properly. This is the code:
#include <iostream>
using namespace std;
int main() {
double i;
double c = 0;
double bsf;
double ssf;
while (cin >> i) {
if (c == 0) {
bsf = i;
cout <<"The largest so far: " << i<<endl;
}
if (c == 1 && i > bsf) {
ssf = bsf;
bsf = i;
cout << "The largest so far: " << i<<endl;
} else if (c > 0 && i > bsf) {
bsf = i;
cout <<"The largest so far: " << i<<endl;
} else if (c > 0 && i < bsf) {
if (i < ssf) {
ssf = i;
cout <<"The smallest so far: " << i <<endl;
}
}
c++;
}
}
In CodeBlocks, this program works properly (I want the program to let me insert as many numbers as I want and to specify me when I write the biggest number and, also, the smallest number (you can make a better idea from the code). The problem appears when I try to define, as I said earlier, a string:
string um;
If I am doing this, the program doesn't recognize the smallest number written. If I write, for example, firstly, the number 220, it will be printed "The largest so far: 220", but if I write after that 45, it will not be printed "The smallest so far: 45".
If you guys can offer me some advices, it would be great.
Thank you!

The Answer is not undefined behavior as far as I can see. But the total lack of an if clause that caters to the OP's requirement.When the second no is entered, c is equal to 1 and in the if clauses there is no code for i <= bsf. So the code must be rewritten as
#include <iostream>
using namespace std;
int main() {
double i;
double c = 0;
double bsf;
double ssf;
while (cin >> i) {
if (c == 0) {
bsf = i;
cout <<"The largest so far: " << i <<endl;
}
if (c == 1 && i > bsf) {
ssf = bsf;
bsf = i;
cout <<"The largest so far: " << i <<endl;
} else if(c == 1 && i <= bsf) {
ssf = i;
cout <<"The smallest so far: " << i <<endl;
} else if (c > 0 && i > bsf) {
bsf = i;
cout <<"The largest so far: " <<i <<endl;
} else if (c > 0 && i < bsf) {
if (i < ssf) {
ssf = i;
cout << "The smallest so far: " << i <<endl;
}
}
c++;
}
}
This will also curb the UB in #Ron 's answer
EDIT : Thank you #drescherjm i forgot to add <=, that has been corrected

In your program you are trying to use local variables:
double bsf; // uninitialized local variable
double ssf; // uninitialized local variable
without initializing them thus causing undefined behaviour. Initialize your (local) variables prior to using them:
double bsf = 0;
double ssf = 0;
The actual culprit is on line 26:
if (i < ssf) // UB access to uninitialized variable `ssf`
Here is a screenshot from Visual Studio with the important info underlined:
Here is a GCC version on Coliru.
There is no std::string variable in your program. If there was one you would need to include the <string> header.

Think in terms of initial values; this code becomes much simpler if you initialize bsf to DBL_MIN and initialize ssf to DBL_MAX. Then as you go through the loop you just have to check the new value against bsf and ssf without all that confusion involving c.

Related

Reversing a number (C++)

I am brand new to C++, and am trying to make a simple program to determine if a user-entered integer is four digits, and if so, to reverse the order of said digits and print that output.
I have a (mostly) working program, but when I try, one of two things happens:
a) if line 16 is commented out and line 17 is active, then the program prints out an infinite number of reversed numbers and the IDE (in this case, repl.it) crashes; or
b) if line 17 is commented out and line 16 is active, then the program prints out one correct line, but the next line is "Your number is too short...again" (look at code below)
#include <iostream>
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main() {
int n, reversedNumber, remainder;
bool loopControl;
char userFinalResponse;
reversedNumber=0;
cout<<"Input a 4 digit integer and press Return\n"<<endl;
cin>>n;
while (loopControl=true){
//if ((n>9999)||(n<1000))
if ((n>9999)||((n<1000)&&(n>0)))
{
cout<<"Your number is too short or too long. Please try again.\n"<<endl;
cin>>n;
loopControl=false;
} else {
while(n != 0)
{
remainder = n%10;
reversedNumber=reversedNumber*10+remainder;
n /= 10;
loopControl=true;
}//closing brace for reversal loop
cout<<"Your reversed number is "<<reversedNumber<<"\n"<<endl;
}//closing brace for else
}//closing brace for "while (loopControl>0){"
return 0;
}//closing brace for "int main() {"
You can try this:
int number = 1874 //or whatever you need
auto str = std::to_string(number);
if (str.length() == 4) {
std::reverse(str.begin(), str.end());
std::cout << str << std::endl;
}
I suggest you to give a look at the algorithm header that contains a lot of useful methods that can help you while developing programs.
According to the cpp tutorials = is the assignment operator, not the comparison operator. Because of this your while loop will never terminate. You can simply initialize loopControl to true, and then set it to false when it's okay to exit:
int n, reversedNumber, remainder;
bool loopControl = true; //Initialize to true
char userFinalResponse;
reversedNumber = 0;
cout << "Input a 4 digit integer and press Return\n" << endl;
cin >> n;
while (loopControl) {
//if ((n>9999)||(n<1000))
if ((n>9999) || ((n<1000) && (n>0)))
{
cout << "Your number is too short or too long. Please try again.\n" << endl;
cin >> n;
loopControl = true; //need to keep on looping
}
else {
while (n > 0)
{
remainder = n % 10;
reversedNumber = reversedNumber * 10 + remainder;
n /= 10;
loopControl = false; //Ok to exit
}//closing brace for reversal loop
cout << "Your reversed number is " << reversedNumber << "\n" << endl;
}
}

Counting occurences of same array value in C++

I recently have been building a program where:
A user is asked to enter a number that will represent the size of a character array.
Then they are asked whether they will want the program to fill the values automatically, or they could press M so they could enter the values manually. They may only enter a-zA-Z values, or they will see an error.
At the end of the program, I am required to count every duplicate value and display it, for example:
An array of 5 characters consists of A;A;A;F;G;
The output should be something like:
A - 3
F - 1
G - 1
I could do this easily, however, the teacher said I may not use an additional array, but I could make a good use of a few more variables and I also can't use a switch element. I'm totally lost and I can't find a solution. I've added the code down below. I have done everything, but the counting part.
#pragma hdrstop
#pragma argsused
#include <tchar.h>
#include <iostream.h>
#include <conio.h>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
void main() {
int n, i = 0;
char masiva_izvele, array[100], masiva_burts;
cout << "Enter array size: ";
cin >> n;
clrscr();
cout << "You chose an array of size " << n << endl;
cout << "\nPress M to enter array values manually\nPress A so the program could do it for you.\n\n";
cout << "Your choice (M/A): ";
cin >> masiva_izvele;
if (masiva_izvele == 'M' || masiva_izvele == 'm') {
clrscr();
for (i = 0; i < n; i++) {
do {
cout << "Enter " << i + 1 << " array element: ";
flushall();
cin >> masiva_burts;
cout << endl << int(masiva_burts);
if (isalpha(masiva_burts)) {
clrscr();
array[i] = masiva_burts;
}
else {
clrscr();
cout << "Unacceptable value, please enter a value from the alphabet!\n\n";
}
}
while (!isalpha(masiva_burts));
}
}
else if (masiva_izvele == 'A' || masiva_izvele == 'a') {
clrscr();
for (i = 0; i < n; i++) {
array[i] = rand() % 25 + 65;
}
}
clrscr();
cout << "Masivs ir izveidots! \nArray size is " << n <<
"\nArray consists of following elements:\n\n";
for (i = 0; i < n; i++) {
cout << array[i] << "\t";
}
cout << "\n\nPress any key to view the amount of every element in array.";
//The whole thing I miss goes here, teacher said I would need two for loops but I can't seem to find the solution.
getch();
}
I would be very thankful for a solution so I could move on and forgive my C++ amateur-ness as I've picked this language up just a few days ago.
Thanks.
EDIT: Edited title to suit the actual problem, as suggested in comments.
One possible way is to sort the array, and then iterate over it counting the current letter. When the letter changes (for example from 'A' to 'F' as in your example) print the letter and the count. Reset the counter and continue counting the next character.
The main loop should run foreach character in your string.
The secondary loop should run each time the main "passes by" to check if the current letter is in array. If it's there, then ++.
Add the array char chars[52] and count chars in this array. Then print out chars corresponding to the array, which count is more than 1.
std::unordered_map<char, int> chars;
...
char c = ...;
if ('A' <= c && c <= 'Z')
++chars[c];
else if ('a' <= c && c <= 'z')
++chars[c];
else
// unexpected char
...
for (const auto p : chars)
std::cout << p.first << ": " << p.second << " ";
Assuming upper and lower case letters are considered to be equal (otherwise, you need an array twice the size as the one proposed:
std::array<unsigned int, 26> counts; //!!!
// get number of characters to read
for(unsigned int i = 0; i < charactersToRead; ++i)
{
char c; // get a random value or read from console
// range check, calculate value in range [0; 25] from letter...
// now the trick: just do not store the value in an array,
// evaluate it d i r e c t l y instead:
++counts[c];
}
// no a d d i t i o n a l array so far...
char c = 'a';
for(auto n : counts)
{
if(n > 0) // this can happen now...
{
// output c and n appropriately!
}
++c; // only works on character sets without gaps in between [a; z]!
// special handling required if upper and lower case not considered equal!
}
Side note: (see CiaPan's comment to the question): If only true duplicates to be counted, must be if(n > 1) within last loop!

Large binaries add

this is my first question, so I hope I will not break any of the given rules here on forum. I would like to ask you for help. Im really programming noob, but for homework I have to make a programm in C++ which will add 2 binary numbers. I was able to make it throught converting to a decimal and adding them. I did it bcs I already had some parts for it in my PC. My question is, everything is working fine unless I enter really big binary numbers. Changing data types make difference in results when our school program checks the code. Im not sure waht to change exactly. Thank you in advance. It looks like proble occure when decimal number with "e" has to be converted-
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
int main ()
{
int k = 0;
int l = 0;
int i = 0;
int j = 0;
double number = 0;
double numberb = 0;
long dec;
string input;
string inputb;
cout << "Enter two binary numbers:" << endl;
cin >> input >> inputb;
if(cin.fail ())
{cout << "Wrong input." << endl;
return 0;
}
for (i = input.length() - 1; i>=0; i-- )
{
if (input[i] != '1' && input[i] != '0')
{
cout << "Wrong input." << endl;
return 0;
}
if (input[i] == '1')
{
number += pow((double)2,(int)j);
}
j++;
}
for (k = inputb.length() - 1; k>=0; k-- )
{
if (inputb[k] != '1' && inputb[k] != '0')
{
cout << "Wrong input." << endl;
return 0;
}
if (inputb[k] == '1')
{
numberb += pow((double)2,(int)l);
}
l++;
}
dec = number+numberb;
vector <double> bin_vector;
long bin_num;
while ( dec >= 1 )
{
bin_num = dec % 2;
dec /= 2;
bin_vector.push_back(bin_num);
}
cout << "Soucet: ";
for ( int i = (double) bin_vector.size() - 1; i >= 0; i-- )
cout << bin_vector[i] << "";
cout << endl;
return 0;
}
Probably your teacher told you that double numbers are great for large numbers. They are, but they have a big disadvantage: They cannot represent large numbers exactly, since they (roughly speaking) only store the first few digits of the number, together with the position of the decimal point, like your pocket calculator shows (for example, 123456E13).
So you should not use double numbers here at all, since you need precise results, no matter how large your numbers are. A better idea is process both strings simultaneously and store the result digit by digit in another string, called result.
By the way: Since double numbers can usually store 53 binary digits precisely, it's good that your tested the program with even more digits.

Simple C++ input files and if statements

I wrote the code and it works except the total is wrong. It is supposed to multiply the distanceRate by the rate and add each cost to make the total, but it's not doing that. Any help would be appreciated.
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
//Declare Variables
ifstream inFile;
double packageWeight;
double distance;
double totalCharge = 0;
double rate;
double distanceRate;
int customerNumber;
double shippingCharge;
int packageCount = 0;
inFile.open("shipping.txt");
if(inFile)
{
cout << "Customer Package Shipping" << endl;
cout << "Number Weight Distance" << endl;
while(!inFile.eof())
{
inFile >> customerNumber;
inFile >> packageWeight;
inFile >> distance;
if(0 < packageWeight <= 2)
rate = 1.10;
else if(2 < packageWeight <=6)
rate = 2.20;
else if(6 < packageWeight <= 10)
rate = 3.70;
else if(10 < packageWeight <=20)
rate = 4.80;
else
cout << "Invalid package weight" << endl;
if( 0 < distance <= 500)
distanceRate = 1;
else if( 500 < distance <= 1000)
distanceRate = 2;
else if(1000 < distance <= 1500)
distanceRate = 3;
else if(1500 < distance <= 2000)
distanceRate = 4;
else
cout << "Invalid distance" << endl;
packageCount += customerNumber;
shippingCharge = rate * distanceRate;
totalCharge += shippingCharge;
cout << fixed << setprecision(2) << showpoint;
cout << setw(2) << customerNumber
<< right << setw(14) << packageWeight
<< setw(13) << distance
<< endl;
} //End of while loop
cout << "\nPackage shipped : " << packageCount << endl;
cout << "Total Charge : $" << totalCharge << endl;
inFile.close();
}
else
{
cout << "Could not open file" << endl;
}
system("pause");
return 0;
}
Some issues that I see in the snippet you gave me are as follows:
As pointed out by billz in a comment, your if statements are invalid. The statement if( 0 < distance <= 500) is not doing what you expect, it evaluates from left to right, so you have 0 < distance (lets say that evaluates to true) so then you have true <= 1000 which isn't going to give the results that you think it will. This actually needs to be broken apart into two separate comparisons like distance > 0 && distance < 500.
As I noted in my comment, you're adding the customer number to the package count, this will most likely always give a wrong value for package count. If your customer numbers are 1, 2, 3, 4 then you claim the package count is 10 when it's actually only 4 (forgive me if I misunderstood the purpose of this field).
You have no default value for distanceRate but you still use it in an operation (possibly uninitialized) which will give unexpected results (as you are seeing). In your else, you should actually give it a dummy value that way you guarantee that it will always be set. You also do reset it, so if it gets set to 4, and then next distance fails the tests and enters the else, you have another calculation on the variable as 4 instead of it's default value. You should initialize any variable that you plan to use unless you have explicit reason not to give it a value at initialization, and anytime you use a variable in a loop you should reset it's value at the start of the loop.
Additional Note (EDIT)
I wouldn't recommend using system("pause"); as it does a lot more behind the scenes than you would want in a simple pause, a better approach I've seen used is:
#include <iostream>
#include <conio.h>
using namespace std;
int main() {
cout << "Press any key to continue!";
_getch();
cout << "Finished";
return 0;
}
EDIT 2
If statments can contain a single line or a code block to execute.
Single line:
if (someValueIsTrue)
executeThisFunction();
Code block:
if (someValueIsTrue) {
executeThisFunction();
alsoThisFunction();
}
Anytime you need to execute more than one statement in an if/else/while/for/do...while/etc... you'll need a code block. I imagine (based on your explanation) that you did:
if (blah)
// ....
else
distanceRate = 0;
cout << "Invalid Distance";
And the compiler only sees that you have the distanceRate = 0 nested in the loop, the cout statement is actually not part of the else but part of the previous block of code. You need to use a code block here.
!inFile.eof() // incorrect
inFile.good() // correct
read on eof() it doesn't do what you might think it does.
if( 0 < distance <= 500) // all the if statements are incorrect
if(distance>0 && distance<=500) // correct
The way you wrote the if condition, it does not do what you think it does.

I'm getting a weird error for a program that seems like it should "just work."

I present to you all a program I'm working on for my college programming course. I still have a little ways to go before it completely meets my assignment's requirements, but I've gotten a basic draft of the program error-free (supposedly) and it appears to run… but then it suddenly kicks me into Xcode's debugger and gives me:
Thread 1: EXC_BAD_ACCESS(code=2, address=0x7fff95c1e5f5)
Here's the command line output, up until it kicks me out:
-----------------------
Quarterly_sales_taxator
-----------------------
How many company divisions will we be dealing with? 2
Am I correct in assuming that there are 4 sales quarters? yes
Please enter the sales Company Division #1 brought in for Sales Quarter #1 20
(lldb)
Here's my code:
//
// quarterly_sales_taxator.cpp
// Ch. 7 program #7
//
// Created by John Doe on 11/27/12.
//
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cctype>
using namespace std;
void read_company_divisions_and_sales_quarters(double **, int, int);
//void write_company_divisions_and_sales_quarters_to_array(double **, int, int); // This will be used later on to read data from a file.
void display_quarterly_sales_array(double **, int, int);
string temp; // A global temporary placeholder variable; I use this several times.
int main()
{
int COMPANY_DIVISIONS,
SALES_QUARTERS = 4;
double **quarterly_sales_form;
cout << "\n\n-----------------------\nQuarterly_sales_taxator\n-----------------------\n\n";
cout << "\nHow many company divisions will we be dealing with? ";
getline(cin, temp);
stringstream(temp)>>COMPANY_DIVISIONS;
while (COMPANY_DIVISIONS < 1 || isdigit(COMPANY_DIVISIONS == false))
{
cout << "\n\n------"
<< "\nError:"
<< "\n------"
<< "\n\nYou have entered an invalid choice."
<< "\nPlease type a number greater than zero. ";
getline(cin, temp);
stringstream(temp)>>COMPANY_DIVISIONS;
}
cout << "\n\nAm I correct in assuming that there are 4 sales quarters? ";
getline(cin, temp);
// Convert to uppercase.
for (int count = 0; count < temp.length(); count ++)
{
temp[count] = toupper(temp[count]);
}
if (temp == "NO" || temp == "NOPE" || temp == "INCORRECT" || temp == "YOU ARE NOT" || temp == "YOU ARE INCORRECT" || temp == "NEGATIVE" || temp == "NEGATORY")
{
cout << "\nOk, then how many sales quarters are we dealing with? ";
getline(cin, temp);
stringstream(temp)>>SALES_QUARTERS;
}
cout << endl << endl;
// This sets up the 2d array.
quarterly_sales_form = new double *[COMPANY_DIVISIONS];
for (int count = 0; count < COMPANY_DIVISIONS; count ++)
{ quarterly_sales_form[COMPANY_DIVISIONS] = new double [SALES_QUARTERS]; }
read_company_divisions_and_sales_quarters(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS);
// write_company_divisions_and_sales_quarters_to_array(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS); // I'll add this feature later.
cout << "\n\nHere's what you entered:\n\n";
display_quarterly_sales_array(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS);
// Since we used a series of pointers, we need to free the allocated space back up.
for (int count = 0; count < COMPANY_DIVISIONS; count ++)
{ delete[] quarterly_sales_form[COMPANY_DIVISIONS]; }
delete[] quarterly_sales_form;
return 0;
}
/*############################################
# read_company_divisions_and_sales_quarters #
############################################*/
void read_company_divisions_and_sales_quarters(double **array, int DIVISIONS, int QUARTERS)
{
for (int count = 0; count < QUARTERS; count++)
{
for (int index = 0; index < DIVISIONS; index++)
{
cout << "\nPlease enter the sales Company Division #" << count+1 << " brought in for Sales Quarter #" << index+1 << " ";
getline(cin, temp);
stringstream(temp) >> array[count][index];
}
}
}
/*################################
# display_quarterly_sales_array #
#################################*/
void display_quarterly_sales_array(double **array, int DIVISIONS, int QUARTERS)
{
for (int count = 0; count < DIVISIONS; count++)
{
cout << "\nCompany division #" << count+1 << ":\n";
for (int index = 0; index < QUARTERS; index++)
{ cout << array[count][index] << ", "; }
}
}
Can some kind soul please tell me what I'm doing wrong?
{ quarterly_sales_form[COMPANY_DIVISIONS] = new double [SALES_QUARTERS]; }
In this line, COMPANY_DIVISIONS should be count.
In addition to what Dan Hulme said, it seems this line
stringstream(temp) >> array[count][index];
should really be
std::istringstream(temp) >> std::skipws >> array[index][count];
In addition to using std::istringstream rather than std::stringstream and making sure that an lvalue is at hand, which isn't strictly needed until the type read becomes more interesting, this also reverses the indices: index runs over COMPANY_DIVISIONS and count over SALES_QUARTERS.
The real question is, of course: Who hands out assignments like this? Pointer manipulations and allocations are best left to low-level library writers. This is C++ not C: we can and should use abstractions. Getting this code exception safe is a major challenge and there is no point in teaching people how to write broken (e.g. exception unsafe) code.