PDA

View Full Version : "Programming In Objective-C" (Book) Excersie

Darkroom
Sep 23, 2008, 03:16 PM
Exercise (from page 126): Write a program that takes an interger keyed in from the terminal and extracts and displays each digit of the interger in English. So, if the user types 932, the program should display "Nine Three Two". (Remember to display "Zero" if the user types in just a 0.) Note: This exercise is a hard one!.

right... so i can't figure out how i could use a for loop in this situation... for loops are not my strong point... i feel that a for loop would reduce the redundent coding i have here so far. also, this code only works for 5 digit numbers. if the user types in 45, it will display "Zero Zero Zero Four Five"... not exactly ideal... i could copy this code 4 more times in different If statements [IE: If (Number < 10)] to go all the way down to one digit input, but again it would have even more redundent code.

thoughts? suggestions?

#include <stdio.h>

int main (int argc, const char * argv[])
{
int number, digit1, digit2, digit3, digit4, digit5;

printf("Enter a number (max 5 digits): ");
scanf("%i", &number);

if (number < 100000)
{
digit1 = number % 100000 / 10000;

switch (digit1)
{
case 0 : printf("Zero "); break;
case 1 : printf("One "); break;
case 2 : printf("Two "); break;
case 3 : printf("Three "); break;
case 4 : printf("Four "); break;
case 5 : printf("Five "); break;
case 6 : printf("Six "); break;
case 7 : printf("Seven "); break;
case 8 : printf("Eight "); break;
case 9 : printf("Nine "); break;
default : printf("Unknown Interger "); break;
}

digit2 = number % 10000 / 1000;

switch (digit2)
{
case 0 : printf("Zero "); break;
case 1 : printf("One "); break;
case 2 : printf("Two "); break;
case 3 : printf("Three "); break;
case 4 : printf("Four "); break;
case 5 : printf("Five "); break;
case 6 : printf("Six "); break;
case 7 : printf("Seven "); break;
case 8 : printf("Eight "); break;
case 9 : printf("Nine "); break;
default : printf("Unknown Interger "); break;
}

digit3 = number % 1000 / 100;

switch (digit3)
{
case 0 : printf("Zero "); break;
case 1 : printf("One "); break;
case 2 : printf("Two "); break;
case 3 : printf("Three "); break;
case 4 : printf("Four "); break;
case 5 : printf("Five "); break;
case 6 : printf("Six "); break;
case 7 : printf("Seven "); break;
case 8 : printf("Eight "); break;
case 9 : printf("Nine "); break;
default : printf("Unknown Interger "); break;
}

digit4 = number % 100 / 10;

switch (digit4)
{
case 0 : printf("Zero "); break;
case 1 : printf("One "); break;
case 2 : printf("Two "); break;
case 3 : printf("Three "); break;
case 4 : printf("Four "); break;
case 5 : printf("Five "); break;
case 6 : printf("Six "); break;
case 7 : printf("Seven "); break;
case 8 : printf("Eight "); break;
case 9 : printf("Nine "); break;
default : printf("Unknown Interger "); break;
}

digit5 = number % 10;

switch (digit5)
{
case 0 : printf("Zero "); break;
case 1 : printf("One "); break;
case 2 : printf("Two "); break;
case 3 : printf("Three "); break;
case 4 : printf("Four "); break;
case 5 : printf("Five "); break;
case 6 : printf("Six "); break;
case 7 : printf("Seven "); break;
case 8 : printf("Eight "); break;
case 9 : printf("Nine "); break;
default : printf("Unknown Interger "); break;
}
}
else
{
printf("Entered Number is too long.");
}
return 0;
}

robbieduncan
Sep 23, 2008, 03:19 PM
If I were you I'd turn the number into a NSString the peal each character off in turn in a loop...

Darkroom
Sep 23, 2008, 03:30 PM
yeah, i kinda figured that's possible. but it wasn't yet discussed in the book... the only things concretely discussed so far are data types, operators, IF/Else, Switch, For, While... ya know, basic C stuff... i think the only thing really Objective-C that was mentioned so far was BOOL... so essentially i'm trying to use a For loop since it's the only thing mentioned so far that i *think* could reduce the redundant code.

robbieduncan
Sep 23, 2008, 03:36 PM
Hmm, OK. A recursive function wound be my next choice. The function would be something like this:

Divide input by 10 and store in newVar.
If newVar>10 call the function with newVar
Get remainder (% operator) for dividing input by 10.
Use remainder to lookup what the number is in english and print it.

This will handily print the number furthest to the left first :D

Another handy hint:
The case statement is no necessary. Store the strings in an array indexed correctly and you can just look them up directly :)

mysterytramp
Sep 24, 2008, 06:15 AM
Part of the issue might be to think of the number from right to left rather than from left to right.

Peel off the digits arithmetically, convert to strings and then PREPEND the string instead of appending the string to your output.

You could use a while loop instead of a for loop, and then user could have an integer of virtually unlimited size.

garethlewis2
Sep 24, 2008, 06:27 AM
There are two solutions to this that don't use any cheating, e.g. using NSString, etc.

The first has already been mentioned and that is to use recursion. You will not run out of stack space, but you will unnecessarily allocate a large amount of memory.

e.g. imagine you had the value
1234
You would first push 4 onto the stack then divide 1234 by 10 to get 123, then call the getdigit function again, which will push 3 onto the stack before dividing by 10, but this time, your stack page contains 4 followed by 3, and then another stack page containing 4.

The other solution is far more elegant and does not involve any recursion. This is to use linked lists. You just use the push operation to keep 'push'ing elements onto the front of the queue. So you first get 4, push this onto the list, then get 3 and push that onto the list, then get 2 and push that , then 1 and push that, and you have a list which looks like

head -> 1 -> 2 -> 3 -> 4 -> nil.

Easy. You still have to code it, and no I will not send you the code, you need to solve these on your own.

MacRumors Guy
Sep 24, 2008, 08:27 AM
You can also count the digits and start dividing from the end.

void print_digits(int number) {
char* digits[10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eigth", "nine"};

int number_len = 1;
int number_copy = number;
while(number_copy /= 10 ) number_len++;

int power = pow(10, number_len - 1);
while(number_len--) {
printf("%s ", digits[number/power]);
number %= power;
power /= 10;
}
}

bbarnhart
Sep 24, 2008, 08:51 PM
#include <stdio.h>
#include <string.h>

int main (int argc, char * const argv[])
{

char numbers[10][10] = {{"Zero"}, {"One"}, {"Two"}, {"Three"}, {"Four"}, {"Five"}, {"Six"}, {"Seven"}, {"Eight"}, {"Nine"} };

char input[100];
printf("Enter number: ");
scanf("%s", &input);

for (int i=0 ; i < strlen(input); i++)
{
printf("%s ", numbers[input[i] - 48]);
}

return 0;
}

Darkroom
Sep 24, 2008, 10:44 PM
wow... yeah, i never would have gotten that... it's nice to see it and learn from example... thanks :)

char numbers[10][10] = {{"Zero"}, {"One"}, {"Two"}, {"Three"}, {"Four"}, {"Five"}, {"Six"}, {"Seven"}, {"Eight"}, {"Nine"} };

your numbers variable has 2 max 10 characters arguments? and then your assigned are wrapped in braces individually... can you explain this to me?

garethlewis2
Sep 25, 2008, 12:21 AM
Urgghhh. Buffer overflow errors with that solution. Vomit

robbieduncan
Sep 25, 2008, 03:27 AM
wow... yeah, i never would have gotten that... it's nice to see it and learn from example... thanks :)

char numbers[10][10] = {{"Zero"}, {"One"}, {"Two"}, {"Three"}, {"Four"}, {"Five"}, {"Six"}, {"Seven"}, {"Eight"}, {"Nine"} };

your numbers variable has 2 max 10 characters arguments? and then your assigned are wrapped in braces individually... can you explain this to me?

It creates a 2D array 10 across and 10 down and pre-fills it with the correct values.

bbarnhart
Sep 25, 2008, 06:57 AM
More better?

#include <stdio.h>
#include <string.h>

int main (int argc, char * const argv[])
{
char* numbers[] = {"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
const int len = 100;
char input[len];
printf("Enter number: ");
fgets(input, len, stdin);

for (int i=0; i < strlen(input); i++)
{
if (input[i] >= '0' && input[i] <= '9')
{
printf("%s ", numbers[input[i] - '0']);
}
}

return 0;
}

mysterytramp
Sep 28, 2008, 03:40 PM
Not terribly elegant -- I think bbarnhart wins that one -- but I muscled through this and here's what I got. I find while loops easier to read than for loops and the switch block easier to follow than an array. Limitations of human processor.

mt

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {

int input, i, digits[100];
printf("Enter number: ");
scanf("%d", &input);
i=1;
while(input > 0) {
digits[i] = input % 10;
input = (input/10);
i=i+1;
}
i=i-1;
while(i > 0) {
switch (digits[i])
{
case 0 : printf("Zero "); break;
case 1 : printf("One "); break;
case 2 : printf("Two "); break;
case 3 : printf("Three "); break;
case 4 : printf("Four "); break;
case 5 : printf("Five "); break;
case 6 : printf("Six "); break;
case 7 : printf("Seven "); break;
case 8 : printf("Eight "); break;
case 9 : printf("Nine "); break;
default : printf("Unknown Integer "); break;
}
i = i-1;
}
printf("\n");

return 0;
}

lee1210
Sep 28, 2008, 03:59 PM
Not terribly elegant -- I think bbarnhart wins that one -- but I muscled through this and here's what I got. I find while loops easier to read than for loops and the switch block easier to follow than an array. Limitations of human processor.

mt

There's certainly something to be said for readability and ease of understanding, but understand that using a switch is equivalent to a very large, nested if-else structure. In something like this example, branching 5-6 times for each of 5 digits is not a big deal vs. constant time access to an array. However, be sure in actual intensive situations you are careful with switch, because it can slow things down.

-Lee

mysterytramp
Sep 29, 2008, 06:48 AM
There's certainly something to be said for readability and ease of understanding, but understand that using a switch is equivalent to a very large, nested if-else structure. In something like this example, branching 5-6 times for each of 5 digits is not a big deal vs. constant time access to an array. However, be sure in actual intensive situations you are careful with switch, because it can slow things down.

-Lee

Thanks for the observation, Lee. This kind of guidance is very, very helpful.

mt

deprecated
Oct 1, 2008, 12:26 PM
#import <stdio.h>
#import <objc/Object.h>

int main()
{
int num, num_ = 0;

printf("enter integer number:");
scanf("%i", &num);

// revert typed number into variable num_
do
{
num_ *= 10;
num_ += num % 10;
num /= 10;
}while (num > 0);

// print each sign of reverted variable
do
{
switch (num_ % 10)
{
case 1:
printf("one");
break;
case 2:
printf("two");
break;
case 3:
printf("three");
break;
case 4:
printf("four");
break;
case 5:
printf("five");
break;
case 6:
printf("six");
break;
case 7:
printf("seven");
break;
case 8:
printf("eight");
break;
case 9:
printf("nine");
break;
case 0:
printf("zero");
break;
}
// print space between each sign
printf(" ");
num_ /= 10;
}while (num_ > 0);

printf("\n");

return 0;
}

theotherbeck
Nov 15, 2008, 05:27 PM
Hi guys,

I just posted another thread trying to figure this out, and then was directed here... Below is what I figure out, but it, like all the other solutions in this thread seem to print the numbers backwards... I believe the exercise was to print them forward in order. Anyone know how to do that? It seems to me there has to be a simple way to turn the number around before running the loop, but I can't figure out what that way would be. Thanks!

// Program to print the numbers entered in english

#import <stdio.h>
#import <objc/Object.h>

int main (int argc, char *argv[])
{
int number, right_digit;

printf ("Enter your number.\n");
scanf ("%i", &number);

//seems like I should reverse the entered number here, but I can't figure out how.

do { //gets the last number
right_digit = number % 10;

//prints the last number as a word
if (right_digit == 0) {
printf("zero");
}
else if (right_digit == 1){
printf("one ");
}
else if (right_digit == 2){
printf("two ");
}
else if (right_digit == 3){
printf("three ");
}
else if (right_digit == 4){
printf("four ");
}
else if (right_digit == 5){
printf("five ");
}
else if (right_digit == 6){
printf("six ");
}
else if (right_digit == 7){
printf("seven ");
}
else if (right_digit == 8){
printf("eight ");
}
else if (right_digit == 9){
printf("nine ");
}

// loses last number from number entered
number /= 10;
} while (number != 0);

return 0;
}

beebauman
Feb 13, 2009, 02:13 PM
deprecated, I think your solution was the one that the author intended. All others (with the exception of the first one by Darkroom) incorporate concepts not yet taught by the book.

mdeh
Feb 14, 2009, 02:08 AM
deprecated, I think your solution was the one that the author intended. All others (with the exception of the first one by Darkroom) incorporate concepts not yet taught by the book.

There is an entire thread on this exercise here:

http://classroomm.com/objective-c/index.php?topic=36.0

srbrian5
Apr 11, 2011, 01:35 AM
Not terribly elegant -- I think bbarnhart wins that one -- but I muscled through this and here's what I got. I find while loops easier to read than for loops and the switch block easier to follow than an array. Limitations of human processor.

mt

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {

int input, i, digits[100];
printf("Enter number: ");
scanf("%d", &input);
i=1;
while(input > 0) {
digits[i] = input % 10;
input = (input/10);
i=i+1;
}
i=i-1;
while(i > 0) {
switch (digits[i])
{
case 0 : printf("Zero "); break;
case 1 : printf("One "); break;
case 2 : printf("Two "); break;
case 3 : printf("Three "); break;
case 4 : printf("Four "); break;
case 5 : printf("Five "); break;
case 6 : printf("Six "); break;
case 7 : printf("Seven "); break;
case 8 : printf("Eight "); break;
case 9 : printf("Nine "); break;
default : printf("Unknown Integer "); break;
}
i = i-1;
}
printf("\n");

return 0;
}

This is the way I did it.. by my self..

int number,divider,divcounter,left_Num, count, cKeeper;

scanf("%i", &number);

left_Num = number; //Set User number

do //No how many digits
{
left_Num /= 10;
++cKeeper;// How many time loop have 2 run

}
while (left_Num != 0);

left_Num = number; //reload user number

while (cKeeper != 0)
{

divider = 10;
count = 0;

do //No how many digits
{
left_Num /= 10;
++count; //how many time run loop to look for correct number

}
while (left_Num != 0);

count -= 1; //Take one out so we get fisrt digit

left_Num = number; //need to keep 'number' intact
divcounter = cKeeper; //Set counter to increase divider

do //Get the digits to diplay number in a word.
{
if (count !=0) //Avoid division of last digits.
left_Num /= 10;
--count;

for(divcounter; divcounter > 2; --divcounter)
{
divider *= 10; //set divider to set correct residual to number
}
}
while (count > 0);

number %= divider; //Get new number value

switch (left_Num) //Display Correct Msg
{
case 0:NSLog(@"Zero");break;
case 1:NSLog(@"One");break;
case 2:NSLog(@"Two");break;
case 3:NSLog(@"Three");break;
case 4:NSLog(@"Four");break;
case 5:NSLog(@"Five");break;
case 6:NSLog(@"Six");break;
case 7:NSLog(@"Seven");break;
case 8:NSLog(@"Eight");break;
case 9:NSLog(@"Nine");break;
default:NSLog(@"Not a digits");break;
}
left_Num = number; //reload user number
--cKeeper; //One time less
}

Dint know that you can accumulate and integer like that. Learn something new every day...

srbrian5
Apr 11, 2011, 03:03 PM
After sleep an take another look on what I did, find to many unnessesary thing so I rewrote it
this my new solution:

int number, left_Num, count, divider;

scanf("%i", &number);

divider = 1; //Set divider
left_Num = number;//Set User number
count = 0; //set counter to zero

while (left_Num > 9)//stop in last digits user enter
{
divider *= 10; //Set the divider to get left num.
left_Num /= 10; // reduce value to end loop
++count; //create count for next loop
}

++count; //since above loop was set to finish 1 digits early we add it here to the count

while (count != 0)
{
left_Num = number / divider; //get the left num
number %= divider; //Get the rest of number digits (ex. if 932, result is 32)
divider /= 10; // decrease divider for update number (ex. update number is 32, divider is 100, result is divider = 10
--count; // decrease counter to finish loop

switch (left_Num)//Display Correct Msg
{
case 0:NSLog(@"Zero");break;
case 1:NSLog(@"One");break;
case 2:NSLog(@"Two");break;
case 3:NSLog(@"Three");break;
case 4:NSLog(@"Four");break;
case 5:NSLog(@"Five");break;
case 6:NSLog(@"Six");break;
case 7:NSLog(@"Seven");break;
case 8:NSLog(@"Eight");break;
case 9:NSLog(@"Nine");break;
default:NSLog(@"Not a digits");break;
}

}
[pool drain];
return 0;
}

tyche
Aug 9, 2011, 09:49 AM
Ok, this was hard. I am reading the Programming in C version but it looks like it has similar problems with the objective-C version.

Anyway, I'm new to C so I tried to solve this by only using what I have been taught in the book so far and didn't cheat by using arrays and stuff.

My solution also covers 0's to the right. eg 100 results in one zero zero. Hope this helps others understand.

int main(void)
{
int count = 0, val = 0, flipval = 0, tval = 0, loop = 0;

printf("Programming in C by Kochan\n");
printf("Chapter 6, example 6\n");
printf("Write a program that takes an integer\nkeyed in from the terminal and extracts and displays\neach digit of the integer in English\n");
printf("-----------------------------------\n");
printf("Enter your number :");
scanf("%i", &val);

// find out how many digits were typed to be used later
tval = val;
do
{
tval = tval / 10;
count++;
}
while (tval !=0);

// now flip the digits once
do
{
flipval = flipval * 10;
flipval = flipval + val % 10;
val = val / 10;
}
while (val > 0);

// now strip each digit and change to a word.
// we use a loop to catch trailing 0's by keeping track of how many digits we started with
// ex. 400 flips to 4 so we need to loop 3 times and add two zero's.
for ( loop =1; loop <= count; loop++)
{
switch (flipval % 10)
{
case 1:
printf("one ");
break;
case 2:
printf("two ");
break;
case 3:
printf("three ");
break;
case 4:
printf("four ");
break;
case 5:
printf("five ");
break;
case 6:
printf("six ");
break;
case 7:
printf("seven ");
break;
case 8:
printf("eight ");
break;
case 9:
printf("nine ");
break;
case 0:
printf("zero ");
break;
default :
printf("zero ");
}
flipval = flipval / 10;
}
return 0;
}

Jun 12, 2014, 06:45 AM
@autoreleasepool {
char temp;
char * s = "[lazyness placeHolder]";
NSLog(@"Enter the number mayne");
while ((temp = getchar()) != '\n') {
s = (temp == '0') ? "zero " :
(temp == '1') ? "one " :
(temp == '2') ? "two " :
(temp == '3') ? "three " :
(temp == '4') ? "four " :
(temp == '5') ? "five " :
(temp == '6') ? "six " :
(temp == '7') ? "seven " :
(temp == '8') ? "eight " :
(temp == '9') ? "nine " : "NaN " ;
if (s[1] != 'a') {
printf("%s",s);
}
}
}

ArtOfWarfare
Jun 12, 2014, 07:01 AM
@autoreleasepool {
char temp;
char * s = "[lazyness placeHolder]";
NSLog(@"Enter the number mayne");
while ((temp = getchar()) != '\n') {
s = (temp == '0') ? "zero " :
(temp == '1') ? "one " :
(temp == '2') ? "two " :
(temp == '3') ? "three " :
(temp == '4') ? "four " :
(temp == '5') ? "five " :
(temp == '6') ? "six " :
(temp == '7') ? "seven " :
(temp == '8') ? "eight " :
(temp == '9') ? "nine " : "NaN " ;
if (s[1] != 'a') {
printf("%s",s);
}
}
}

If someone puts in string that doesn't end in \n, this would crash... Right?

Jun 12, 2014, 07:10 AM
If someone puts in string that doesn't end in \n, this would crash... Right?
It shouldn't as when typing in the terminal you have to press "Enter" or "Return". It has a spectacular chance of crashing if reading from a file as I have no EOF checks

bbarnhart
Jun 16, 2014, 08:12 AM
Since this thread was resurrected I thought I would try it in Swift.

import Foundation

func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)
}

let numbers = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"]

println("Enter numbers: ")

var inputString:NSString = input()

for var index = 0; index < inputString.length; ++index {
let asciiValue = inputString.characterAtIndex(index)

if asciiValue >= 48 && asciiValue <= 57 {
let numberIndex = Int(asciiValue) - 48
println("\(numbers[numberIndex])")
}
}