Please excuse - and do not hesitate to point out - any violation against etiquette that I might be committing here… I am new here.

I started to learn C a few months ago as a hobby as part of a bigger project, namely to learn about computers in general. I have had so much fun reading Code - The Hidden Language of Computer Hardware and Software by Charles Petzold. But that’s another story…

I was about to buy a few new SSDs and needed to do some budgeting. Instead of using my phone’s calculator, I decided to try to write a calculating program in C, because I hadn’t touched programming for some weeks or months because life and I wanted to see if my knowledge had matured some.

The goal was to have it do the four standard arithmetics and also save the last result in a variable, which I just called “memory” for lack of bette phrasing on my part. Maybe next week I’ll figure out how to make it possible to use the value saved in memory instead of having to type a number.

I welcome any constructive criticism on how and why this code is up to code or not(sorry…), if it can be improved and how or even if it’s just garbage and why that is. I am just proud that it worked without gcc throwing any errors.

#include <stdio.h>

int main(void) {

        int num1 = 0;
        int num2 = 0;
        int choice = 0;
        int memory = 0;

        printf("Welcome to the Calculator of the century!\n\n");

        while (1) {
                printf("What would you like to do?\n\n");
                printf("(1) Add two numbers\n(2) Subtract two numbers\n(3) Multiply two numbers\n(4) Divide two numbers\n(5) Show memory\n(6) Exit\n\n");
                printf("Enter 1, 2, 3, 4, 5 or 6: ");
                scanf("%d", &choice);

                if (choice >= 6 || choice < 1) break;

                if (choice == 5) {
                        printf("\n%d in memory.\n\n", memory);
                } else if (choice < 5 || choice > 0) {
                        printf("\nEnter the first number: ");
                        scanf("%d", &num1);
                        printf("Enter the second number: ");
                        scanf("%d", &num2);
                }

                if (choice == 1) {
                        printf("\nThe sum of %d and %d is %d\n\n", num1, num2, num1 + num2);
                        memory = num1 + num2;
                } else if (choice == 2) {
                        printf("\nThe difference of %d and %d is %d\n\n", num1, num2, num1 - num2);
                        memory = num1 - num2;
                } else if (choice == 3) {
                        printf("\nThe product of %d and %d is %d\n\n", num1, num2, num1 * num2);
                        memory = num1 * num2;
                } else if (choice == 4) {
                        printf("\nThe quotient of %d and %d is %d\n\n", num1, num2, num1 / num2);
                        memory = num1 / num2;
                }
        }

        printf("\nWe hope to see you soon again!\n");
        return 0;
}
  • vrek@programming.dev
    link
    fedilink
    English
    arrow-up
    7
    ·
    12 days ago

    All the other tips are great. I would also recommend checking out a switch statement, for example https://www.geeksforgeeks.org/c/c-switch-statement/

    This will clean up alot of the else if statements. Also I would work on code to organization. For example you test if the choice is greater than or equal to 6 or less than 1, then if it is equal to 5 then check again if it’s less than 5 and greater than 0. You already did that third check.

    If you want to go slightly more advanced I would put the steps to ask for and save the input numbers into a function then just call that function on each of the following choices. Would add a functional call but would remove another if statement. If you name it well it would also help on code readability.

    Also if you want to take this farther like taking more than 2 numbers or more than 1 operation (for example 2 + 3 * 4) look into reverse polish notation. Basically it’s how to store the equation to make executing them correctly easier. That might be a little advanced for you at this stage though.

      • vrek@programming.dev
        link
        fedilink
        English
        arrow-up
        2
        ·
        11 days ago

        Just warning you, the rpn suggestion is pretty complex and would be a complete rewrite. You are on chapter 2, rpn would probably be covered in the second book.

  • Victoria@lemmy.blahaj.zone
    link
    fedilink
    English
    arrow-up
    6
    ·
    edit-2
    12 days ago

    A classic beginners C program! Some points of inspiration:

    • for better readability, try splitting the operations into functions.
    • you could look into using a switch statement instead of chained if-else
    • see what happens if you enter something that isn’t a number, and how you could fix it.
      • vrek@programming.dev
        link
        fedilink
        English
        arrow-up
        2
        ·
        11 days ago

        General computing tip: if that happens you can press ctrl and c and it will stop the current program(assuming windows). Useful when making console apps especially when you are learning and are likely to make mistakes and infinite loops.

        • emotional_soup_88@programming.devOP
          link
          fedilink
          English
          arrow-up
          2
          ·
          11 days ago

          Thanks! I’m doing this on Linux, which I failed to mention in the post. I terminated the program with ctrl + c, but it was still interesting to me how such a short, seemingly uncomplicated snippet could tax my Ryzen 7 5800 X3D so much that the fans needed to increase their speed. Couldn’t a malicious actor theoretically disrupt a target machine by having an unnoticeably insignificant program loop in the background, taxing the CPU to it’s usable limits? This is off topic of course, but still interesting.

          • vrek@programming.dev
            link
            fedilink
            English
            arrow-up
            3
            ·
            11 days ago

            For a small amount of time in a lot of cases. It would likely run out of memory and crash the system.

  • who@feddit.org
    link
    fedilink
    English
    arrow-up
    5
    ·
    edit-2
    11 days ago

    Just in case you aren’t aware, int division throws away remainders. (And float/double tends to accumulate small inaccuracies.) You’ll want to keep that in mind if using this code for budgeting or any other money calculations.

    Congratulations on writing a working program!

      • who@feddit.org
        link
        fedilink
        English
        arrow-up
        2
        ·
        11 days ago

        When you get to the point where accurate fractional amounts matter, or if you start processing very large numbers, consider using an arbitrary precision arithmetic library instead of the simple CPU operations that C exposes.

      • vrek@programming.dev
        link
        fedilink
        English
        arrow-up
        2
        ·
        11 days ago

        Also look up the modulo operator. It’s similar to integer division but ONLY returns the remainder. It’s useful if you want to have something with multiple division steps for example.

        38 hours is how many days? 38 / 24 = 1 with your current setup

        38 / 24 = 1.583333333 if you use floats

        38 % 24 = 14… % is the modulo operator

        Combine your setup and the modulo you could output something like “there is 1 day and 14 hours over course of 38 hours” which is much more human usable since most people don’t know how long 0.583333333 is but know 14 hours.

        Or doing money… I’ll leave this up to you as a mental exercise for you but say you want to give someone $46.28 in cash. How many and what type of bills and coins would you give? Hint while 4628 pennies would be true it’s not the answer you want.

      • ulterno@programming.dev
        link
        fedilink
        English
        arrow-up
        1
        ·
        11 days ago

        You can also get the qalc program from the qalc or libqalculate package, which is a calculator in which you can simply type in the expression in a line and get the answer.

        That might also end up showing you what kinds of goals you want to be setting.

  • towerful@programming.dev
    link
    fedilink
    arrow-up
    3
    ·
    edit-2
    11 days ago

    Heck yeh! Great work.
    I think most critique has been covered.

    I consider too-many-indentations to be a code smell.
    Not actually an issue, but maybe there is…

    There is nothing wrong with your code, and no reason to change it (beyond error catching as you have discovered). It runs, is easy to follow, and doesn’t over-complicate.

    I like descriptive function names and early returns (ie, throw or return on all the conditions that means this function shouldn’t continue, then process the parameters to return a result).
    This could massively clean up what’s going on.
    There could be a “getUserCommand()” that returns the desired number, or 0 if it’s invalid.
    If the returned value is 0, then break.
    If the returned value is 6, then print values; then break.
    Otherwise we know the value should be 1-5.

    You could use an Enum to define the choices.
    This way, the print lines and the conditional tests can both reference the enum. It also removes “magic numbers” (IE values that appear in code with no explanation).
    In something simple like this, it doesn’t really matter. But it improves IDE awareness (helping language servers suggest code/errors/fixes). And Makes the code SOO much more descriptive (Ie “choice == 3” becomes “choice == Choices.Product”).

  • ulterno@programming.dev
    link
    fedilink
    English
    arrow-up
    1
    ·
    11 days ago

    If you feel like making a more elaborate thingy, which can take full inputs like “1 + 2” (I know I wanted to, back when I made my first calculator), you can check out this link for starters https://www.calcworld.net/infix-to-postfix-converter/

    Except that instead of storing the postfix output in another string (as is done on the website), you want to be segregating each and every value into separate variables (perhaps in an array), while separating the values from the operators.

    Once that is done, you can then take the values 1-by-1 and apply the operations.

    It becomes fun after that.