Home > Back-end >  Why does this C code to check a credit card based on the Luhn algorithm not work?
Why does this C code to check a credit card based on the Luhn algorithm not work?

Time:02-25

I wrote this code in to check if a credit card number is valid according to the Luhn algorithm:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

bool ccc(string cc) {
  vector<string> digits;
  int aux;
  for (int n = 0; n < cc.length();   n) {
    digits.push_back(to_string(cc.at(n)));
    cout << digits[n];
  }
  for (int s = 1; s < digits.size(); s  = 2) {
    aux = stoi(digits[s]);
    aux *= 2;
    digits[s] = to_string(aux);
    aux = 0;
    for (int f = 0; f < digits[s].length();   f) {
      aux  = stoi(to_string(digits[s].at(f)));
    }
    digits[s] = to_string(aux);
    aux = 0;
  }
  for (int b = 0; b < digits.size();   b) {
    aux  = stoi(digits[b]);
  }
  aux *= 9;
  if (aux % 10 == 0) {
    return true;
  } else {
    return false;
  }
}

int main(int argc, char* argv[]) {
  string crecar;
  cout << "CC:\n";
  cin >> crecar;
  if (ccc(crecar)) {
    cout << "Valid\n";
  } else {
    cout << "Invalid\n";
  }
}

And I compile with no errors or warnings and I get the following output:

CC:
4895045418823857
52565753485253524956565051565355Invalid

It should print first every digit of digits, I used that to check what is the program doing internally, but I get that number that is too big. Why is this program failing and what should I do to fix it?

CodePudding user response:

Consult the to_string documentation (example) and you'll see that there is no overload for char, but char is easily convertible to an int, so the int overload will be used. Unfortunately you don't get the digit. You get the character's encoded value. So, assuming ascii, to_string('4') won't return a string containing 4, it'll return a string containing the ascii value of 4: 52.

If you look at the strange number as a stream of 2 digit numbers you'll see you have an ascii representation of your original number.

52 56 57 53 48 52 53 52 49 56 56 50 51 56 53 55
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | 
4  8  9  5  0  4  5  4  1  8  8  2  3  8  5  7 

The hack fix for this problem is to change

digits.push_back(to_string(cc.at(n)));

to

digits.push_back(string(1,cc.at(n)));

construct a string that contains 1 copy of the given character and place it in the vector

An immediate readability improvement is

digits.push_back(cc.substr(n,1));

get a sub-string of the current character we're looking at and put it in digits.

But all this to string to int back to string is make-work. Just store ints and operate on ints . If you have digits you can convert digit into an int with digit -'0' and back again with digit '0'. This will save you and the the computer a lot of effort.

CodePudding user response:

I'm not sure why your code is so long. According to the wikipedia page on the algorithm in question:

function checkLuhn(string purportedCC) {
    int nDigits := length(purportedCC)
    int sum := integer(purportedCC[nDigits-1])
    int parity := (nDigits-2) modulus 2
    for i from 0 to nDigits - 2 {
        int digit := integer(purportedCC[i])
        if i modulus 2 = parity
            digit := digit × 2
        if digit > 9
            digit := digit - 9 
        sum := sum   digit
    }
    return (sum modulus 10) = 0
}

I don't know what you started with, but yours just seems really weird.

  • Related