{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блоги: заметки с тегом C",
    "_rss_description": "Автоматически собираемая лента заметок, написанных в блогах на Эгее",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": false,
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/blogengine.me\/blogs\/tags\/c\/",
    "feed_url": "https:\/\/blogengine.me\/blogs\/tags\/c\/json\/",
    "icon": false,
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/blogengine.me\/blogs\/",
            "avatar": false
        }
    ],
    "items": [
        {
            "id": "126030",
            "url": "https:\/\/dsokolovskiy.com\/blog\/all\/credit-card-validation-in-c\/",
            "title": "Credit card validation in C",
            "content_html": "<p>I <a href=\"\/blog\/all\/super-mario-pyramids-in-c\/\">keep learning programming<\/a>, and today I share my baby walkthrough of the second homework from the CS50 course titled Credit.<\/p>\n<p>As a quick disclaimer, I used only tools I’ve learned from the two lessons I had so far.<\/p>\n<p>Here is the problem to solve:<\/p>\n<div class=\"question\"><p>A credit (or debit) card, of course, is a plastic card with which you can pay for goods and services. Printed on that card is a number that’s also stored in a database somewhere, so that when your card is used to buy something, the creditor knows whom to bill. There are a lot of people with credit cards in this world, so those numbers are pretty long: American Express uses 15-digit numbers, MasterCard uses 16-digit numbers, and Visa uses 13- and 16-digit numbers. And those are decimal numbers (0 through 9), not binary, which means, for instance, that American Express could print as many as 10^15 = 1,000,000,000,000,000 unique cards! (That’s, um, a quadrillion.)<\/p>\n<p>Actually, that’s a bit of an exaggeration, because credit card numbers actually have some structure to them. All American Express numbers start with 34 or 37; most MasterCard numbers start with 51, 52, 53, 54, or 55 (they also have some other potential starting numbers which we won’t concern ourselves with for this problem); and all Visa numbers start with 4. But credit card numbers also have a “checksum” built into them, a mathematical relationship between at least one number and others. That checksum enables computers (or humans who like math) to detect typos (e. g., transpositions), if not fraudulent numbers, without having to query a database, which can be slow. Of course, a dishonest mathematician could certainly craft a fake number that nonetheless respects the mathematical constraint, so a database lookup is still necessary for more rigorous checks.<\/p>\n<p>Write a program that prompts the user for a credit card number and then reports (via printf) whether it is a valid American Express, MasterCard, or Visa card number, per the definitions of each’s format herein. So that we can automate some tests of your code, we ask that your program’s last line of output be AMEX\\n or MASTERCARD\\n or VISA\\n or INVALID\\n, nothing more, nothing less. For simplicity, you may assume that the user’s input will be entirely numeric (i.e., devoid of hyphens, as might be printed on an actual card) and that it won’t have leading zeroes. But do not assume that the user’s input will fit in an int! Best to use get_long from CS50’s library to get users’ input.<\/p>\n<\/div><p>First, I’ll prompt a user to input a number using the <i>get_long<\/i> function from the CS50 library:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nint main(void)\r\n{\r\n    long card_number = get_long(&quot;Number: &quot;);\r\n}<\/code><\/pre><p>Next, I’ll do what seems to be the most challenging part of the problem, which is to calculate the checksum of a credit card. In the problem description, they provide additional information on Luhn’s Algorithm that determines the validity of a card as follows:<\/p>\n<ol start=\"1\">\n<li>Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.<\/li>\n<li>Add the sum to the sum of the digits that weren’t multiplied by 2.<\/li>\n<li>If the total’s last digit is 0, the number is valid!<\/li>\n<\/ol>\n<p>Let’s take the card number 4003600000000014 as an example. For the sake of visibility, let me underline every other digit, starting with the number’s second-to-last digit:<\/p>\n<p><u>4<\/u> 0 <u>0<\/u> 3 <u>6<\/u> 0 <u>0<\/u> 0 <u>0<\/u> 0 <u>0<\/u> 0 <u>0<\/u> 0 <u>1<\/u> 4<\/p>\n<p>How to extract those digits from a number in C? Turns out, in maths, there is a great operation that can give us the remainder after dividing one number by another, and it’s called <i>modulo<\/i>, or mod. You can totally start laughing here, but honestly, I never heard of it before. For example, <i>1234 % 10 = 4<\/i> (with modulo operation being expressed by the percent sign), since 4 is the last digit in the number 1234.<\/p>\n<p>Okay, that was the last digit. But how to get to the second-to-last digit, and then get every other digit from there? This might be not as obvious (at least it wasn’t at first to me), but since we’re dealing with whole numbers, a simple division by 10 basically moves us to one character in a number at a time. For example, <i>1234 \/ 10 = 123,4<\/i>, but since the integer numbers get truncated, the result is actually 123.<\/p>\n<p>Pretty cool, huh? Now let’s try to get every second number using the combination of division and modulo operations in the code:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Calculating checksum\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing the last digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n        printf(&quot;%i&quot;, second_to_last_digit);\r\n    }\r\n    printf(&quot;\\n&quot;);\r\n}<\/code><\/pre><p>This code prints 10000604, which are exactly the digits we need from the card number <u>4<\/u>0<u>0<\/u>3<u>6<\/u>0<u>0<\/u>0<u>0<\/u>0<u>0<\/u>0<u>0<\/u>0<u>1<\/u>4. Keep in mind it’s not a number ten million six hundred four, but individual digits printed one after another. The order of digits is reversed, though it’s irrelevant in this case.<\/p>\n<p>Next, according to Luhn’s Algorithm, I need to multiply each digit by 2 and get the sum of all of them combined. And I haven’t found a better solution than again using the same modulo and division operations, but this time on the extracted digits:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Calculating checksum\r\n    int every_second_digit = 0;\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n    int digit1;\r\n    int digit2;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing the last digit and adding to every_other_digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Mupliplying second last digit\r\n        second_to_last_digit *= 2;\r\n\r\n        \/\/ Adding digits together to get the sum of every_second_digit\r\n        digit1 = second_to_last_digit % 10;\r\n        digit2 = second_to_last_digit \/ 10;\r\n        every_second_digit += digit1 + digit2;\r\n    }\r\n    printf(&quot;%i&quot;, every_second_digit);\r\n    printf(&quot;\\n&quot;);\r\n}<\/code><\/pre><p>I’m pretty sure it could be done more elegantly, but I’m using only the knowledge I have so far from the first week of introduction to programming. Importantly, this code works, providing the result of the number 13, as you would expect from the sum of digits 2 + 1 + 2 + 8. Yay!<\/p>\n<p>Lastly, to finish off the checksum, I’m going to find every other digit, add them together, and then add both sums in the final <i>checksum<\/i> variable:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Calculating checksum\r\n    int every_second_digit = 0;\r\n    int every_other_digit = 0;\r\n    int checksum = 0;\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n    int digit1;\r\n    int digit2;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing the last digit and adding to every_other_digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n        every_other_digit += last_digit;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Mupliplying second last digit\r\n        second_to_last_digit *= 2;\r\n\r\n        \/\/ Adding digits together to get the sum of every_second_digit\r\n        digit1 = second_to_last_digit % 10;\r\n        digit2 = second_to_last_digit \/ 10;\r\n        every_second_digit += digit1 + digit2;\r\n    }\r\n\r\n    \/\/ Getting checksum\r\n    checksum = every_second_digit + every_other_digit;\r\n\r\n    printf(&quot;%i\\n&quot;, checksum);\r\n}<\/code><\/pre><p>This code now prints the number 20, which is exactly the kind of value I want from a valid credit card. The hardest part is done!<\/p>\n<p>Next, I’ll calculate the number of digits in the card number using a simple loop:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Counting the number of digits in the card number\r\n    long n = card_number;\r\n    int number_of_digits = 0;\r\n    do\r\n    {\r\n        n \/= 10;\r\n        number_of_digits++;\r\n    }\r\n    while (n != 0);<\/code><\/pre><p>To keep the value of that <i>card_number<\/i> intact, I added a new variable called <i>n<\/i> and assigned its value to <i>card_number<\/i>, so I can do the maths with the <i>n<\/i> instead. In plain English, that loop says the following: while the card number is not equal to zero, divide the card number by 10, and for every division increase the number of <i>number_of_digits<\/i> variable which I use as a counter by one.<\/p>\n<p>For example, if I were to type in the number 1234, it would go as follows:<\/p>\n<ol start=\"1\">\n<li>1234 \/ 10 = 123; the counter increases from 0 to 1;<\/li>\n<li>123,4 \/ 10 = 12; the counter increases from 1 to 2;<\/li>\n<li>12,34 \/ 10 = 1; the counter increases from 2 to 3;<\/li>\n<li>1 \/ 0 = 10; the counter increases from 3 to 4;<\/li>\n<\/ol>\n<p>Now the card number gets equal to zero, and the loop ends with the counter equal to 4, which is the correct number of digits in the number 1234.<\/p>\n<p>Next, I’ll make another counter to get the first two digits of the card number using pretty much the same logic:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Getting the first two digits of the card number\r\n    int first_two_digits = 0;\r\n    long i = card_number;\r\n    while (i &gt; 100)\r\n    {\r\n        i \/= 10;\r\n        first_two_digits = i;\r\n    }<\/code><\/pre><p>Lastly, I’ll check the validity of the checksum and then check what credit company the card belongs to based of the card number length and starting digits.<\/p>\n<p>So here is my final code:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ A program in C that checks the validity of a given credit card number\r\n\r\n#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Counting the number of digits in the card number\r\n    long n = card_number;\r\n    int number_of_digits = 0;\r\n    do\r\n    {\r\n        n \/= 10;\r\n        number_of_digits++;\r\n    }\r\n    while (n != 0);\r\n\r\n    \/\/ Getting first two digits of the card number\r\n    int first_two_digits = 0;\r\n    long i = card_number;\r\n    while (i &gt; 100)\r\n    {\r\n        i \/= 10;\r\n        first_two_digits = i;\r\n    }\r\n\r\n    \/\/ Calculating checksum\r\n    int every_second_digit = 0;\r\n    int every_other_digit = 0;\r\n    int checksum = 0;\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n    int digit1;\r\n    int digit2;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing last digit and adding to every_other_digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n        every_other_digit += last_digit;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Mupliplying the second last digit\r\n        second_to_last_digit *= 2;\r\n\r\n        \/\/ Adding digits together to get the sum of every_second_digit\r\n        digit1 = second_to_last_digit % 10;\r\n        digit2 = second_to_last_digit \/ 10;\r\n        every_second_digit += digit1 + digit2;\r\n    }\r\n\r\n    \/\/ Getting checksum\r\n    checksum = every_second_digit + every_other_digit;\r\n\r\n    \/\/ Checking for the card validity\r\n    int validity = checksum % 10;\r\n    if (validity == 0)\r\n    {\r\n        if ((number_of_digits == 15) &amp;&amp; (first_two_digits == 34 || first_two_digits == 37))\r\n        {\r\n            printf(&quot;AMEX\\n&quot;);\r\n        }\r\n        else if ((number_of_digits == 16) &amp;&amp; (first_two_digits &gt;= 51 &amp;&amp; first_two_digits &lt;= 55))\r\n        {\r\n            printf(&quot;MASTERCARD\\n&quot;);\r\n        }\r\n        else if ((number_of_digits == 16 || number_of_digits == 13) &amp;&amp; (first_two_digits \/ 10 == 4))\r\n        {\r\n            printf(&quot;VISA\\n&quot;);\r\n        }\r\n        else\r\n        {\r\n            printf(&quot;INVALID\\n&quot;);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        printf(&quot;INVALID\\n&quot;);\r\n    }\r\n}<\/code><\/pre><h2>Update<\/h2>\n<p>A week later after posting this solution, I decided to get back to this problem and see if I could improve the code, particularly focusing on the checksum part as it’s essentially the main part.<\/p>\n<p>Here is my updated code for this function:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Calculate checksum using Luhn's Algorithm\r\nint calculate_checksum(long long number)\r\n{\r\n    int sum = 0;\r\n    int digit;\r\n    bool is_second_digit = false;\r\n\r\n    while (number &gt; 0)\r\n    {\r\n        digit = number % 10; \/\/ Get the last digit\r\n        number \/= 10; \/\/ Reduce the number by one digit\r\n\r\n        if (is_second_digit)\r\n        {\r\n            digit *= 2;\r\n            sum += digit % 10 + digit \/ 10; \/\/ Split double numbers into single digits, e.g. 12 into 1 and 2\r\n        }\r\n        else\r\n        {\r\n            sum += digit;\r\n        }\r\n\r\n        \/\/ Switch the boolean, alternating between odd and even digits\r\n        is_second_digit = !is_second_digit;\r\n    }\r\n\r\n    return sum;\r\n}<\/code><\/pre>",
            "date_published": "2024-02-25T14:25:23+05:00",
            "date_modified": "2024-03-11T20:07:37+05:00",
            "tags": [
                "C",
                "CS50",
                "programming"
            ],
            "author": {
                "name": "Daniel Sokolovskiy",
                "url": "https:\/\/dsokolovskiy.com\/blog\/",
                "avatar": "https:\/\/dsokolovskiy.com\/blog\/pictures\/userpic\/userpic@2x.jpg?1732048793"
            },
            "_date_published_rfc2822": "Sun, 25 Feb 2024 14:25:23 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "126030",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        }
    ],
    "_e2_version": 4079,
    "_e2_ua_string": "Aegea 11.0 (v4079e)"
}