My task is to create a program to ensure that unauthorized users cannot get into the system. (This is just a scenario, not the real thing). I was given a text file with 300 numbers on it. The user has to type in the number, if it is not included in the text file access will be denied. If it is included in the text file, access will be granted. The rest will be shown below.
So far this is what I have done
#include <iostream>
#include <fstream>
using namespace std;
bool mySequentialSearch(int data[300], int key, int size)
{
for(int i=0; i<size; i++)
{
if (data[i] == key)
return true;
}
return false;
}
int main()
{
int codes;
string line;
ifstream fin ("SystemAccessCodes.txt");
while (fin>>codes)
{
for(int i=0; i<3; i++)
{
cout<<"\nAttempt "<< i+1 << "/3 : ENTER 4 DIGIT CODE: ";
int ans;
cin>>ans;
if(mySequentialSearch(&codes, ans, 300))
{
cout<<"===================="<<endl;
cout<<" Access Granted "<<endl;
cout<<" Welcome "<<endl;
cout<<"===================="<<endl;
system ("pause");
return 0;
}
else
{
cout<<"\nNot matching! Try Again"<<endl;
}
fin.close();
}
}
system ("pause");
return 0;
}
My problem is I don't know how to use the textfile as an array. And it only reads the first number of the file.
Here is some of the numbers in the file (1450
1452
1454
1456
1458
1460) and the program I built only reads 1450.
Separate reading the codes and checking the user input. It makes no sense to do all that in a single loop.
int codes[300];
for(int i = 0; i < 300 && fin; ++i) {
fin>>codes[i];
}
fin.close();
for(int i=0; i<3; i++)
{
cout<<"\nAttempt "<< i+1 << "/3 : ENTER 4 DIGIT CODE: ";
int ans;
cin>>ans;
if(mySequentialSearch(codes, ans, 300))
{
cout<<"===================="<<endl;
cout<<" Access Granted "<<endl;
cout<<" Welcome "<<endl;
cout<<"===================="<<endl;
system ("pause");
return 0;
}
else
{
cout<<"\nNot matching! Try Again"<<endl;
}
}
The better way in c++ is to use a std::vector<int> instead of the raw array though:
std::vector<int> codes;
int code;
while(fin>>code) {
codes.push_back(code);
}
Instead of your mySequentialSearch() function, you can simply use std::vector::find() then.
Here you go:
I think it would be good to use an unordered_set here. To get that, make sure you use #include <unordered_set>
int codes;
std::string line;
std::ifstream fin("SystemAccessCodes.txt");
//lets use a set.
//Sets cannot contain duplicates. If the number is in the set, it is a valid code.
//it might be a better option to use strings rather than ints as passwords
//(large numbers could cause problems)
std::unordered_set<int> codeset;
//populate the set
while (fin >> codes)
{
codeset.insert(codes);
}
fin.close();
//now run this iteration
for (int i = 0; i < 3; i++)
{
std::cout << "\nAttempt " << i + 1 << "/3 : ENTER 4 DIGIT CODE: ";
int ans;
std::cin >> ans;
//count returns either 0 or 1: 0 if the ans is not in it, 1 if it is
if(codeset.count(ans))
{
std::cout << "====================\n";
std::cout << " Access Granted \n";
std::cout << " Welcome \n";
std::cout << "====================\n";
system("pause");
return 0;
}
else
{
std::cout << "\nNot matching! Try Again" << std::endl;
}
}
system("pause");
return 0;
Notes:
Using "using namespace std" pollutes the global namespace. I prefer to use "std::"
Your mySequentialSearch causes an n^2 runtime of your program. Using sets cuts it down to n (linear).
For more information on sets: http://en.cppreference.com/w/cpp/container/unordered_set
For more information on ifstream: http://en.cppreference.com/w/cpp/io/basic_ifstream
It would probably be a good idea to add some error checking (file doesn't exist, bad input, etc.)
Related
As the title states, I need to write a program that sums ages without asking the user to enter a specific number of ages to add beforehand. User shall just keep entering the desired ages until he writes "OK". Then, the program will stop and give the result. I've tried creating a string and when the string is equal to "OK" the program stops. However, I cannot figure it out.
int x,age;
int total=0;
int nofpeople=0;
int average=0;
string check;
cout<<"Enter the ages and when you're done write 'OK'." << endl;
while(check!="OK")
{
cin>>x;
if(x>0)
{
age=x;
nofpeople++;
total=total+age;
average=total/nofpeople;
}
else
{
check="OK";
}
}
cout<<"Number of people you have entered=" << nofpeople << endl;
cout<<"Sum of ages=" << total<< endl;
cout<<"Average of ages=" <<average;
return 0;
I have a code like this but this code obviously give result for the cases that I input to x "OK" or some randow letters like"adsfasd".I want it to work specificly for "OK".
I think something like this should work, I used istringstream class to convert the ages into integers, with error checking in case it doesn't work.
int x,age;
int total=0;
int nofpeople=0;
int average=0;
string check;
cout<<"Enter the ages and when you're done write 'OK'." << endl;
while(check!="OK")
{
string temp;
cin>>temp;
istringstream iss(temp);
iss >> x;
if(x>0)
{
age=x;
nofpeople++;
total=total+age;
average=total/nofpeople;
}
else if (temp.compare("OK") == 0)
{
check="OK";
}
else
{
cerr << "Invalid or negative number entered" << endl;
}
}
cout<<"Number of people you have entered=" << nofpeople << endl;
cout<<"Sum of ages=" << total<< endl;
cout<<"Average of ages=" <<average;
return 0;
Update 1: I need help with this the second part of this. I am asking the user to input numbers and to stop by using a zero. But then I want to display that code back. This is how far I got because when I want to display it it gives me different numbers. I'm ignoring user errors assuming when they input the first time it will be correct. But I do want them to input negative numbers.
#include <iostream>
#include <iomanip>
using namespace std;
int main ()
{
float data;
int count=0;
int*arr=new int[count];
//get amount of numbers inputted
cout<<"Please enter floating point data.\n";
cout<<"After the last number has been entered press 0 (zero) \n";
cin>>data;
for (; data != 0 ; ++count)
{
cin>>data;
}
cout<<count<<endl;
cout<<endl;
//display back data
cout<<"The numbers enterd are: "<<endl;
for(int i=0; i<count; i++)
{
cout<<arr[i]<<endl;
}
cout<<endl;
system ("pause");
return 0;
}
**Update 2:**This code is part of a bigger project I'm working on. My professor is never going to see the code he just cares that it is working. The design of my code is not a priority in this case. Also I have never used std::vector before so I needed another way to do it. But this is what I did and it worked fine. I also commented off delete []arr because my code wouldn't run properly if I didn't do that.
#include <iostream>
#include <iomanip>
using namespace std;
int main ()
{
double data;
int count=0;
double *arr =new double[count];
//get data
cout<<"Please enter floating point data."<<endl;
cout<<"After the last number has been entered press 0 (zero)"<<endl;
do
{
cin>>arr[count];
data = arr[count];
count++;
}while(data != 0);
//display back data
cout<<"The numbers entered are: "<<endl;
for(int i=0; i<(count-1); i++)
{
cout<<arr[i]<<endl;
}
//delete []arr;
system ("pause");
return 0;
}
The given example code,
#include <iostream>
#include <iomanip>
using namespace std;
int main ()
{
float data;
int count=0;
int*arr=new int[count];
//get amount of numbers inputted
cout<<"Please enter floating point data.\n";
cout<<"After the last number has been entered press 0 (zero) \n";
cin>>data;
for (; data != 0 ; ++count)
{
cin>>data;
}
cout<<count<<endl;
cout<<endl;
//display back data
cout<<"The numbers enterd are: "<<endl;
for(int i=0; i<count; i++)
{
cout<<arr[i]<<endl;
}
cout<<endl;
system ("pause");
return 0;
}
… has many issues:
Coding: using float for no reason.
The default floating point type in C and C++ is double. E.g. the literal 3.14 is of type double, and any float value is promoted to double when passed to variadic C function. Only use float where a requirement is imposed by the context, e.g. a C API, or storing a zillion values in limited memory.
Coding: using a raw array and a new-expression.
The task is trivial when using std::vector. It's not a good idea to reinvent the wheel again and again. An exercise that requires you to reinvent std::vector or its most basic features should be very clear about that aspect: this isn't, so presumably reinvention is not required or what it's about.
Design: signalling end-of-input via special value.
That value can't be inputted.
Coding: an input loop that doesn't store the numbers.
Each number is stored in the same variable as the previous number, erasing the previous number. Store the numbers in a std::vector. E.g. you can use the push_back method.
Coding: inconsistent convention for newline on output.
Either use endl, or "\n", as default. Don't mix them randomly. Consistency is very important because someone reading the code, who assumes a competent programmer, must treat every departure from the established defaults as being due to some reason. When there is no reason this wastes time and effort.
Tool usage: the system( "pause" ) is silly, counter-productive & non-portable.
In Visual Studio, which it appears you're using, just run the program via Ctrl+F5. Or place a breakpoint on the last right brace of main, and run the program in the debugger via F5.
Coding: the return 0; is superfluous.
main is the only function that has a default return value. It has that in both C and C++. The default, 0 for success, is there to be used.
Example code with the above points, plus some, fixed.
This code is for C++11 or later so it won't compile directly with Visual C++ 2010.
I leave it as an exercise for you to translate it to C++03, which is what your current compiler can handle. Do consider upgrading. It's a free tool.
#include <iostream>
#include <iomanip> // std::setw
#include <string> // std::(string, stod)
#include <vector> // std::vector
using namespace std;
using Half_float = float; // Most often a silly choice.
using Float = double; // Default in C++.
using Extended_float = long double; // Same as double in Visual C++.
auto read_line()
-> string
{ string line; getline( cin, line ); return line; }
auto main() -> int
{
cout << "Please enter floating point numbers like " << 3.15 << ", one per line.\n";
cout << "After the last number just press return again (i.e. a blank line).\n";
vector<Float> numbers;
for( ;; )
{
cout << "#" << numbers.size() + 1 << "? ";
string const line = read_line();
if( line.empty() )
{
break;
}
numbers.push_back( stod( line ) ); // Here you CAN do input validation.
}
cout << numbers.size() << " numbers entered.\n";
cout << "\n";
cout << "The numbers entered were: \n";
for( int i = 0; i < int( numbers.size() ); ++i )
{
cout << setw( 3 ) << i << ": " << numbers[i] << "\n";
}
}
If you have C++ 11 or above, use auto
replace
for(int i=0; i<count; i++)
{
cout<<arr[i]<<endl;
}
with
for(auto v: arr){
cout << v << endl;
}
Please remember, you'll need compiler supporting C++11 to use auto.
If C++ < 11, Use std::for_each
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
void print(float v){
cout << v << endl;
}
int main ()
{
float data;
int count=0;
std::vector<float> arr;
//get amount of numbers inputted
cout<<"Please enter floating point data.\n";
cout<<"After the last number has been entered press 0 (zero) \n";
while(cin>> data && data != 0)
{
arr.push_back(data);
++count;
}
cout<<count<<endl;
cout<<endl;
//display back data
cout<<"The numbers enterd are: "<<endl;
std:for_each(arr.begin(), arr.end(), print);
cout<<endl;
system ("pause");
return 0;
}
The code will access out-of-bounds of arr, which has zero elements, unless you enter 0 for the first prompt.
You didn't assign what you read to "elements or arr" (actually there will be no elements in arr) at all.
There will be no reason why you should use array of int to store float data.
You should use std::vector, which works as variable-size array.
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
int main ()
{
float data;
int count=0;
vector<float> arr;
//get amount of numbers inputted
cout<<"Please enter floating point data.\n";
cout<<"After the last number has been entered press 0 (zero) \n";
while(cin >> data && data != 0)
{
arr.push_back(data);
}
count = arr.size();
cout<<count<<endl;
cout<<endl;
//display back data
cout<<"The numbers enterd are: "<<endl;
for(int i=0; i<count; i++)
{
cout<<arr[i]<<endl;
}
cout<<endl;
return 0;
}
vector<int> var;
int numb;
cout<<"Enter number: ";
while (cin>>numb) {
if (cin.get()==char(32)) {
var.push_back(numb);
shellsort(var);
for (int i=0; i<var.size(); i++) {
cout<<var[i]<<" ";
}
} else if (cin.get()=='\n') {
break;
}
}
I used ascii code 32 to read space and a sort function. Loop the value to show current list. The problem is the current sorted list wont show during input of value. What to do?
You are calling, cin.get(), twice unnecessarily, fix that, and you are good to go.
Here is the fixed code:
vector<int> var;
int numb;
cout<<"Enter number: ";
while(cin>>numb)
{
char c = cin.get();
if(c==char(32))
{
var.push_back(numb);
shellsort(var);
for(int i=0;i<var.size();i++)
{
cout<<var[i]<<" ";
}
cout<<endl;
}
else if(c=='\n')
{
break;
}
}
Im a beginner to C++. Its my first year in college. Im completely stuck at this.I have to make a program which takes input 4 strings then check if some value already exists if it does then output value exists and thats it, if not, if they all are unique(all 4 strings) then output them in ascending order.Code bellow works and it already outputs them in ascending order, but how to find if values repeats before writing them?
sorry for my bad English guys i hope u understand what I am trying to say here
string name[4];
string temp;
for(int i=0;i<4;i++){
cout<<"Enter "<<i+1<<" string"<<endl;
getline(cin,name[i]);
}
for(int i=0;i<4;i++){
for(int j=i+1;j<4;j++){
if(name[i]>name[j]){
temp=name[i];
name[i]=name[j];
name[j]=temp;
}
}
}
for(int i=0; i<4; i++){
cout<<name[i]<< " ";
}
You could use the string comparison to check it before pushing it. This is if you want to check that the string is unique, not if you have shared words within each string (which is slightly more complicated.
string name[4];
string temp;
for(int i=0;i<4;i++)
{
cout<<"Enter "<<i+1<<" string"<<endl;
getline(cin,name[i]);
}
int failed = 0;
for(int i = 0;i<4;i++)
{
for(int j=0;j<i;j++)
{
// Check if the string is the same as any previous strings.
if (name[i].compare(name[j]) != 0)
{
failed = 1;
cout<<"String exists multiple times: "<<name[i];
}
}
}
// Check if there were any shared strings
if(failed==0)
{
for(int i=0; i<4; i++)
{
cout<<name[i]<< " ";
}
}
Reference:
http://www.cplusplus.com/reference/string/string/compare/
So the best way is going to be to use a better container!
Lets have a look at a std::set here.
std::set is an associative container that contains a sorted set of
unique objects.
So how can we best use this, there are many examples, but we can look at your particular one.
#include <set> // For Set
int main() {
set<string> names; // our fun easy ordered set.
string name; // a name to read in
unsigned int nameCounter = 0; // a counter
// loop until we have 4 correct names.
while (nameCounter < 4) {
cout<<"Enter "<<nameCounter+1<<" name"<<endl;
getline(cin,name);
// Check that when they enter it into the set that it is actually inserted.
// Here we are being clever because "insert" returns a tuple with a bool
// to tell us if we put it in correctly.
if (!names.insert(name).second) {
cout << "That was not unique!" << endl;
} else {
nameCounter++;
}
}
// Now we can loop through the names which is already sorted for us!
for (auto listName : names) {
cout << listName << " ";
}
cout << endl;
}
Wasn't that easy!? It is almost always better to utilize the std library than do things your self!
Here is a live example.
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((name[i]==name[j]) && (i!=j)){
cout<<"already exits";
}
I am making a number-guessing game where the user is asked to input a four-digit number. It is possible, however, that the user inputs less or more than four digits and/or a non-integer input (i.e. invalid input). My code stores the user input into an integer-type array. I just realized now that my code will still recognize "invalid inputs" as valid since the array where the input is being stored is declared as an integer-type. Below is a portion of my code:
#include <iostream>
using namespace std;
void guess(int num_guess[], int size);
int main(){
int list[4];
guess(list, 4);
for(int i = 0; i < 4; i++){
cout << list[i];
}
cout << endl;
}
void guess(int num_guess[], int size){
int number;
cin >> number;
for(int i = size-1; i >= 0; i--){
num_guess[i] = number%10;
number /= 10;
}
}
cout << list[i]; isn't really part of the original code, but this was how I found out that invalid inputs are still accepted. I encountered a similar problem before when I was making a rational roots calculator program in Python, but it was much easier then to detect and exclude unwanted inputs. My question is, how do I fix my code so that it can detect invalid inputs and output something like "Invalid input" and then proceed to ask the user for another input.
The following is a function to check if a string is a 4 digit positive integer. If the number could be negative, you just need to check if the s[0] == '-'.
bool check(string &s){
if(s.size() != 4) return false;
for(int i=0; i < 4; i++){
if(s[i] < '0' || s[i] > '9') return false;
}
return true;
}
The following is a function to convert a string to an int:
#include <stringstream>
int strToInt(string &s){
stringstream ss(s);
int ans;
ss >> ans;
return ans;
}
To exclude non integer inputs try the following:
void skip_to_int(){
// if is not an integer
if(cin.fail()){
// check character type
cin.clear();
char ch;
while(cin>>ch){
// throw away non digits
if(isdigit(ch)){
// put back if digit to be written
cin.unget();
return;}
}
}
else error ("no input");
}
And your input prompt function will look like this:
cout << "Please enter an integer" << endl;
int n=0;
if(cin>>n){
// integer OK, proceed
}
else{
cout << "That was not a numeric value, try again." << endl;
skip_to_int();}
Here's my solution. Beware, it uses C++11. Certainly not necessary if you use std::stringstream, but this should work pretty well.
I presume you don't want negative numbers. I also presume that any number of 0's in front doesn't make the number a 4-digit number. It will cut off padded 0's, so 01234 is a 4 digit number, but 0123 isn't.
void guess(int num_guess[], int size)
{
int number;
// if the length of the number isn't 4, try again until it is
do {
std::cin >> number;
if(std::to_string(number).length() != size)
std::cout << "You messed up the input. How hard could it be? Try again..." << std::endl;
} while(std::to_string(number).length() != size);
// by now, the size is definitely 4. insert it by digit into num_guess
for(int i = size-1; i >= 0; i++) {
num_guess[i] = number%10;
number /= 10;
}
}
#include <iostream>
#include <limits>
int main() {
int i = 0;
std::cout << "Please enter a number with four digits: ";
while( !(std::cin >> i) || !(i / 1000.0f >= 1.0f) )
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Invalid entry." << std::endl;
std::cout << "Please enter a number with four digits: ";
}
}
the std::cin.clear() clears all errors flags on current stream structure and std::cin.ignore() cleans up the input stream itself. Once we don't know the size of stream 'til this operation I have used the maximum possible value of a stream size to make sure any stream length could be cleaned.
add #include "math.h"
and change guess
void guess(int num_guess[], int size){
int number = 0;
bool firstTime = true;
do
{
if (!firstTime)
cout << " Error, try again " << endl;
firstTime = false;
cin >> number;
} while (number<pow(10, size-1) || number>=pow(10, size));
for(int i = size-1; i >= 0; i--){
num_guess[i] = number%10;
number /= 10;
}
}