C command line argument validation errors - c

Thank you everyone who helped me yesterday. I have one more issue with my code.
The purpose of the program is to take a command line argument and use it as a key to encrypt some plaintext entered by the user and to shift it by the number of letters given. The program should accept a single command-line argument, a non-negative integer. If any of the characters of the command-line argument is not a decimal digit, the program should print the message Usage: ./caesar key and return from main a value of 1.
When I test it, I receive the following error messages:
handles lack of key
failed to execute program due to segmentation fault
:( handles non-numeric key
timed out while waiting for program to exit
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
//Declare the encrypting function
void encrypt(string plaintext, int k, string ciphertext);
int main(int argc, string argv[])
{
string plaintext;
int n = strlen(plaintext);
char ciphertext[n+1]; //the lenght of the plaintext+ 1 extra char which i
int k = atoi(argv[1]); //Convert string into an integer, i.e parsing
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
for (int i = 0, m = strlen(argv[1]); i < m; i++)
{
if (isdigit(argv[1][i]))
{
plaintext = get_string("Plaintext:");
encrypt(plaintext, k, ciphertext); //calling the encryption function
printf("ciphertext: %s\n", ciphertext);
return 0;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
}
void encrypt(string plaintext, int k, string ciphertext)
{
for (int i = 0, n = strlen(plaintext); i < n; i++)
{
if (isupper(plaintext[i]))
{
int pi = plaintext[i] - 65;
char ci = ((pi + k) % 26) + 65;
ciphertext[i] = ci;
}
else if (islower(plaintext[i]))
{
int pi1 = plaintext[i] - 97;
char ci1 = ((pi1 + k) % 26) + 97;
ciphertext[i] = ci1;
}
else
{
ciphertext[i] = plaintext[i];
}
}
}

I've updated your code as little as possible. Most of it was just re-arranging things.
int main(int argc, string argv [])
{
// Check for correct number of args
if (argc != 2)
{
puts("Please supply a key.");
puts("Usage: ./caesar key");
return 0;
}
// Check that argv[1] is all digits (i.e. positive integer)
for (int i = 0, n = strlen(argv[1]); i < n; i++) {
if (!isdigit(argv[1][i])) {
puts("Usage: ./caesar key");
return 1;
}
}
// Get user string
string plaintext = get_string("Plaintext:");
if (!plaintext) return 1;
// My compiler does not allow VLAs so I use malloc
char *ciphertext = malloc(strlen(plaintext) + 1);
int k = atoi(argv[1]); //Convert string into an integer, i.e parsing
encrypt(plaintext, k, ciphertext); //calling the encryption function
printf("ciphertext: %s\n", ciphertext);
// Free up allocated mem
free(ciphertext);
free(plaintext);
return 0;
}
void encrypt(string plaintext, int k, string ciphertext)
{
int n = strlen(plaintext);
for (int i = 0; i < n; i++)
{
if (isupper(plaintext[i]))
{
int pi = plaintext[i] - 65;
char ci = ((pi + k) % 26) + 65;
ciphertext[i] = ci;
}
else if (islower(plaintext[i]))
{
int pi1 = plaintext[i] - 97;
char ci1 = ((pi1 + k) % 26) + 97;
ciphertext[i] = ci1;
}
else
{
ciphertext[i] = plaintext[i];
}
}
// Don't forget to append nul-terminator
ciphertext[n] = '\0';
}

Related

CS50 Caesar. invisible characters printing after upper case letters

I've written the below code for the Caesar project in CS50 and I felt like it was hitting the brief, but when I have run the check, both of the checks containing uppercase letters are coming back incorrect There seems to be some extra characters printed between each of the uppercase letters that don't appear when I run the code myself.
Am I missing something in my code that's causing this to happen?
the message from Check50
:( encrypts "BARFOO" as "EDUIRR" using 3 as key
expected "ciphertext: ED...", not "ciphertext: E\..."
:( encrypts "BaRFoo" as "FeVJss" using 4 as key
expected "ciphertext: Fe...", not "ciphertext: F\..."
my code
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
bool only_digits(string s);
char rotate(int, int);
int main(int argc, string argv[])
{
//make sure key is entered correctly
{
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
int cont = only_digits(argv[1]);
if (cont != 1)
{
return 1;
}
else
{
// convert key from string to int
int key = atoi(argv[1]);
string plain = get_string("plain text: \n");
// rotate the letters using the key
printf("ciphertext: ");
{
for (int i = 0, len = strlen(plain); i < len; i++)
{
rotate(plain[i], key);
}
}
printf("\n");
}
}
}
}
//rotate the letters using the key
char rotate(int p, int i)
{
// rotate uppers
if isupper(p)
{
p = p - 65;
char c = (p + i) % 26;
c += 65;
printf("%c", c);
}
// rotate lowers
if islower(p)
{
p = p - 97;
char c = (p + i) % 26;
c += 97;
printf("%c", c);
}
// if its a character keep the same
else
{
printf("%c", p);
}
return 0;
}
//make sure key entered is only digits
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (!isdigit(s[i]))
{
printf("Usage: ./caesar key\n");
return 0;
}
else
{
;
}
}
return 1;
}
While I am unsure if it's your only bug, you forgot an else if in your rotate function such that upper case letters would print in the first case but also the else to the second case after they had been modified.
char rotate(int p, int i)
{
// rotate uppers
if isupper(p)
{
p = p - 65;
char c = (p + i) % 26;
c += 65;
printf("%c", c);
}
// rotate lowers
else if islower(p) // without else if here, upper cases would fall into the else below with p - 65
{
p = p - 97;
char c = (p + i) % 26;
c += 97;
printf("%c", c);
}
// if its a character keep the same
else
{
printf("%c", p);
}
return 0;
}

substitution cs50 - handle repeating characters in key

This code is for the CS50 Harvard course Pset 2 substitution.
one section of my program requires a check on the key to make sure characters are not repeated. I am failing this check as it reads ' :( Handles duplicate characters in Key - timed out while waiting for program to exit'
What needs to be fixed in my code to pass this final check?
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[])
{
printf("\n");
//check if we have correct number of command line arguments
if (argc != 2)
{
printf("Usage: ./substitution key\n");
printf("(Please enter only 2 command line arguments)\n");
return 1; //error
}
//initialize global variables for use//
//length of key
int s = strlen(argv[1]);
//copy of key may be altered if it is not valid yet
string k = argv[1];
// if else to check if our key is 26 characters
if (s == 26)
{
for (int i = 0; i < 26; i++)
{
//checks each index in k to see if it is alpha or not, throws error if not
if (!isalpha(k[i]))
{
printf("Usage: ./substitution key\n");
printf("(Key must be alphabetical)\n");
return 1; //error
}
}
for (int i = 0; i < s; i++)
{
for (int j = i + 1; j < s; j++)
{
if (isupper(k[i]))
{
k[i] = tolower(k[i]);
}
if (k[i] == k[j])
{
printf("Usage: ./substitution key\n");
printf("(Key can not have repeating characters)\n");
return 1; //error
}
}
}
}
else
{
//if we dont have 26 characters
printf("Usage: ./subsitution key\n");
printf("Key must be 26 characters\n");
return 1;
}
//true key for our cipher
string key = k;
//ask user for plaintext
string plaintext = get_string("Plaintext: ");
int n = strlen(plaintext);
printf("ciphertext: ");
char *ciphertext = malloc(n);
for (int i = 0; i < n; i++)
{
//plaintext = Hello (H - 65 = 7 (8TH INDEX) IN OUR KEY)
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
int j = plaintext[i] - 'A';
printf("%c", toupper(key[j]));
}
if (islower(plaintext[i]))
{
int q = plaintext[i] - 'a';
printf("%c", tolower(key[q]));
}
}
else if (isdigit(plaintext[i]))
{
printf("%c", plaintext[i]);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
check50 tells you what argument it uses for the test. When you run your code with that argument, does it complain about duplicate characters in the key?
This program will not find a duplicate if the second occurance of a character is in upper case.

Encryption of text works for lower case only, upper case letters are unchanged

I am working on a pset and I need some help. The purpose of the program is to take a command line argument and use it as a key to encrypt some plaintext entered by the user and to shift it by the number of letters given. The uppercase letters should stay upper case, lower - lower. All other symbols should remain unchanged. My code encrypts only the lower case letters but not the upper case.
Please help me to figure out why.
void encryption(string plaintext, int k, string ciphertext);
int main(int argc, string argv[])
{
string plaintext;
int n = strlen(plaintext);
char ciphertext[n+1]; //the lenght of the plaintext+ 1 extra char which i
int k = atoi(argv[1]); //Convert string into an integer, i.e parsing
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
for (int i = 0, m = strlen(argv[1]); i < m; i++)
{
if (isdigit(argv[1][i]))
{
plaintext = get_string("Plaintext:");
encryption(plaintext, k, ciphertext); //calling the encryption function
printf("Ciphertext: %s\n", ciphertext);
return 0;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
}
void encryption(string plaintext, int k, string ciphertext)
{
for (int i = 0, n = strlen(plaintext); i < n; i++)
{
if (isupper(plaintext[i]))
{
int pi = plaintext[i] - 65;
char ci = ((pi + k) % 26) + 65;
ciphertext[i] = ci;
}
if (islower(plaintext[i]))
{
int pi1 = plaintext[i] - 97;
char ci1 = ((pi1 + k) % 26) + 97;
ciphertext[i] = ci1;
}
else
{
ciphertext[i] = plaintext[i];
}
}
}

Try to use += on string to stack char(s) in C

I know it sounds real stupid, but It is cuz I just lightly learned Java and Python last year...
now I am try to do C properly with CS50.
on week 2, there is Caesar encipher text program task.
I tried to use += on string to stack char(s) one by one.
And of course it didn't work.
but is there any other way to do it similarly?
here is the code
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
string encipher(string x, int y);
int main(int argc, string argv[])
{
string key = argv[1];
bool num_flag = false;
for (int i = 0; i < strlen(key); i++)
{
int k = isdigit(key[i]);
if (k == 0)
{
num_flag = true;
}
}
if (num_flag == true)
{
printf("Usage: ./caesar key\n");
}
else
{
int keys = atoi(argv[1]);
string c = get_string("plaintext: ");
string ciphertext = encipher(c, keys);
printf("ciphertext: %s\n", ciphertext);
}
}
string encipher(string x, int y)
{
string cip = "";
for (int i = 0; i < strlen(x); i++)
{
int low = islower(x[i]);
int upper = isupper(x[i]);
if (low != 0)
{
char lo = x[i] - 97;
char c = (lo + y) % 26;
char l = c + 97;
cip += l;
}
else if (upper != 0)
{
char up = x[i] - 65;
char c = (up + y) % 26;
char u = c + 65;
cip += u;
}
else
{
cip += x[i];
}
}
return cip;
}
.
I changed code to pass the test, but not perfect either...
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
string encipher(string x, int y);
int main(int argc, string argv[])
{
if(argc != 2)
{
printf("Usage: ./caesar key\n");
}
else
{
string key = argv[1];
bool num_flag = false;
for (int i = 0; i < strlen(key); i++)
{
int k = isdigit(key[i]);
if (k == 0)
{
num_flag = true;
}
}
if (num_flag == true)
{
printf("Usage: ./caesar key\n");
}
else
{
int keys = atoi(argv[1]);
string c = get_string("plaintext: ");
string cipher = encipher(c, keys);
printf("ciphertext: %s\n", cipher);
}
}
}
string encipher(string x, int y)
{
for (int i = 0; i < strlen(x); i++)
{
int low = islower(x[i]);
int upper = isupper(x[i]);
if (low != 0)
{
char lo = x[i] - 97;
char c = (lo + y) % 26;
char l = c + 97;
x[i] = l;
}
else if (upper != 0)
{
char up = x[i] - 65;
char c = (up + y) % 26;
char u = c + 65;
x[i] = u;
}
}
return x;
}
Thanks for helping newbie!
with strncat() you can add chars to an existing string.
( strncat(char DESTINATION STRING, const char SOURCE STRING, AMOUNT OF CHARS YOU WANT TO ADD FROM THE SOURCE) )
In C you can't add string like other high-level languages. You have to use a special function in string.h. Like strcat(first_string, second_string);
An alternative is: char *strncat(char *dest, const char *src, size_t n) to add the first n characters (you can interprete size_t like int).

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;
}
}
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);
}

Resources