0

When I run this program my count variable goes only up to 10 for a reason I don't understand and I want it to go up to 16 in order to check if the input from the user is a card number (16 digits). I dont specifically want to check if it is a card number, I just want to check if it has 16 digits.

void payment() {
    int payway;
    int cardnum;
    int count = 0;
    
    printf("Type 1 if you want to pay with card and have a discount or 2 if you want to pay with cash:\n");
    scanf("%d", &payway);
    switch (payway) {
      case 1:
        {
            do {
                printf("Type your CC number:\n");
                scanf("%d", &cardnum);
                while (count != 0) {
                    cardnum = cardnum / 10;
                    count++;
                }
            } while (count != 16);
        }
        break;
    }
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Caz
  • 11
  • 6
  • 6
    Credit card “numbers” are really strings. A card number is just a sequence of characters used to identify the card. It is not intended to represent a mathematical number that you do arithmetic on. So read it as a string of characters, not as a number. The `int` type in your C implementation is not big enough to hold numbers represented by 16-digit numerals, so you lose data as soon as `scanf("%d", &cardnum)` executes, and there is no way to tell what the user entered. Read a string instead and test that it is the right length and contains only digit characters. – Eric Postpischil Jan 15 '22 at 13:17
  • Check `isdigit` on every character and leave it as a string. Credit cards don't always have 16 numbers. I would strongly recommend that if you deal with credit card numbers, you have someone with sufficient experience implement this. Anyone dealing with credit card numbers is required to be PCI DSS compliant. – Cheatah Jan 15 '22 at 13:24
  • `2^31` (the maximum value for your ints) is about `10^9` ... or 9/10 digits – pmg Jan 15 '22 at 13:26
  • 1
    As an integer, how would you deal with leading zeros in a "number"? You might say that card numbers don't have them for that reason, but phone numbers certainly can (sometimes a double-0), and the same applies. Not only that, but you need to examine the digits of the card number. It makes no sense to convert the string that was entered to an integer, and then extract the digits which you were given in the first place. – Weather Vane Jan 15 '22 at 13:52
  • I always use dashes or spaces, like "1234-5678-9012-4567" or "1234 5678 9012 4567". It's way too easy to have typos otherwise. – Brendan Jan 15 '22 at 17:48

2 Answers2

1

The line

scanf("%d", &cardnum);

will have undefined behavior if the matched number is not representable as an int, i.e. if it is out of range.

An int is only guaranteed to be able to represent numbers from -32767 to +32767, although on most modern platforms, it is able to represent numbers from -2,147,483,648 to +2,147,483,647. Either way, an int will probably not be sufficient to represent a 16-digit number.

However, a long long int (or simply long long) is guaranteed to be able to represent numbers from -9,223,372,036,854,775,807 to +9,223,372,036,854,775,807. This is guaranteed to be sufficient to represent any 16-digit number.

Therefore, the simplest solution to your problem would be to change the line

int cardnum;

to

long long cardnum;

and change

scanf("%d", &cardnum);

to:

scanf("%lld", &cardnum);

However, it is generally better to store long numbers such as phone numbers and credit card numbers as strings, even if they consist only of digits. That way, you don't have to worry about the numerical limitations of an int or a long long.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

use a string instead of an int value. example:

char c[] = "123";
size_t len = sizeof(c) / sizeof(char);
len--;

so you can store the size of the array in var len.

  • An alternative is to use a `unsigned long long`(which can store 19 digits). Additionally, international standards allow for credit card numbers with length 8-19 digits (not strictly 16 digits, which are simply the most common) – João Neto Jan 15 '22 at 14:07
  • 2
    It's more reliable to do `strlen(c)` because `char c[20] = "123";` would give an incorrect answer from the `sizeof` calculation. Especially if the buffer `char c[20];` was provided for user input, it cannot tell you the length of the user's entry. – Weather Vane Jan 15 '22 at 14:13
  • 1
    @JoãoNeto: `unsigned long long` cannot tell you if the user entered “0123456789012345789”, which is not a valid credit card “number” because it has 20 digits but would produce a number that can be represented in `unsigned long long`. Credit card “numbers” are not numbers, so do not use integer types for them. – Eric Postpischil Jan 15 '22 at 14:14
  • @WeatherVane yes, i wrote just an example. – costantinium Jan 15 '22 at 14:21
  • @Eric Postpischil: Most definitely! Best to use a string! Was just discussing an alternative :) And indeed, some CC numbers may start with a zero (https://stackoverflow.com/questions/7164858/can-credit-card-numbers-contain-leading-zeros), which makes the usage of integer types even less adequate. – João Neto Jan 16 '22 at 15:06