1

I want to loop back to the main function in my program but I can't simply call it again in another function due to main being undeclared in the part of the code where the other functions are, is there a way I can fix this?

#include <stdio.h>
#include <conio.h>
#include <cbm.h>
int integer1;
int integer2;
int integer3;
int option;
char choice;

void addition (){
  integer3 = integer1 + integer2;
  printf("%d\n", integer3);
  integer1 = 0;
  integer2 = 0;
  integer3 = 0;
  main();
}

void subtraction (){
  integer3 = integer1 - integer2;
  printf("%d\n", integer3);
  integer1 = 0;
  integer2 = 0;
  integer3 = 0;
  main();
}

void multiplication (){
  integer3 = integer1 * integer2;
  printf("%d\n", integer3);
  integer1 = 0;
  integer2 = 0;
  integer3 = 0;
  main();
}

void division (){
  integer3 = integer1 / integer2;
  printf("%d\n", integer3);
  integer1 = 0;
  integer2 = 0;
  integer3 = 0;
  main();
}

int main()
{ 
   printf("ADVANCED CALCULATOR VERSION 0.2\n");
   printf("CALCULATOR OPTIONS ARE:\n");
   printf("1. ADDITION\n");
   printf("2. SUBTRACTION\n");
   printf("3. MULTIPLICATION\n");
   printf("4. DIVISION\n");
   printf("5. ADVANCED OPERATIONS\n");
   printf("PLEASE SELECT YOUR OPTION.\n");
   scanf("%d", &option);
   if (option == 1){
      printf("FIRST NUMBER?\n");
      scanf("%d", &integer1);
      printf("SECOND NUMBER?\n");
      scanf("%d", &integer2);
      addition();
      }
      else if (option == 2){
        printf("FIRST NUMBER?\n");
        scanf("%d", &integer1);
        printf("SECOND NUMBER?\n");
        scanf("%d", &integer2);
        subtraction();
      }
      else if (option == 3){
        printf("FIRST NUMBER?\n");
        scanf("%d", &integer1);
        printf("SECOND NUMBER?\n");
        scanf("%d", &integer2);
        multiplication();
      }
      else if (option == 4){
        printf("FIRST NUMBER?\n");
        scanf("%d", &integer1);
        printf("SECOND NUMBER?\n");
        scanf("%d", &integer2);
        division();
      }
      else {
        printf("Bruh");
        //exit();
         }
}

I have tried to solve this issue on my own but I could not really find anything good (and possibly understand anything I found since I'm new to C). I would put the main statement first but then that would just cause the other functions to not be declared. Any advice would help, thanks!

  • `printf()` is also a function. What do you think happens when you call `printf()` from `main()` and `printf()` is done running? – Andrew Henle Aug 22 '22 at 23:23
  • 1
    You don't call main from one of your functions. You design your software so that you return to it. (Possibly inside of a loop it contains.) I believe calling main() is specifically disallowed, but I have to look for a reference. – Avi Berger Aug 22 '22 at 23:24
  • 1
    `main()` should only be executed once. You'd be better off adding a `while` loop to `main()`. Then have each of your arithmetic functions simply `return` back to `main()`. Then `main()` can start another iteration of the `while` loop, prompting the user to make a selection. – narwahl Aug 22 '22 at 23:24
  • 2
    @AviBerger: Calling `main` recursively is legal in C, but illegal in C++. However, it is generally not advisable in both languages. – Andreas Wenzel Aug 22 '22 at 23:25
  • Actually, you are allowed to call main in C, its C++ where its disallowed. Still, I wouldn't do it. It'll turn your program into a convoluted mess. Ant what happens when main returns to the function that called it? – Avi Berger Aug 22 '22 at 23:27
  • @AndreasWenzel Yeah, I was just looking that up and typing a new comment. Reminds me of when I shelled out from emacs, didn't realize it, started emacs again, did it again. Don't remember how many levels down I was when I realized what I had been doing. – Avi Berger Aug 22 '22 at 23:30
  • I don't know if you are notified of 'edits'. Please check the recent change to the `division()` function in my answer to avoid problems.. – Fe2O3 Aug 23 '22 at 02:23

3 Answers3

2

Use a while loop

Put a while loop in your main

int main()
{ 
  while(true)
  {
    ...
  }
  return 0;
)

and remove the calls to main()

SargeATM
  • 2,483
  • 14
  • 24
2

You could add a prototype declaration of main immediately after the #include directives:

int main( void );

However, although it is legal to call main recursively in C, this is generally not recommended. The more you do this, the more the stack will grow, and this could lead to a stack overflow if you do this thousands or millions of times.

A better option would be for the content of your main function to run in an infinite loop and for you to add an additional input option to exit the program:

int main( void )
{
    for (;;) //infinite loop
    {
        printf(
            "ADVANCED CALCULATOR VERSION 0.2\n"
            "CALCULATOR OPTIONS ARE:\n"
            "1. ADDITION\n"
            "2. SUBTRACTION\n"
            "3. MULTIPLICATION\n"
            "4. DIVISION\n"
            "5. ADVANCED OPERATIONS\n"
            "6. QUIT\n"
            "PLEASE SELECT YOUR OPTION.\n"
        );

        if ( scanf( "%d", &option ) != 1 )
        {
            printf( "Invalid input!\n" );
            exit( EXIT_FAILURE );
        }

        switch ( option )
        {
            case 1:
            case 2:
            case 3:
            case 4:
                printf( "FIRST NUMBER?\n" );
                if ( scanf( "%d", &integer1 ) != 1 )
                {
                    printf( "Invalid input!\n" );
                    exit( EXIT_FAILURE );
                }

                printf( "SECOND NUMBER?\n" );
                if ( scanf( "%d", &integer2 ) != 1 )
                {
                    printf( "Invalid input!\n" );
                    exit( EXIT_FAILURE );
                }

                switch ( option )
                {
                    case 1:
                        addition();
                        break;
                    case 2:
                        subtraction();
                        break;
                    case 3:
                        multiplication();
                        break;
                    case 4:
                        division();
                        break;
                }
                break;
            case 5:
                printf( "Not yet implemented!\n" );
                break;
            case 6:
                printf( "Quitting program as requested.\n" );
                exit( EXIT_SUCCESS );
            default:
                printf( "Invalid input!\n" );
        }
    }
}

Now, you can remove the calls to main in all of your functions.

Note that in the code above, I have also replaced your if...else if chain with a nested switch statement to prevent code duplication. I have also added a bit of input validation.

You will have to add #include <stdlib.h> in order to use the function exit.

It is also worth noting that using global variables is generally considered bad programming practice. I have rewritten your entire program to use function arguments and local variables instead:

#include <stdio.h>
#include <stdlib.h>

void addition ( int left, int right )
{
    printf( "The result is %d.\n", left + right );
}

void subtraction ( int left, int right )
{
    printf( "The result is %d.\n", left - right );
}

void multiplication ( int left, int right )
{
    printf( "The result is %d.\n", left * right );
}

void division ( int left, int right )
{
    printf( "The result is %d.\n", left / right );
}

int main( void )
{
    for (;;) //infinite loop
    {
        int option;
        int left, right;

        printf(
            "ADVANCED CALCULATOR VERSION 0.2\n"
            "CALCULATOR OPTIONS ARE:\n"
            "1. ADDITION\n"
            "2. SUBTRACTION\n"
            "3. MULTIPLICATION\n"
            "4. DIVISION\n"
            "5. ADVANCED OPERATIONS\n"
            "6. QUIT\n"
            "PLEASE SELECT YOUR OPTION.\n"
        );

        if ( scanf( "%d", &option ) != 1 )
        {
            printf( "Invalid input!\n" );
            exit( EXIT_FAILURE );
        }

        switch ( option )
        {
            case 1:
            case 2:
            case 3:
            case 4:
                printf( "FIRST NUMBER?\n" );
                if ( scanf( "%d", &left ) != 1 )
                {
                    printf( "Invalid input!\n" );
                    exit( EXIT_FAILURE );
                }

                printf( "SECOND NUMBER?\n" );
                if ( scanf( "%d", &right ) != 1 )
                {
                    printf( "Invalid input!\n" );
                    exit( EXIT_FAILURE );
                }

                switch ( option )
                {
                    case 1:
                        addition( left, right );
                        break;
                    case 2:
                        subtraction( left, right );
                        break;
                    case 3:
                        multiplication( left, right );
                        break;
                    case 4:
                        division( left, right );
                        break;
                }
                break;
            case 5:
                printf( "Not yet implemented!\n" );
                break;
            case 6:
                printf( "Quitting program as requested.\n" );
                exit( EXIT_SUCCESS );
            default:
                printf( "Invalid input!\n" );
        }
    }
}

Another issue is that scanf is generally not recommended for user input. When used with user input, it often behaves in a non-intuitive manner, such as

  • not always reading a whole line of input at a time, and
  • accepting input as such "6abc" as valid input for the number 6.

Here is a demonstration of these two issues using a program compiled with the code posted above:

Demonstration of first issue:

ADVANCED CALCULATOR VERSION 0.2
CALCULATOR OPTIONS ARE:
1. ADDITION
2. SUBTRACTION
3. MULTIPLICATION
4. DIVISION
5. ADVANCED OPERATIONS
6. QUIT
PLEASE SELECT YOUR OPTION.
1
FIRST NUMBER?
30 50
SECOND NUMBER?
The result is 80.

Demonstration of second issue:

ADVANCED CALCULATOR VERSION 0.2
CALCULATOR OPTIONS ARE:
1. ADDITION
2. SUBTRACTION
3. MULTIPLICATION
4. DIVISION
5. ADVANCED OPERATIONS
6. QUIT
PLEASE SELECT YOUR OPTION.
1
FIRST NUMBER?
5
SECOND NUMBER?
6abc
The result is 11.

It would be better if the input were rejected in both cases.

For this reason, instead of using scanf, I recommend using the function fgets to always read an entire line of input. After reading the input as a string, it can be converted to an integer using the function strtol, and the rest of the string can be checked for input that does not belong there (such as "abc" when the user enters "6abc"). Instead of calling both of these functions every time you to read an integer from input, it would probably be better to create your own function which combines both function calls. Also, it would be good if that function would automatically reprompt the user for input, if the user input is invalid. In the second code snippet of this answer of mine to another question, I have created such a function, which I call get_int_from_user.

If I replace all calls to scanf with calls to the function get_int_from_user, then the program will have the following behavior instead:

ADVANCED CALCULATOR VERSION 0.2
CALCULATOR OPTIONS ARE:
1. ADDITION
2. SUBTRACTION
3. MULTIPLICATION
4. DIVISION
5. ADVANCED OPERATIONS
6. QUIT
PLEASE SELECT YOUR OPTION.
1
FIRST NUMBER?
30 50
Unexpected input encountered!
FIRST NUMBER?
30
SECOND NUMBER?
50
The result is 80.
ADVANCED CALCULATOR VERSION 0.2
CALCULATOR OPTIONS ARE:
1. ADDITION
2. SUBTRACTION
3. MULTIPLICATION
4. DIVISION
5. ADVANCED OPERATIONS
6. QUIT
PLEASE SELECT YOUR OPTION.
1
FIRST NUMBER?
5
SECOND NUMBER?
6abc
Unexpected input encountered!
SECOND NUMBER?
6  
The result is 11.

As you can see, the program no longer has the issues mentioned above.

Here is the full code of the program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>

int get_int_from_user( const char *prompt );

void addition ( int left, int right )
{
    printf( "The result is %d.\n", left + right );
}

void subtraction ( int left, int right )
{
    printf( "The result is %d.\n", left - right );
}

void multiplication ( int left, int right )
{
    printf( "The result is %d.\n", left * right );
}

void division ( int left, int right )
{
    printf( "The result is %d.\n", left / right );
}

int main( void )
{
    for (;;) //infinite loop
    {
        int option;
        int left, right;

        printf(
            "ADVANCED CALCULATOR VERSION 0.2\n"
            "CALCULATOR OPTIONS ARE:\n"
            "1. ADDITION\n"
            "2. SUBTRACTION\n"
            "3. MULTIPLICATION\n"
            "4. DIVISION\n"
            "5. ADVANCED OPERATIONS\n"
            "6. QUIT\n"
        );

        option = get_int_from_user( "PLEASE SELECT YOUR OPTION.\n" );

        switch ( option )
        {
            case 1:
            case 2:
            case 3:
            case 4:
                left = get_int_from_user( "FIRST NUMBER?\n" );

                right = get_int_from_user( "SECOND NUMBER?\n" );

                switch ( option )
                {
                    case 1:
                        addition( left, right );
                        break;
                    case 2:
                        subtraction( left, right );
                        break;
                    case 3:
                        multiplication( left, right );
                        break;
                    case 4:
                        division( left, right );
                        break;
                }
                break;
            case 5:
                printf( "Not yet implemented!\n" );
                break;
            case 6:
                printf( "Quitting program as requested.\n" );
                exit( EXIT_SUCCESS );
            default:
                printf( "Invalid input!\n" );
        }
    }
}

int get_int_from_user( const char *prompt )
{
    //loop forever until user enters a valid number
    for (;;)
    {
        char buffer[1024], *p;
        long l;

        //prompt user for input
        fputs( prompt, stdout );

        //get one line of input from input stream
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            fprintf( stderr, "Unrecoverable input error!\n" );
            exit( EXIT_FAILURE );
        }

        //make sure that entire line was read in (i.e. that
        //the buffer was not too small)
        if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
        {
            int c;

            printf( "Line input was too long!\n" );

            //discard remainder of line
            do
            {
                c = getchar();

                if ( c == EOF )
                {
                    fprintf( stderr, "Unrecoverable error reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        //attempt to convert string to number
        errno = 0;
        l = strtol( buffer, &p, 10 );
        if ( p == buffer )
        {
            printf( "Error converting string to number!\n" );
            continue;
        }

        //make sure that number is representable as an "int"
        if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
        {
            printf( "Number out of range error!\n" );
            continue;
        }

        //make sure that remainder of line contains only whitespace,
        //so that input such as "6sdfj23jlj" gets rejected
        for ( ; *p != '\0'; p++ )
        {
            if ( !isspace( (unsigned char)*p ) )
            {
                printf( "Unexpected input encountered!\n" );

                //cannot use `continue` here, because that would go to
                //the next iteration of the innermost loop, but we
                //want to go to the next iteration of the outer loop
                goto continue_outer_loop;
            }
        }

        return l;

    continue_outer_loop:
        continue;
    }
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • Thank you for your response, I did not know global variables were not really good in practice. I will keep this advice in mind in the future. – Mr Buddyboi Aug 23 '22 at 00:40
  • @Fe2O3: My goal is to show OP that using function arguments instead of global variables makes the code cleaner. If I start adding `if` branches, OP will get the opposite impression. – Andreas Wenzel Aug 23 '22 at 04:42
  • @Fe2O3: Yes, that is probably correct, but I wanted to show OP how to use function arguments instead of global variables while keeping the function structure. If I simply had removed these functions, then there would no longer have been a reason to use function arguments. – Andreas Wenzel Aug 23 '22 at 04:48
  • @AndreasWenzel "would have no reason to use function arguments"... except when calling `printf()` and/or `scanf()`... (I agree that scanf should be banned and binned.) – Fe2O3 Aug 23 '22 at 04:50
  • @MrB: Note that meanwhile, I have added an alternative solution to my answer, which does not use `scanf`. – Andreas Wenzel Aug 23 '22 at 05:59
1

Kudos to you. You are obviously working very hard at this problem.

The following is offered as a less repetitious version of your code. I hope this helps make you a better programmer. This is a 'partially condensed' version of what you have written.

Notice the two comments in the following code referring to "infinite loop" that will 'restart' execution at the top of the loop.

Keep at it!

#include <stdio.h>
#include <conio.h>
#include <cbm.h>

int integer1;
int integer2;
int option;

void get2nums() {
    printf( "FIRST NUMBER?\n" );
    scanf( "%d", &integer1);
    printf( "SECOND NUMBER?\n");
    scanf( "%d", &integer2);
}

void addition() {
    get2nums();
    printf( "%d\n", integer1 + integer2 );
}

void subtraction() {
    get2nums();
    printf( "%d\n", integer1 - integer2 );
}

void multiplication() {
    get2nums();
    printf( "%d\n", integer1 * integer2 );
}

void division() {
    get2nums();
    if( integer2 == 0 )
        printf( "Div by 0 undefined\n" );
    else
        printf( "%d with %d remainder\n", integer1 / integer2, integer1 % integer2 );
}

int main() {
    // for( ;; ) { // uncomment this line and below for infinite looping
    printf("ADVANCED CALCULATOR VERSION 0.2\n");
    printf("CALCULATOR OPTIONS ARE:\n");
    printf("1. ADDITION\n");
    printf("2. SUBTRACTION\n");
    printf("3. MULTIPLICATION\n");
    printf("4. DIVISION\n");
//  printf("5. ADVANCED OPERATIONS\n"); // TODO
    printf("PLEASE SELECT YOUR OPTION.\n");

    scanf( "%d", &option );

    if( option == 1 )
        addition();

    else if( option == 2 )
        subtraction();

    else if( option == 3 )
        multiplication();

    else if( option == 4 )
        division();

    else
        printf( "Bruh" );
    // }  // uncomment this line for infinite looping
    return 0;
}

As some rather 'undocumented but advanced' lines of code have been proposed, I offer this to the student for careful study. It contains some elements that you won't encounter until the later chapters of the textbook. But, it's been fun for an hour.

#include <stdio.h>
#include <stdlib.h>

typedef void(*func_t)(int,int);

void stdOut( char op, int res, int i1, int i2 ) {
    printf( "\n%d %c %d = %d%c", i1, op, i2, res, "\n "[op=='/'] );
}

void add( int i2, int i1 ) { stdOut( '+', i1 + i2, i1, i2 ); }
void sub( int i2, int i1 ) { stdOut( '-', i1 - i2, i1, i2 ); }
void mul( int i2, int i1 ) { stdOut( '*', i1 * i2, i1, i2 ); }
void dvd( int i2, int i1 ) {
    if( i2 == 0 ) { printf( "Div by 0 undefined\n" ); return; }
    stdOut( '/', i1 / i2, i1, i2 );
    printf( "with %d remainder\n", i1 % i2 );
}

int getInt( char *prompt ) {
    char buf[64]; // sufficient
    printf( "%s", prompt );
    fgets( buf, sizeof buf, stdin );
    return atoi( buf );
}

void get2nums( func_t f ) { f( getInt( "SECOND NUMBER: " ), getInt( "FIRST NUMBER: ") ); }

int main() {
    func_t f[] = { &add, &sub, &mul, &dvd, };

    printf("ADVANCED CALCULATOR VERSION 0.2");
top:
    printf(
        "\nCALCULATOR OPTIONS ARE:\n"
        "0. Quit\n"
        "1. ADDITION\n"         "2. SUBTRACTION\n"
        "3. MULTIPLICATION\n"   "4. DIVISION\n"
//      "5. ADVANCED OPERATIONS\n" // TODO
    );

    int opt = getInt( "PLEASE SELECT YOUR OPTION: " );
    switch( opt ) {
        case 0: printf( "\nBye-bye\n" ); return 0;
        case 1:
        case 2:
        case 3:
        case 4: get2nums( f[ opt - 1 ] ); break;
        default:
            printf( "\nBruh\n\n" );
    }
    goto top;

    return 0;
}

Output:

ADVANCED CALCULATOR VERSION 0.2
CALCULATOR OPTIONS ARE:
0. Quit
1. ADDITION
2. SUBTRACTION
3. MULTIPLICATION
4. DIVISION
PLEASE SELECT YOUR OPTION: 3
FIRST NUMBER: 42
SECOND NUMBER: 54

42 * 54 = 2268

CALCULATOR OPTIONS ARE:
0. Quit
1. ADDITION
2. SUBTRACTION
3. MULTIPLICATION
4. DIVISION
PLEASE SELECT YOUR OPTION: 4
FIRST NUMBER: 8
SECOND NUMBER: 3

8 / 3 = 2 with 2 remainder

CALCULATOR OPTIONS ARE:
0. Quit
1. ADDITION
2. SUBTRACTION
3. MULTIPLICATION
4. DIVISION
PLEASE SELECT YOUR OPTION: 0

Bye-bye
Fe2O3
  • 6,077
  • 2
  • 4
  • 20