0

This is my current programm in which i take 3 different (or the same) values of N Natural Numbers and calculate their checksum, the usage of long datatype is a must as i also need to be able to calculate the checksum of values that exceed the MAX of int. I cant change the datatype. Now I also need to catch when the user enters a a non natural numbers e.g -23, 2.3 ... Ive made if statements that catch if a negative number and a number that exceeds the MAX of long is entered, the actual problem is that when i enter decimal numbers it skips my if conditions and prints out the printf functions but not any of the other functions, ive tried catching the decimal number with x % 1 !=0 which does not work because the actual value of x doesnt seem to be stored as a decimal but rather a whole number , ive confirmed this in various places in my programm by printing the value of x. Im really new to C barely 2 weeks into studying and havent really grasped everything, but i really just cant seem to find the problem in my Programm. I know my code looks like spaghetti code.

P.S Excuse my awful english

#include <stdio.h>
#include <stdlib.h>
int checksum(long q){
    long countingVariable = 0;

    while(q > 0)
    {
        countingVariable += q%10; // steht für sx = s + q%10
        q/=10;     // steht für q = q/10

    }
    return countingVariable;
}

int main(void) {

    long x,y,z;
    long long max_long = 2147483647;

    printf("Bitte geben sie ihre erste Zahl ein:\n"); // enter first number
    scanf("%ld",&x);

    long sx = quersumme_1(x); // checksum of x first number

    if ( x > 0 && x < max_long && x % 1 != 0){    // check if positive  and natural number

        printf("Bitte geben Sie ihre zweite Zahl ein:\n"); //enter second number
        scanf("%ld",&y);

        if (y > 0 && y < max_long){

            long sy = quersumme_2(y); //checksum of y second number
            printf("Bitte geben sie ihre dritte Zahl ein:\n");// enter third number
            scanf("%ld",&z);

            if (z > 0 && z < max_long){
                long sz = quersumme_3(z); // checksum of z 3rd number
                if (sx>sy && sx>sz && sy>=sz){
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",x,sx);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",y,sy);
                    printf("die Quersumme s der Zahl %ld ist %ld\n",z,sz);
                } else if (sx>sy && sx>z && sz>sy){
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",x,sx);
                    printf("die Quersumme s der Zahl %ld ist %ld\n",z,sz);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",y,sy);
                } else if (sy>sx && sy>sz && sx>=sz){
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",y,sy);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",x,sx);
                    printf("die Quersumme s der Zahl %ld ist %ld\n",z,sz);
                } else if (sy>sx && sy>sz && sz>sx){
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",y,sy);
                    printf("die Quersumme s der Zahl %ld ist %ld\n",z,sz);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",x,sx);
                } else if(sz>sx && sz>sy && sx>=sy){
                    printf("die Quersumme s der Zahl %ld ist %ld\n",z,sz);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",x,sx);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",y,sy);
                } else if(sz>sx && sz>sy && sy>sx){
                    printf("die Quersumme s der Zahl %ld ist %ld\n",z,sz);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",y,sy);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",x,sx);
                } else if (sx==sy && sx==sz && sy==sz){
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",x,sx);
                    printf("Die Quersumme s der Zahl %ld ist %ld\n",y,sy);
                    printf("die Quersumme s der Zahl %ld ist %ld\n",z,sz);
                }
// the big if tree is just a sorting "algorithm" it sorts the values of checksums 

            }if (z < 0){ //check for negative number z
                printf("Falsche Eingabe: Minus Zahl"); //error
                exit(0);
            }if (z > max_long){ // cant exceed Max value of long
                printf("Falsche Eingabe: Zahl overflowed long");// error
                exit(0);
            }
        }if (y < 0){ //check for negative number y
            printf("Falsche Eingabe: Minus Zahl"); // error
            exit(0);
        }if (abs(y) > max_long){ // cant ewxceed max value of long
            printf("Falsche Eingabe: Zahl overflowed long"); /error
            exit(0);
        }

    }if (x < 0){ //check for negative numbers
        printf("Falsche Eingabe: Minus Zahl"); // error
        printf("%ld",x);
        exit(0);
    }
    if (x > max_long){ // cant exceed max of long
        printf("Falsche Eingabe: Zahl overflowed long"); // error
        exit(0);
    }

    return 0;
}
  • All your `quersumme_X` functions are identical. Why do you need 3 functions that do the same thing? – Barmar Dec 17 '21 at 00:35
  • i didnt how to give one recursion 3 values and how to also let it return 3 values thats why i choose to make seperate recursions as is it was easier for me – Meilen Weit Dec 17 '21 at 00:37
  • There's no recursion. You can just write one function, and call it each place that you need a checksum. `long sx = quersumme(x); ... long sy = quersumme(y);` – Barmar Dec 17 '21 at 00:38
  • That's one of the main features of functions, you can call the same function as many times as you want. – Barmar Dec 17 '21 at 00:39
  • The proper way to get user input is to ① Get user input as a _string_ ② Parse the string ③ Test that the entire string was properly parsed. In the case of integer values, it is a known issue with C and C++ that you cannot stop a user from entering a negative value for unsigned input, so you will have to manually check that the string does not lead with a `'-'` minus sign. – Dúthomhas Dec 17 '21 at 00:39
  • oh, i guess im just to tired to think straight thank you ill try to edit out the extra functions – Meilen Weit Dec 17 '21 at 00:40
  • 1
    If you want to detect negative numbers, just check `if (x < 0)` and report an error. – Barmar Dec 17 '21 at 00:42
  • im sorry i should have translated the german parts that was my fault, as to variable naming i have to use the xyz and sx sy sz variables – Meilen Weit Dec 17 '21 at 00:43
  • In general you shouldn't use `scanf()` if you want to validate input. – Barmar Dec 17 '21 at 00:43
  • ye i did that i check with every if statement of the different values if they are below 0 – Meilen Weit Dec 17 '21 at 00:43
  • again im sorry but i have to use them as they are a requirement because weve been working very strictly with printf and scanf – Meilen Weit Dec 17 '21 at 00:44
  • See https://stackoverflow.com/questions/31633005/validate-the-type-of-input-in-a-do-while-loop-c for some information – Barmar Dec 17 '21 at 00:50
  • TIP: use *functions* that do exactly one thing. Don't mix user input with business logic. Divide&conquer. – wildplasser Dec 17 '21 at 00:50
  • If you have to use `scanf()`, the best you can do is check the return value to tell if it was able to scan all the inputs you requested. If it returns fewer, report an error and abort. – Barmar Dec 17 '21 at 00:51
  • you mean something like if(scanf("%lf",&x) != 1 ) ? – Meilen Weit Dec 17 '21 at 01:00

2 Answers2

1

The best is to use fgets() read the line of user input into a string and then parse the string.

Let us say you are stuck with scanf() (too bad).

First, check return value

// scanf("%ld",&y);
if (scanf("%ld",&y) != 1) {
  printf("Non-numeric input, end-of-file or input error");
  exit(0);
}

Now read the next character

unsigned char ch;
if (scanf("%c",&ch) != 1) {
  printf("Failed to read next character");
  exit(0);
}
if (!isspace(ch)) {
  printf("Unexpected character following a number %d %c\n", ch, ch);
  exit(0);
}

Now check for range

if (y < min_long || y > max_long) {
  printf("Out of range %ld\n", y);
  exit(0);
}

Simplifications exist.


Again better to use fgets().

A robust, but unchecked, example:

#define LINE_SZ 100 // Max expected line size
char buf[LINE_SZ * 2]; // Let us read even up to 2x expected

if (fgets(buf, sizeof buf, stdin) == NULL) {
  printf("Nothing read\n", y);
  exit(EXIT_FAILURE);
}

errno = 0;
char *endptr;
long y = strtol(buf, &endptr, 0);
if (buffer == endptr) {
  printf("Non-numeric input \"%s\"\n", buf);
  exit(EXIT_FAILURE);
}

if (errno || y < long_min || long_max) {
  printf("Input \"%s\" outside [%ld %ld] range\n", buf, long_min, long_max);
  exit(EXIT_FAILURE);
}

// Skip trailing white-space
while (isspace((unsigned char)*endptr)) {
  endptr++;
}
if (*endptr) {
  printf("Trailing junk in \"%s\"\n", buf);
  exit(EXIT_FAILURE);
}

printf("Success %ld\n", y);

If you cannot use fgets() to read a line into a string, try

char buf[100];
if (scanf(" %99[^\n]", buf) == 1) {
  // OK, now process the string
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • i wish i could use it but they specified that scanf need to be used, as to your example what kind of function is isspace() does it check whether a char has been input or ? – Meilen Weit Dec 17 '21 at 01:23
  • 2
    @MeilenWeit 1) "but they specified that scanf need to be used" --> consider your are being taught to pre-1990s standards. Sigh. 2) `isspace(ch)` (from ``) tests if the character was a white-space such as `' '`, `'\n'`, `'\t'`, `'\r'`, etc. – chux - Reinstate Monica Dec 17 '21 at 01:27
  • When you say, "non-numeric input," you are making an educated guess; `stdin` might have been closed, for example. `errno` probably has more information, if you wanted? – Neil Dec 17 '21 at 14:32
  • 1
    @Neil True, when `scanf("%ld",&y) != 1`, not only non-numeric input text, could be end-of-file or input error. C standard library does not specify that `errno` is set by `scanf()` for any reason - perhaps you are thinking of some implementation extension? Code could use `feof()` and `ferror()` to distinguish an `EOF` return. – chux - Reinstate Monica Dec 17 '21 at 18:34
0

A long type can not store a decimal value, and scanf will always try to match what the user entered to the type of value you told it to expect.

In your case, %ld means that if user enters a decimal number, scanf will ignore the '.' and everything after it, and only put digits before '.' in y.

There is one way to deal with this in C:

Read a string from the user and check the characters in it to make sure they are all digits (or that there is no decimal point or whatever else you need to check).

Then you can use atol to convert the string to long.

In any case, you should check the value scanf returns.

This usually is not taught in beginner classes, but scanf returns how many items from the user it matched to your expectations and stored in the variables you provided.

In your case it should return 1 if a valid integer was entered.
This method won't tell you if the user entered a decimal number or a word instead of a natural number, but you will know if the input was valid or not.

Lev M.
  • 6,088
  • 1
  • 10
  • 23
  • 2
    It is not correct that “`scanf` will ignore” a “decimal number” and “not put anything in `y`.” `scanf` matches character-by-character, so input of “34.56” will match “%ld” up until the “.”, and `scanf` will store 34 in the corresponding object and return 1. Also, “decimal number” should not be used in this context to mean a number with a decimal point in it; it is ambiguous whether it means a numeral using base ten as opposed to hexadecimal or binary or a numeral with a decimal point. OP may have used the terminology, but we clarify the phrasing, not continue the ambiguity. – Eric Postpischil Dec 17 '21 at 01:01
  • `strtol` should be used to convert to `long` rather than `atol`, as it provides sufficient information for error checking. – Eric Postpischil Dec 17 '21 at 01:01
  • thanks a lot this explains a lot as to why my my programm runs but doesnt scan anything after i enter a decimal number, but then why does a printf of x y z return the whole number of the decimal 3.5 to 3 NVM somebody already explained it – Meilen Weit Dec 17 '21 at 01:08
  • @EricPostpischil thanks for pointing out the error about `scanf`, I fixed the post. Regarding using "decimal number", while I agree, I always try to use same terms as the person asking the question unless they are extremely inappropriate to make sure the person who asked understands my answer. I know SO is so everyone can use the answers, and it is designed for English speakers, but not everyone here is a native English speaker, and the person asking currently needs the answer the most. – Lev M. Dec 17 '21 at 11:08