Home > Software engineering >  Caesar Encryption in C
Caesar Encryption in C

Time:04-26

Hello I am working on a Caesar encryption program. Right now it takes as an input the file with the message to encrypt, the key

The input is currently in this format:

"text.txt", "ccc"

I need to convert this into taking a number so that it fits my requirements, so something like this:

"text.txt", "3"

Then i need to convert this "3" back into "ccc" so that the program still works. The logic being that 3 translates to the third letter of the alphabet "c", and is repeated 3 times. Another example would be if the key entered is "2", it should return "bb".

This is what i have so far but its giving me a lot of warnings and the function does not work correctly.

#include <stdio.h>

void number_to_alphabet_string(int n) {
    char buffer[n];
    char *str;
    str = malloc(256);

    char arr[8];

    for(int i = 0; i < n; i  ) {
        buffer[i] = n   64;
        //check ASCII table the difference is fixed to 64
        arr[i] = buffer[i];
        strcat(str, arr);
    }

    printf(str);
}

int main(int argc, char *argv[]) {
    const char *pt_path = argv[1];  //text.txt
    char *key = argv[2];    //3
    number_to_alphabet_string((int)key); //should change '3' to 'CCC'
}

CodePudding user response:

Your problem is that you have a function

void number_to_alphabet_string(int n) 

that takes an int but you call it with a char*

char* key = argv[2];    //3
number_to_alphabet_string(key);

My compiler says

1>C:\work\ConsoleApplication3\ConsoleApplication3.cpp(47,34): warning C4047: 'function': 'int' differs in levels of indirection from 'char *'

You need

char* key = argv[2];    //3
number_to_alphabet_string(atoi(key));

to convert that string to a number

CodePudding user response:

With char *key = argv[2];, the cast (int) key does not reinterpret the contents of that string as a valid integer. What that cast does is take the pointer value of key, and interprets that as an integer. The result of this is implementation-defined, or undefined if the result cannot be represented in the integer type (a likely outcome if sizeof (int) < sizeof (char *)).

The C standard does not define any meaning for these values.

Here is a test program that, depending on your platform, should give you an idea of what is happening (or failing to happen)

#include <stdio.h>

int main(int argc, char **argv) {
    if (sizeof (long long) >= sizeof (char *))
        printf("Address %p as an integer: %lld (%llx)\n",
                (void *) argv[0],
                (long long) argv[0],
                (long long) argv[0]);
}

As an example of implementation-defined behaviour, on my system this prints something like

Address 0x7ffee6ffdb70 as an integer: 140732773948272 (7ffee6ffdb70)

On my system, casting that same pointer value to (int) results in undefined behaviour.

Note that intptr_t and uintptr_t are the proper types for treating a pointer value as an integer, but these types are optional.


To actually convert a string to an integer, you can use functions such as atoi, strtol, or sscanf. Each of these have their pros and cons, and different ways of handling / reporting bad input.

Examples without error handling:

int three = atoi("3");
long four = strtol("4", NULL, 10);
long long five;
sscanf("5", "%lld", &five);

number_to_alphabet_string has a few problems.

malloc can fail, returning NULL. You should be prepared to handle this event.

In the event malloc succeeds, the contents of its memory are indeterminate. This means that you need to initialize (at least partially) the memory before passing it to a function like strcat, which expects a proper null terminated string. As is, strcat(str, arr); will result in undefined behaviour.

Additionally, memory allocated by malloc should be deallocated with free when you are done using it, otherwise you will create memory leaks.

char *foo = malloc(32);

if (foo) {
    foo[0] = '\0';
    strcat(foo, "bar");
    puts(foo);
    free(foo);
}

In general, strcat and the additional buffers are unnecessary. The use of char arr[8]; in particular is unsafe, as arr[i] = buffer[i]; can easily access the array out-of-bounds if n is large enough.

Additionally, in strcat(str, arr);, arr is also never null terminated (more UB).

Note also that printf(str); is generally unsafe. If str contains format specifiers, you will again invoke undefined behaviour when the matching arguments are not provided. Use printf("%s", str), or perhaps puts(str).


As far as I can tell, you simply want to translate your integer value n into the uppercase character it would be associated with if A=1, B=2, ... and repeat it n times.

To start, there is no need for buffers of any kind.

void number_to_alphabet_string(int n) {
    if (1 > n || n > 26)
        return;

    for (int i = 0; i < n; i  )
            putchar('A'   n - 1);

    putchar('\n');
}

When passed 5, this will print EEEEE.

If you want to create a string, ensure there is an additional byte for the terminating character, and that it is set. calloc can be used to zero out the buffer during allocation, effectively null terminating it.

void number_to_alphabet_string(int n) {
    if (1 > n || n > 26)
        return;

    char *str = calloc(n   1, 1);

    if (str) {
        for (int i = 0; i < n; i  )
            str[i] = 'A'   n - 1;

        puts(str);
        free(str);
    }
}

Note that dynamic memory is not actually needed. char str[27] = { 0 }; would suffice as a buffer for the duration of the function.

A cursory main for either of these:

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

void number_to_alphabet_string(int n);

int main(int argc, char *argv[]) {
    if (argc > 1)
        number_to_alphabet_string(atoi(argv[1]));
}

Note that with an invalid string, atoi simply returns 0, which is indistinguishable from a valid "0" - a sometimes unfavourable behaviour.

CodePudding user response:

  1. You can't use a cast to cast from a char array to an int, you have to use functions, such as atoi().
  2. You never free your str after you allocate it. You should use free(str) when you no longer need it. Otherwise, it will cause a memory leak, which means the memory that you malloc() will always be occupied until your process dies. C doesn't have garbage collection, so you have to do it yourself.
  3. Don't write things such as char buffer[n];, it can pass the compile of GCC, but it can't in MSVC. And that isn't the stander way of declaring an array with variable length. use
char* buffer = malloc(n);

//don't forget to free() in order to avoid a memory leak
free(buffer);
  • Related