I'm trying to create a Ceasar Cipher. For this test, I used a key of 1 and plain text of "hello." When doing so, I get the error message "Segmentation fault (core dumped)". I know this means I am trying to access an illegal memory location, and it's happening while calling the "encrypt" function, but that's all I know.
Depiction of the error I'm getting while debugging.
And here is my code.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
bool isValidKey(string);
string encrypt(string, int);
string c;
int main(int argc, string argv[])
{
if (argc != 2 || isValidKey(argv[1]) == 0)
{
printf("Useage: ./caesar key\n");
return 0;
}
string p = get_string("plaintext: ");
c = encrypt(p, atoi(argv[1]));
printf("%s", c);
return 0;
}
bool isValidKey(string key)
{
for (int i = 0; i < strlen(key); i++)
{
if (isdigit(key[i]) == 0)
{
return false;
}
}
return true;
}
string encrypt(string plain, int k)
{
for (int i = 0; i < strlen(plain); i++)
{
if (isalpha(plain[i]) != 0)
{
if (islower(plain[i]) != 0)
{
c[i] = ((plain[i] - 97 + k) % 26) + 97;
}
else
{
c[i] = ((plain[i] - 65 + k) % 26) + 65;
}
}
}
return c;
}
The variable c declared in the file scope
string c;
is a null pointer. The above declaration is equivalent to
char *c;
or in fact to
char *c = NULL;
So using the null pointer within the function encrypt like
c[i] = ((plain[i] - 97 + k) % 26) + 97;
invokes undefined behavior.
Also it is a bad idea when a function like encrypt depends on a global variable.
Also using magic numbers like for example 97 makes the program unclear.
As the function parameter does not have the qualifier const then it will be logical to convert the passed string in place.
Pay attention to that the user can pass a very big integer value as a key. In this case your function will invoke undefined behavior.
So the function can look like
string encrypt( string plain, int k)
{
k = k % 26;
for ( size_t i = 0, n = strlen( plain ); i < n; i++ )
{
if ( isalpha( ( unsigned char )plain[i] ) )
{
if ( islower( plain[i] ) )
{
plain[i] = ( plain[i] - 'a' + k ) % 26 + 'a';
}
else
{
plain[i] = ( plain[i] - 'A' + k ) % 26 + 'A';
}
}
}
return plain;
}
The variable c should be removed and in main it is enough to write
string p = get_string( "plaintext: " );
puts( encrypt( p, atoi( argv[1] ) ) );
You need to allocate memory for c.
string encrypt(string plain, int k)
{
c = malloc(strlen(plain) + 1);
for (int i = 0; i < strlen(plain); i++)
{
if (isalpha(plain[i]) != 0)
{
if (islower(plain[i]) != 0)
{
c[i] = ((plain[i] - 97 + k) % 26) + 97;
}
else
{
c[i] = ((plain[i] - 65 + k) % 26) + 65;
}
}
}
return c;
}
And in main() you should add free(c); before return 0;
Related
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);
}
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;
}
}
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;
}
I'm trying to figure out why my code is not iterating correctly on z. I would like to iterate every 1 z, but it seems like it's a bit random. Does anyone have any suggestions on how I might do this? If there anything else I'm doing wrong, please let me know. I think I'm really close. I'm also curious how I block spaces/other characters from being encrypted.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int shift(char c);
int main(int argc, string argv[])
{
// Check to see if two arguments are enterted at launch
int cipher = 0;
if (argc != 2)
{
// If not return error & return 0
printf("Usage: ./vigenere keyword \n");
return 1;
}
else
{
int strlength = strlen(argv[1]);
// Iterates through characters in second argument (key), checking to see
if they are digits
for (int k = 0; k < strlength; k++)
{
if (isdigit(argv[1][k]))
{
// If not return error & return 1
printf("Usage: ./vigenere keyword\n");
return 2;
}
}
//char *c =argv[1];
string plaintext = get_string("Plaintext: ");
int len = (int) strlen(plaintext);
//int b = atoi(c);
//char code[len];
//strcpy (code, plaintext);
int z=0;
for (int j = 0; j < len; j++)
{
int key = shift(argv[1][z]);
//printf("%i",z);
if (isupper(argv[1][z]))
{
//printf("theory\n");
cipher = ((((plaintext[j] - 'A') + key) + 'A'));
//cipher = ((((plaintext[j] - 'A') + key) % 26) + 'A');
//printf("%c", (((plaintext[j] - 'A') + key) % 26) + 'A');
//printf("%i",z);
printf("%c",cipher);
}
if (islower(argv[1][z]))
{
//printf("theory\n");
cipher = (((plaintext[j] - 'a') + key) + 'a');
//printf("%i",z);
printf("%c",cipher);
}
//z++;
//else if (!isalpha(plaintext[j]))
//{
//printf("%c", plaintext[j]);
//}
if (z > strlen(argv[1])-1)
{
z=0;
}
/* else
{
z++;
}
else
{
z++;
}
*/
//z++;
}
printf("\n");
}
}
int shift(char c)
{
int i = c;
if (i <= 'Z' && i >= 'A')
{
return ((i - 'A') % 26);
}
else
{
return ((i - 'a') % 26);
}
}
My intent with this code is to make a vignere cipher.
I can compile my code with gcc but when I run the program and pass 2 strings in the command line I have a segmentation fault. Initially I had tried to control the int value of j with a separate if-statement in my for-loop such as:
if( i % strlen(msg) == 0) {
j = 0;
}
else {
j++;
}
However, it was not clear to me if this would produce my intended result, to execute an expression in this if-statement and to then continue with the next if-statement. So, I substitute a conditional statement and the code compiles. However, in both cases I get a segmentation fault, using either method with j.
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *msg = argv[1];
char *key = argv[2];
int i, j, sl, ky, mg;
sl = strlen(key);
j = 1;
int encrypt[strlen(msg)];
if(isalpha(key) && argc == 3) {
;
}
else
perror("run program from cmd line with 2 strings \n");
return 1;
for(i = 1; i <= sl; i++) {
(i % strlen(key) == 0) ? j = 0 : j++;
mg = msg[i];
ky = key[j];
if(isalpha(msg[i])) {
if(isupper(msg[i])) {
msg[i] = 'A' + (('A' - msg[i]) + ('A' - key[j]) % 26);
}
else if(islower(msg[i])) {
msg[i] = 'a' + (('a' - msg[i]) + ('a' - key[j]) % 26);
}
else {
msg[i] = msg[i];
}
}
}
return 0;
}
Okay well I fixed some oversights such as lines 38 and 42. This snippet of code works as a cipher but it only works some of the time.
for(i = 0; i < sl; i++) {
(i % strlen(key) == 0) ? j = 0 : j++;
mg = msg[i];
ky = key[j];
if(isalpha(msg[i])) {
if(isupper(msg[i])) {
encrypt[i] = 'A' + ((( msg[i] - 'A') + (key[j]) - 'A') % 26);
}
else if(islower(msg[i])) {
encrypt[i] = 'a' + (((msg[i] - 'a') + (key[j]) - 'a') % 26);
}
else {
encrypt[i] = msg[i];
}
}
}
for(i = 0; i < strlen(msg); i++) {
printf("%c", encrypt[i]);
I am attending the online course cs50 on Edx and I have an assignment in which I have to create a program where the user enters a keyword ( used then for encryption ) and a string that needs to be encrypted in Vigenere cipher.
Vigenere works by encrypting a text following a keyword: for example if my string is "Hello" and my keyword is "abc" : a is equal to 0 in alphabetical characters, b to 1, and c to 2; so the letter h in the string is encrypted without switching characters ( s letter a in the keyword is = 0), the letter e is switched by one position and is encrypted to f, and so on. If the keyword has a length less than that of the string (like in this case) the encryption has to use again the first character of the keyword and this is my problem.
In fact, I think I implemented well the whole program but I am not sure how to take into consideration if a keyword has less characters than the string entered.
The program is now returning only the first char of my string encrypted and the first char not encrypted and then it stops.
I do not ask for a complete solution, but I just want to understand how I can solve my program problem.
Here is my program:
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int vigenere_low( char c )
{
int v = c - 'a';
return v;
}
int vigenere_up( char c )
{
int v = c - 'A';
return v;
}
int keyword_low( char c )
{
int k = c - 'a';
return k;
}
int keyword_up( char c )
{
int k = c - 'A';
return k;
}
int main( int argc, string argv[] )
{
string p;
string keyword = argv[1];
if ( argc != 2 )
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
for ( int i = 0, n = strlen(keyword); i < n; i++ )
{
if ( !isalpha( keyword[i]) )
{
printf("Usage: ./vigenere keyword(alphabetical) \n");
return 1;
}
}
p = GetString();
int j = 0;
for ( int i = 0, n = strlen( p ); i < n; i++ )
{
if ( isalpha( p[i]) )
{
if ( islower( p[i]) )
{
if ( islower( keyword[j]) )
{
int a = (( vigenere_low( p[i]) + keyword_low( keyword[j]) ) % 26 ) + 'a';
printf("%c", a);
j++;
}
else
{
int a = (( vigenere_low( p[i]) + keyword_up( keyword[j]) ) % 26 ) + 'a';
printf("%c", a);;
j++;
}
}
if ( isupper( p[i]) )
{
if ( islower( keyword[j]) )
{
int a = (( vigenere_up( p[i]) + keyword_low( keyword[j]) ) % 26 ) + 'A';
printf("%c", a);
j++;
}
else
{
int a = (( vigenere_up( p[i]) + keyword_up( keyword[j]) ) % 26 ) + 'A';
printf("%c", a);
j++;
}
}
else
{
printf("%c", p[i] );
}
}
return 0;
}
}
... not sure how to take into consideration if a keyword has less characters than the string entered.
Accessing keyword[j] beyond the end of keyword[] is bad. (Undefined behavior). This happens with OP's code when the key is shorter than the alpha part of the message.
Simply re-use the keyword[] string as needed. Hint: reset j.
Mouse over for answer.
int j_length = strlen(keyword);
...
j++;
if (j >= j_length) j = 0;
I've been going round in circles with this now for a few hours. It manages the first word of the recommended test (Meet me at the park at eleven am) gets over the first spaces, gives a correct letter for m then prints several spaces before ending. Many thanks in advance.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int allstralpha();
int main(int argc, string argv[])
{
string keyw = argv[1];
if(argc == 2 && allstralpha(keyw))
{
string plaint = GetString();
int c = 0;
int kl = strlen(keyw);
int k = 0;
int p = 0;
int j = 0;
for(int i = 0, n = strlen(plaint); i < n; i++)
{
if(isalpha(plaint[i]))
{
if(isupper(keyw[j]))
{
k = keyw[(j % kl)] - 65;
if(isupper(plaint[i]))
{
p = plaint[i] -65;
c = ((k + p) % 26) + 65;
printf("%c", (char) c);
}
else if(islower(plaint[i]))
{
p = plaint[i] -97;
c = ((k + p) % 26) + 97;
printf("%c", (char) c);
}
}
else if(islower(keyw[j]))
{
k = keyw[(j % kl)] - 97;
if(isupper(plaint[i]))
{
p = plaint[i] - 65;
c = ((k + p) % 26) + 65;
printf("%c", (char) c);
}
else if(islower(plaint[i]))
{
p = plaint[i] - 97;
c = ((k + p) % 26) + 97;
printf("%c", (char) c);
}
}
j++;
}
else
{
printf("%c", (char) plaint[i]);
}
}
}
else
{
printf("Sorry that is not a vaild parameter\n");
return 1;
}
}
int allstralpha(string s)
{
for(int i = 0, n = strlen(s); i < n; i++)
{
if(!isalpha(s[i]))
{
return 0;
}
}
return 1;
}
int allstralpha();
int allstralpha(string s)
{
...
}
Your function definition and declaration don't match. You should declare int allstralpha(string s);
In first line of main:
int main(int argc, string argv[])
{
string keyw = argv[1];
...
}
First you should check if (argc > 1) before accessing argv[1]
For the actual code itself, you provide the plain text, but I can't see the keyword.
I use these values from wikipedia, vigenère cipher for testing:
Plaintext: ATTACKATDAWN
Key: LEMONLEMONLE
Ciphertext: LXFOPVEFRNHR
Minimum code to finish this:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, const char* argv[])
{
const char *str = "Meet me at the park at eleven am";
const char *key = "bacon";
int keylen = strlen(key);
int len = strlen(str);
for (int i = 0, j = 0; i < len; i++)
{
int c = str[i];
if (isalnum(c))
{
//int k = function of key and `j`...
//offset k...
if (islower(c))
{
c = (c - 'a' + k) % 26 + 'a';
}
else
{
c = (c - 'A' + k) % 26 + 'A';
}
j++;
}
putchar(c);
}
putchar('\n');
return 0;
}