Creating a program loop for the first time in objective-c - c

I am trying to add some "replay-value" if you will to my temperature scale conversion console program in Objective-C by adding a simple loop.
Now, here is the code for my current main.m file:
#import <Cocoa/Cocoa.h>
#import "class.h"
int main(int argc, char *argv[])
{
int result;
int prompt, prompt2, sourceTempText;
double sourceTemp;
printf("Please choose a source temperature scale:\n[1] Fahrenheit\n[2] Celsius\n[3] Kelvin\n[4] Rankine\n\n");
result = scanf("%i", &prompt);
if (result != 1)
printf("I couldn't understand your input, I need only one number!");
else if (result == EOF)
printf("I apologize, I encountered an error when trying to read your input.");
else if (result == 1)
{
printf("\nNow, please enter the temperature you would like to convert:\n\n");
scanf("%lf", &sourceTemp);
Temperature *converter = [[Temperature alloc] init];
switch (prompt)
{
case 1:
//end-user chooses Fahrenheit
[converter setFahrenheitValue:sourceTemp];
sourceTempText = 1;
break;
case 2:
//end-user chooses Celsius
[converter setCelsiusValue:sourceTemp];
sourceTempText = 2;
break;
case 3:
//end-user chooses Kelvin
[converter setKelvinValue:sourceTemp];
sourceTempText = 3;
break;
case 4:
//end-user chooses Rankine
[converter setRankineValue:sourceTemp];
sourceTempText = 4;
break;
}
printf("\nNow, please choose a target temperature scale:\n[1] Fahrenheit\n[2] Celsius\n[3] Kelvin\n[4] Rankine\n\n");
scanf("%i", &prompt2);
char *scales[4] = { "Fahrenheit", "Celsius", "Kelvin", "Rankine" };
switch (prompt2)
{
case 1:
//end-user chooses Fahrenheit
printf("%lf degrees %s is %lf degrees Fahrenheit\n", sourceTemp, scales[prompt-1], [converter fahrenheitValue]);
break;
case 2:
//end-user chooses Celsius
printf("%lf degrees %s is %lf degrees Celsius\n", sourceTemp, scales[prompt-1], [converter celsiusValue]);
break;
case 3:
//end-user chooses Kelvin
printf("%lf degrees %s is %lf degrees Kelvin\n", sourceTemp, scales[prompt-1], [converter kelvinValue]);
break;
case 4:
//end-user chooses Rankine
printf("%lf degrees %s is %lf degrees Rankine\n", sourceTemp, scales[prompt-1], [converter rankineValue]);
break;
}
}
}
OK, so I would like to prompt the user with a printf statement, asking them if they would like to convert another temperature once they have made their first conversion.
The prompt would ask the end-user to press 0 to exit the program, or 1 to make another conversion.
My first inclination was to declare an integer variable which would be set to 0 or 1 from scanf once the end-user has inputted their choice.
Then, if the new variable == 1, then it would loop back to the beginning, if not, it would exit the program.
Pretty simple, huh?
Just wondering, is there a more efficient way to loop this program or is this a good way, at least with the basic knowledge I have now.

Yes you could just put it in a loop, and ask the exit question right before the end of the loop. Depending on the answer, you could just exit(0). Or you could integrate it in the first question; 1=Fahrenheit, 2=..., 0 = Exit.
The loop could just be while(1) { ... }. Another approach would be to have a variable before the loop:
int done = 0;
and then loop over while ( !done ) { ... }. (read this as "while not done"). In the loop, set done=1 when you're done, and the loop will then terminate.
(for clarity: it will terminate only after completing the whole { ... } block, but you will find that out - if you come to that point you need to read(/ask) about continue and break)
There are a few things to consider: does your loop need to clean up? Here
Temperature *converter = [[Temperature alloc] init];
you allocate some memory. If you just loop again, you will allocate some more memory. And so on: this is called a "memory leak". This goes on until you run out of memory and the program would crash (although it would take a long long time in this case).
So you should really release the converter when you're done with it, by doing
[converter release];
This way you will not leak any memory.
Also this would be a good moment to put parts of your program in a separate function, because it becomes a little bit unclear what exactly is happening when it gets bigger and bigger.

Related

Hexadecimal Number convertor

i trying to write a Recursion function that get a decimal number and print the value in hexadecimal
but i dont know what worng in my code
please help me i still new in Recursion and dont get it complitly...
my code:
void PrintHexadecimalNumber(int n)
{
if (n%16==0)
return ;
PrintHexadecimalNumber(n/16);
switch ((n % 16))// A-F cases
{
case (10):
printf("A");
break;
case (11):
printf("B");
break;
case (12):
printf("C");
break;
case (13):
printf("D");
break;
case (14):
printf("E");
break;
case (15):
printf("F");
break;
}
if ((n%16)<10)
printf(n%16);
}
Your code isn't going to work because of the test you've written to stop the recursion.
if (n%16==0)
If you have the number (in hex) 10, the function will stop immediately because n % 16 will be 0. What you actually want to test for is when n is 0. Like this
if (n==0)
Your switch statement should also be expanded out to include the values 0 to 9 rather than having a separate if statement after it. You can group them together by leaving out the break
switch(n % 16)
{
/* existing case statements go here */
case 0:
case 1:
case 2:
...
case 9:
printf("%d",n % 16); // also fixing this as per comments above.
break;
}
Or you could just use printf("%x",n % 16) and do away with the switch completely if what you're trying to do is explore how recursion works.

I don't know what is causing a segmentation fault

I am trying to create a simple "diary", where you add workers and then write them how many hours they have worked. But every time I get to the switch statement, I get a segmentation fault. I don't know what is causing it and my knowledge is not yet on the level where I can find it myself.
The code:
include <stdio.h>
include <stdlib.h>
include <string.h>
int vybera(int pocet){
int vyber;
int i;
printf("\nKtery zamestnanec?\n");
for(i = 0; i < pocet; i++){
printf("%d\n", i + 1);
}
scanf("%d", vyber);
return vyber;
}
int main(int argc, char** argv) {
int worker;
int pocet;
int i;
int vyber;
int pomoc;
int odprac = 0;
printf("Kolik zamestnancu chcete pridat: ");
scanf("%d%*c", &pocet);
char workforce[pocet][100];
printf("Zadejte %d jmen: \n", pocet);
for(i = 0; i < pocet; i++){
gets(workforce[i]);
}
for(i = 0; i < pocet; i++){
printf("%s\n", workforce[i]);
}
vyber = vybera(pocet);
switch(vyber){
case 1:
worker = vyber - 1;
printf("Vybrali jste %s.\n", workforce[worker]);
printf("Pocet odprac. hodin: ");
scanf("%d", pomoc);
odprac += pomoc;
strcat(workforce[worker], (", %c", odprac + '0'));
break;
case 2:
worker = vyber - 1;
printf("Vybrali jste %s.\n", workforce[worker]);
printf("Pocet odprac. hodin: ");
scanf("%d", pomoc);
odprac += pomoc;
strcat(workforce[worker], (", %c", odprac + '0'));
break;
case 3:
worker = vyber - 1;
printf("Vybrali jste %s.\n", workforce[worker]);
printf("Pocet odprac. hodin: ");
scanf("%d", pomoc);
odprac += pomoc;
strcat(workforce[worker], (", %c", odprac + '0'));
break;
case 4:
worker = vyber - 1;
printf("Vybrali jste %s.\n", workforce[worker]);
printf("Pocet odprac. hodin: ");
scanf("%d", pomoc);
odprac += pomoc;
strcat(workforce[worker], (", %c", odprac + '0'));
break;
case 5:
worker = vyber - 1;
printf("Vybrali jste %s.\n", workforce[worker]);
printf("Pocet odprac. hodin: ");
scanf("%d", pomoc);
odprac += pomoc;
strcat(workforce[worker], (", %c", odprac + '0'));
break;
default:
printf("Spatny vyber.\n");
}
for(i = 0; i < pocet; i++){
printf("%s\n", workforce[i]);
}
return (EXIT_SUCCESS);
}
I am really at my wits end, and need every help I can get. The reason why I'm posting this even though there are many question on the segementation fault topic is that none of them are using my code. I appreciate any help and all of your patience.
EDIT: I'm from Czechia, hence why most of my variables and all my printf outputs are in czech. Just FYI.
change: scanf("%d", vyber); to scanf("%d", &vyber) do the same with pomoc;
Explanation: Because vyber variable is int you need to explicitly pass the address value with "&" ampersand, unlike a string(which implicitly passes its address). The segmentation fault indicates you are trying to access a memory which doesn't belong to you. In this case vyber.
You've already been told where the problem is, but let me briefly mention how you can find the (next) problem yourself. Basically, there are (at least) three ways:
Use a debugger to run your program line by line until it crashes. A debugger will also let you stop the program and examine the values of any variables to see what the code is actually doing.
You haven't told us what OS, compiler and IDE (if any) you're using, so I can't recommend any specific debugger (and in any case that's really not on-topic for SO), but there almost certainly is a debugger available for your system, whatever it is. Learning how to use a debugger takes a little effort, but it's definitely worth it.
If you can't or don't want to use a debugger for some reason, you can do "poor man's debugging" by adding printf() statements into your code that show what's happening. That way, you can see how far the program gets before crashing, and you can also print out the values of variables to get a better idea of what's happening.
I would recommend printing to the standard error stream (with fprintf(stderr, "...")), since it won't interfere with normal output of the program, and since the error stream will be automatically flushed every time you print to it, so that there's no risk of buffered output being lost if the program crashes.
A useful trick is to prefix such debugging print statements with if (DEBUG), like this:
if (DEBUG) fprintf(stderr, "This is an example of debugging output.\n");
Then, at the top of your program, include a line like:
#define DEBUG 1
That way, you can easily turn the debugging output off by changing the 1 to a 0. (There are also more advanced ways to change the definition at compile time, or to configure your IDE to change it depending on the build target, but that's outside the scope of the answer.)
Finally, you can do "bisection debugging". Basically, make a copy of your program (or, better yet, commit it into your version control system) and start removing parts of the code until the problem stops happening. At that point, you'll know that the problem is related to something in the last piece of code you removed. You can then undo the most recent change, and remove something else, and keep doing that until you've reduced your program to the simplest possible example that still demonstrates the problem.
At that point, it should be easy to see what the problem is, since you no longer have any irrelevant code left to distract you. Or, if not, at least you have a short piece of code that cleanly demonstrates the problem and which you can post on Stack Overflow to ask for help. :)
scanf("%d", pomoc);
This is incorrect syntax for the scanf() function. It should be:
scanf("%d", &pomoc);
This same error is replicated in the input statement for vyber
scanf("%d", &vyber)
This happens because you are trying to access an out-of bounds location in memory with the scanf() function. Since you don't reference the variable vyber and pomoc, the compiler tries to access the memory spot at an address equal to the variable stored in vyber and pomoc, rather than the memory location of these respective variables. This goes into undefined behavior, which is why you get a seg-fault.

Code is ignoring IF command in C, Issues with FOR

I had posted on here before, but I was never able to get the help I needed.
I'm working on a school project and I can not get my program to work properly.
The program should prompt the user to enter the number of gallons used and
the number of miles driven for each of the 3 tanks of gas. The program should
then calculate and display the miles per gallon obtained for each tank. Once
processing is complete for the 3 tanks, the program will calculate the overall
mileage(total gallons / total miles) and display a friendly "Goodbye" message.
The issue i am having is that I can not get it to display to OVERALL Millage. it ends after looping 3 times.
I know different loop statements need conditions to be met, but I cant get the FOR loop to work properly. Im getting really frustrated, cause I know this should not be this hard.
Code
#include <stdio.h>
int main(void)
{
int miles,i=3;
float gallons, mg, overall = 0, avg = 0;
while(i>0)
{
printf("Enter the gallons used: ");
scanf("%f", &gallons);
printf("Enter miles driven: ");
scanf("%d", &miles);
mg = miles/gallons;
printf("The miles/gallon for this tank was : %f\n", mg);
overall += miles;
avg += gallons;i--;
}
if(gallons == 0)
{
printf("\n\n The overall miles/gallon was: %f\n", overall/avg);
exit(0);
}
return 0;
}
If I read your code correctly, then what is preventing the overall mileage from being printed is the following final if statement:
if (gallons == 0)
If you remove it, then the overall mileage should print. Use this pattern:
while (i > 0)
{
// your while loop here
}
printf("\n\n The overall miles/gallon was: %f\n", overall/avg);
exit(0);
This if (if (gallons == 0) {})block is out of while loop.
First, you need to move the if loop inside while loop.
and this if condition should be for variable i as follow and not for gallons.
if (i == 0)
{
printf("\n\n The overall miles/gallon was: %f\n", overall/avg);
}
In this case, after 3 iteration, value of i will be 0 so it will enter into the if block and calculate and print the overall miles/gallon.
Adding to Tim Biegeleisen's answer:
mg = miles/gallons;
What if gallons equals to 0? e.g. 0 miles for 0 gallons
This will lead to floating point exception.
A simple if-else can solve this problem!
if(!gallons)
mg = 0;
else
mg = miles/gallons;

Scanning multiple inputs and outputting based on the amount true/false - in C

I have an assignment that is supposed to ask the user a few questions about temperature in regards to a plane launch.
EX:
What is the average temperature?
Lowest temperature in the past day?
Is it raining?
Now the program is suppose to take the input and base it on a few conditions
temperature must be 42 degrees
temperature couldn't have dropped below 32
Can't be raining
So I got the output that gives 'the okay' for the plane launch by nesting some 'if statements', that's all good. The problem is that, depending on the number of incorrect statements, it'll output something different.
EX:
If the only issue is that the temperature is below 32 degrees, it'll output:
"The plane is not launching because the temperature has dropped below 32 degrees in the past day"
If the temperature dropped below 32 degrees AND it's raining, the program will spit out
"The plane is not launching because:
The temperature is below 32 degrees
it's raining"
I know that I can make a whole bunch of if statements for each situation but that'll just make my code massive and confusing. Surely there must be a simpler way to set it up in which 'there are 2 statements false, so print this depending on which 2'. Should I make a switch statement?
The last class I took I separated all of the work into functions and then just called down each one into the main when needed. In this course, we have to do all of the work in the main function and it is kinda confusing because I began learning a different way.
Thanks in advance.
The ternary operator combined with format strings is a handy way to solve this problem.
The ternary operator allows you to conditionally-assign a value based on some boolean expression, and format strings let you inject other strings into your printfs, even empty strings:
char *cond1 = temperature_is_low ? "the temperature is low" : "";
char *cond2 = is_raining ? "it's raining" : "";
char *sep = (temperature_is_low && is_raining) ? " and " : "";
printf("The plane will not launch because %s%s%s.\n", cond1, sep, cond2);
If you can't use ternary operators or format strings, you could do the same thing by separating the print over multiple lines:
printf("The plane will not launch because ");
if (temperature_is_low)
printf("the temperature is low");
if (temperature_is_low && is_raining)
printf(" and ");
if (is_raining)
printf("it's raining");
printf(".\n");
You could do something like:
#define avgTmpErrMsg "the temperature is below 42 degrees"
#define lowTmpErrMsg "the temperature has dropped below 32 degrees in the past day"
#define rainingErrMsg "it's raining"
short state = (avgTmp < 42) + ((lowTmp < 32)<<1) + ((raining)<<2); // store the state in one simple variable
short nErr = (avgTmp < 42) + (lowTmp < 32) + (raining); // number of error
switch(nErr){
case 0: // no error
printf("could launch\n");
break;
case 1: // one error
printf("The plane is not launching because %s\n", msg(state,1));
break;
case 2: // 2 errors
printf("The plane is not launching because:\n%s\n%s\n",msg(state,1),msg(state,2));
break;
case 3: // 3 errors
printf("The plane is not launching because:\n%s\n%s\n%s\n",msg(state,1),msg(state,2),msg(state,3));
break;
}
char* msg(short err,short n) {
/* print the nth error stored in err */
return ((err&1 && (!(--n)))? avgTmpErrMsg : ((err&2 && (!(--n)))? lowTmpErrMsg : rainingErrMsg));
}

C switch statement with do-while interleaved [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does Duff's device work?
I am trying to understand how this is working. Any help would be appreciated.
#include<stdio.h>
void duff(int count)
{
int n=(count+7)/8;
printf("n=%d count =%d\n",n,count%8);
switch(count%8){
case 0: do{ printf("case 0\n");
case 7: printf("case 7\n");
case 6: printf("case 6\n");
case 5: printf("case 5\n");
case 4: printf("case 4\n");
case 3: printf("case 3\n");
case 2: printf("case 2\n");
case 1: printf("case 1\n");
}while( --n >0);
}
}
main(){
int count;
scanf("%d",&count);
duff(count);
}
Basically if the switch case evaluates to case statement 2, then the do statment of the while is never executed. But i ran this program and it gave me the output, but unable to explain:
output:
3
n=1 count =3
case 3
case 2
case 1
This is known as duff's device and is used in code optimization techniques to reduce branch instructions. The reason that it works is that by default case statements without breaks fall through to the next case so when you hit case 3, you keep going through to case 2 and case 1.
Both the do and the case "statements" are essentially just "goto labels". They don't add any actual code. They just tell while and switch (respectively) where to jump to. In other words, there is no code for the do to (not) execute.
(That said, it is somewhat remarkable/bizarre that C's grammar allows cases to exist in children of the switch, rather just as direct children of a switch.)
There are no break statements between the cases so the cases fall through. Therefore n=3 causes case 3: case 2: and case 1: to be executed.

Resources