I write this code and declare the c variable in if chains,
but the compiler gives me an error saying you did not declare this variable.
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int k = atoi(argv[1]);
printf ("%i\n", k);
string p = get_string ("Plaintext: \n");
for (int i = 0; i < strlen(p); i++)
{
if (isalpha(p[i]))
{
if (islower(p[i]))
{
char c = (((p[i] - 97) + k) % 26) + 97;
return 0;
}
else if (isupper(p[i]))
{
char c = (((p[i] - 65) + k) % 26) + 65;
return 0;
}
else{
char c = (((p[i] - 65) + k) % 26) + 65;
}
p[i] = c;
}
}
printf ("%s\n", p);
return 0;
}
Error message:
test2.c: In function ‘main’:
test2.c:34:20: error: ‘c’ undeclared (first use in this function)
34 | p[i] = c;
| ^
test2.c:34:20: note: each undeclared identifier is reported only once for each function it appears in
'If' block itself is a scope, and you define a scope and the variables are only accessible inside the scope, not outside, and not at the boundary either.
For sure, the c variable should be declared outside the For loop:
char c = ' ';
for ...
The error would occur at following line:
p[i] = c;
It is because c is local scope at the following line:
if (islower(p[i]))
{
char c = (((p[i] - 97) + k) % 26) + 97;
return 0;
}
and
{
char c = (((p[i] - 65) + k) % 26) + 65;
return 0;
}
and
else{
char c = (((p[i] - 65) + k) % 26) + 65;
}
Local scope means that it will be released after exit the }.
Additionally, after first 2 condition of if, else if, there is also return after define value to c. If so, the API will return immediate and c is not used at any line because the assignment p[i] = c; will not execute.
You declare c as a local scope !
So you should declare c before this if statements like that:
if (isalpha(p[i]))
{
char c = 0;
if (islower(p[i]))
{
c = (((p[i] - 97) + k) % 26) + 97;
return 0;
}
else if (isupper(p[i]))
{
c = (((p[i] - 65) + k) % 26) + 65;
return 0;
}
else{
c = (((p[i] - 65) + k) % 26) + 65;
}
p[i] = c;
Related
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;
I'm working on my PSet2 Caesar Problem. After finishing my code here is the mistakes I got. Any advice how to fix them? Really appreciated.
caesar.c:46:10: error: use of undeclared identifier 'i'
for (i = 0; i < strlen(plaintext); i++)
^
caesar.c:46:17: error: use of undeclared identifier 'i'
for (i = 0; i < strlen(plaintext); i++)
^
caesar.c:46:40: error: use of undeclared identifier 'i'
for (i = 0; i < strlen(plaintext); i++)
^
caesar.c:48:31: error: use of undeclared identifier 'i'
if (isupper(plaintext[i]))
^
caesar.c:50:39: error: use of undeclared identifier 'i'
printf("%c", (((plaintext[i] - 65) + k) %26) + 65);
^
caesar.c:52:36: error: use of undeclared identifier 'i'
else if (islower(plaintext[i]))
^
caesar.c:54:39: error: use of undeclared identifier 'i'
printf("%c", (((plaintext[i] - 97) + k) %26) + 97);
^
caesar.c:58:36: error: use of undeclared identifier 'i'
printf("%c", plaintext[i]);
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
//Check that there is one command-line argument
if (argc != 2)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else printf ("Success!\n");
//Define the key
string key = argv[1];
//Check if input is a digit
for (int i = 0; i < strlen(argv[1]); i++)
{
if (!isdigit(argv[1][i]))
{
printf ("Usage: ./caesar key\n");
return 1;
}
else printf ("Success!\n%s\n", key);
}
//Get plain text from user
string plaintext = get_string("Plaintext: ");
//Define key
int k = atoi(key);
printf("ciphertext: ");
//Obtain ciphertext
for (i = 0; i < strlen(plaintext); i++)
{
if (isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] - 65) + k) %26) + 65);
}
else if (islower(plaintext[i]))
{
printf("%c", (((plaintext[i] - 97) + k) %26) + 97);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
"use of undeclared identifier 'i'" means that you have not declared the identifier i before using it - the compiler doesn't recognize the name.
In this case the code should be for (int i = 0; ...
Good to see you're doing cs50. You have missed a little, yet important thing. Since you have not declared the variable i outside any loop, thus, it is only available to that loop. So, when you are using it anywhere outside the loop, it's actually undeclared variable, and that's what is happening here.
So, you need to declare i in the last for loop too. I've attached the modified code.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
//Check that there is one command-line argument
if (argc != 2)
{
printf ("Usage: ./caesar key\n");
return 1;
}
else printf ("Success!\n");
//Define the key
string key = argv[1];
//Check if input is a digit
for (int i = 0; i < strlen(argv[1]); i++)
{
if (!isdigit(argv[1][i]))
{
printf ("Usage: ./caesar key\n");
return 1;
}
else printf ("Success!\n%s\n", key);
}
//Get plain text from user
string plaintext = get_string("Plaintext: ");
//Define key
int k = atoi(key);
printf("ciphertext: ");
//Obtain ciphertext
for (int i = 0; i < strlen(plaintext); i++) // declared i
{
if (isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] - 65) + k) %26) + 65);
}
else if (islower(plaintext[i]))
{
printf("%c", (((plaintext[i] - 97) + k) %26) + 97);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
I may be wrong, but could you not implement as a prototype inside main, so that it finds and refers to it later? Example:
int main(void) {
int i;
//all your code here
}
I don't know for sure that this would work, but typically when I get the error you have, doing this fixes it.
I'm taking the course Harvard CS50x and this is the caesar problem set.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Nope\n");
return 1;
}
int k = atoi(argv[1]);
if (k < 0)
{
printf("Nope\n");
return 1;
}
else
{
string code = GetString();
for (int i = 0, n = strlen(code); i < n; i++)
{
if islower(code[i])
printf("%c", (((code[i] + k) - 97) % 26) + 97);
else if isupper(code[i])
printf("%c", (((code[i] + k) - 65) % 26) + 65);
else
printf("%c", code[i]);
}
printf("\n");
return 0;
}
}
I don't understand what the problem is with this code but when I try to compile I get this:
To use the function atoi you need to include the header <stdlib.h>
#include <stdlib.h>
It seems the function GetString is not declared in the header <cs50.h>. Instead try to use the function get_string. For example
string code = get_string( "Enter a text: " );
These if statements
if islower(code[i])
printf("%c", (((code[i] + k) - 97) % 26) + 97);
else if isupper(code[i])
are incorrect. Expressions used in if statements shall be enclosed in pafrentheses. For example
if ( islower( ( unsigned char )code[i] ) )
printf("%c", (((code[i] + k) - 97) % 26) + 97);
else if ( isupper( ( unsigned char )code[i] ) )
Also it is a bad idea to use magic numbers like for example 97 or 65. Instead use 'a' and 'A'.
I have the following formula:
ciphertext[i] = ((plaintext[i] -'a' + k) % 26) + 'a';
I'm trying to solve for plaintext[i] given ciphertext[i].
I'm using a vigenere cipher. If I convert plain text to cipher text shouldn't there be a way to convert the cipher text back to plain text?
Here's the entire code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[]){
if (argc !=2){
printf("FATAL ERROR: All hail Caesar!");
return 1;
}
for(int i = 0, n=strlen(argv[1]);i < n;i++){
if(!isupper(argv[1][i]) && !islower(argv[1][i])){
printf("FATAL ERROR: All hail Mark Anthony!");
return 1;
}
}
int cipherlength = strlen(argv[1]),ciphercount=0;
char cipherkey[strlen(argv[1])];
for(int i = 0, n=strlen(argv[1]);i < n;i++){
cipherkey[i] = argv[1][i];
}
string plaintext = NULL;
int k;
do{
printf("plaintext: ");
plaintext = get_string();
printf("ciphertext: ");
}while(plaintext == NULL);
char ciphertext[strlen(plaintext)];
char xiphertext[strlen(plaintext)];
k = atoi(argv[1]);
for (int i = 0,n=strlen(plaintext);i < n; i++){
int index = ciphercount % cipherlength;
if(isupper(cipherkey[index])) k = cipherkey[index] - 'A';
else if(islower(cipherkey[index])) k = cipherkey[index] - 'a';
if ((int)plaintext[i] >= 65 && (int)plaintext[i] <= 90){
ciphertext[i] = ((plaintext[i] -'A' + k) % 26) + 'A';
xiphertext[i] = ((plaintext[i] -'A' - k) % 26) + 'A';
ciphercount++;
}else if ((int)plaintext[i] >= 97 && (int)plaintext[i] <= 122){
ciphertext[i] = ((plaintext[i] -'a' + k) % 26) + 'a';
xiphertext[i] = ((plaintext[i] -'a' - k) % 26) + 'a';
ciphercount++;
}else {
ciphertext[i] = plaintext[i];
xiphertext[i] = plaintext[i];
}
printf("%c %c %c /n",plaintext[i],ciphertext[i],xiphertext[i]);
}
printf("\n");
}
When I enter abcdefghijklmnopqrstuvwxyz using random as the key word I get:
rbpgsrxhvmyxdnbsedjthykjpz as ciphertext[]
but when I enter rbpgsrxhvmyxdnbsedjthykjpz again using random as the key word I get:
abcdefghijklSnUpWXYt[v]^_z as xiphertext[]
so it works up to the letter m
You wouldn't be able to solve it, because % 26 operation produces the same values for different plaintext[i]s. You can produce one possible plaintext of a great number of possibilities by computing
plaintext[i] = ((ciphertext[i]-'a'- k) % 26) + 'a';
Demo.
thanks, I needed to add the following:
if ((plaintext[i] - 'a' - k)%26 < 0)xiphertext[i] = ((plaintext[i] -'a' - k + 26) % 26) + 'a';
First of all there is no one that I can ask this kind of question so please pardon me
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[]) {
string key = argv[1];
int l = strlen(argv[1]);
if (argc != 2) {
return 0;
}
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha(key[i])) {
return 0;
}
key[i] = tolower(key[i]);
key[i] = key[i] - 97;
}
string txt = GetString();
for (int k = 0, p = strlen(txt); k < p; k++) {
if (isalpha(txt[k])) {
if (isupper(txt[k])) {
printf("%c", (((txt[k] - 65) + (key[k % l])) % 26 + 65));
}
if (islower(txt[k])) {
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
}
} else
if (!isalpha(txt[k])) {
printf("%c", txt[k]);
}
}
printf("\n");
return 0;
}
I can't quite get these 2 lines of code
key[i] = key[i] - 97;
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97));
Is there an easy explanation of why did we use the first and how the second one works?
The key used for the Vigenere cypher is supposed to be all letters. The first expression converts the string into an array of offsets, 0 for a, 1 for b, etc. 97 is the ASCII code for 'a'. It would be more readable to write:
for (int i = 0, n = strlen(key); i < n; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]);
key[i] = key[i] - 'a';
}
For the second expression, if the character txt[k] is a lower case letter, printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97)); computes and prints the transposed letter by adding the shift value (each character in key is used as a shift value one after the other, shifting by 0 for a, 1 for b etc.). Here are the steps:
The program computes the letter index txt[k] - 97, 97 being the ASCII code for 'a',
it then adds the shift value key[k % l], cycling the values in key in a circular fashion,
it takes the modulo 26 to get a letter index between 0 and 25.
it finally adds 97, the ASCII value of 'a' to convert the index back into a lowercase letter.
It would be less redundant and more readable to write it this way:
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % l]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % l]) % 26 + 'a';
}
putchar(c);
}
Also note that argv[1] should not be passed to strlen() before checking that enough arguments have been passed on the command line.
Here is a modified version of the program:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("missing key argument\n");
return 1;
}
string key = argv[1];
int klen = strlen(key);
if (klen == 0) {
printf("key cannot be empty\n");
return 1;
}
for (int i = 0; i < klen; i++) {
if (!isalpha((unsigned char)key[i])) {
printf("key '%s' must contain only letters\n", key);
return 1;
}
key[i] = tolower((unsigned char)key[i]) - 'a';
}
string txt = GetString();
for (int i = 0, j = 0; txt[i] != '\0'; i++) {
int c = (unsigned char)txt[i];
if (isupper(c)) {
c = (c - 'A' + key[j++ % klen]) % 26 + 'A';
} else
if (islower(c)) {
c = (c - 'a' + key[j++ % klen]) % 26 + 'a';
}
putchar(c);
}
putchar('\n');
return 0;
}
key[i] = key[i] - 97;
That line's use is to give key[i], which value represents the value of a caracter in ascii it's index in our alphabet. Then, 'a' will be given the value 0, 'b' the value 1 .... , and 'z' the value 25.
As for the second line,
printf("%c", (((txt[k] - 97) + (key[k % l])) % 26 + 97))
it prints the caracter which's ascii value is
(((txt[k] - 97) + (key[k % l])) % 26 + 97))
The substraction of 97 has the same purpose as explained above.
The % 26 is the modulus, ie the remainder of ((txt[k] - 97) + (key[k % l])) when divided per 26 (integer division). Then, 97 is added again to convert the order, or index of the result into a corresponding ascii value.
This page might give you some more insight about the character representation in C.
As for the meaning of k,i and l, I let you grasp the inner functionning of the cypher by yourself, but the whole encryption happens in the second line you wished an explanation for.
PS : The parts with '65' are just the same, but with uppercase letters, since 'A' value in ascii is 65.