1

I'm trying to generate a 16 digit random card number in a function for a bank account creating sample. I tried the code below, but it didn't work.

void generate_card_number() {
    srand(time(0));
    long long int cardnumber = 0;
    int i, randctrl;

    for (i = 0; i < 15; i++) {
        do {
            randctrl = rand() % 9;
        } while (randctrl == 0);
        cardnumber += ((10^i) * randctrl);
    }
    printf("\nThe Card Number : %lld", cardnumber);
}

Could you help me, please?

Frext
  • 25
  • 1
  • 6
  • 1
    Are you planning to do any arithmetic operations on this number? I would recommend using a 16 character long string for this purpose if not – shree.pat18 May 29 '21 at 15:06
  • Try instead to generate a 16-char string (reserve space for terminating `'\0'`) ... where each character is `'0'` to `'9'` – pmg May 29 '21 at 15:06
  • Indeed, call `rand()` once for each digit. A card 'number' and a phone 'number' etc. are called *numbers* but they are actually character strings, and that is the format they should should stay in, from how you read them off a card, or type them into a keyboard, through how they are stored. Not as integers. Think about it. In UK most phone numbers begin with one or two '0' characters. How would you know about them if stored as an integer? – Weather Vane May 29 '21 at 15:15
  • 1
    If it doesn't make sense to "add 1", "divide by 3", "check if it's prime", ... it should not be a number. – pmg May 29 '21 at 15:21
  • 1
    [Why is my power operator (^) not working?](https://stackoverflow.com/q/4843304/995714) – phuclv May 29 '21 at 15:23
  • 1
    `rand() % 9` gives a number in the range `0` .. `8`. If you didn't want any `0` you could have just added `1` instead of looping. – Weather Vane May 29 '21 at 15:26

3 Answers3

4

There are several different issues with your program:

  1. The most noticeable is this line:

    cardnumber+= ( (10^i) * randd ) ;
    

    which does not do what you think it does. The ^ operator performs the bitwise XOR of the two operands, it does not compute a power.

  2. You are excluding 0 from your digits with a loop, that's unneeded (can be done without a loop) and also seems wrong, since 0 is a perfectly valid digit. If you want to force your number to have 16 digits then you only want the most significant one to be different than 0, not all of them.

  3. Your loop runs for i=0 to 14, so you are generating 15 digits, not 16.

  4. You are calling srand(time(0)) every time you call this function. This will make the function generate the same number if called within the same second (time(0) returns the current timestamp in seconds). You probably do not want this, and should call srand() only once in your main().

  5. There is no reason for your numbers to be signed, this can only cause potential problems, use unsigned.

Here's a reasonably simple version of the code which achieves what you want. If you are looking for a faster / more optimized version you might want to check out this other answer by chqrlie.

void generate_card_number()
{
    unsigned long long cardnumber;
    unsigned i;

    // Ensure most significant digit is not 0
    cardnumber = rand() % 9 + 1;

    // Add 15 more digits (which can also be 0)
    for (i = 0; i < 15; i++)
    {
        cardnumber *= 10;
        cardnumber += rand() % 10;
    }

    printf("\nThe Card Number : %llu", cardnumber);
}
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
3

There are several problems in your code:

  • srand(time(0)); is used to seed the pseudo-random number generator. Use it just once in the main() function otherwise all numbers generated during the same second will be identical.
  • To generate a 16 digit random number, the only digit that cannot be zero is the first one, all others can be, unlike what your code does.
  • 10^i does not compute the i-th power of 10 in C, it evaluates 10 xor i.
  • you do not compute enough digits.
  • randd is undefined.

It is easier to compute the digits from the most significant to the least significant. Here is a modified version:

#include <stdlib.h>

void generate_card_number() {
    // start with a digit between 1 and 9
    long long cardnumber = 1 + rand() % 9;
    // add the remaining 15 digits
    for (int i = 1; i < 16; i++)
        cardnumber = cardnumber * 10 + rand() % 10;
    printf("The Card Number: %lld\n", cardnumber);
}

Since RAND_MAX is guaranteed to be larger than 10000, you can compute 4 digits at a time:

#include <stdlib.h>

void generate_card_number() {
    // start with a number between 1000 and 9999
    long long cardnumber = 1000 + rand() % 9000;
    cardnumber = cardnumber * 10000 + rand() % 10000; // add 4 digits
    cardnumber = cardnumber * 10000 + rand() % 10000; // add 4 digits
    cardnumber = cardnumber * 10000 + rand() % 10000; // add the last 4 digits
    printf("The Card Number: %lld\n", cardnumber);
}

On most platforms, RAND_MAX is much larger, so here is alternative to take advantage of this and use fewer calls to generate the number:

#include <stdlib.h>

void generate_card_number() {
#if RAND_MAX >= 100000000
    // start with a number between 10000000 and 99999999
    long long cardnumber = 10000000 + rand() % 90000000;
    cardnumber = cardnumber * 100000000 + rand() % 100000000; // add 8 digits
#else
    // start with a number between 1000 and 9999
    long long cardnumber = 1000 + rand() % 9000;
    cardnumber = cardnumber * 10000 + rand() % 10000; // add 4 digits
    cardnumber = cardnumber * 10000 + rand() % 10000; // add 4 digits
    cardnumber = cardnumber * 10000 + rand() % 10000; // add the last 4 digits
#endif
    printf("The Card Number: %lld\n", cardnumber);
}

Note however that card numbers have extra contraints, such as restricted value ranges and must have a valid Luhn checksum.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
2

As pointed out in comments, if you don't have to do any arithmetic operations with card numbers like addition, subtraction etc. It might be a better idea to store card number as a string instead:

int getRandomDigit() {
    return rand() % 10;
}

void generateCardNumber(char cardNumber[], int size) {
    for (int i = 0; i < size; i++) {
        cardNumber[i] = '0' + getRandomDigit();
    }
    cardNumber[size] = '\0';
}

int main() {
    srand(time(NULL));
    const int size = 16;
    char card1[size + 1], card2[size + 1];

    generateCardNumber(card1, size);
    generateCardNumber(card2, size);

    printf("%s\n", card1);
    printf("%s\n", card2);
}

Above code generates a 16 digit card digit as follows:

0216624478324435
8815844216687237
Rohan Kumar
  • 5,427
  • 8
  • 25
  • 40
  • 1
    `char card1[SIZE+1], card2[SIZE+1]` and write the null terminator. Apart from that I would also use a string, definitely not an integer, and not use hard-coded values all derived from the card number length. – Weather Vane May 29 '21 at 15:34
  • Thanks a lot for your reviews. I've updated my answer as per your comments – Rohan Kumar May 29 '21 at 15:38