Search code examples
ccs50vigenere

Can't find out why my program isn't doing what it's supposed to do


As part of the CS50 Harvard programming course, which I'm currently attending, I'm doing an exercise called "Vigenere".

My program is doing everything right (it's going line by line and the expected behavior is met) except when I receive input that starts with a b.

Once it reaches the end of the input string it doesn't loop back around to the first character in the array, but if the input doesn't start with a b it works like it should.

Have been googling, debugging but just can't figure it out. Have tried doing it in a lot of other different ways too but I just can't get it to work.

#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <ctype.h>

    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            printf("Error.\n");
            return (1);
        }
        string input = argv[1];

        for (int i = 0; input[i] != '\0'; i++)
        {
            if (!isalpha(input[i]))
            {
                printf("Error.\n");
                return (1);
            }
        }
        string plaintext = get_string("plaintext: ");
        string cipher = argv[1];
        printf("ciphertext: ");
        int i = 0;
        int j = 0;
        int code = 0;

        while (plaintext[i] != '\0')
        {
            if (cipher[j] >= 97)
            {
                cipher[j] = cipher[j] - 97;
            }
            if (isupper(cipher[j]))
            {
               cipher[j] = cipher[j] - 65;
            }
            if (islower(plaintext[i]))
            {
                printf("%c", 'a' + (plaintext[i] - 'a' + cipher[j]) % 26);
                j++;
            }
            if (isupper(plaintext[i]))
            {
                printf("%c", 'A' + (plaintext[i] - 'A' + cipher[j]) % 26);
                j++;
            }
            if (plaintext[i] == ' ')
            {
                printf("%c", plaintext[i]);
            }
            if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
            {
                printf("%c", plaintext[i]);
            }
            if (cipher[j] == '\0' && plaintext[i] != ' ')
            {
                j = 0;
            }
            i++;
        }
        printf("\n");
        return (0);
    }

As explained above, whenever my command line input starts with a b the program doesn't work as expected. Doesn't happen when input is not a b.


Solution

  • the cipher manipulation you are doing in your code can cause j to always zero and lead to first char being printed repeatedly.

    this is caused due to the behaviour of the ascii -> non-ascii -> ascii, which is the desired behaviour from the ciphering process

    In order to fix the problem you need to use only the value of the cipher and not the manipulation on it in the condition. What I did was copy the value to a different pointer and by so keeping the condition to refer to the original char of the original cipher using malloc and memset.

    The code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    
        int main(int argc, char *argv[])
        {
    
            char *input = argv[1];
    
            for (int i = 0; input[i] != '\0'; i++)
            {
                if (!isalpha(input[i]))
                {
                    printf("Error.\n");
                    return (1);
                }
            }
            char *plaintext = "aaaaaaa";
            char *cipher = argv[1];
            //<============================
            char *moving_cipher;
            moving_cipher = (char *) malloc(3);
            memcpy(moving_cipher, cipher, 3);
            //<============================
            printf("ciphertext: ");
            int i = 0;
            int j = 0;
            int code = 0;
    
            while (plaintext[i] != '\0')
            {
                if (cipher[j] >= 97)
                {
                    moving_cipher[j] = cipher[j] - 97;
                }
                if (isupper(cipher[j]))
                {
                   moving_cipher[j] = cipher[j] - 65;
                }
                if (islower(plaintext[i]))
                {
                    printf("%c", 'a' + (plaintext[i] - 'a' + moving_cipher[j]) % 26);
                    j++;
                }
                if (isupper(plaintext[i]))
                {
                    printf("%c", 'A' + (plaintext[i] - 'A' + moving_cipher[j]) % 26);
                    j++;
                }
                if (plaintext[i] == ' ')
                {
                    printf("%c", plaintext[i]);
                }
                if (!isalpha(plaintext[i]) && !isspace(plaintext[i]))
                {
                    printf("%c", plaintext[i]);
                }
                if (cipher[j] == '\0' && plaintext[i] != ' ')
                {
                    j = 0;
                }
                i++;
            }
            printf("\n");
            return (0);
        }
    

    Notice: I checked in the problematic inputs as you wrote in your comments, this is why you need to find the desired size in a smart why and not hard coded.

    Input: "baz"

    output before fix: "bazbbbb"

    output after fix: "bazbazb"