1

I have to input whole numbers and the program has to stop if I put in a negative number. It has to sum up every whole number I've inputed that has a "7" in it, but for some reason, it counts "70" as "7". I'm quite new with programming and I'm stuck on this.

#include <stdio.h>
int main() {
    int number = 1, temp_var = 0, sum = 0;
    while (number >= 0) {
        printf("Put in a number: ");
        scanf_s("%d", &number);
        while (number >= 1) {
            temp_var = number % 10;
            if (temp_var == 7)
            {
                sum = sum + number;
                break;
            }
            number = number / 10;
        }
    }
    printf("%d", sum);
    return 0;
}
  • 1
    Please show your expected output versus the actual one and describe what your program is supposed to do at all. It is not clear how you conclude that "it counts 70 as 7" – Eugene Sh. Apr 06 '22 at 17:34
  • 2
    what is the reason for `break` inside of `if (temp_var == 7)` test? – Iłya Bursov Apr 06 '22 at 17:35
  • 2
    You are looping on `number` and eventually it becomes zero. But, you're doing: `sum = sum + number;` You want the _original_ value of `number` for this. So, just above the loop (just after the `scanf_s`) do: `int original_number = number;` and change the sum to: `sum = sum + original_number;` – Craig Estey Apr 06 '22 at 17:36
  • 1
    Have you tried running your code line by line in a debugger while monitoring the values of all variables, in order to determine at which point your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – Andreas Wenzel Apr 06 '22 at 17:37
  • @EugeneSh. If I put in 7, 70 and -5, my expected output is the sum of 70 and 7 = 77. Instead I get 14. Same thing happens if I put 700 instead of 70, I get 14. – StressedBanana Apr 06 '22 at 17:37
  • Your _outer_ loop is `while (number >= 0)`. But, again, because the inner loop _trashes_ `number` this loop will only execute _once_ – Craig Estey Apr 06 '22 at 17:39
  • @StressedBanana that is exactly what your code is implemented to do. 70 loops twice, once with 0 as the modulus, the second time with 7. `number` is `7` at that point, not 70, by your own doing, so the original value of the original number is long-since lost. Use a temporary for your loop and don't futz with `number` during said-same. – WhozCraig Apr 06 '22 at 17:40
  • What is this program expected to do? To sum numbers? Then why this manipulation with `% 10` is needed? – Eugene Sh. Apr 06 '22 at 17:42
  • @EugeneSh. it's supposed to accumulate all user-entered numbers equal or greater to zero that contain at least one digit `7` . E.g. 710, 37, 12 will result in 747. The 12 will be excluded (no `7` digit) – WhozCraig Apr 06 '22 at 17:46
  • If you only want to sum numbers that contain a digit 7 in decimal, then write a function that is passed a number and reports yea or nay (`int contains7(int number) { while (number != 0) { if (abs(number % 10) == 7) return 1; number /= 10; } return 0; }`) and call it in your loop (`if (contains7(number)) sum += number;`). This avoids trashing your data. Generally, write functions; don't put it all in `main()`. – Jonathan Leffler Apr 06 '22 at 17:47
  • @WhozCraig Thanks, looks like I was not attentive when reading the question... – Eugene Sh. Apr 06 '22 at 17:48
  • @EugeneSh. It wasn't entirely intuitive for me either. No worries. – WhozCraig Apr 06 '22 at 17:49
  • zero is not a negative number but will also terminate the loop, which is not your stated requirement. – Clifford Apr 06 '22 at 22:19

3 Answers3

1

Your code is incorrect: you modify number in order to test if it has 7 among the digits of its base 10 representation so you do not add the original value if the test succeeds. You should use a separate variable to test the digit values.

The termination test if number is negative works, but is not straightforward for the casual reader.

Here is a modified version:

#include <stdio.h>

int main() {
    int number, temp_number, sum = 0;
    for (;;) {
        printf("Put in a number: ");
        if (scanf("%d", &number) != 1 || number < 0)
            break;
        for (temp_number = number; temp_number; temp_number /= 10) {
            if (temp_number % 10 == 7) {
                sum = sum + number;
                break;
            }
        }
    }
    printf("%d\n", sum);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

You are modifying number then adding that modified value when the least significant digit becomes zero (so 70 adds 7, while 770 or 771 for example would both add 77).

You should retain the original input value and add that whilst modifying a copy of the original to detect the digit 7.

Alternatively accept a string input, scan it for '7' characters and if so convert to an integer and add it. For example:

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

int main()
{    
    char input[16] = "" ;
    int sum = 0;
    bool got_input = false ;
    
    do
    {
        got_input = scanf_s( "%s", input, sizeof(input) ) != 0 ;
        for( const char* scan = input;
             got_input && *scan != 0 && isdigit((int)(*scan));
             scan++ )
        {
            if( *scan == '7' )
            {
                sum += atoi( input ) ;
                break ;
            }
        }
    }
    while( got_input && isdigit((int)(*input)) ) ;
    
    printf("Sum: %d", sum );

    return 0;
}

If the input starts with any non-digit/non-whitespace character the input loop terminates. Trailing non-digit characters in input are ignored.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • The test `*scan != 0 && isdigit(*scan)` is redundant. – chqrlie Apr 06 '22 at 23:12
  • The outer loop will stop if the number entered has initial spaces or a positive sign. – chqrlie Apr 06 '22 at 23:13
  • The `char` argument to `isdigit()` should be cast as `(unsigned char)` to avoid potential undefined behavior on negative character values on platforms where `char` is signed by default. – chqrlie Apr 06 '22 at 23:14
  • The `while( isdigit(*input) )` test will crash on unexpected end of file. – chqrlie Apr 06 '22 at 23:15
  • @chqrlie. All fair points - will fix. Re the loop stopping on initial space (or any non-digit character) - yes - I point that out in the answer. That is exactly the purpose of `&& isdigit(*scan)`. The `*scan != 0` is a hang-over from having input using `scanf_s`, but that was not recognised at https://www.onlinegdb.com/online_c_compiler where I tested it. Using `scanf_s` would resolve the leading space issue and require the NUL string terminator test. The point about the `isdigit()` parameter and EOF agreed. – Clifford Apr 07 '22 at 06:29
0

There are some issues:

  1. You are looping on number and it eventually becomes zero.
  2. When you try to add to the sum, you want the original value of number but you're using the partially modified value.
  3. You want to preserve the original value and use a temp copy in the loop.
  4. The while (number >= 0) in the outer loop won't stop immediately if a negative number is executed (i.e. an extra loop iteration is performed). We want to use an if after the scanf_s.
  5. Because number gets trashed by the inner loop, the outer loop will only execute once.

Here's the refactored code. It is annotated:

#include <stdio.h>

int
main(void)
{
    int number = 1,
        temp_var = 0,
        sum = 0;

// NOTE/BUG: this will loop once too often
#if 0
    while (number >= 0) {
#else
    while (1) {
#endif

        printf("Put in a number: ");
        scanf("%d", &number);
// NOTE/FIX: correct way to stop on negative number
#if 1
        if (number < 0)
            break;
#endif

// NOTE/FIX: to prevent "number" from being trashed, we should use a temp
// value in the loop
        int temp_number = number;

        while (temp_number >= 1) {
            temp_var = temp_number % 10;

            if (temp_var == 7) {
                sum = sum + number;
                break;
            }

            temp_number = temp_number / 10;
        }
    }

    printf("%d\n", sum);

    return 0;
}

In the code above, I used cpp conditionals to denote old vs. new code:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

Here's a slightly cleaned up version that puts the digit match code in a function:

#include <stdio.h>

// hasdigit -- decide if a given number contains a given decimal digit
int
hasdigit(int number,int dig)
{
    int temp_var;
    int match = 0;

    while (number != 0) {
        temp_var = number % 10;

        match = (temp_var == dig);
        if (match)
            break;

        number = number / 10;
    }

    return match;
}

int
main(void)
{
    int number;
    int sum = 0;

    while (1) {
        printf("Put in a number: ");
        scanf("%d", &number);
        if (number < 0)
            break;

        if (hasdigit(number,7))
            sum += number;
    }

    printf("%d\n", sum);

    return 0;
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • 1
    The one exit point 'rule' (or 'one return statement' rule) makes your code far more obscure than it need be. `if (number % 10 == dig) return 1;` is far simpler and easier to read. And you can use `if (abs(number % 10) == dig) return 1;` to ensure that negative numbers are handled correctly too. – Jonathan Leffler Apr 06 '22 at 18:42