Objective-c calculator program by using CommandLineTool - objective-c

Hi guys I've created a main.m file a calculator.h and calculator.m file
before writing down my code my problem is that the program doesn't ask for the operator it only asks for 1st and 2nd number.
here are my codes for the main.m
int num1,num2;
char op;
Calculator *myCalculator=[[Calculator alloc]init];
NSLog(#"Please Enter The First Number");
scanf("%i",&num1);
NSLog(#"Please Choose a mathematical operation '+', '-', '*', '/' :");
scanf("%c",&op);
NSLog(#"Please Enter The Second Number");
scanf("%i",&num2);
switch (op) {
case '+':
NSLog(#"The Result is : %i",[myCalculator Add:num1 :num2]);
break;
case '-':
NSLog(#"The Result is : %i",[myCalculator Sub:num1 :num2]);
break;
case '*':
NSLog(#"The Result is : %i",[myCalculator Mul:num1 :num2]);
break;
case '/':
NSLog(#"The Result is : %i",[myCalculator Div:num1 :num2]);
break;
default:
NSLog(#"Unknown Operator");
break;
}
and my codes for the implementation are as follows:
-(int) Add:(int)num1 :(int)num2
{
return num1+num2;
}
-(int) Sub:(int)num1 :(int)num2
{
return num1-num2;
}
-(int) Mul:(int)num1 :(int)num2
{
return num1*num2;
}
-(int) Div:(int)num1 :(int)num2
{
return num1/num2;
}
any help will be appreciated thanks in advance !

Haven't done anything like this in awhile, but when I made a small text based RPG battle system I ran into a similar problem. The user presses enter after inputting a number, right? The number will get scanned into num1 and the newline character will get scanned into op. Log the value of op before your switch.

Related

Simple Math App

I am new in Objective C, and I need to do a basic math application within a 5 times loop. Users will need to state what operation will perform (+,-,*,/) and the program will generates two random numbers to do math operations. Then the user will do the math and the program will compare his input with the correct answer. At the end the user will receive a score % and a custom message according to right or wrong answer. I am a bit stuck. First I did the program which generates two random numbers and run nicely. However when I added the rest of the code I have a warning message that says that the implementation is incomplete. I am also unable to see what is happening whit the else structure within the case because I received errors indicating "Expected expression" in each one of them.
Any help is very much appreciated.
Here is my code:
#import <Foundation/Foundation.h>
#interface myMath : NSObject
//methods
-(int) getRandomNumber;
-(void) add: (double) result;
-(void) subtract: (double) result;
-(void) multiply: (double) result;
-(void) divide: (double) result;
#end
#implementation myMath
//returns a random number between 1 and 100
-(int) getRandomNumber{
return (arc4random()%(100-1))+1;
}
#end
#interface Calculator : NSObject
#property double setaccumulator, accumulator; //Synt all methods.
#end
#implementation Calculator{
double accumulator;
}
-(void) setAccumulator: (double) value;
{ accumulator = value; }
-(void) clear
{ accumulator = 0; }
-(double) accumulator
{ return accumulator; }
-(void) add: (double) value
{ accumulator += value; }
-(void) subtract: (double) value
{ accumulator -= value; }
-(void) multiply: (double) value
{ accumulator *= value; }
-(void) divide: (double) value
{ accumulator /= value; }
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
myMath *myMathStuff;
myMathStuff = [[myMath alloc] init];
int rnum1 = [myMathStuff getRandomNumber];
int rnum2 = [myMathStuff getRandomNumber];
double result;
char operator;
Calculator *myCalculator = [[Calculator alloc]init];
int n, right, wrong, cont;
n = 0, right, wrong, cont = 0;
NSLog(#"The random numbers are %i and %i", rnum1, rnum2);
while (n <= 5){
NSLog(#"What operation do you want to perform? (+ . - . * . / .");
scanf(" %c", &operator);
[myCalculator setAccumulator:(double) rnum1];
switch (operator) {
case '+':
[myCalculator add: rnum2];
NSLog(#"Please type the addition result: ");
scanf("%lf", &result);
if (result == rnum1)
right =+1;
NSLog(#"Congratulations, you did it right!");
else
wrong =+1;
NSLog(#"Sorry, the addition result is: %.2f", [myCalculator accumulator]);
break;
case '-':
[myCalculator subtract: rnum2]
NSLog(#"Please type the subtraction: ");
scanf("%lf", &result);
if (result == rnum1)
right =+1;
NSLog(#"Congratulations, you did it right!");
else
wrong =+1,
NSLog(#"Sorry, the subtraction result is: %.2f", [myCalculator accumulator]);
break;
case '*':
[myCalculator multiply: rnum2];
NSLog(#"Please type the multiplication result: ");
scanf("%lf", &result);
if (result == rnum1)
right =+1;
NSLog(#"Congratulations, you did it right!");
else
wrong =+1,
NSLog(#"Sorry, the multiplication result is: %.2f", [myCalculator accumulator]);
break;
case '/':
[myCalculator divide: rnum2];
NSLog(#"Please type the division result: ");
scanf("%lf", &result);
if (result == rnum1)
right =+1;
NSLog(#"Congratulations, you did it right!");
else
wrong =+1,
NSLog(#"Sorry, the division result is: %.2f", [myCalculator accumulator]);
break;
default:
break;
}
++n;
}
NSLog(#"You were right %i", right);
NSLog(#"You were wrong %i", wrong);
if (right == 4)
NSLog(#"Excellent you have a perfect 100 percent score");
else if (right == 3)
NSLog(#"Good job you have a 80 percent score");
else if (right == 2)
NSLog (#"Well, you have a 60 percent score");
else if (right ==1)
NSLog(#"Sorry, you have received a 20 percent score");
}
return 0;
}
I made some changes on the myMath implementation and I also changed the lines where the "else" appears as I show below. I am still getting the expected expression. If somebody else can see what I am not seeing I would appreciate your input.
Part of the code I changed:
switch (operator) {
case '+':
[myMathStuff add: rnum2];
NSLog(#"Please type the addition result: ");
scanf("%lf", &result);
if (result == rnum1)
right =+1;
NSLog (#"Congratulations, you did it right!");
else {
wrong =+1;
NSLog (#"Sorry, the addition result is: %.2f", [myMathStuff accumulator]);
}
break;
I was able to find the solution.
You are getting implementation is incomplete because in your MyMath class you are saying that you have 5 methods at the class level, and only one of those (GetRandomNumber) is actually implemented.
You need to finish the contract - that is - code out what the other four methods are going to do (add, subtract, multiply, divide).

Simple Objective-C calculator program printing continuously

I'm writing my first real objective C program and it's to make a very simple calculator like in the book Programming in Objective-C 2.0 by Stephen Kochan.
Anyway, whenever I run the program it just continually prints the same thing over and over again, not giving me the option to type anything else. The code is below, and if anyone could help I think the problem is somewhere between the while loop and the switch function. Thank you in advance!
#import <Foundation/Foundation.h>
#interface Calculator : NSObject {
double number, accumulator;
char operator;
}
-(void) add: (double) n;
-(void) subtract: (double) n;
-(void) multiply: (double) n;
-(void) divide: (double) n;
#end
#implementation Calculator
-(void) add: (double) n {
accumulator += n;
NSLog(#"%fl", accumulator);
}
-(void) subtract: (double) n {
accumulator -= n;
NSLog(#"%fl", accumulator);
}
-(void) multiply: (double) n {
accumulator *= n;
NSLog(#"%fl", accumulator);
}
-(void) divide: (double) n {
if (n == 0)
NSLog(#"Error! You can't divide by 0!");
else
accumulator /= n;
NSLog(#"%fl", accumulator);
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
double number, accumulator;
char operator;
Calculator *myCalc = [[Calculator alloc] init];
NSLog(#"Begin calculations by typing a number then S");
scanf("%lf, %c", &accumulator, &operator);
while (operator != 'E') {
NSLog(#"%lf", accumulator);
NSLog(#"What would you like to do next?");
scanf("%lf, %c", &number, &operator);
switch (operator) {
case '+':
[myCalc add: number];
break;
case '-':
[myCalc subtract: number];
break;
case '*':
[myCalc multiply: number];
break;
case '/':
[myCalc divide: number];
break;
default:
break;
}
}
}
return 0;
}
scanf is generally a bad function to use. It's generally better to read an input line into a string and then use sscanf (or some other parser) on the string.
However, the fix in this case is simple. scanf returns the number of input items successfully assigned. You expect two. If there's an error, or end-of-file is reached, it will return less than two. Thus:
int rc = scanf("%lf, %c", &number, &operator);
if (rc < 2) {
break;
}
In short: don't use scanf(). It doesn't work how you think it does.
I'm already tried explaining what's wrong, but basically it doesn't like newlines and stuff and it's pedantic. Search SO for similar questions. The easy solution is to replace scanf() with something actually useful, such as
char buf[0x100];
char *end;
fgets(buf, sizeof buf, stdin);
accumulator = strtod(buf, &end);
while (isspace(*end))
end++;
operator = *end;
Also, your calculator logic is flawed. The myCalc object doesn't share the identically named accumulator variable with the main() function. Your program basically doesn't take into account the first number entered. Also, I don't see what purpose the "type 'S'" part serves, there's absolutely no check for entering "S" in the code, only "E" for end.
On a side note: we're in C (basically), but it's still not a good idea to use C++ keywords as identifiers. Let new and operator be reserved. Call that variable op.
Also, as a design improvement, you can abstract away the big switch statement into the calculator class, and that way you could write something like [myCalc performOp:'+' withNumber:number]; etc.

Print string representation of an enum, NSLog

I am trying to NSLog some enums I have. For example this piece of code prints the integer representation of the enum, but I want it to output the actual string name, in this case MON. How can I do that?
#import <Foundation/Foundation.h>
int main(void)
{
typedef enum {
SUN,
MON,
TUES
} DAYS;
DAYS d = MON;
NSLog(#"%#", d);
return 0;
}
The LLDB debugger will show the string identifiers. So instead of using NSLog you could use a breakpoint with a debugger command action ("p d" in your case) and set the breakpoint to automatically continue after evaluating.
You can configure a breakpoint by right-clicking on the blue marker.
Not easily. The string identifier for an enum value is for the developer, but internally it's simply a value with a particular type (in your example, DAYS).
You could write a translation method, to return the name of the enum value, e.g
- (NSString*)nameForDay:(DAYS)day {
switch (day) {
case SUN:
return #"SUN";
break;
case MON:
return #"MON";
break;
case TUES:
return #"TUES";
break;
default:
return nil;
break;
};
return nil;
}
It's a nasty way of doing it, as it's not wholly resilient to the enum values changing, but its a way to associate a string with an enum value.

Switch with typedef enum type from string

I used the typedef enum below but the switch always return the default case why ?
typedef enum {
first,
LatestNews,
Opinion,
Special,
Sports,
Thisweek,
} NAChannelTitle;
-(NSString *)getImageName:(NSString *)channelName {
NAChannelTitle temp = (NAChannelTitle)[channelName stringByReplacingOccurrencesOfString:#" " withString:#""];
NSLog(#"Temp : %#",temp);
switch (temp) {
case first:
return #"background-channel-sporttitle-portrait.png";
break;
case LatestNews:
return #"background-channel-title-portrait.png";
break;
case Opinion:
return #"background-channel-title-portrait.png";
break;
case Special:
return #"background-channel-sporttitle-portrait.png";
break;
case Sports:
return #"background-channel-sporttitle-portrait.png";
break;
case Thisweek:
default:
return #"background-channel-title-portrait.png";
break;
}
return nil;
}
You can't convert a string to enum, since the enums names are not saved, instead, you can create a function that does it, by comparing strings, this is longer, but I don't think you have other option. a macro may help:
NAChannelTitle getEnumTitle(NSString *sTitle) {
#define CHECK_ENUM(X) if([sTitle isEqualToString:##X]) return X
CHECK_ENUM(first);
// the same for all enum
return defaultEnum; // add this to the enum
#undef CHECK_ENUM
}
then you may do:
NAChannelTitle temp = getEnumTitle(channelName);
NSLog(#"Temp : %d",temp);
switch (temp) {
case first:
return #"background-channel-sporttitle-portrait.png";
break;
case LatestNews:
return #"background-channel-title-portrait.png";
break;
case Opinion:
return #"background-channel-title-portrait.png";
break;
case Special:
return #"background-channel-sporttitle-portrait.png";
break;
case Sports:
return #"background-channel-sporttitle-portrait.png";
break;
case Thisweek:
default:
return #"background-channel-title-portrait.png";
break;
}
return nil;
This is what ppl looking for . Here is the shortest answer without any string comparison:
// Zoey.h
typedef enum {
turnLeft,
turnRight,
turnTop,
turnBottom
} arrowType;
// Zoey.m
NSString * const arrowTypeTypeArray[] = {
#"turnLeft",
#"turnRight",
#"turnTop",
#"turnBottom"
};
// A method to convert an enum to string.is it short enuff eh ?
-(NSString*) arrowTypeEnumToString:(arrowType)enumVal
{
return arrowTypeArray[enumVal];
}
// An extra method to retrieve the int value from the C array of NSStrings
-(arrowType) arrowTypeStringToEnum:(NSString*)strVal
{
int retVal;
for(int i=0; i < sizeof(arrowTypeArray)-1; i++)
{
if([(NSString*)arrowTypeArray[i] isEqual:strVal])
{
retVal = i;
break;
}
}
return (arrowType)retVal;
}
You're converting a string to an enum, this doesn't work. Strings are pointers, enums are numbers, and even though you can cast them, a pointer won't have the same value.
You'll need something like:
if([temp isEqualToString:#"LatestNews"]){ ... }
and so on. Or some method to convert to an enum, which you can then switch on.
Also those break statements are useless
The enum, stands for enumeration - you are just creating names for some integers.
typedef enum {
first,
LatestNews,
Opinion,
Special,
Sports,
Thisweek,
} NAChannelTitle;
means that first is 0, LatestNews is 1, and so on.
In your function you are casting a NSString to NSInteger - hence you are not getting correct values.
You need to use the [string isEqualToString:] method to compare your string to some conditional values.
Enumeration declaration explained

the best way to implement readable switch case with strings in objective-c?

In other dynamic languages like ruby, javascript etc. you can do simply this:
switch(someString) {
case "foo":
//do something;
break;
case "bar":
// do something else;
break;
default:
// do something by default;
}
In objective-c, because it's derived very colsely from c language, you can't do that. My best practice for this is:
#import "CaseDemo.h"
#define foo 1
#define bar 2
static NSMutableDictionary * cases;
#implementation CaseDemo
- (id)init
{
self = [super init];
if (self != nil) {
if (cases == nil) {
// this dict can be defined as a class variable
cases = [[NSMutableDictionary alloc] initWithCapacity:2];
[cases setObject:[NSNumber numberWithInt:foo] forKey:#"foo"];
[cases setObject:[NSNumber numberWithInt:bar] forKey:#"bar"];
}
}
return self;
}
- (void) switchFooBar:(NSString *) param {
switch([[cases objectForKey:param] intValue]) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
#end
It's seems to be ok, but #define makes foo and bar like a reserved word, and I can't use in my code. If I replace define constants with class constants, this problem is fixed, because in other classes I must use MyClassName before the constant name. But how can I minimize the object allocation for this simple task? Someone have a "better practice" for this?
EDIT:
The code below is what I wanted to do, but it's a little bit unconfortable to get the values of the enum or #define. Because I created an application what have just an input where I can write the string to get that hash and go back to xcode and set the values for the enums. So my problem is I can't do that in runtime time, because of the main behavour of switch case statement... Or if I do that with that NSDictionary way -> its have a lot of overhead compared with this solution.
#import "CaseDemo.h"
typedef enum {
foo = 1033772579,
bar = -907719821
} FooBar;
unsigned int APHash(NSString* s)
{
const char* str = [s UTF8String];
unsigned int len = [s length];
unsigned int hash = 0xAAAAAAAA;
unsigned int i = 0;
for(i = 0; i < len; str++, i++)
{
hash ^= ((i & 1) == 0) ? ( (hash << 7) ^ (*str) * (hash >> 3)) :
(~((hash << 11) + ((*str) ^ (hash >> 5))));
}
return hash;
}
#implementation CaseDemo
- (void) switchFooBar:(NSString *) param {
switch(APHash(param)) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
#end
NOTE: the hash function can defined elsewhere in common namespace to use it anywhere, typically I create a Utils.h or Common.h for this kind of stuff.
NOTE2: In "real word" we need to use some cryptographic hashing function, but now I used the algorithm by Arash Partow to keep the example simple.
So, my final question: Is there a way to evaluate these values with the preprocessor somehow? I think no, but maybe? :-)
Something like:
// !!!!!! I know this code is not working, I don't want comments about "this is wrong" !!!!
// I want a solution to invoke method with preprocessor, or something like that.
typedef enum {
foo = APHash(#"foo"),
bar = APHash(#"bar")
} FooBar;
UPDATE: I found a "maybe solution" but it seems to be work with g++ 4.6> only. generalized constant expressions may be do it for me. But I'm still testing...
typedef enum {
foo,
bar
} FooBar;
- (void) switchFooBar:(NSString *) param {
switch([[cases objectForKey:param] intValue]) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
NSString * extension = [fileName pathExtension];
NSString * directory = nil;
NSUInteger index = [#[#"txt",#"png",#"caf",#"mp4"] indexOfObjectPassingTest:^
BOOL(id obj, NSUInteger idx, BOOL *stop)
{
return [obj isEqualToString:extension];
}];
switch (index)
{
case 0:
directory = #"texts/";
break;
case 1:
directory = #"images/";
break;
case 2:
directory = #"sounds/";
break;
case 3:
directory = #"videos/";
break;
default:
#throw [NSException exceptionWithName:#"unkonwnFileFormat"
reason:[NSString stringWithFormat:#"zip file contain nknown file format: %#",fileName]
userInfo:nil];
break;
}
The technique is extracted from production code and modified to use colors for this example. The premise is that a string comes in with the text name of a color from some external feed. This inbound color name is matched against known Crayola color names in the system. If the new color name matches any known Crayola color name strings, the numeric value for HTML hex code equivalent of that Crayola color name is returned.
First use http://www.unit-conversion.info/texttools/crc/ and put all of your known Crayola color names through it to get numerical equivalents. These will be used in the case statements. Then put those values into an enumerated for cleanliness (e.g. LivingColors below). These numbers become equivalent to the actual color name string.
Then at run time the variable text is put through the same function, but internal to your code, to generate the same kind of numeric constant. If the numeric constant from the code matches the statically generated constant, then the text strings that they represent are exactly equal.
The internal code function is crc32() found in zlib.h. This generates a unique number based upon the text put through it just like the web page converter above. The unique number from crc32() can then be used in a common C switch() statement to match against the known colors which were pre-processed into numbers into the enumerated.
To use the native system function crc32() to generate CRC32B values, include the /usr/lib/libz.1.dylib in your project for linking. Be sure to include or #import <zlib.h> in your source that references crc32()
Implement an Objective C category on NSString to make the native NSString class understand the crc32: and htmlColor: messages.
Finally, read/get the name of the color into an NSString object, then send the string the htmlColor: message, it switches to match the 'strings' and returns the HTML hex equivalent value for a Crayola color name.
#import <zlib.h>
#define typedefEnum( enumName ) typedef enum enumName enumName; enum enumName
/**
#see Crayola Web Colors https://www.w3schools.com/colors/colors_crayola.asp
#see CRC32B value generator for static case strings http://www.unit-conversion.info/texttools/crc/ or http://www.md5calc.com
*/
#define typedefEnum( enumName ) typedef enum enumName enumName; enum enumName
typedefEnum( LivingColors ) {
kRedColor = 0xc22c196f, // "Red" is 0xED0A3F in HTML
kBlueberryColor = 0xfbefa670, // "Blueberry" is 0x4F86F7 in HTML
kLightChromeGreenColor = 0x44b77242, // "Light Chrome Green" is 0xBEE64B in HTML
kPermanentGeraniumLakeColor = 0xecc4f3e4, // "Permanent Geranium Lake" is 0xE12C2C in HTML
kIlluminatingEmeraldColor = 0x4828d5f2, // "Illuminating Emerald" is 0x319177 in HTML
kWildWatermelonColor = 0x1a17c629, // "Wild Watermelon" is 0xFD5B78 in HTML
kWashTheDogColor = 0xea9fcbe6, // "Wash the Dog" is 0xFED85D in HTML
kNilColor = 0xDEADBEEF // could use '0' but what fun is that?
};
// generates the CRC32B, same used to check each ethernet packet on the network you receive so it’s fast
- (NSUInteger) crc32 {
NSUInteger theResult;
theResult = (NSUInteger)crc32( 0L,
(const unsigned char *) [self UTF8String],
(short)self.length);
return theResult;
}
/// #return the HTML hex value for a recognized color name string.
- (NSUInteger) htmlColor {
NSUInteger theResult = 0x0;
LivingColors theColorInLivingColor = kNilColor;
theColorInLivingColor = (LivingColors) [self crc32];
// return the HTML value for a known color by effectively switching on a string.
switch ( theColorInLivingColor ) {
case kRedColor : {
theResult = 0xED0A3F;
}
break;
case kBlueberryColor : {
theResult = 0x4F86F7;
}
break;
case kLightChromeGreenColor : {
theResult = 0xBEE64B;
}
break;
case kPermanentGeraniumLakeColor : {
theResult = 0xE12C2C;
}
break;
case kIlluminatingEmeraldColor : {
theResult = 0x319177;
}
break;
case kWildWatermelonColor : {
theResult = 0xFD5B78;
}
break;
case kWashTheDogColor : {
theResult = 0xFED85D;
}
break;
case kNilColor :
default : {
theResult = 0x0;
}
break;
}
return theResult;
}
For the example an Objective C Category was made to add the two methods the existing Cocoa class NSString, rather than subclass it.
The end result is that an NSString object appears to have the ability to natively get a CRC32B value of itself (very handy beyond this example) and can essentially switch() on the color’s name string that possibly came in from the user, a text file, etc. to identify a match much faster than any text string comparison can occur.
Fast, efficient, and reliable, this approach can easily be adapted to any kind of variable text matching to static known value text. Bear in mind that CRC32B checksums are generated by bitwise operations and the C switch statement use bitwise operations optimized at compile time. Remember this is speedy because CRC32B is the highly optimized function used to check each ethernet packet your Mac/iPhone/iPad receives... even when you download multi-gigabyte files like macOS Sierra.