Function A called out of function A? - c

I'm still a newbie in programming, but I'm trying to make a program that's slightly larger and consists in way more functions than usual. And I want to make a repeatable 'Main menu' (which from you can access the rest of program's functions), but when I'm trying to call out the function again, nothing's happening. It looks like this:
void mainMenu()
{
//clear console screen
//menu of the program
//i.e "Press 1 to choose something
//console screen is cleared again, then new options appear
//"Press E to go back to main menu"
unsigned char v;
v = getch();
if (v == 'E')
mainMenu();
}
What am I doing wrong? Shouldn't the mainMenu() be called out again, clear screen etc? I guess I could just return something from function which would cause the program to call mainMenu() again (and change mainMenu() to int for example), but there must be some workaround, which I'm missing.

You must add an option for exiting out of the loop too !
void mainMenu()
{
system( "cls" );
cout << "1. blah1\n2. blah2\n3. blah3\n4. Main menu\nE. Exit\n\n";
unsigned char v = getch();
if ( v == '1' )
{
cout << "blah1\n";
// Call procedure for blah1
}
else if ( v == '2' )
{
cout << "blah2\n";
// Call procedure for blah2
}
else if ( v == '3' )
{
cout << "blah3\n";
// Call procedure for blah3
}
else if ( v == '4' )
{
mainMenu();
}
if ( v == 'E' )
{
return;
}
}
int main()
{
mainMenu();
}

You mentioned that you are a newer to programming, but have you heard of the control structure in c++ called a switch/case statement? It might be suitable for the simple menu that you are trying to implement. You can read about it here.
A quick example in regards to your desired use case could look something like:
void mainMenu()
{
unsigned char v, w;
v = getch();
switch(v)
{
case 'E':
mainMenu();
break;
case 'A':
w = getch();
if (w == 1)
callFunctionA();
else
mainMenu();
break;
case 'B':
callFunctionB();
break;
// etc... You can have as many 'case' statements as you want depending on
// how many possibilities you want to handle on the user's input.
default:
break;
}
}

I would recommend implementing your function this way:
void mainMenu()
{
unsigned char v;
do
{
//clear console screen
//menu of the program
//i.e "Press 1 to choose something
//console screen is cleared again, then new options appear
//"Press E to go back to main menu"
v = getch();
} while (v == 'E'); // Repeat do-while-loop if user entered 'E'
}
Now there's no change for stack overflow, because there's no recursion involved.

Related

Program is not returning to main function

#include <stdio.h>
#include<math.h>
int taskchoice, a;
void Menu() {
printf("What would you like to do: \n Fish = 1\n Hunt = 2 \n Cook = 3\n Boss = 4\n");
scanf("%d", &a);
if (a == 1) {
Fishing();
}
if (a == 2) {
printf("Hunting\n");
}
if (a == 3) {
printf("Cooking\n");
}
if (a == 4) {
printf("Bossing\n");
}
else {
abort();
}
}
void Fishing() {
printf("Time to fish me lord?\n");
return;
}
int main() {
Menu();
printf("Would you like to go back to the menu?");
//my fishing function is working as intended but the question is, why does it not display
//anything that is posted after the menu(); in the main function
//I am new to C and thank you for taking the time to look at my question.
}
The issue is, there are multiple occurrences of if statement, and the last if-else statement is what makes decides the returning path.
So instead of having multiple if, go with if else-if, because it is sure that the user will input a single int value.
Use the following in place of Menu() function:
void Menu() {
printf("What would you like to do: \n Fish = 1\n Hunt = 2 \n Cook = 3\n Boss = 4\n");
scanf("%d", &a);
if (a == 1) {
Fishing();
}
else if (a == 2) {
printf("Hunting\n");
}
else if (a == 3) {
printf("Cooking\n");
}
else if (a == 4) {
printf("Bossing\n");
}
else {
abort();
}
}
Add return value on main since you have a datatype for your main function.
int main(){
return 0;
}
If not change int main to void main.
Lastly remove void on your finish function. Since the function does not return anything. It returns back to main and ends the main function.

How do you make a menu interface that accepts double digit integers or characters in C?

I was fumbling with this program for the last couple of hours and I can't seem to find a way to get this program to work. I started out with a switch statement style menu but then I had an issue where the menu would fall through and exit and I couldn't figure that out so I just switched my code over to an if else based menu. The idea behind the program is as follows:
Write and test a C program that implements a stack based integer-based calculator. The program accepts input until q is entered. However my difficulties lie in getting the menu to accept numbers larger than 10.
I have every single function working properly in my program except when I enter a two digit integer it will store both digits individually. I know that this is because I have the menu setup to read and work with chars, but I wasn't able to figure out how to get an array of chars to work. I've never programmed in C before so the idea of dynamic memory allocation alludes me as I'm not entirely sure when it is necessary. Here is the source code I have for the program so far:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define SIZE 6
int stack[SIZE]; //stack size
int top = 0; //top of stack
void pop();
void clear();
void display();
void top_element();
void add();
void multiply();
void subtract();
void division();
void power();
int main()
{
char input;
int flag = 1;
while(flag == 1)
{
printf(": ");
scanf(" %c",&input);
if(isdigit(input))
{
if(top < SIZE)
{
stack[top] = input - '0';
top++;
}
else
printf("Error: stack overflow\n");
}
else if(input=='p')
pop();
else if(input=='c')
clear();
else if(input=='d')
display();
else if(input=='=')
top_element();
else if(input=='+')
add();
else if(input=='*')
multiply();
else if(input=='-')
subtract();
else if(input=='/')
division();
else if(input=='^')
power();
else if(input=='q')
flag = 0;
else
printf("Error: invalid command\n");
}
printf("Goodbye!\n");
return 0;
}
void pop()
{
if(top==0)
printf("Error: stack is empty\n");
else
top--;
}
void clear()
{
top=0;
}
void display()
{
int i;
if(top == 0)
printf("Error: stack is empty\n");
else
{
for(i = top - 1; i >= 0; i--)
printf("%d\n",stack[i] );
}
}
void top_element()
{
printf("%d\n",stack[top-1] );
}
void add()
{
if(top<2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans=stack[top-1]+stack[top-2];
stack[top-2]=ans;
top--;
}
}
void multiply()
{
int ans=stack[top-1]*stack[top-2];
stack[top-2]=ans;
top--;
}
void subtract()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans = (stack[top-2] - stack[top-1]);
stack[top-2]=ans;
top--;
}
}
void division()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
if(stack[top-1]==0)
printf("Error: attempt to divide by 0\n");
else
{
int ans = (stack[top-2]/stack[top-1]);
stack[top-2]=ans;
top--;
}
}
}
void power()
{
if(top < 2)
printf("Error: not enough operands for the requested operation\n");
else
{
int ans = pow(stack[top - 2], stack[top - 1]);
stack[top - 2] = ans;
top--;
}
}
I have a few things to note and don't want to turn this into a TLDR so I'll try to keep each issue to separate paragraphs. You can take this all with a grain of salt; it is just advice, after all.
The format directive you're looking for is %2[0123456789]. Pass a pointer to a location suitably sized to store three characters (i.e. char something[3]; the third byte for the null character) and check the return value. This directive needs to go in a call to scanf on its lonesome, or you'll likely have an aneurysm debugging an issue related to empty fields later on, so the "green light" return value indicating your program is successfully processing good input is that scanf("%2[0123456789]", ptr_into_array_of_char) will return 1. Any other return value means amber or red lights happened. Mind you, I'm interpreting your specs (which are incomplete) quite strictly here... in reality I'd just use %d and be happy that my users are halving their chances of developing arthritis by entering 1 instead of 01 (and you're also less likely to have aneurysms when not dealing with %[).
Our compilers usually issue error messages and abort compilation when we make some syntax error, but this requirement goes against that grain: "The program accepts input until q is entered." I hope your full spec explains what should happen when the user deviates from the expectations. I suppose you could issue an error, clear the stack, read to end of line and just operate as though the program restarted... something like scanf("%*[^\n]"); getchar(); puts("Error message here"); top = 0;? We typically use some key combination like CTRL+d (on Linux) or CTRL+Z (on Windows) to close stdin thus denoting termination of input.
"the idea of dynamic memory allocation alludes me" and so you'll be thankful to know that you probably shouldn't use dynamic memory allocation here, unless you want your stack to grow beyond the hardcoded 6 slots that you've set, perhaps...
I assume the title for this question is mixed up in the confusion; you're not designing a menu, but instead implementing a grammar. Look how gccs "menu" is designed for inspiration here. If you're ever tempted to design a menu around stdin, stop; perhaps what you really want is a GUI to point and click because that's not how Unix tends to work.
Declaring void fubar(void); followed by void fubar() { /* SNIP */ } is undefined behaviour due to some technical historical artefacts, and the same goes for int main()... This is why you might be best to choose a book which teaches C specifically, written by somebody reputable, to learn C. There are lots of subtle nuances that can trap you.
On the note of function prototypes and so forth, consider that a stack is a generic data structure. As an alternative thought experiment, consider what a pain strcpy would be to use if it only operated on arrays declared with file scope. It follows logically that all of its external data requirements should come from its arguments, rather than from a variable i.e. stack declared with file scope.
We're taught to use memory somewhat cautiously, and it seems to me as though using a variable solely as a controlling expression like this contravenes those lessons. Where constructs such as break, continue and goto exist, a cleaner alternative without variable declarations (and thus an extra free register to use for something else) is possible.
The problem is not in scanf() this time but in the way you parse the input.
It is not wrong to parse the input character by character, to the contrary it make things much easier, at least in almost all of the cases. But parsing character by character means also that you parse every positive number larger than nine also character by character or better digit by digit--you have to build the complete number out of the single digits. You parse from "the left to the right", so just multiply by ten and add the digit. Rinse and repeat until you have no digits left and put the result on the stack.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define SIZE 6
/* you should look up what "static" means and when and how to use */
static int stack[SIZE]; //stack size
static int top = 0; //top of stack
/*
* You need to expicitely add "void" to the argumet list.
* It defaults to "int" otherwise.
* Please do yourself a favor and switch all warnings on.
*/
void pop(void);
void clear(void);
void display(void);
void top_element(void);
void add(void);
void multiply(void);
void subtract(void);
void division(void);
void power(void);
/* Most checks and balances omitted! */
int main(void)
{
/* "int" to make things easier */
int input;
int flag = 1, anumber;
while (flag == 1) {
printf(": ");
/* get a(n ASCII) character */
input = fgetc(stdin);
if (isdigit(input)) {
anumber = 0;
/*
* We have a digit. Parse input for more digits until
* no further digits appear and add all digits to "anumber".
* We assume a decimal representation here.
*/
/* TODO: check for overflow! */
for (;;) {
anumber *= 10;
anumber += input - '0';
input = fgetc(stdin);
if (!isdigit(input)) {
break;
}
}
/* Push number on the stack */
if (top < SIZE) {
stack[top] = anumber;
top++;
} else {
printf("Error: stack overflow\n");
}
}
/* "input" from fgetc() is an integer, we can use a switch */
switch (input) {
case 'p':
pop();
break;
case 'c':
clear();
break;
case 'd':
display();
break;
case '=':
top_element();
break;
case '+':
add();
break;
case '^':
power();
break;
case 'q':
flag = 0;
break;
default:
printf("Error: invalid command\n");
break;
}
}
printf("Goodbye!\n");
return 0;
}
void pop(void)
{
if (top == 0)
printf("Error: stack is empty\n");
else
top--;
}
void clear(void)
{
top = 0;
}
void display(void)
{
int i;
if (top == 0)
printf("Error: stack is empty\n");
else {
for (i = top - 1; i >= 0; i--)
printf("%d\n", stack[i]);
}
}
void top_element(void)
{
printf("%d\n", stack[top - 1]);
}
void add(void)
{
if (top < 2)
printf("Error: not enough operands for the requested operation\n");
else {
int ans = stack[top - 1] + stack[top - 2];
stack[top - 2] = ans;
top--;
}
}
/* Using pow() from math.h is not a good idea beause it uses floating point */
/* TODO check for overflows! */
static int integer_pow(int x, int n)
{
int r;
r = 1;
while (n != 0) {
if (n & 1) {
r *= x;
}
x *= x;
n >>= 1;
}
return r;
}
void power(void)
{
if (top < 2)
printf("Error: not enough operands for the requested operation\n");
else {
int ans = integer_pow(stack[top - 2], stack[top - 1]);
stack[top - 2] = ans;
top--;
}
}
Test:
$ ./stackbcalc
: 123+23=
Error: not enough operands for the requested operation
: 23
: Error: invalid command
: q
Goodbye!
Does not work. Why? The function add() expects two operands on the stack. You need to put the + also on the stack (it is an integer) and once you are at the end with = you can evaluate the stack. You might need to learn something about infix/postfix/prefix notation to succesfully do so.
Hint: I would also ignore whitespace (space and tab, maybe even return) in the switch.

Getting choice from input

I want to prompt the user to press a key.This key will be stored in a variable and a switch statement is applied on the key to execute the corresponding command.I wrote a code,which seems a bit nasty and inefficient because it makes a call to the function GetAsyncKeyState in an exhausting way,specially if the keys are too many.Is there a simpler approach to this?
#include <stdio.h>
#include <Windows.h>
int GetChoice(int *keys,size_t size);
int main(void)
{
int keys[] = {'A','B','F'};
int cKey = GetChoice(keys,3);
switch(cKey)
{
case 'A':
puts("you pressed : A!");
break;
case 'B':
puts("you pressed : B!");
break;
case 'F':
puts("you pressed : F!");
break;
}
Sleep(2000);
return 0;
}
int GetChoice(int *keys,size_t size)
{
size_t n;
while(1)
{
for(n = 0 ; n < size ; n++)
{
if(GetAsyncKeyState(keys[n]))
return keys[n];
}
}
return 0;
}
Well you need to only change from
int cKey = GetChoice(keys,3);
to
char cKey;
cKey=getch();
you do not need the
int GetChoice(int *keys,size_t size)
function. Just remove it too. Your entire code should look like
#include <stdio.h>
#include<conio.h>
int main(void)
{
char cKey;
cKey=getch();
switch(cKey)
{
case 'A':
puts("you pressed : A!");
break;
case 'B':
puts("you pressed : B!");
break;
case 'F':
puts("you pressed : F!");
break;
}
Sleep(2000);
return 0;
}
You are mixing apples and oranges. If you output messages with puts(), you should probably read input from standard input with getchar(). Reading the keyboard state with GetAsyncKeyState() is only consistent if you display information on the screen using the Windows API. Doing this in C has gone out of fashion a long time ago already. Good luck!
If you're trying to program in C, use C constructs, not Windows constructs. Take a look at K&R (Kernighan and Ritchie) section 1.5. K&R is available in PDF form. Just search for it.
If you use the async key state, you will have to apply your own detection for liftoff.

The invalid choice in the code appears in the output screen

Why does the "Invalid" appear in my output under everything? The invalid choice is the last thing in the menu, am I'm using the statement right or what exactly is wrong?
#include <stdio.h>
void two_assesments();
void three_assesments();
void four_assesments();
void five_assesments();
void six_assesments();
int main( void )
{
int c;
printf("\n*****Student Grade Calculator*****\n\n");
printf(" Developed By...\n");
printf(" Carlos\n");
printf(" University of South Wales\n");
printf(" =================================================================\n");
printf("\n");
printf("\n Please enter the number of assessments in the module : \n");
scanf("%d",&c);
if (c==2) {
two_assesments();
}
if (c==3) {
three_assesments();
}
if (c==4) {
four_assesments();
}
if (c==5) {
five_assesments();
}
if (c==6) {
six_assesments();
}
else
if (c=!7); {
{ printf("\nInvalid"); }
}
return(0);
}
The problem is here
else
if (c=!7); { . . .
You have a ; after if ()
I would suggest you use a switch statement like this
switch (c) {
case 2: two_assesments(); break;
case 3: three_assesments(); break;
case 4: four_assesments(); break;
case 5: five_assesments(); break;
case 6: six_assesments(); break;
default: printf("\nInvalid\n");
}
to make your code more readable.
To understand the problem, consider what happens if the user enters 2. The first if statement evaluates true and the two_assesments function is called. The next three if statements fail. Then we get to the if (c==6). That also fails, so the else is evaluated. And here you have two problems.
First is the semi-colon. Because you have a semicolon after the if (c=!7) the compiler sees your code as
if (c==6) {
six_assesments();
}
else {
if (c=!7)
; /* do nothing */
}
printf("\nInvalid");
In other words, because of the semicolon, the final if statement has no effect, and the printf isn't even part of the else. So "Invalid" always gets printed.
The other problem is the =!. What you meant to say was if (c!=7). By reversing the = and the !, you actually assign 0 to c, and the if always evaluates to false. The compiler should be giving you a warning about that.
A slightly improved version of the code would look like this
if (c==2)
two_assesments();
else if (c==3)
three_assesments();
else if (c==4)
four_assesments();
else if (c==5)
five_assesments();
else if (c==6)
six_assesments();
else
printf("\nInvalid");

Refactoring simple card counting function into multiple functions?

I'm just starting to learn C from Head First C, but I'm having difficulty understanding how refactor my code into multiple functions, more specifically, I don't know how to get functions to work and am confused how to take user input.
How would I incorporate a function like the one below into the main function? What are some other function examples I could use to refactor? Thank you so much!
void get_card_name(char *prompt, char *card_name)
Main function
int main()
{
char card_name[3];
int count = 0;
while ( card_name[0] != 'X' ) {
puts("Enter the card_name: ");
scanf("%2s", card_name);
int val = 0;
switch(card_name[0]) {
case 'K':
case 'Q':
case 'J':
val = 10;
break;
case 'A':
val = 11;
break;
case 'X':
continue;
default:
val = atoi(card_name);
if ((val < 1) || (val > 10)) {
puts("I dont understand that value!");
continue;
}
}
if ((val > 2) && (val < 7)) {
count++;
} else if (val == 10) {
count--;
}
printf("Current count: %i\n", count);
}
return 0;
}
The generic answer when it comes to refactoring is "If it looks complicated or hard to read, try to break it down into smaller pieces that are easier to read (and understand).".
In your case you have this:
int main() {
/* Initial state needed later on */
/* Do some complicated stuff */
}
To refactor this, you need to find out what parts of the initial state you need to keep close to whatever you are going to move away into its own function. In your example, card_name and count are both used inside the complicated bit, and nowhere else. So you can, and should, keep those close the complicated bits:
void do_card_stuff() {
char card_name[3];
int count = 0;
/* Do some complicated stuff */
}
int main() {
do_card_stuff();
}
And, lo and behold, you've refactored your code. If you still think that the card stuff looks complicated, try to break it up into more pieces:
int get_card_value(char card) {
/* Do some complicated stuff */
return value;
}
int do_card_stuff() {
char card_name[3];
int count = 0;
int value;
/* Loop */
/* Get card value from user */
value = get_card_value(card_name[0]);
}
int main() {
do_card_stuff();
}
Just keep at it until it's just silly to break it into smaller bits and you're done. Also, try to keep in mind that the code you break out should be as generic as possible since this will let you re-use this code later on (potentially in other projects).

Resources