I've started programming using C++ few weeks back.
I'm working on an application store user input data into an array list. When entering user data the application must be able to check whether the user already exists in the array list.
The program is unable to store the user input or able to check whether the user already exists in the array list..
int linearSearch(int array[], int size, int searchValue)
{
for (int i = 0; i < size; i++)
{
if (searchValue == array[i])
{
return i;
break;
}
}
return -1;
}
void customerReg(){
const int Capacity = 99;
int cnic[Capacity];
int customerNic;
int search = 0;
cout << "Enter Customer NIC: \n";
cin >> cnic[Capacity];
search = linearSearch(cnic, Capacity, customerNic);
if (search != -1){
cout << "Customer is already registered!\n";
}
else {
string customerName;
cout << "Enter Customer Name: \n";
cin >> customerName;
}
What about:
...
cout << "Enter Customer NIC: \n";
cin >> customerNic; // <=== instead of: cnic[Capacity];
Other remarks:
the break is not necessary: the return will already interupt the search loop
cnic[Capacity] is out of range, so puting a value in it might cause some troubles
cnic[] is not initialised
It is not clear how you fill cnic[], which is by the way local to the function and be lost as soon as you return from it.
Depending how you initalize/fill cnic, it could make sense to keep track of the number of customers that are registered in the table.
Edit:
I assume that you can't use vectors or maps for your exercise, and that you're right at the beginning of your learning.
So I suppose that customerReg() is the first function that you are working on, and that others will follow (display, delete, modifiy...). If this is the case, you have to keep your customer data outside the functions:
const int Capacity = 99;
int cnic[Capacity] {};
int customer_count=0; // counter to the last customer inserted
Then in customerReg() you should call your search function using the number of customers instead of the maximal Capacity:
search = linearSearch(cnic, customer_count, customerNic);
Later, in the else branch you have to insert the new id into the array:
else {
if (customer_count==Capacity) {
cout << "Oops ! Reached max capacity"<<endl;
else {
string customerName;
cout << "Enter Customer Name: \n";
cin >> customerName;
...
cnic[customer_count] = customerNic; // here you store the id
... // store (I don't know where) the other customer elements you've asked for
customer_count++; // increment the number of users that are stored.
}
}
Related
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 (¤t_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;
}
}
}
In my code, I want to add one student info into my class pointer array and the array size will increase each time a new student is added. Here is my code:
My header file:
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student();
void AddStudent(Student *tempStudent[], int countStudent, int sizeOfArray);}
My Class definition file:
void Student::AddStudent(Student *tempStudent[], int countStudent, int sizeOfArray)
{
for (int i = countStudent; i < sizeOfArray; i++)
{
cout << "Please enter student id (4 digits only): ";
cin >> tempStudent[i]->studentID;
cout << "Please enter student name: ";
cin >> tempStudent[i]->studentName;
}
}
My Main.cpp file
int *totalStudent = new int;
*totalStudent = 1;
int i, j, countStudent = 0;
int sizeOfArray = *totalStudent;
Student *newStudent[*totalStudent];
//Each time a new student is added, I will allocate a new memory for the array element, then add student Info using function.
for (i = countStudent; i < *totalStudent; i++)
{
newStudent[i] = new Student;
newStudent[i]->AddStudent(newStudent, countStudent, sizeOfArray);
countStudent++;
*totalStudent++;
}
When I run my code, I get an undefined reference error, so I do not know If I am able to increase my array or not. I intend to use C++ syntax so I use new and delete. Thank you for your help.
P.S: Here is my new code and it runs great, the only missing is the studentID for the first element in array.
In my main class:
int numStudent = 0;
int i, j, countStudent = 1;
Student *newStudent = new Student[countStudent];
AddStudent(newStudent, countStudent, numStudent);
My Student.h
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
};
Student AddStudent(Student *newStudent, int &countStudent, int &numStudent);
and My Student.cpp
Student AddStudent(Student *newStudent, int &countStudent, int &numStudent)
{
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
cin >> tempStudent.studentID;
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
newStudent[numStudent] = tempStudent;
numStudent++;
if (numStudent == countStudent)
{
Student *newStudentSize = new Student[countStudent + 1];
for (int i = 0; i < numStudent; i++)
{
newStudentSize[i] = newStudent[i];
}
delete []newStudent;
return *newStudentSize;
countStudent += 1;
}
}
Running this code will give me the following result:
StudentID: 11
StudentName: Dat
StudentID: 23
StudentName: Michael
Printing:
StudentID: 0
StudentName: Dat
StudentID: 23
StudentName: Michael
While it doesn't make sense to increase the array for each new student (it's inefficient) here's one way you can do it (I didn't even try to make your code compile because it has a number of issues and is unnecessarily complicated). Note that tempStudent (in the code snippet below) doesn't even have to be created using new. This solution stores Student objects in the students array (although it's easy to modify it to store Student object pointers instead). That said, usually, you'll just want to create an array of large enough size to accomodate all students (just set studentCount to some appropriate number and not 1 like in the example below).
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student(){};
};
int main(){
int studentCount=1;
Student * students = new Student[studentCount];
int numStudents=0;
bool done=false;
char finished='N';
while (!done){
//Student *tempStudent = new Student();
//create a Student on the stack
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
//No input checking is done here
cin >> tempStudent.studentID;
No input checking is done here
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
students[numStudents] = tempStudent;
numStudents++;
cout << "Stop entering students: Y or N";
cin >> finished;
done = finished=='Y' or finished=='y' ? true : false;
if(numStudents==studentCount){
students = ReallocateStudents(students, studentCount, studentCount*2);
studentCount *= 2;
}
}//end while
//print the students info
for(int i=0;i<numStudents;i++){
Student st = students[i];
cout << st.studentID << " " << st.studentName << std::endl;
}
//deallocate the students array or if you place this in the main like you did, the program will exit immediately so there's no need to deallocate
return 0;
}
Student * ReallocateStudents(Student* st, int oldSize, int newSize){
Student * newStudents = new Student[newSize];
//copy the existing values from the old array to the new one
for(int i=0;i<oldSize;i++){
newStudents[i] = st[i];
}
delete [] st; //delete the old array
return newStudents;
}
UPDATE:
Since you don't want to do everthing in the main(), just create a free AddStudents function and do everything there. Alternatively, you can create a
static function inside the Student class. It makes no sense to create AddStudent as a member of Student because that would require you to use an instance of Student to add a new instance, which makes for poor design (not to mention technical issues etc).
int main(){
// some code here
Students * allStudents = AddStudents();
//print students
}//end main
Students * AddStudents(){
int studentCount=1;
Student * students = new Student[studentCount];
int numStudents=0;
bool done=false;
char finished='N';
while (!done){
//create a Student on the stack
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
//No input checking is done here
cin >> tempStudent.studentID;
No input checking is done here
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
students[numStudents] = tempStudent;
numStudents++;
cout << "Stop entering students: Y or N";
cin >> finished;
done = finished=='Y' or finished=='y' ? true : false;
if(numStudents==studentCount){
students = ReallocateStudents(students, studentCount,
studentCount*2);
studentCount *= 2;
}
}//end while
return students;
}
This is simple and easy to both understand and maintain so I suggest using this approach.
addStudent does not do anything with the Student object it belongs to. So there is no need to put it in the 'Student' class. (Or you could rather rewrite it so it does something with the student object it belongs to). And it currently does not "add" anything, so the name is confusing.
What is technically wrong with it depends on what you want it to do. Currently it initializes student objects expected to already exist and pointed to by an array, from a specific array index, to the end of the array. That could well be a useful function, if that is what you want it to do. But you then must call it correctly with an array of pointers that point to valid Student objects, which you currently do not.
Currently in main you have a loop that initializes pointers in an array. And each time you initialize a pointer, you call AddStudent(..). The problem is that 'AddStudent()' tries to initialize ALL the student pointed to by your array.
This has two major problems (In addition to all the other problems with your loop).
Each time you create a new student, all your existing students will be
initialized again with new input from std::cin. (So for n students, you will
try to do n*n initializations)
While the loop in main is running, not all pointers in your array points
to existing Student objects. This may result in important data being
overwritten, a program crash or something totally different and unexpected.
You should sit back and reevaluate how you want to do things. Trying to fix single bugs in your existing code, one after another, will just create more bugs.
Just a hint to get you started:
class Student
{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student();
void init_from_cin();
};
And in your class definition file:
void Student::init_from_cin()
{
cout << "Please enter student id (4 digits only): ";
cin >> studentID;
cout << "Please enter student name: ";
cin >> studentName;
}
If you create a new Student like this:
Student *new_student = new Student;
new_student->init_from_cin();
Then after calling init_from_cin(), the Student object pointed to by new_student should be initialized.
How to create and initialize multiple Student objects in a loop, is left as exercise for the reader. But when you do it, you should understand what your lower and upper bounds of your loop are supposed to be. And you should also understand why moving the upper bound further away while your loop is running is a bad idea.
And never forget that sane programming languages start array indexing with 0.
I am working on an assignment which has the following goals:
Store user provided customer info into an array of structs.
Write functions to add, display all or retrieve a customer(s).
I have an issue with writing my findCust (retrieval routine). I would like to prompt the user for a first and last name of any customer, and then to find the relevant customer in the array of customers and print out their information. I'm kind of stuck and not sure how to proceed.
This is what I have so far:
void findCust(Customer customers[], int loc)
{
string name;
const int t = 100;
cout << "\nEnter the name of the customer you would like to look up: ";
getline(cin, name);
cout << endl;
for (int i = 0; i <= loc; i++) {
}
}
This is how the Customer struct is:
struct Customer {
string firstname;
string lastname;
Address home;
Address business;
};
Here's my main function:
int main() {
title("Customer Contact Menu");
int choice = 0;
int loc = 0;
const int SIZE = 100;
Customer contacts[SIZE];
while (choice < 5) {
choice = displayMenu();
switch (choice) {
case 1:
contacts[loc] = getCustomer();
loc++;
break;
case 2:
for (int x = 0; x < loc; x++) {
showCustomer(contacts[x]);
}
break;
case 3:
findCust(contacts,loc);
break;
case 4:
endProg();
}
}
}
I want to know how exactly to read information stored in the customer array, and compare it to the user input. I tried using a customer.compare command, I've tried a few things as well, I tried a linear search etc. But the problem with this is user input can't be compared to a structure. That's the part I'm stuck on.
If I understood your question correctly you want to read and find a customer, and then print their information. In order to do this I would structure the function like so:
void findCust(Customer customers[], int array_size)
{
string first_name, last_name;
cout << "\nEnter the name of the customer you would like to look up: ";
cin >> first_name >> last_name;
for (int i = 0; i < array_size; i++) {
}
}
Inside the for loop you can run a linear search and just iterate over all the customers and compare them. i.e. Go through the array and for each customers[i].firstname and customers[i].lastname check if they match the first_name and last_name variables.
If they do then call print(customers[i]) which is the function that will print out the given customer. You can have the function's definition be similar to void print(Customer customer) and this can contain all the printing to the stream.
Hopefully that helps you get started.
I have written a function in a program for entering a unique number but its not working. Something is wrong with the for loop.
I need to validate that employee id is unique.
I have made a structure named employee and "emp.id" is employee id. When the user inputs an id, it should not match previous Id's which user might have entered before. This is just a function of the main program, which validates that employee id is unique.
void uniquieid()
{
int check,i;
string code;
string tempemp1;
cout<< "enter id";
cin>> code;
while(!(num-1))
{
for(i=0;i<=num-1;i++)
{
if(emp[i].id.compare(code)==0)//comparing
{
check =1;
cout<<"enter id again";
break;
}
if(check=0) //csaasc
{
emp[i].id=code;
}
}
}
getch();
}
If the order that the ids are entered doesn't matter, I would do something like (note: untested):
using EmpIds = std::set<std::string>;
void addUniqueId(EmpIds& ids)
{
std::pair<EmpIds::iterator, bool> inserted;
const char* again = "";
do {
std::cout << "enter id" << again;
again = " again";
std::string id;
if (!(std::cin >> id))
throw std::runtime_error("No more ids!");
inserted = ids.insert(id);
} while (!inserted.second);
}
There are so many things wrong with the code, but maybe it should look more like this:
void uniqueid() {
int check=1;
string code;
string tempemp1;
cout<< "enter id";
while(check) {
cin >> code;
check = 0;
for (int i = 0; i < num; ++i) {
if (emp[i].id.compare(code)==0) {
check = 1;
cout << "enter id again";
break;
}
}
if (check==0) {
/* emp[i].id=code; */
}
}
getch();
}
Note how int check=1; starts at 1 to mean that the code needs re-entering.
So while(check) means that while the code is not unique keep going.
The for loop does the compare as before, but note the idiomatic form.
The other if (check==0) is outside the for loop and this means that no duplicates were detected so code can be used. However, I'm not sure which employee the code should apply to so I've just commented out the code.
Can you post the employee structure?
Because from this, everything looks OK, but your if function refers to emp.
So something in your structure is causing the problem.
Without your structure, anyone answering probably won't be able to find the problem.
Right now, all i can advise you to do is store employee ids in a vector and iterate through it using a for loop.
You could do
void uniqueid() {
std::vector<std::string> empIds;
std::string code;
CODE TO STORE IDs INTO VECTOR HERE;
int vectorLength = empIds.size();
std::cout << "enter id";
std::cin >> code;
for (int i = 0; i < vectorLength; i++) {
if (empIds[i] == code) {
std::cout << "enter id again";
std::cin >> code;
} else {
empIds.push_back(code);
}
}
}
For a start, something like the below should work.
map <string, bool> seen;
bool isUniqueId(string id)
{
return seen[id];
}
void addId(string id)
{
seen[id] = true;
}
From main(), whenever user inputs a string id, use isUniqueId(id) to ensure its unique, and if its unique, call addId(id).
Edit : (upon request from the OP)
Your transformed code may look like below after using map.
// Global map, defaults to false
map <string, bool> seen; // seen map to store if an id is seen already or not.
void uniqueId()
{
bool good = true; // set up a good flag to check if id is good or not.
int numEmployees = 0; // Count to store number of employees with unique ids so far
string id;
cout<< "enter id\n";
cin>> id;
while(good)
{
good = false; // Assume this is unique!
if(seen[id]) // Check if we already saw this id before
{
good = true; // Alas! We already have seen this id
cout<<"enter id again\n";
continue; // If id already exists, ask for another id setting good = true;
// Note that the above continue is NOT required as loop will run again (good = true).
// Just for clarity sake.
}
else
{
// Voila, we have a new employee with unique id.
seen[id] = true; // Unique, mark as seen now
emp[numEmployees].id=code; // Note numEmployees here
numEmployees++; // Increment the count
}
}
getch();
}
At the end of while loop, you would have successfully gotten a unique id from user, otherwise it will keep asking the user for new id.
I'm really confused. I have to make this lab for a class and I can't seem to have the search only display one result but all of the months of the year. I also can't seem to figure out why its not displaying the TotalRainfall when I input 0 into the month of the year.
Thank you.
#include <iostream>
#include <fstream>
const int MaxSize = 12; //How many weather lines will be available.
using namespace std;
struct WeatherInformation
{
int Month; //Months of the year
float TotalMonthsRainfall; //Total amount of rainfall
float HighTemp; //The Highest temperature of the month.
float LowTemp; //The Lowest temperature of the month.
float AverageTemp; //The Average temperature of the month.
};
WeatherInformation WeatherArray[MaxSize]; //Declaring a month array of MaxSize
void ReadFile(ifstream& MyinFile, WeatherInformation WeatherArray[]);
void WeatherMonthSearch (WeatherInformation WeatherArray[]);
int main()
{
float TotalRainfall = 0;
int count = 1; //Counts how many times the for loop goes.
int MonthOfWeather; //User input of the month.
char ProgramRedo; //User input if they want to reuse the program.
char exit_char; //User input to exit the program.
ifstream MyinFile; //Variable that uses file.
ReadFile (MyinFile, WeatherArray); //Call ReadFile Function
WeatherMonthSearch (WeatherArray); //Call WeatherMonthSearch Function
MyinFile.close(); //Closes file.
}
//Brett Holmes
//4/30/2013
//PreCondition:You need a file labeled weather.dat
//PostCondition: It puts the file variables into an array.
void ReadFile(ifstream& MyinFile, WeatherInformation WeatherArray[])
{
float TotalRainfall = 0;
char exit_char;
int count = 0;
int Month = 0;
cout << "Your Weather Machine" << endl << endl;
MyinFile.open("weather.dat");
if (!MyinFile)
{ //no
cout << "Can't open input file." << endl; //Tests the right file.
char exit_char; //End Program
cout << "Press any key to exit" << endl;
cin >> exit_char;
}
for(count = 1; count < MaxSize; count++) //Puts the file variables in the array.
{
WeatherArray[count].Month = WeatherArray[count].Month + 1;
MyinFile >> WeatherArray[count].TotalMonthsRainfall;
MyinFile >> WeatherArray[count].HighTemp;
MyinFile >> WeatherArray[count].LowTemp;
(WeatherArray[count].AverageTemp = ((WeatherArray[count].HighTemp + WeatherArray[count].LowTemp)/2));
(TotalRainfall = TotalRainfall + WeatherArray[count].TotalMonthsRainfall);
}
}
//Brett Holmes
//4/30/13
//PreCondition:You need to have the months already put into an array in a struct.
//PostCondition:Outputs the rainfall stats the user puts in then asks to run again.
//Outputs a error message if they type in the month wrong.
void WeatherMonthSearch (WeatherInformation WeatherArray[])
{
float TotalRainfall;
int months;
int MonthOfWeather;
char ProgramRedo;
do
{
bool MonthFound = false;
cout << "Please input the number of the Month. Ex. 1=Jan. 2=Feb. etc \n\n";
cin >> MonthOfWeather;
for(int i = 1; i <= MaxSize; i++)
{
months = WeatherArray[i].Month;
if(months == MonthOfWeather ) //Finds the artist and outputs the results
{
cout << "\nTotal Months Rainfall: " << WeatherArray[i].TotalMonthsRainfall << " \n";
cout << "Highest Temperature: " << WeatherArray[i].HighTemp << " \n";
cout << "Lowest Temperature: " << WeatherArray[i].LowTemp << " \n";
cout << "Average Temperature: " << WeatherArray[i].AverageTemp << " \n";
MonthOfWeather = true;
}
}
if(MonthOfWeather == 0)
{
cout << "The total rainfall for the year is: " << TotalRainfall << ".";
}
if(MonthFound == false)
{
cout << "\nMonth Number error. Month not found. Try again.\n\n";
MonthOfWeather = false;
}
cout << "Would you like to look up another month of weather?\n";
cout << "Enter a 'Y' if yes and 'N' if no.\n";
cin >> ProgramRedo;
}while(ProgramRedo == 'Y');
}
Several obvious problems:
Arrays in C++ is 0-based, so your for loop is off-by-one. In your search function, for(int i = 1; i <= MaxSize; i++) should be for(int i = 0; i < MaxSize; i++). Similarly, in your read function, for(count = 1; count < MaxSize; count++) should be for(count = 0; count < MaxSize; count++) (If you want to skip index 0 because you are using it as a signal value, then you should set MaxSize to 13 and have the loop start at 1.)
Why are you assigning a boolean to MonthOfWeather? Do you mean MonthFound?
You read function is not setting the months correctly. WeatherArray[count].Month = WeatherArray[count].Month + 1; should be WeatherArray[count].Month = count; if you are using a 1-based loop or WeatherArray[count].Month = count + 1; if the loop is 0-based.
You calculated your total rainfall in the read function, but the result is stored in a local variable so it's lost when the read is done. Either make TotalRainfall a global variable or do your calculations in your search function.
There are a lot of redundant variable definitions: for example, your weather data array is a global so there is no reason to actually pass it around; exit_char is declared twice in your read function; the first five lines of your main() declared variables that you never used.
Also, your read function does not actually exit the program on failure - it even still attempts to read from the stream and then call your search function! If error-checking is a requirement, you should either have the read function return a boolean and check that the read function succeeded before calling your search function, or simply call std::exit after that cin >> exit_char;.
So, one problem you have is that you have local variables that appear in multiple places, but appears like you expect them to actually contain the same information.
For example, I see three different TotalRainFall. One in main, which is just there, not used for anything, one in ReadFile which is calculated, and one in WeatherMonthSearch, which is not set to anything.
I suspect you want all three of these to actually do something. One way to achieve that would be to remove the local ones in ReadFile and WeatherMonthSearch, and instead pass in the one from main (as a reference into ReadFile).
There's also a few places where you use variables without initializing them. Make it a habit to initialize EVERYTHING and EVERYWHERE!
Enable warnings in your compiler - if you have any form or reasonably new compiler (gcc or MS Visual Studio of recent vintage), it should tell you at least some of these things.