Search code examples
cclang

Declaring/defining an unused variable changes the output from an unrelated variable


Scenario

I have an odd bug where when I add a random variable to the code it changes the output. I figured out what was causing the issue, however I am not entirely sure why it is causing the issue.

The code is intended to validate credit card numbers using the Luhns Algorithm. It is part of the edX CS50 course, however I decided to try it without their custom-built libraries in an attempt to learn as much as possible.

The issue I am encountering is, if I run the code below as-is, then the answer comes out wrong (i.e., a '9' appended to the integer output). Now if I uncomment either int random_integer = 0; or char random_character = 'M';, then the output works entirely as anticipated.

  • Wrong output (leaving those random variables commented): 209
  • Correct output (uncommenting one (or both) of those random variables): 20

Oddly enough, I noticed that if I change char sum_to_str[3]; to char sum_to_str[10];, the problem goes away entirely.

Please let me know your thoughts as I am newer to C and am interested in understanding the nuances.

Code

#include <stdio.h> // For Standard Input/Output
#include <stdlib.h> // For the atoi() function
#include <string.h> // For the strchr() and strlen() functions

// This value is the length plus one
#define MAX_INPUT_LENGTH 255

int main(void) {
    char user_input[MAX_INPUT_LENGTH];
    char *p;

    // Output CLI instructions
    printf("Welcome to the Credit Card Validator!!\n");
    printf("INSTRUCTIONS: At the prompt, please provide a CC number.\n");
    printf("NOTES ON LENGTH: Visa -> 13 || 16, AmEx -> 15 and MC -> 16\n");

    // Algorithm
    char example_card_num[] = "4003600000000014";

    // Check the length
    int card_num_length = strlen(example_card_num);

    int skip_flag = 0;
    int sum_of_values = 0;
    char value_at_index;
    char str_of_evens[20];
    for (int i = card_num_length - 1; i >= 0; i--) {
        char sum_to_str[3];
        switch (skip_flag) {
            case 0:
                // Add 'odd' values together
                value_at_index = example_card_num[i];
                sum_of_values = sum_of_values + atoi(&value_at_index);

                // Toggle flag
                skip_flag = 1;
                break;
            case 1:
                // Add 'even' values together (with multiplier)
                value_at_index = example_card_num[i];

                // 1. Convert each str to int
                // 2. Multiply by two
                // 3. Convert back to str in new variable
                sprintf(sum_to_str, "%d", (atoi(&value_at_index) *2));

                // Concatenate each substring to a new string
                strcat(str_of_evens, sum_to_str);
                 
                // Toggle flag
                skip_flag = 0;
                break;
        }
    }

    // int random_integer = 0;
    // char random_character = 'M';

    char value_at_index_two;
    for (int i = 0; i < strlen(str_of_evens); i++) {
        value_at_index_two = str_of_evens[i];
        sum_of_values = sum_of_values + atoi(&value_at_index_two);
    }

    printf("~~~~~~~~~~~\n");
    printf("Sum of Values 01: %d\n", sum_of_values);

    // Terminate the program
    return 0;
}

I tried the following:

  • Commenting/uncommenting the int random_integer = 0; then recompiling
  • Adding the char random_character = 'M'; then toggling it as a comment and recompiling
  • Modified the char sum_to_str[3]; to char sum_to_str[3];

I also tried to change the input (i.e., example_card_num[]) slightly to determine if there was something throwing an arbitrary "9" or if the appended number changed, which it did.


Solution

  • Your issue is caused by undefined behavior due to improper memory usage:

    1. Uninitialized str_of_evens → It contains garbage data, which causes strcat() to behave unpredictably
    2. Using atoi() on a single character → atoi() expects a null-terminated string, but you're passing a single character
    3. Buffer overflow in sum_to_strchar sum_to_str[3]; is too small for storing two-digit numbers safely

    I'm attaching the corrected version:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAX_INPUT_LENGTH 255
    
    int main(void) {
    
        char user_input[MAX_INPUT_LENGTH];
        char *p;
        printf("Welcome to the Credit Card Validator!!\n");
        printf("INSTRUCTIONS: At the prompt, please provide a CC number.\n");
    
        char example_card_num[] = "4003600000000014";
    
        int card_num_length = strlen(example_card_num);
    
        int skip_flag = 0;
        int sum_of_values = 0;
        char value_at_index;
    
        char str_of_evens[20] = {0};
       
        for (int i = card_num_length - 1; i >= 0; i--) {
            char sum_to_str[4] = {0};
    
            switch (skip_flag) {
                case 0:
                    value_at_index = example_card_num[i];
    
                    sum_of_values += value_at_index - '0';
    
                    skip_flag = 1;
                    break;
                case 1:
                    value_at_index = example_card_num[i];
                    
                    int multiplied_value = (value_at_index - '0') * 2;
                    
                    sprintf(sum_to_str, "%d", multiplied_value);
                    
                    strncat(str_of_evens, sum_to_str, sizeof(str_of_evens) - strlen(str_of_evens) - 1);            
                   
                    skip_flag = 0;
    
                    break;
            }
        }
        char value_at_index_two;
        for (size_t i = 0; i < strlen(str_of_evens); i++) {
            value_at_index_two = str_of_evens[i];
            sum_of_values += value_at_index_two - '0';
        }
    
        printf("~~~~~~~~~~~\n");
    
        printf("Sum of Values 01: %d\n", sum_of_values);
    
        return 0;
    }