Ahmed Nabil Ahmed Nabil - 29 days ago 6
C Question

Strange char appears in the output

I'm trying to obfuscate word which is stored in string and my code sometimes works and sometimes doesn't. Here is my code:

// main function
int main(int argc, string argv[])
{
string k, plaintext;
int size, i = 0, key = 0;
k = argv[1];
size = strlen(k);
if (argc < 2 || !isNummeric(k, size) || k < 0)
return 1;
else
plaintext = GetString();
size = strlen(plaintext);
char ciphertext[size];
key = atoi(k);
while(i < size)
{
if (isalpha(plaintext[i]))
{
encipher(key, i, &ciphertext[i], plaintext);
}
else
{
ciphertext[i] = plaintext[i];
}
i++;
}
printf("%s\n",ciphertext);
}


A key is received from the user to shift each letter and I need to check whether the key is numeric value or not so I made
isNummeric
function to do that

bool isNummeric(string k, int size)
{
int c=0;
for(int i=0; i<size; i++)
{
if(!isdigit(k[i]))
c++;
}
if(c==0)
return true;
return false;
}


Now to encipher I made function to shift each letter:

void encipher(int k, int i, char *pt, string plaintext)
{
int p, c;
if(islower(plaintext[i]))
{
p=plaintext[i]-'a';
c=(p+k)%26;
*pt=c+97;
}
else
{
p=plaintext[i]-'A';
c=(p+k)%26;
*pt=c+65;
}
}


here is my output

Answer

Assembling multiple comments from the question into fixed code yields the following code which seems to work:

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

static bool isNumeric(string k, int size)
{
    for (int i = 0; i < size; i++)
    {
        if (!isdigit((unsigned char)k[i]))
            return false;
    }
    return true;
}

/* There are too many arguments to this function - but it works */
static void encipher(int k, int i, char *pt, string plaintext)
{
    int p, c;
    if (islower((unsigned char)plaintext[i]))
    {
        p = plaintext[i] - 'a';
        c = (p + k) % 26;
        *pt = c + 'a';
    }
    else
    {
        p = plaintext[i] - 'A';
        c = (p + k) % 26;
        *pt = c + 'A';
    }
}

int main(int argc, string argv[])
{
    string k = argv[1];
    if (argc < 2 || !isNumeric(k, strlen(k)))
        return 1;
    string plaintext = GetString();
    int size = strlen(plaintext);
    char ciphertext[size + 1];
    int key = atoi(k);
    for (int i = 0; i < size; i++)
    {
        if (isalpha(plaintext[i]))
        {
            encipher(key, i, &ciphertext[i], plaintext);
        }
        else
        {
            ciphertext[i] = plaintext[i];
        }
    }
    ciphertext[size] = '\0';
    printf("%s\n", ciphertext);
}

The program was called csr13, and gives the following outputs:

$ csr13 4
The Quick Brown Fox Jumped Over The Lazy Dog
Xli Uymgo Fvsar Jsb Nyqtih Sziv Xli Pedc Hsk
$ csr13 22
Xli Uymgo Fvsar Jsb Nyqtih Sziv Xli Pedc Hsk
The Quick Brown Fox Jumped Over The Lazy Dog
$

A better design for the encipher function would pass the single character plus the 'key' offset and would return the encrypted character:

#include <assert.h>
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

static bool isNumeric(string k, int size)
{
    for (int i = 0; i < size; i++)
    {
        if (!isdigit((unsigned char)k[i]))
            return false;
    }
    return true;
}

static int encipher(int k, int c)
{
    assert(isalpha(c));
    if (islower(c))
        return (c - 'a' + k) % 26 + 'a';
    else
        return (c - 'A' + k) % 26 + 'A';
}

int main(int argc, string argv[])
{
    string k = argv[1];
    if (argc < 2 || !isNumeric(k, strlen(k)))
        return 1;
    string plaintext = GetString();
    int size = strlen(plaintext);
    char ciphertext[size + 1];
    int key = atoi(k);
    for (int i = 0; i < size; i++)
    {
        if (isalpha(plaintext[i]))
            ciphertext[i] = encipher(key, plaintext[i]);
        else
            ciphertext[i] = plaintext[i];
    }
    ciphertext[size] = '\0';
    printf("%s\n", ciphertext);
}