Bank Account iOS App Structure - ios

Last semester in an assignment the class had to model a bank account in C++. This semester we are doing the same thing except in objective-c and in the form of an iOS app. I've just begun and have a basic storyboard set up to test my deposits however I cannot get my total balance to add up and I'm pretty sure it is because I instantiate my Account object with the deposit IBAction. How should this be done properly? I only need a push in the right direction and I'm confident I can hit the ground running from there with the rest. See attached code:
- (IBAction)deposit:(id)sender {
Account *acc =[[Account alloc]init];
double damount = [_textField.text doubleValue] ;
[acc deposit:(damount)];
_display.text = [NSString stringWithFormat:#"%f", acc.getBalance];
}
Original C++ code as requested:
int main(){
char szFName[32];
char szLName[32];
char szSIN[12];
char szAccType[10];
double dBalance;
int op;
Account *acc[MAX_ACCOUNTS];
int count=0;
while (count<MAX_ACCOUNTS)
{
cout << "Customer's First Name : " << flush;
cin >> szFName;
cout << "Customer's Last Name : " << flush;
cin >> szLName;
cout << "Customer's SIN : " << flush;
cin >> szSIN;
cout << "Account Type : " << flush;
cin >> szAccType;
cout << "Opening Balance : " << flush;
cin >> dBalance;
if ( !strcmp(szAccType,"Checking") )
acc[count] = new CheckingAcc(szFName, szLName, szSIN, szAccType, dBalance);
else if ( !strcmp(szAccType,"VIP") )
acc[count] = new VIPAcc(szFName, szLName, szSIN, szAccType, dBalance);
else if ( !strcmp(szAccType,"Saving") )
acc[count] = new SavingAcc(szFName, szLName, szSIN, szAccType, dBalance);
else
{
cout << "Incorect account type." << endl;
continue;
}
count++;
}

The problem you're facing is that you're creating a new bank account every time instead of maintaining a single account and adding to it.
In your original program you created an array of accounts acc that persisted during the lifetime of the user input. Since you've moved from a procedural program to a UI program with a run loop, you'll need a more persistent place to store it.
Generally, a good spot would be a property on your view controller or higher up if the objects need to persist longer than the view controller:
#property Account *account;
...
- (id)init
{
if (self) {
_account = [[Account alloc] init];
}
return self;
}
...
[self.account deposit:(damount)];
Since this is for class, you will probably want to review your textbook for topics like properties and instance variables.

Related

How to print a String in a C++ Builder console application?

I am trying to print the contents of a String in a console application. I am doing a test and would like to visualize the content for debugging purposes.
Here is my code:
bool Tests::test001() {
std::string temp;
CDecoder decoder; // Create an instance of the CDecoder class
String input = "60000000190210703800000EC00000164593560001791662000000000000080000000002104302040235313531353135313531353153414C4535313030313233343536373831323334353637383930313233";
String expected_output = "6000000019";
String output = decoder.getTPDU(input); // Call the getTPDU method
std::cout << "Expected :" << expected_output.t_str() <<std::endl;
std::cout << "Obtained :" << output.t_str() <<std::endl;
return output == expected_output; // Return true if the output is as expected, false otherwise
}
This is what I get:
Running test: 0
Expected :024B8874
Obtained :00527226
Test Fail
Press any key to continue...
This is what I want to get:
Running test: 0
Expected :6000000019
Obtained :0000001902
Test Fail
Press any key to continue...
Here the Obtained value is a substring of the input I chose randomly (a shift to the left by two characters).
Whether I use t_str() or c_str() the result is the same.
In C++Builder 2009 and later, String (aka System::String) is an alias (ie, a typedef) for System::UnicodeString, which is a UTF-16 string type based on wchar_t on Windows and char16_t on other platforms.
Also, the UnicodeString::t_str() method has been deprecated since around C++Builder 2010. In modern versions, it just returns the same pointer as the UnicodeString::c_str() method.
You can't print a UnicodeString's characters using std::cout. You are getting memory addresses printed out instead of characters, because std::cout does not have an operator<< defined for wchar_t*/char16_t* pointers, but it does have one for void* pointers.
You need to use std::wcout instead, eg:
std::wcout << L"Expected :" << expected_output.c_str() << std::endl;
std::wcout << L"Obtained :" << output.c_str() << std::endl;
If you want to use std::cout, you will have to convert the String values to either System::UTF8String (and put the console into UTF-8 mode) or System::AnsiString instead, eg:
std::cout << "Expected :" << AnsiString(expected_output).c_str() << std::endl;
std::cout << "Obtained :" << AnsiString(output).c_str() << std::endl;
This seems to do the work:
std::wcout
Here is the working code:
// Member function to run test001
bool Tests::test001() {
std::string temp;
CDecoder decoder; // Create an instance of the CDecoder class
String input = "60000000190210703800000EC00000164593560001791662000000000000080000000002104302040235313531353135313531353153414C4535313030313233343536373831323334353637383930313233";
String expected_output = "6000000019";
String output = decoder.getTPDU(input); // Call the getTPDU method
std::wcout << "Expected: " << expected_output <<std::endl;
std::wcout << "Obtained: " << output <<std::endl;
return output == expected_output; // Return true if the output is as expected, false otherwise

Parsing an integer and HEX value in Ragel

I am trying to design a parser using Ragel and C++ as host langauge.
There is a particular case where a parameter can be defined in two formats :
a. Integer : eg. SignalValue = 24
b. Hexadecimal : eg. SignalValue = 0x18
I have the below code to parse such a parameter :
INT = ((digit+)$incr_Count) %get_int >!(int_error); #[0-9]
HEX = (([0].'x'.[0-9A-F]+)$incr_Count) %get_hex >!(hex_error); #[hexadecimal]
SIGNAL_VAL = ( INT | HEX ) %/getSignalValue;
However in the above defined parser command, only the integer values(as defined in section a) gets recognized and parsed correctly.
If an hexadecimal number(eg. 0x24) is provided, then the number gets stored as ´0´ . There is no error called in case of hexadecimal number. The parser recognizes the hexadecimal, but the value stored is '0'.
I seem to be missing out some minor details with Ragel. Has anyone faced a similar situation?
The remaning part of the code :
//Global
int lInt = -1;
action incr_Count {
iGenrlCount++;
}
action get_int {
int channel = 0xFF;
std::stringstream str;
while(iGenrlCount > 0)
{
str << *(p - iGenrlCount);
iGenrlCount--;
}
str >> lInt; //push the values
str.clear();
}
action get_hex {
std::stringstream str;
while(iGenrlCount > 0)
{
str << std::hex << *(p - iGenrlCount);
iGenrlCount--;
}
str >> lInt; //push the values
}
action getSignalValue {
cout << "lInt = " << lInt << endl;
}
It's not a problem with your FSM (which looks fine for the task you have), it's more of a C++ coding issue. Try this implementation of get_hex():
action get_hex {
std::stringstream str;
cout << "get_hex()" << endl;
while(iGenrlCount > 0)
{
str << *(p - iGenrlCount);
iGenrlCount--;
}
str >> std::hex >> lInt; //push the values
}
Notice that it uses str just as a string buffer and applies std::hex to >> from std::stringstream to int. So in the end you get:
$ ./a.out 245
lInt = 245
$ ./a.out 0x245
lInt = 581
Which probably is what you want.

Memory allocation and delete in a class

Having trouble with memory allocation and pointers
I'm having trouble with pointers and dynamic memory. I made a class FileReader that read from a file formated like this.
FirstName,LastName,Year,GPA
String,String,String,Integer
Chris,Knight,Fr,3.8
Mitch,Taylor,Jr,3.5
The first line, I stored it in a vector called Names
and 2nd line in vector called Types.
I also made a vector that holds void pointers since it will hold arbitrary types
My question is, how can I free up those memory in the heap?
#ifndef RECORD_H
#define RECORD_H
class Record{
private:
//POINTER VARIABLES
int *intPtr;
double *doublePtr;
vector<string*> stringPtrList;
//NAMES,TYPES, AND VALUES
vector<string> Names;
vector<string> Types;
vector<void*> Values;
public:
Record(vector<string> _names, vector<string> _types, vector<string>_values){
Names = _names;
Types = _types;
//ALOCATING MEMORY
for (unsigned i = 0; i < Types.size(); i++){
string *stringPtr = new string;
stringPtrList.push_back(stringPtr);
}
for (unsigned int i = 0; i < Types.size(); i++){
if (Types[i] == "Integer"){
intPtr = new int;
*intPtr = stoi(_values[i]);
Values.push_back((void*)intPtr);
}
else if (Types[i] == "Double"){
doublePtr = new double;
*doublePtr = stod(_values[i]);
Values.push_back((void*)doublePtr);
}
else if (Types[i] == "String"){
*stringPtrList[i] = _values[i];
Values.push_back((void*)stringPtrList[i]);
}
else{
cout << "No match Type" << endl;
}
}
}
Record(const Record &r){
int *intPtr = new int;
intPtr = r.intPtr;
double *doublePtr = new double;
doublePtr = r.doublePtr;
for (int i = 0; i < r.stringPtrList.size(); i++){
stringPtrList[i] = new string;
stringPtrList[i] = r.stringPtrList[i];
}
}
~Record(){
delete intPtr, doublePtr;
for (int i = 0; i < Types.size(); i++){
delete stringPtrList[i];
}
cout << "Pointer are deleted" << endl;
}
friend ostream&operator <<(ostream &os, const Record &r){
for (unsigned int i = 0; i < r.Types.size(); i++){
if (r.Types[i] == "Integer"){
os << "Integer: " << *(int*)r.Values[i] << endl;
}
else if (r.Types[i] == "String"){
os << "String" << *static_cast<string*>(r.Values[i]) << endl;
}
else if (r.Types[i] == "Double"){
os << "Double" << *(double*)r.Values[i] << endl;
}
else{
cout << "Fatal Error!" << endl;
}
}
cin.get();
return os;
}
};
#endif
GPA has to be a float, not an int. 3.5 can not be an int.
This sounds like homework question. Even if it isn't, it sounds like you are over-complicating things. Just use a list (vector) of structs.
If you really have to be able to handle any type, just use a value-pair type of stuct, something along the lines of:
struct Record
{
string value;
VAR_TYPE type; //this is some enum you defined.
}
Keep a list of columns with types and column index, so easily process each record as you read it.
Since you know the type of each record, you can cast it to that when you are actually going to use it.
It's much cleaner that way, no need for dynamic allocation (which is slow) and messing with void pointers.

Non-iteratively getting the list of instruments in a soundfont using FluidSynth

Is there a function that can return the list of all the instruments (preset names) in a soundfont file in FluidSynth or at least the number of presets in each soundbank?
I was able to get instrument names and banks using fluidsynth. The command you want to send is "inst 1" (obtain all instruments for the soundfont loaded in position 1).
$ echo "inst 1" | fluidsynth /path/to/FluidR3_GM.sf2
FluidSynth version 1.1.6
Copyright (C) 2000-2012 Peter Hanappe and others.
Distributed under the LGPL license.
SoundFont(R) is a registered trademark of E-mu Systems, Inc.
Type 'help' for help topics.
000-000 Yamaha Grand Piano
000-001 Bright Yamaha Grand
000-002 Electric Piano
000-003 Honky Tonk
000-004 Rhodes EP
000-005 Legend EP 2
000-006 Harpsichord
000-007 Clavinet
...
...
...
128-035 Jazz 3
128-036 Jazz 4
128-040 Brush
128-041 Brush 1
128-042 Brush 2
128-048 Orchestra Kit
This is not exactly "non-iterative", but it's the only way I could find to get a list of all the presets in a soundfont file.
fluid_preset_t* preset = new fluid_preset_t();
// Reset the iteration
sf->iteration_start(sf);
// Go through all the presets within the soundfont
int more = 1;
while (more) {
more = sf->iteration_next(sf, preset); // Will return 0 if no more soundfonts left
if (more) {
// Get preset name
char* presetname = preset->get_name(preset);
int banknum = preset->get_banknum(preset);
int num = preset->get_num(preset);
// Do something with the presetname, bank number and program number
// Such as add it to some list so that you can refer to it later
}
}
... where sf is a soundfont object.
Found this while going through the API documentation at http://fluidsynth.sourceforge.net/api/index.html. Note the menu at the top with links to the data structures, files, etc.
I tried this:
static void inspectsoundfont()
{
fluid_sfont_t* sfont = fluid_synth_get_sfont_by_id(synth, font_id);
for (int bank = 0; bank < 16384; bank++)
{
for (int num = 0; num < 128; num++)
{
fluid_preset_t* preset = fluid_sfont_get_preset(sfont, bank, num);
if (preset == nullptr)
continue;
const char* name = fluid_preset_get_name(preset);
std::cout << "bank: " << bank << " index: " << num << " " << name << std::endl;
}
}
}
synth is the synthesiser object, and font_id is from fluid_synth_sfload. Gave me a list of banks and preset names.

Passing a pointer to a linked list in C++

I have a fairly basic program that is intended to sort a list of numbers via a Linked List.
Where I am getting hung up is when the element needs to be inserted at the beginning of the list. Here is the chunk of code in question
Assume that root->x = 15 and assume that the user inputs 12 when prompted:
void addNode(node *root)
{
int check = 0; //To break the loop
node *current = root; //Starts at the head of the linked list
node *temp = new node;
cout << "Enter a value for x" << endl;
cin >> temp->x;
cin.ignore(100,'\n');
if(temp->x < root->x)
{
cout << "first" << endl;
temp->next=root;
root=temp;
cout << root->x << " " << root->next->x; //Displays 12 15, the correct response
}
But if, after running this function, I try
cout << root->x;
Back in main(), it displays 15 again. So the code
root=temp;
is being lost once I leave the function. Now other changes to *root, such as adding another element to the LL and pointing root->next to it, are being carried over.
Suggestions?
This because you are setting the local node *root variable, you are not modifying the original root but just the parameter passed on stack.
To fix it you need to use a reference to pointer, eg:
void addNode(node*& root)
or a pointer to pointer:
void addNode(node **root)

Resources