strcpy_s unhandled exception? - c++

I'm trying to use strcpy_s, but I'm having this error:
Unhandled Exception...
struct Item {
//Item's
int code; // Code
char* name[20];
int amount; //Amount in stock
int minAmount; //Minimum amount
float price; //Price
};
The important lines are the beginning and the line with the "#########" beside it. (spot = 0, name string was received, store was initialized in main()).
//add an item to store
void addItem(Item* store, int maxItems, int &numItems)
{
if (maxItems == numItems)
{
cout << "ERROR \n";
return;
}
int spot = numItems; // our item's spot in store[]
int code; // inputted code
//Item's attributes' input
cout << "enter code : \n"; //code
cin >> code;
store[spot].code = code; //Code
cout << "enter name : \n"; //Name
_flushall();
char* name = new char[20];
gets_s(name, 20);
numItems++; //forward the number of items
strcpy_s(*store[spot].name, 20, name); //Name UNHANDLED EXCEPTION ############################
cout << "enter amount : \n"; //Amount in stock
do
{
cin >> store[spot].amount;
if (store[spot].amount < 0) //not negative
cout << "ERROR \n";
} while (store[spot].amount < 0);
cout << "enter minimum amount : \n"; //Minimum amount for orders
do
{
cin >> store[spot].minAmount;
if (store[spot].minAmount < 0) //not negative
cout << "ERROR \n";
} while (store[spot].minAmount < 0);
cout << "enter price : \n"; //Price
do
{
cin >> store[spot].price;
if (store[spot].price < 0) //not negative
cout << "ERROR \n";
} while (store[spot].price < 0);
}

I would advice you to test calling strcpy_s and every other suspicious part of the code separately and see it there is any problem, if there is, work around it and then insert it in the addItem function.
From is visible in the posted code, you seem to be passing a pointer variable with the dereference operator in front of it in most of the functions you use, for example the signature of strncpy_s() is:
errno_t strncpy_s(char *restrict dest,
rsize_t destsz,
const char *restrict src,
rsize_t count);
You need to pass the first parameter without the * as it is a pointer: Item* store, i.e. as pass it as: store[spot].name.
Check this article about pointer assignment, which will help you understand how to pass a pointer as an argument to a function.
Edit after a comment
Your second error message could be because the member name of store is not a pointer, you probably need to pass it using & operator, i.e. pass its address:
strcpy_s(&store[spot].name, 20, name);

Related

Function with structure as argument producing error: free(): invalid pointer: 0x00007efd47b

I've made an addDepartment function that takes a structure as an argument. When I enter input to initialize the "dept[counter].departmentHead" at the bottom of the function, it triggers the error message.
I'm copying the logic from another code I wrote using classes instead of structures and that one works fine so I'm really not sure why this one isn't working. Tried messing with the index to make sure I wasn't going over the size of the array but that doesn't seem to fix the issue.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstring>
using namespace std;
struct Department{
string departmentName;
string departmentHead;
int departmentID;
double departmentSalary;
};
//...
Department addDepartment(Department dept[3]){
int repeat=0;
int counter=0;
if (counter>2){
cout<<"The array is full, you can not add any more Departments."<<endl;
}
else{
cout << "Please Enter Department Details:"<<endl;
cout << "Department ID : ";
cin >> dept[counter].departmentID;
for(int x=0; x<3; x++){
for (int y=x+1; y<3; y++){
if(dept[x].departmentID==dept[y].departmentID)
repeat++;
}
}
if(repeat!=0)
cout<<"Value must be unique!"<<endl;
else{
cout << "Department Name : ";
cin >> dept[counter].departmentName;
cout << "Head of Department : ";
cin >> dept[counter].departmentHead;
counter++;
}
}
}
//...
int main()
{
Employee emp[5];
Department dept[3];
initialID(emp,dept,0);
initialID(emp,dept,1);
int response;
while(response!=6){
displayMenu();
cout<< "Please make a selection : \n";
cin >> response;
while((response!=1)&&(response!=2)&&(response!=3)&&(response!=4)&&(response!=5)&&(response!=6)){
cout<< "Please enter a valid choice (1 - 6): ";
cin >> response;
}
if(response==1){
addDepartment(dept);
}
else if(response==2){
//addEmployee(emp,dept);
}
else if(response==3){
}
else if(response==4){
}
else if(response==5){
//salaryReport(dept);
}
}
cout << "Thank you, goodbye.";
}
Why it breaks.
The addDepartment function never actually returns a department. When the function exits, the space where the return newly created Department would be is left uninitialized. This causes undefined behavior. The compiler tries to destruct the Department object like it normally would, but because it was never initialized, free gets called on garbage (causing the error).
We can fix this by adding a line to addDepartment returning the actual department:
Department addDepartment(Department dept[3]){
int repeat=0;
int counter=0;
if (counter>2){
cout<<"The array is full, you can not add any more Departments."<<endl;
}
else{
cout << "Please Enter Department Details:"<<endl;
cout << "Department ID : ";
cin >> dept[counter].departmentID;
for(int x=0; x<3; x++){
for (int y=x+1; y<3; y++){
if(dept[x].departmentID==dept[y].departmentID)
repeat++;
}
}
if(repeat!=0)
cout<<"Value must be unique!"<<endl;
else{
cout << "Department Name : ";
cin >> dept[counter].departmentName;
cout << "Head of Department : ";
cin >> dept[counter].departmentHead;
counter++;
}
}
return /* some department */;
}
Alternatively, you could make addDepartment void.
Other considerations. Don't pass raw C arrays to functions. It doesn't do what you intend.
If you want to pass a copy of an array, pass a std::array, which will be copied automatically:
Department addDepartment(std::array<Department, 3> dept);
If want to access the elements of an existing array, pass a pointer:
Department addDepartment(Department* dept, int count);
One problem that I see is that you are creating an array of 3 Department objects in main and assuming that you have 5 elements in initialID.
Change main to create an array of 5 Department objects.
int main()
{
Employee emp[5];
Department dept[5];
...

File I/O Binary Dynamic Array Crashed

#include iostream
#include cmath
#include fstream
#include cstdlib
#include string
using namespace std;
class Device {//Input and store Device Description and Serial Numbers
protected:
string serial_number;
string device_description;
public:
Device() {
serial_number = ("6DCMQ32");
device_description = ("TheDell");
}
};
class Test {//Input and store Test Description, recent day, and month;
Calculate the next day
protected:
string Test_Description;
static int recent_month, recent_day, recent_year, new_month;
static int nmonth, next_month, next_day, next_year, max_day;
public:
Test() {
Test_Description = ("Virtual");
}
static void getMonth(ostream & out) {//Calculates the next/new month
next_month = recent_month + nmonth;
new_month = next_month % 12;
if (next_month >= 12) {
cout << "The next Date: " << new_month << " / ";
}
else {
out << "The next Date: " << next_month << " / ";
}
}
static void getDay(ostream & out) { //Calculates day of next month
if (new_month == 4 || new_month == 6 || new_month == 9 || new_month == 11) {
max_day = 30;
}
else if (new_month == 2) {
max_day = 29;
}
else {
max_day = 31;
}
if (recent_day > max_day) {
out << max_day << " / ";
}
else {
out << recent_day << " / ";
}
}
static void getYear(ostream & out) {// Calculate the year of next month
next_year = recent_year + next_month;
if (next_year >= 12) {
out << recent_year + (next_month / 12) << endl;
}
else {
out << next_year << endl;
}
}
static void getDate(ostream & out) {// Collects the output of each element of next date
getMonth(out), getDay(out), getYear(out);
}
};
int Test::recent_month;
int Test::recent_day;
int Test::recent_year;
int Test::new_month;
int Test::nmonth;
int Test::next_month;
int Test::next_day;
int Test::next_year;
int Test::max_day;
class Lab : public Device, public Test {
protected:
static int n;
public:
friend istream & operator>>(istream & in, Lab & lab) {// Inputs
cout << "Enter Device Desciption and Serial Number: ";
getline(cin, lab.device_description);
getline(cin, lab.serial_number);
cout << "Enter Test Desciption: ";
getline(cin, lab.Test_Description);
cout << "Enter the Number of months: ";
in >> nmonth;
cout << "Enter the Most Recent Date(mm/dd/yyyy): ";
in >> recent_month >> recent_day >> recent_year;
return in;
}
friend ostream & operator<<(ostream & out, Lab & lab) {//Outputs everything in Device Class
out << lab.device_description << endl;
out << lab.serial_number << endl;
out << lab.Test_Description << endl;
getDate(out);
return out;
}
static void getN() {
cout << "Enter the number of devices: ";
cin >> n;
}
static void getWrite() {
Lab *obj = new Lab[n];
if (obj == 0) {
cout << "Memory Error";
exit(1);
}
for (int i = 0; i<n; i++) {
cin >> obj[i];
cout << endl;
}
ofstream myfile("Device.dat", ios::binary);
myfile.write((char*) obj, n * sizeof(Lab));
delete[] obj;
}
static void getRead() {
ifstream file2("Device.dat", ios::binary);
Lab *obj2 = new Lab[n];
if (obj2 == 0) {
cout << "Memory Error";
exit(1);
}
file2.read((char*) obj2, n * sizeof(Lab));
for (int i = 0; i < n; i++) {
cout << obj2[i];
cout << endl;
}
delete[] obj2;
}
};
int Lab::n;
void main() {
Lab L;
L.getN();
L.getWrite();
L.getRead();
getchar();
getchar();
system("pause");
}
The program keeps on crashing after outputting the values
Purpose: is to enter the number of months for the next test date of device with input of serial number,
Device Description, Test Description, recent date, and the number of months of two tests. At the end the
program must be searched by having the user to input the serial number and the next date, if these two are
valid everything in the device is listed out.
I am using Microsoft Visual Studios 2017
std::string is far too complicated a data structure to simply write to a file unfortunately. At it's simplest, a string is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness. Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code. Either way accessing memory that has not been assigned to the pointer invokes Undefined Behaviour, and with UB anything can happen. Don't count on crashes or consistency.
Generally you would use your operator << overloads to serialize the structure to the file rather than trying to binary write. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.
The protocol is going to be a set of functions that convert simpler data types to and from their file equivalents.
A typical method for writing a string is to first write the length of the string and then write the contents of the string. Something like
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
And reading
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
bundle these up inside functions and you've started on your protocol. Add to them functions for other data types you need to store.
These functions are then called by functions that convert larger datatypes and on up until you reach the most complex of the structures you need to write. For an array, use a loop. If you have a length of variable size, prefix the length just like with a string.
Side note: When reading or writing numbers care must be taken to ensure the number is a known, fixed size. int, for example, can be any size 16 bits or greater so long at it's not larger thanlong. You don't necessarily know that the file reader will be using the same sizedint`, so you should prefer a Fixed Width Integer large enough to store the values required. Different computers also may store their binary information in different orders. This is called Byte Order or Endian. Make sure everyone is using the same endian.

Sorting Linked Lists - move nodes or swap data members?

I have a simple question. I'm working on a C++ app that is a contact list app. It stores names, addresses, numbers, ages, etc for multiple people. I'm using stucts and linked lists (nodes). I'm building the sort list function, to alphabetize the list. I'm currently wondering if it's better to actually reorder the list by moving the structs as a whole or by swapping the data members inside each node. At first, I considered moving the nodes, but now swapping the data members seems more safe, as I don't have to reorder the list. At any rate, I don't know if either possesses any benefits over the other.
EDIT: Here's the source code I'm working on. Notice the sort function is incomplete. Also, I'm still a novice programmer, so the coding will probably have a ton of issues, from a professional standpoint. That, alongside the fact I'm not close to being done with it. I'm only writing it to practice coding over my summer break between programming classes.
#include <iostream>
#include <fstream>
#include <string.h>//for functions in date function
#include <time.h> //for functions in date function
#include <sys/stat.h>//for mkdir functions
#include <unistd.h>//for usleep function
#include <ctype.h>//for toupper function in swap function
using namespace std;
struct PersonInfo
{
char FirstName[20];
char LastName[20];
char Address[40];
char PhoneNumber[20];
int Age;
PersonInfo *Link;
};
bool EmptyFileChecker(ifstream &FI, const char *P);
void AddPeopleToList(PersonInfo *&HeadPointer);
void RebuildOldList(ifstream &FI, PersonInfo *&HeadPointer, const char *P);
void DisplayList(PersonInfo *HeadPointer);
void SaveSettings(ofstream &FO, const PersonInfo *HeadPointer, const char *P);
void DisplayMenu(PersonInfo *&HeadPointer, const char *P, ifstream &FileIn, ofstream &FileOut);
void SortContacts(PersonInfo *&HeadPointer);
bool NamesInOrder(const char LastName1[], const char LastName2[]);
string Date();
//Delete Contact
//ENCRYPT LIST?
//Check for memory leaks in code and destructor?
//Return something - noun-like
//void adjective - like
int main()
{
PersonInfo *HeadPointer;
const char *Path = "/Users/josephlyons/Library/Application Support/The Lyons' Den Labs/TheLyons'DenContactInformation.txt";//code variable for username
ifstream FileIn;
ofstream FileOut;
mkdir("/Users/josephlyons/Library/Application Support/The Lyons' Den Labs", ACCESSPERMS);//MODE??
if (!EmptyFileChecker(FileIn, Path))
AddPeopleToList(HeadPointer);
else
RebuildOldList(FileIn, HeadPointer, Path);
DisplayMenu(HeadPointer, Path, FileIn, FileOut);
//SortContacts(HeadPointer);
SaveSettings(FileOut, HeadPointer, Path);
}
void DisplayMenu(PersonInfo *&HeadPointer, const char *P, ifstream &FileIn, ofstream &FileOut)
{
short int MenuChoice;
do
{
cout << "(1) Display Contact List\n";
cout << "(2) Organize Contact List\n";//delete when done with program and automatically sort list before saving.
cout << "(3) Add Contact/s\n";
cout << "(4) Delete Contact/s\n";
cout << "(5) Quit\n\n";
cout << "Choice: ";
cin >> MenuChoice;
if (MenuChoice == 1)
DisplayList(HeadPointer);
else if (MenuChoice == 2)
SortContacts(HeadPointer);
else if (MenuChoice == 3)
AddPeopleToList(HeadPointer);
else if (MenuChoice == 4)
cout << "choice 4";
}
while(MenuChoice != 5);
}
bool EmptyFileChecker(ifstream &FI, const char *P)//DONE
{
FI.open(P);
if (FI.fail())
return false;
else if (FI.eof())//return 0 if file doesnt exist or if file is empty
return false;
else
return true;
}
void AddPeopleToList(PersonInfo *&HeadPointer)
{
PersonInfo *CurrentPosition;
char UserChoice;
do
{
CurrentPosition = new PersonInfo;
if (CurrentPosition == NULL)
{
cout << "Not enough memmory to make new contact.";
return;
}
cout << "\nEnter First Name: ";
cin >> CurrentPosition->FirstName;
CurrentPosition->FirstName[0] = toupper(CurrentPosition->FirstName[0]);//automatically capitalize first name
cout << "Enter Last Name: ";
cin >> CurrentPosition->LastName;
CurrentPosition->LastName[0] = toupper(CurrentPosition->LastName[0]);//automatically capitalize last name
cin.ignore();//flushes a single newline left in input buffer from previous cin >>
cout << "Enter Adress: ";
cin.getline(CurrentPosition->Address, 40);//using cin.get() to allow for spaces in address
cout << "Enter Phone Number: ";
cin.getline (CurrentPosition->PhoneNumber, 20);//using cin.get() to allow for spaces in number
cout << "Enter Age: ";
cin >> CurrentPosition->Age;
cout << "\nAdd another contact? Y/N: ";
cin >> UserChoice;
cout << "\n";
CurrentPosition->Link = HeadPointer;
HeadPointer = CurrentPosition;
}
while (UserChoice == 'y' || UserChoice == 'Y');
SortContacts(HeadPointer);
}
void RebuildOldList(ifstream &FI, PersonInfo *&HeadPointer, const char *P)
{
PersonInfo *TemporaryPersonPointer;
char EndOfListChecker = 1;//initialized at a not 0 to allow entrance into loop
while (EndOfListChecker != 0)
{
TemporaryPersonPointer = new PersonInfo;
if (TemporaryPersonPointer == NULL)
cout << "Not enough memory to generate the full list";
FI >> TemporaryPersonPointer->FirstName;
FI >> TemporaryPersonPointer->LastName;
FI.ignore();//flushes a single newline from input
FI.getline(TemporaryPersonPointer->Address, 40);
FI.ignore();
FI.getline(TemporaryPersonPointer->PhoneNumber, 20);
FI >> TemporaryPersonPointer->Age;
TemporaryPersonPointer->Link = HeadPointer;
HeadPointer = TemporaryPersonPointer;
FI.get(EndOfListChecker);
while (EndOfListChecker == '\n')
{
FI.get(EndOfListChecker);
}
if (EndOfListChecker != 0)
FI.putback(EndOfListChecker);
}
}
void DisplayList(PersonInfo *HeadPointer)
{
do
{
cout << "\nFirst Name: ";
cout << HeadPointer->FirstName << endl;
cout << "Last Name: ";
cout << HeadPointer->LastName << endl;
cout << "Adress: ";
cout << HeadPointer->Address << endl;
cout << "Phone Number: ";
cout << HeadPointer->PhoneNumber << endl;
cout << "Age: ";
cout << HeadPointer->Age;
cout << "\n\n";
HeadPointer = HeadPointer->Link;
usleep(75000);
}
while (HeadPointer != NULL);
cout << "Press enter to go to main menu: ";
cin.ignore(2);
cout << "\n";
}
void SaveSettings(ofstream &FO, const PersonInfo *HeadPointer, const char *P)
{
FO.open(P);
if (FO.fail())
cout << "Couldn't Open File\n";
while (HeadPointer != NULL)
{
FO << HeadPointer->FirstName << endl;
FO << HeadPointer->LastName << endl;
FO << HeadPointer->Address << endl;
FO << HeadPointer->PhoneNumber << endl;
FO << HeadPointer->Age << endl << endl;
HeadPointer = HeadPointer->Link;
}
FO << (char) 0 << endl;
FO << "Date of Settings: " << Date() << endl;
FO.close();
}
void SortContacts(PersonInfo *&HeadPointer)
{
PersonInfo *MovingPointer1;//used to "crawl" down list
PersonInfo *MovingPointer2;//used to "crawl" down list
PersonInfo *StaticPointer;//always points at first node to give HeadPointer a way to link back to the list at end
PersonInfo *TemporaryPointer;//holds a node during a swap
bool ZeroSwapsOccured = false;//initialized at false to allow entrance into loop once
MovingPointer1 = StaticPointer = HeadPointer;//set all to point at first node
MovingPointer2 = HeadPointer->Link;
while (ZeroSwapsOccured == false)
{
ZeroSwapsOccured = true;
while (MovingPointer2->Link != NULL)
{
if (!NamesInOrder(MovingPointer1->LastName, MovingPointer2->LastName))
{
ZeroSwapsOccured = false;
//Temp = MP1
//MP1 = MP2
//MP2 = TEMP
MovingPointer1->Link = MovingPointer2->Link;
MovingPointer2->Link = MovingPointer1;
HeadPointer->Link = MovingPointer2;
}
}
}
HeadPointer = StaticPointer;//link HeadPointer back to list after sort
}
bool NamesInOrder(const char LastName1[], const char LastName2[])
{
for (int i = 0; LastName1[i] || LastName2[i]; ++i)//go until you get to the end of the larger name
{
if(toupper(LastName1[i]) < toupper(LastName2[i]))
return true;
if(toupper(LastName1[i]) > toupper(LastName2[i]))
return false;
}
return true;//this will only be used if same last name
//build in fucntionality to then go to first name after last name, if both last names are the same
}
string Date()//not my code here - just modified it to read easier
{
char Time[50];
time_t now = time(NULL);
strftime(Time, 50, "%b, %d, %Y", localtime(&now)); //short month name
return string(Time);
}
First - You're reordering the list in both cases.
Second -
Swapping two nodes usually takes five operations:
Change the node one back from the first node to point to the second node.
Change the node one back from the second node to point to the first node.
Store the first node's next pointer in a temporary pointer.
Change the first node's next pointer to the second node's next pointer.
Change the second node's next pointer to the temporary pointer.
Swapping two variables takes at least three operations:
Store the first variable in a temporary variable.
Change the first variable to the second variable.
Change the second variable to the first variable.
But now multiply that by the number of struct members.
The struct should have at least 2 data members - a pointer and a payload - so off the bat you're looking at, at least, 6 operations. Which will increase by 3 for each member in the struct. So you're better off just swapping the nodes.
No memory should be moving. The nodes in a linked list are not ordered in memory but only in relation to each-other via pointer(s) to the next/previous nodes in the list. your operation can be done with only a few pointer assignments.
Swapping the data is more costly and complex. For example, to swap the data, you will need to swap the name, address, numbers, ages etc.
On the other hand, swapping the node means just swapping two memory location address inside your list. So, swapping the nodes is highly preferable.
Secondly, if you add more metaData fields to your node, you won't have to change the sort code to swap the newly added data field.
So you have a linked list that you want to sort. To do it correctly and efficiently you have to use the correct sorting algorithm which in this case is the Merge Sort. For sure you should not swap the nodes' data.
Check this link: http://www.geeksforgeeks.org/merge-sort-for-linked-list/
If node data size is larger, that time it's better to swap node's position rather than swap node's data (swapping data will be bad choice).
Reasons of choosing moving the pointer implementation over swapping the data:
Let's suppose you want to add a new field to your contact list after some time. If you swap data, you will have to change your code every time you make changes to your contact list field.
As fields in contact list increase, overhead for swapping the data will grow.

Array of structs prints zeros when called, but displays correct input when not called (short code)

The purpose of the program is a bank account interface, where the user can create 4 accounts and can transfer funds between them. I opted for an array of structs to handle the “bank account” info, and a switch to handle the user options.
Problem:
The account creation function, called in case ‘a’, appears to create the accounts as intended, and displays them properly. However, the results in the other cases are not as designed.
Case ‘b’ will display the inputted array information, only if nothing is called (including the function that displays the array information), otherwise when the display() is called it prints zeros (what it is initialized to before account creation).
Case ‘c’ will display the inputted array information if nothing is called, as well as if only the function which displays the date/time is called. Otherwise it prints zeros.
Question:
Why is the array of structs displaying zeros when I call the display function, but will display the user input when it’s not called, as long as nothing else is (except the time function in case ‘c’), and what can I do to fix it?
Notes:
I converted the account creation function to return a pointer to the struct hoping that might help, it didn’t seem to change anything. I converted the switch statement to a series of if’s to see if that would change anything, it did not (reversed back to switch). Case ‘d’ and case default work as intended. The Program is not complete (my transfer() isn’t written). I’m aware “using namespace std;” is a nono.
I appreciate your time and any advice offered.
#include <iostream>
#include <ctime>
const int SIZE = 4;
using namespace std;
struct bank //Bank Account Structure to hold account numbers and balances
{
int num; // number of account
int checkdigit; // ending account number checkdigit appended to account number
float bal; // balance of account
};
void menu(); //MenuPrompt
bank* input(bank[]); // Struct Account Input
void display(bank[]); // Struct Account Display
void initialize(bank[]); // Struct Account Initialization
char transferprompt(bank s[]); // Transfer Menu
int createaccounts(); //Create Account Numbers and Balances
void time(); //Displays the Current date, month, year, and time.
void clearscreen(); //Prints 40lines to clear the screen
int main()
{
bank accounts[SIZE]; // Array of bank-account structs
initialize(accounts); // Removes garbage values
char select; //User input variable
bank *ptr;
ptr = &accounts[0];
menu(); //Runs MenuPrompt
cin >> select; //Grabs user input
select = static_cast<char>( tolower( select ) ); //Ensures user input is lowercase (for switch statement)
clearscreen();
switch ( select )
{
case 'a': //Creates Accounts
input(accounts);
clearscreen();
main();
display(accounts);
break;
case 'b': //Transfers between accounts
//display(accounts);
transferprompt(accounts);
//main();
break;
case 'c': //Displays day, month, year, time, + Account Information.
time();
break;
case 'd': //Exits Program
break;
default: //Invalid Input failsafe; Restarts menu prompt.
cout<<"Invalid selection. Restarting...\n";
main();
break;
}
}
char transferprompt(bank s[])
{
}
bank* input(bank s[]) // Creates Bank Accounts
{
bank accounts[SIZE]; // Array of bank-account structs
bank *ptr; // Pointer to struct
ptr = &accounts[0]; // Points pointer to array of bank-account structs
cout << "Account Creation Selected; Create " << SIZE << " accounts..." << endl;
for (int i = 0; i < SIZE ; i++)
{
cout << "Enter Account Number: ";
cin >> s[i].num;
s[i].checkdigit = s[i].num % 5;
cout << "Enter Account Balance: ";
cin >> s[i].bal;
}
return ptr;
}
void display(bank s[]) //Displays Bank Accounts
{
for (int i = 0; i < 4; i++)
{
cout << "Account: " << s[i].num << s[i].checkdigit;
cout << " has balance: $" << s[i].bal << endl;
}
}
void initialize(bank s[]) // Removes Garbage values
{
for (int i = 0; i < 4; i++)
{
s[i].num = 0;
s[i].checkdigit = 0;
s[i].bal = 0;
}
}
void clearscreen() // Clears screen
{
cout << string(40, '\n');
}
void time() // Display Time function
{
time_t t = time(NULL);
tm* ptr = localtime(&t); // ptr = Pointer to compute time
cout << endl;
cout << endl;
cout << "Date: " << (ptr->tm_mon)+1 <<"/"<< (ptr->tm_mday)<< "/" << (ptr->tm_year)+1900 << endl;
cout << "Time: " << (ptr->tm_hour) <<":"<< (ptr->tm_min)<< ":" << (ptr->tm_sec) << endl;
}
void menu() // Menu Prompt
{
cout << "Parkville Bank Client Program; Edit your accounts:\n";
cout << "a. Create " <<SIZE<<" accounts\n";
cout << "b. Transfer money from 1 account to another\n";
cout << "c. Display account balances\n";
cout << "d. Quit the program\n\n";
}
This function is not correct:
bank* input(bank s[]) // Creates Bank Accounts
{
bank accounts[SIZE]; // Array of bank-account structs
bank *ptr; // Pointer to struct
ptr = &accounts[0]; // Points pointer to array of bank-account structs
// ... lines removed ...
return ptr; // <-- Undefined behavior
}
You are returning a pointer to a local variable / array. Returning pointers or references to local variables is undefined behavior. The reason why is that since the array is local, once the function returns, it doesn't logically exist anymore. So you're eventually pointing to an non-existing entity.
What you probably wanted to do is something like this:
bank* input(bank* s) // Creates Bank Accounts
{
cout << "Account Creation Selected; Create " << SIZE << " accounts..." << endl;
for (int i = 0; i < SIZE ; i++)
{
cout << "Enter Account Number: ";
cin >> s[i].num;
s[i].checkdigit = s[i].num % 5;
cout << "Enter Account Balance: ";
cin >> s[i].bal;
}
return &s[0];
}
Since s was passed in, you probably meant to pass the address of the first element of this entity instead. Also note that this:
bank* input(bank s[]) // Creates Bank Accounts
is no different than this:
bank* input(bank* s) // Creates Bank Accounts
as arrays decay to pointers.
I would really recommend you use containers such as std::vector instead of raw arrays and global constants to keep track of the number of entities (for example, SIZE). Then
Another issue with your program is that you're recursively calling main. Don't do this, as it is not legal C++. Instead, use the proper looping constructs such as while() and do-while().

How can I ignore a specific part of code the first time a loop is ran?

I'm writing a project for articles in store and I need help with the following :
I have declared a struct with elements:
struct pole{
int sifra; // code
string opis; // description
float cena; // price
int vlez_kol; // qty
int izlez_kol; // qty
float dan_stapka; //
float iznos; //
int datum; // date
};
And my program's code has this :
for (int i = 0; i < br_artikli; i++){
cout << "Enter the description of the product" << endl;
vlez_artikl(artikli[i]);
}
And my function is the following :
void vlez_artikl(pole &artikli){
do{
cin.clear();
cin.ignore();
getline(cin, artikli.opis);
}while(golemina_string(artikli.opis) >= 30);
}
And golemina_string function is to check length of string:
int golemina_string(string text){
return text.length();
}
So, I was wondering, how can I make the program output an ERROR when the user enters a string >= 30 length, and to not show it before he makes an error. I tried several ways, but couldn't manage it. So, I thought of maybe adding
cout << "Error" << endl;
In the beginning of the function for inputting data, and somehow ignore (not display the text) the first time when the program enters the function, but I haven't found any way to do that, any help is appreciated.
Example:
Enter the description of the product
When user inputs: wewrfoeshfoisfhoiasohidasfdhioadfsoihadsfhioafhiodsafoihdsoaihdsf
To output error and let him choose a new number.
Something like this:
void vlez_artikl(pole &artikli){
for(;;) {
cin.clear();
cin.ignore();
getline(cin, artikli.opis);
if (golemina_string(artikli.opis) >= 30)
cout << "String too long, try again" << endl;
else break;
}
}