c++: for not working as intended [closed] - c++

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
My question is when I run the code,and call for the list,so I press 3,nothing happens and it just skips over the code in for(). Why does this occur and how can I fix it?
Simple code would be welcome.I am now to this.
The first two int before the main checks if the student is qualified for the school,or not.i tested those and they are working great.
The struct describes a student.He/She has a name(nev),marks (bacmagy,bacrom,bacmat,bacvalasz).A boolean value(langexam) is present,to represent is the student has a language exam or not.
bsiker is true,if the formula in calculateBac turns out to be true.
atmente is true,if bsiker and langexam are both true.
The listing would spit out the name,bsiker and atmente.
#include <iostream>
using namespace std;
int atmegye(bool elso, bool masodik){
if (elso && masodik)
return true;
else
return false;
}
int calculateBac(double magy, double mat, double rom, double val){
double osszeg = magy + mat + rom + val;
osszeg = osszeg / 4;
if (magy < 5 || mat < 5 || rom < 5 || val < 5 || osszeg < 6)
return false;
else
return true;
}
int main(){
struct diak{
char nev[32];
bool langexam, atmente, bsiker;
double bacmagy, bacrom, bacmat, bacvalasz, bac;
};
diak v[150];
bool cap = false;
int opcio;
int j, n = 0;
int i = 0;
do{
cout << "\n Welcome. \n 1-new studient \n 2-Change a studient's details \n 3-List \n 4-Exit \n";
cin >> opcio;
switch (opcio){
case 4:{
return 0;
}
case 1:{
cout << "Please give the name of the student: ";
cin >> v[i].nev;
cout << "Hungarian mark: ";
cin >> v[i].bacmagy;
cout << "Romanian mark: ";
cin >> v[i].bacrom;
cout << "Maths mark: ";
cin >> v[i].bacmat;
cout << "Optional mark: ";
cin >> v[i].bacvalasz;
cout << " Do you have a language exam? Please respond with 1 or 0: ";
cin >> v[i].langexam;
v[i].bsiker = calculateBac(v[i].bacmagy, v[i].bacrom, v[i].bacmat, v[i].bacvalasz);
v[i].atmente = atmegye(v[i].bsiker, v[i].langexam);
i = i + 1;
i = n;
cout << n;
break;
}
case 3: {
for(i = 0; i < n; i++)
cout << v[i].nev << " " << v[i].bsiker << " " << endl;
break;
}
}
}while (opcio != 5);
}

This line is wrong:
i = n;
it should be:
n = i;
Your code is just undoing the i = i + 1; line that precedes it.

n is initialized as 0 and never set to any other value. Therefore your for loop is not supposed to run any iteration

The problem is in the for loop's conditional. You initialized the value of n to 0, and that value never seems to change. The variable i is also initialized to 0 inside the for loop. When the user chooses option 3, the for loop conditional ( 0 < 0) is evaluated which is false, so the for loop is skipped every time. So, to fix this problem, you need to update the value of n somewhere in your code, or you need to change your conditional statement. Hope this helps!

I know this probably won't help for your assignment, but here's a (one of many) way to handle this is a more c++-like manner, and without using OOP.
The standard library and the c++ type system give us plenty of useful tools to avoid writing bugs in the first place (that's really nice!), and find the one that are left at compile-time (saves a ton of time!). That's what the biggest difference between c and c++ is, and it is a very important one.
#include <iostream>
#include <vector>
#include <string>
#include <string.h>
// fixed-size record to save in data file, for example.
struct diak{
char nev[32];
bool langexam, atmente, bsiker;
double bacmagy, bacrom, bacmat, bacvalasz, bac;
};
void atmegye(diak& student)
{
student.atmente = student.bsiker && student.langexam;
}
void calculateBac(diak& student) // computes grades average, checks if passed.
{
double osszeg = student.bacmagy + student.bacmat + student.bacrom + student.bacvalasz;
student.bac = osszeg / 4.0;
student.bsiker = student.bacmagy >= 5
&& student.bacrom >= 5
&& student.bacmat >= 5
&& student.bacvalasz >= 5
&& student.bac >= 5; // this last test unnecessary, but rules are rules.
}
void AddNewStudent(std::ostream& os, std::istream& is, std::vector<diak>& students)
{
diak new_student;
std::string temp;
while(temp.empty())
{
os << "Student name: ";
is >> temp; // using a temp buffer avoids out of bounds errors
}
if (temp.length() >= sizeof(new_student.nev))
temp.resize(sizeof(new_student.nev) - 1);
strcpy(new_student.nev, temp.c_str());
// input values below SHOULD be validated for range (0-100)
// or whatever makes sense for your school.
os << "Hungarian mark: "; is >> new_student.bacmagy;
os << "Romanian mark: "; is >> new_student.bacrom;
os << "Maths mark: "; is >> new_student.bacmat;
os << "Optional mark: "; is >> new_student.bacvalasz;
// example validation. Validating user input is the worst!
// above ^^^ grades ^^^ can use a common function for validation.
for(;;)
{
os << " Do you have a language exam? Please respond with 1 or 0:";
is >> temp;
if (temp == "0")
{
new_student.langexam = false;
break;
}
if (temp == "1")
{
new_student.langexam = true;
break;
}
// not a valid entry, try again!
}
calculateBac(new_student);
atmegye(new_student);
students.push_back(new_student);
}
void EditSudent(std::ostream& os, std::istream& is, std::vector<diak>& students)
{
// query which student then edit using streams 'os' and 'is' for i/o.
}
// could also be used to write to file...
void PrintStudents(std::ostream& os, const std::vector<diak>& students)
{
// maybe by printing a student number you could reuse this
// function from EditStudent()...
//
// At the same time, it is only 2 lines of code. You decide.
for(size_t i = 0; i < students.size(); i++)
os << students[i].nev << " " << students[i].bsiker << "\n";
os.flush();
}
int main()
{
std::vector<diak> students; // could also be an std::list<>
while(true) // 1 less line of code than do {...} while, and easier to read.
{
int opcio = 0;
std::cout << "\n Welcome."
"\n 1-new studient"
"\n 2-Change a studient's details"
"\n 3-List "
"\n 4-Exit \n";
std::cin >> opcio;
switch (opcio)
{
case '1':
AddNewStudent(std::cout, std::cin, students);
break;
case 2:
EditSudent(std::cout, std::cin, students); // << queries student and edit that
break;
case 3:
PrintStudents(std::cout, students);
break;
case 4:
return 0;
}
}
}
Note how the tasks are very well delimited into their own function, this also helps finding bugs faster, as it makes the code easier to read and reason about (the famous divide and conquer strategy).
Having the students array (or list) as a single entity simplifies its management, no extra variable to keep up to date, etc...
In a more serious application, the input validation would be best done using a template, and would give the user an escape character so he could cancel adding the new student at any time.

Related

How can I throw a error if the user enters more than one integer

So this is my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
long int iterFunc(int);
long int recurFunc(int);
int main() {
int n;
while(true){
try{
cout << "Enter: ";
if (!(cin >> n))
throw("Type Error");
if (n < 0)
throw n;
else
if (n == 0)
break;
cout << "Iterative: " << iterFunc(n) << endl;
cout << "Recursive: " << recurFunc(n) << endl;
}
catch(int n){
cout << "Error. Enter positive number." << endl;
}
catch(...){
cin.clear();
cin.ignore(100, '\n');
cout << "Error. Please enter a number" << endl;
}
}
cout << "Goodbye!";
return 0;
}
long int iterFunc(int n){
vector<long int> yVec = {1, 1, 1, 3, 5};
if (n <= 5)
return yVec[n - 1];
else
for(int i = 5;i < n; i++){
long int result = yVec[i - 1] + 3 * yVec[i- 5];
yVec.push_back(result);
}
return yVec.back();
}
long int recurFunc(int n){
switch (n) {
case 1:
case 2:
case 3:
return 1;
break;
case 4:
return 3;
break;
case 5:
return 5;
break;
default:
return recurFunc(n - 1) + 3 * recurFunc(n - 5);
break;
}
}`
The program shoud accept only one integer and return the y of the function using both iterative and recursive implemetations. Ex.: 30, 59, 433. How can I throw an error message if the user enters more then one integer, separated by space? Ex.: '3 45 32'.
I tried using if (cin.getline == ' ') throw("Error name") but the program still executes and return the y of the function for number in the input
Something like this works:
int main()
{
std::string str;
std::cout << "? : ";
std::getline(std::cin, str);
std::string::size_type pos(0);
int i = std::stoi(str, &pos);
if (pos != str.length())
return 1;
}
I found a part of my old code that might come in handy.
int val;
do
{
cin>>val;
if(!cin){ //you can add more conditions here
cin.clear();
cin.sync();
/* additional error handling */
}
else{
break; //input is correct - leaving loop
}
}while(true); //or here
Basically what !cin does is - it checks what type of value you actually want to write to, because it's needed anyway to figure out if data type is written to the correct type of our val. This means, that "30" or "433" etc. are integers (correct), "s" or "string" etc. are strings (or char*, correct me if I am wrong) (incorrect).
This also means, that "3 45 32" should be interpreted as string, which should result in another loop run.
Note: I didn't really test this code, so it might be completely wrong.
Edit: Okay now after some tests I realised this code needs some retweaking.
Firstly, "3 45 32" is not interpreted as string (now understandable). Instead, first number (before whitespace) is saved as an integer and all other numbers are stored in the buffer (next cin will be filled with it), which we can avoid using cin.clear() and cin.sync() once again.
The question is - is it okay for you to accept the first integer and ignore everything after the first whitespace? If not, you will have to save the input as string and extract whatever data you want from it.
I am leaving the original answer as is for simplicity of finding references in this edit.

Console is being flooded when error checking for things that are not an int

I'm trying to only allow integer values into my program, so I've made the following function. The function is similar to other ones I've seen online, and mine seems to work just fine up until I add an ! in front of it to check if something is not an int.
Function to check if input is an integer:
bool isInteger(std::string s)
{
for (int i = 0; i < s.length(); i++)
{
if (isdigit(s[i]) == false)
{
return false;
}
return true;
}
}
Function being put to use:
int getLevel()
{
int level;
std::cout << "Level One\n";
std::cout << "Level Two\n";
std::cout << "Level Three\n";
std::cout << "Level Four\n";
std::cout << "Level Five\n";
std::cout << "Enter your level (1-5): ";
std::cin >> level;
while (!isInteger(std::to_string(level)) || level < 1 || level > 5)
{
std::cout << "Enter an integer value between 1-5 inclusive: ";
std::cin >> level;
}
clrscr();
return level;;
}
I believe the function works just fine until I put the ! in front of it. I am trying to only allow integer input into my program, and when I enter a double or string, the console becomes flooded with the message "Enter an integer value between 1-5 inclusive: " and doesn't give any time to enter an input. I am fairly new to c++ programming and could use some advice. Thank you!
std::cin >> level;
will try to read an integer and it will never read anything other than an integer. If this fails std::cin's failbit is set and further input operations (like std::cin >> level; inside the loop) are skipped.
You need to check if the reading succeeded and ignore the current input if not. Like this for example:
std::cout << "Enter your level (1-5): ";
while(!(std::cin >> level) || level < 1 || level > 5) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Enter an integer value between 1-5 inclusive: ";
}
As little semi-related hint: level will always be an integer. Converting it to a string will always be the string-representation of an integer, so isInteger(std::to_string(level)) will always be true, unless level is negative, because you don't check for the sign.
Also that return true; in isInteger must be outside the loop, else you only check the first character.
Thanks to all the replies and clarification, I've managed to come up with a solution of my own.
New isInteger function that now checks for everything that is needed including inputs like "0004" that a user suggested above:
bool errorCheck(std::string s)
{
int intLevel;
std::stringstream tempLvl(s);
tempLvl >> intLevel;
for (int i = 0; i < s.length(); i++)
{
if (isdigit(s[i]) == false || s[0] == '0' || intLevel < 1 || intLevel > 5)
{
return false;
}
}
return true;
}
The method in action:
std::cout << "Enter your level (1-5): ";
std::cin >> stringLevel;
while (!errorCheck(stringLevel))
{
std::cout << "Enter an integer value between 1-5 inclusive: ";
std::cin >> stringLevel;
}
std::stringstream lvl(stringLevel);
lvl >> level;
clrscr();
return level;
}
Please let me know if you spot any problems with the code or have any easier solutions. Thanks for all the help!
ok i am gonna tell u the fact that console input extracts the input from console so if u ever tried to do something like that
i.e read string in place of integer the cin is going to be in bad state you can check this fact by putting an if like this
if(!cin>>level) break;
and u will find it working actually stream takes input from the console and convert it to boolean value so u can always check it's state bad state return false else true...... ..
SO,finally the bug is in cin>>level...
I hope u understood.... also check out that return true statement..
i am gonna put u reference link for more answer on this bug...
user enters String instead of Int

Elegant C++ Code: How to write more efficient code using while loops and conditional statements

Would you be able to give me some suggestions for how I could simplify my code?
#include <iostream>
#include<fstream>
#include<string>
using namespace std;
int main() {
string current_users[5];
string new_users[5], new_user;
ifstream read;
read.open("current.txt");
for (int index = 0; index < 5; index++) {
read >> current_users[index];
}
read.close();
cout << "Enter a username: ";
cin >> new_user;
char user_choice;
int index = 0, new_index = 0;
while (index <= 5) {
if (new_user == current_users[index]) {
cout << "That username already exists."
<< " Enter a different username: ";
cin >> new_user;
index = 0;
continue;
}
if (index < 5)
index++;
else {
new_users[new_index] = new_user;
cout << "\nWelcome " << new_user << endl;
new_index++;
if (new_index < 5) {
cout << "Would you like to register another user?:"
<<"'Y' for yes or 'N' for no";
cin >> user_choice;
}
if (user_choice == 'Y' || user_choice == 'y') {
cout << "\nEnter a new username: ";
cin >> new_user;
index = 0;
}
else
break;
}
}//end of while
system("pause");
return 0;
}
This program asks a user to enter a username and checks if that username already exists. If it exists, it prompts the user to use a different username, also checking if that username already exists. If the username is unique the program welcomes the new user and asks if the user wants to register another new user (weird, but I wanted to try it). If the user wants to add another user to the "website" per say then the program runs again, checking for redundancy. I limited this program to 5 possible usernames to check and add for ease of testing. There's no errors.
The code is just chunky. I came up with this problem. I'm not in school. Can't afford it and wasn't admitted to any school where I applied. Any suggestions for online schools that offer degrees in computer science?
Here are some suggestions:
Array of Structures not parallel arrays
Use a std::vector of structures and not parallel arrays:
struct Record
{
std::string new_user;
std::string current_user;
};
std::vector<Record> database;
Processors that use a data cache like to have their elements close together. Here, new_user[0] would be next to current_user[0] in the cache.
With your parallel arrays, new_users[0] is next to current_user[4]; so the processor has to go past 4 elements to get to the first new_users element.
Loop Unrolling
You could eliminate the for loop for reading in your values:
read >> current_users[0];
read >> current_users[1];
read >> current_users[2];
read >> current_users[3];
read >> current_users[4];
This eliminates the overhead associated with a for loop.
Convert to all Lower or all Upper case before comparing
You can reduce the number of comparisons by converting to uppercase or lowercase before comparing:
if (std::toupper(user_choice) == 'Y')
Most of what you have is good. I'd wrap everything into a function and use std::find from the standard library in order to find duplicates.
template<std::size_t N, std::size_t M>
void GetUsers( std::string (&new_users)[N], std::string const (&current_users)[M] ) {
int idx = 0;
while (idx < 5) {
std::cout << "Enter a username: ";
std::string user; std::cin >> user;
if (std::find(current_users.begin(), current_users.end(), user) != current_users.end()) {
std::cout << "That username already exists.\n";
continue;
} else {
new_users[idx++] = user;
if (idx < 5) {
std::cout << "Would you like to register another user? [Y/n]: ";
if (std::tolower(std::cin.get()) == 'y') {
continue;
}
}
break;
}
}
}

Having trouble looping through an array in c++ [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I seem to be looping through my array wrong, I've got it set up to prompt the user for a list of numbers and I am supposed to be comparing it to another number that the user sets.
#include <iostream>
using namespace std;
bool chk = true;
int main() {
/*
Write a program that asks the user to type 10 integers of an array and an integer s.
Then search the value s from the array and display the value of s if it is found in
the array otherwise print sorry not found..
*/
int userArray[10], i, greater = 0;
int s;
cout << "Enter a check number: \n";
cin >> s;
if (chk = true) {
//prompt for array list
for (i = 0; i < 9; i++) {
if (i == 0) {
cout << "Enter ten numbers: " << "\n";
cin >> userArray[i];
}
else {
cin >> userArray[i];
}
chk = false;
}
//loop through the array
for (int i = 0; i <= 10; i++) {
if (s = userArray[i]) {
//for testing
cout << userArray[i];
//cout << s;
}
else {
cout << "No match found!";
}
//I was just using this to pause the console and let me inspect result
cin >> greater;
return 0;
}
}
}
I assume the following code is where the problem lies. The idea is i set s = 2 enter in a list of numbers and then compare to s and print s if there is a match if not I print No match found. When I enter in a number that i know matches s it seems to print the first number in the array, but i thought since I loop through the numbers one by one in the for loop that it should display when it reaches the right number not when it stops. Thanks in advance
//loop through the array
for (int i = 0; i <= 10; i++) {
if (s = userArray[i]) {
//for testing
cout << userArray[i];
//cout << s;
}
else {
cout << "No match found!";
}
You are using a single equals sign. This is setting s to userArray[i] so it always evaluates to true. For comparisons, use double equal signs, like this:
if (s == userArray[i]) {...}
Also, your return statement is inside your loop (credit to #UnholySheep).
you are comparing with a single assignment operator = you should be using the equal operator instead ==
if (s = userArray[i]) with in the for loop is one example.
you also doing the same mistake in
if (chk = true)

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.