1

I'm a little confused with this problem, because I got it to work and submitted and got full credit, but the code only words when I print the initial variables before the loop. This code works:

int main(int argc, string argv[]) {
    // c = (p + k) % 26, where c is result text, p is input and k
    // is key

    //considers if arg count is two
    if (argc == 2) {
        int n = strlen(argv[1]);
        int check = 0;

        if (isdigit(argv[1][0])) {
            for (int i = 1; i < n; i++) {
                if (isdigit(argv[1][i]) || argv[1][i] == '0') {
                    check++;
                } else {
                    check--;
                }
            }
        }

        // verifies all characters are numeric
        if (check != n - 1) {
            printf("Usage: ./caesar key\n");
            return 1;
        }
    } else {
        printf("Usage: ./caesar key\n");
        // returning 1 identifies an error and exits the program
        return 1;
    }

    int key = atoi(argv[1]);

    string plaintext = get_string("plaintext: ");

    printf("%i\n", key);
    printf("%s\n", plaintext);

    int m = strlen(plaintext);

    printf("%i\n", m);

    char ciphertext[m];
    int usekey = (key % 26);
    printf("%i\n", key);

    // NEED to figure out how to handle wrap around
    // need to understand ASCII
    for (int i = 0; i < m; i++) {
        int c = plaintext[i];

        //encrypts upper case letters
        if (c >= 65 && c <= 90) {
            //incorporates wrap around for uppercase
            if (c + usekey >= 90) {
                int val = 90 - c;
                int key2 = usekey - val;
                char cipher = 64 + key2;
                ciphertext[i] = cipher;
            }
            //considers if key works fine
            else {
                char cipher = c + usekey;
                ciphertext[i] = cipher;
            }
        }
        //encrypts lower case letters
        else if (c >= 97 && c <= 122) {
            //incorporates wrap around for lowercase
            if (c + usekey >= 122) {
                int val = 122 - c;
                int key2 = usekey - val;
                char cipher = 96 + key2;
                ciphertext[i] = cipher;
            } else {
                char cipher = c + usekey;
                ciphertext[i] = cipher;
            }
        } else {
        //encrypts punctuation
            ciphertext[i] = c;
        }
        printf("*\n");
    }

    printf("ciphertext: %s\n", ciphertext);

}

However, this code, does not work (for encrypts a as b using 1 as key, and for world, say hello! as iadxp, emk tqxxa! using 12 as key). It randomly prints different characters after the correct answer, and I cannot figure out why.

int main(int argc, string argv[]) {
    // c = (p + k) % 26, where c is result text, p is input and k
    // is key

    //considers if arg count is two
    if (argc == 2) {
        int n = strlen(argv[1]);
        int check = 0;

        if (isdigit(argv[1][0])) {
            for (int i = 1; i < n; i++) {
                if (isdigit(argv[1][i]) || argv[1][i] == '0') {
                    check++;
                } else {
                    check--;
                }
            }
        }

        // verifies all characters are numeric
        if (check != n - 1) {
            printf("Usage: ./caesar key\n");
            return 1;
        }
    } else {
        printf("Usage: ./caesar key\n");
        // returning 1 identifies an error and exits the program
        return 1;
    }

    int key = atoi(argv[1]);

    string plaintext = get_string("plaintext: ");

    int m = strlen(plaintext);

    char ciphertext[m];
    int usekey = (key % 26);

    // NEED to figure out how to handle wrap around
    // need to understand ASCII
    for (int i = 0; i < m; i++) {
        int c = plaintext[i];

        //encrypts upper case letters
        if (c >= 65 && c <= 90) {
            //incorporates wrap around for uppercase
            if (c + usekey >= 90) {
                int val = 90 - c;
                int key2 = usekey - val;
                char cipher = 64 + key2;
                ciphertext[i] = cipher;
            }
            //considers if key works fine
            else {
                char cipher = c + usekey;
                ciphertext[i] = cipher;
            }
        }
        //encrypts lower case letters
        else if (c >= 97 && c <= 122) {
            //incorporates wrap around for lowercase
            if (c + usekey >= 122) {
                int val = 122 - c;
                int key2 = usekey - val;
                char cipher = 96 + key2;
                ciphertext[i] = cipher;
            } else {
                char cipher = c + usekey;
                ciphertext[i] = cipher;
            }
        }
        //encrypts punctuation
        else {
            ciphertext[i] = c;
        }
    }
    printf("ciphertext: %s\n", ciphertext);
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 1
    missing zero terminator? maybe do: `char ciphertext[m + 1]; ciphertext[m] = '\0'; /* no more changes */` – pmg May 23 '20 at 09:59
  • regarding: `int n = strlen(argv[1]);` 1) the function: `strlen()` returns a `size_t` NOT a `int`. 2) the value returned from `strlen()` is the index to the NUL termination byte and indexes start at 0, not 1. 2) regarding: `for (int i = 1; i < n; i++)` This skips checking the first char of the command line parameter. Suggest: `for( size_t i = 0; i – user3629249 May 24 '20 at 06:38
  • this convoluted code: `if (isdigit(argv[1][i]) || argv[1][i] == '0') { check++; } else { check--; }` could be replaced with: `if( isdigit( argv[1][i] ) ) { check++; }` and `if (check != n - 1)` replaced with: `if( check != n )` then eliminate: `if (isdigit(argv[1][0])) {` – user3629249 May 24 '20 at 06:43
  • regarding `else if (c >= 97 && c <= 122)` using hard coded values, like this, limits the encoding the ASCII. and is difficult to understand. Suggest: `else if (c >= 'a' && c <= 'z')` An even better approach would be to use the function `isalpha()` from the header file: `ctype.h` – user3629249 May 24 '20 at 06:49

2 Answers2

0

I think your if conditions is not works as it should be. you can print 'argv[1][i]' and see the problem. here is my code may help you.

bool isNumber(char number[])
{
    int i = 0;

    for (; number[i] != 0; i++)
    {
        if (!isdigit(number[i]))    //check if there is something that is not digit
        {
            return false;
        }
    }

    return true;
}

int main(int argc, string argv[])
{

    if (argc == 2 && isNumber(argv[1]) == 1)
    {
        int k = atoi(argv[1]);
        string plainText, chipherText;
        plainText = get_string("plaintext: ");
        printf("ciphertext: ");
        for (int i = 0, n = strlen(plainText) ; i < n; i++)
        {
            // checking if it is lowercase 97 = a to 112 = z and if it + 13 characters along.
            if (plainText[i] >= 'a' && plainText[i] <= 'z')
            {
                printf("%c", (((plainText[i] - 'a') + k) % 26) + 'a'); // print out lowercase with key
            } // if it it between uppercase A and Z
            else if (plainText[i] >= 'A' && plainText[i] <= 'Z')
            {
                printf("%c", (((plainText[i] - 'A') + k) % 26) + 'A'); // print out uppercase with key
            }

            else

            {
                printf("%c", plainText[i]);
            }
        }

        printf("\n");

        return 0;
    }
    else if (argc != 2 || isNumber(argv[1]) == 0)
    {
        printf("Error\n");
        return 1;
    }
}
erdem
  • 1
  • 1
0

You allocate m bytes for cyphertext, which is not enough for the null terminator, which you do not set either, causing random characters to appear after the encrypted output. This is actually undefined behavior, so anything can happen including a program crash.

You do not need to store the encrypted text, just output it one byte at a time. Also do not use ASCII values such as 65 and 90, use character constants 'A' and 'Z' that are much more readable.

Here is a simplified version:

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

int main(int argc, string argv[]) {
    if (argc != 2) {
        printf("Usage: ./caesar key\n");
        // returning 1 identifies an error and exits the program
        return 1;
    }
    char *p;
    int key = strtol(argv[1], &p, 10);
    if (*p || p == argv[1]) {
        printf("caesar: invalid argument: %s\n", argv[1]);
        return 1;
    }
    string plaintext = get_string("plaintext: ");
    // assuming ASCII
    for (size_t i = 0; plaintext[i]; i++) {
        int c = plaintext[i];

        if (c >= 'A' && c <= 'Z') {
            c = 'A' + (c - 'A' + key) % 26;
        } else
        if (c >= 'a' && c <= 'z') {
            c = 'a' + (c - 'a' + key) % 26;
        }
        putchar(c);
    }
    putchar('\n');
    free(plaintext);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189