Trying to do a Caesar cipher.
enum alfabeto{
A=0,B,C,D,E,F,G,H,I,L,M,N,O,P,Q,R,S,T,U,V,Z // 21
};
void cifra(char *string, int k){
enum alfabeto letter; // initialize the enum letter
size_t i = 0; // initialize counter
while (*(string+i)!='\0'){ // while string is not ended
letter = *(string+i); // attempt to "link" the enum letter to the equivalent (already uppercased) char
printf("%d", letter);
letter = (letter+k) % 21; // then it increases of a factor k and if it goes out of 21, it should take the right value
printf(" %d\n", letter);
++i;
}
}
Output:
$ ./"cesare"
write the text:
>TEST
choose the factor k:
>2
84 8
69 14
83 7
84 8
The values are wrong... maybe because I can't "link" a enum value to a char... How could I do this?c
letter = *(string+i); // attempt to "link" the enum letter to the equivalent (already uppercased) char
Should be:
letter = *(string+i) - 'A'; // attempt to "link" the enum letter to the equivalent (already uppercased) char
That way, 'A' will map to zero, as required.
// A B C D E F G H I J K L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
const int offsetTable[] = {0,1,2,3,4,5,6,7,8,-1,-1,9,10,11,12,13,14,15,16,17,18,19,-1,-1,-1,20};
const char charLookupTable[] = "ABCDEFGHILMNOPQRSTUVZ";
// Should probably use a struct for the above to prevent size mis-matches
const int offsetTableSize = 21;
void cifra(char *str, int k){
char letter;
int newLetterOffset;
printf("%s\n", str); // Show initial string.
while (letter = *str++){ // while string is not ended
const int oldLetterOffset = offsetTable[letter - 'A']; // Get the old letter's offset.
if(letter <= 'A' || letter >= 'Z' || oldLetterOffset == -1)
{
printf("\nBad character %c found - ending string processing\n", letter);
return;
}
newLetterOffset = (oldLetterOffset + k) % offsetTableSize; // Get the letter's position, add the global offset, and wrap to table size.
printf("%c", charLookupTable[newLetterOffset]); // Use that offset to read the character's value from the shortened alphabet.
}
printf("\n\n");
}
int main()
{
cifra("HELLO", 0);
cifra("HELLO", 1);
cifra("HELLo", 1);
cifra("YELLO", 1);
return 0;
}
Notice I needed 2 tables to do the work as we had to go into and out of your shortened character set. Typically, we would use a struct to hold those 2 arrays, but I kept it simple for this example. Also, the arrays do not need to be global, but I placed them there also to keep things simpler.
Notice I also changed your printf() values to use characters and strings to make it easier to read.
Finally, I added some error checking as you cannot trust a user to give you a good string. Many a security flaw or random crash has resulted from that.
Related
I'm trying to create a program in C that prints the letters from alphabet that are not in gussed_character. All unused letters are saved in available_character.
Code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
void letters(const char gussed_character[], char available_character[]){
char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
int gussed_character_lenght = strlen(gussed_character);
int alphabet_lenght = strlen(alphabet);
int counter = 0;
for(int i = 0; i<alphabet_lenght; i++){
counter = 0;
for(int j = 0; j<gussed_character_lenght; j++){
if(alphabet[i] != gussed_character[j]){
counter++;
}
if(counter == gussed_character_lenght){
available_character[i] = alphabet[i];
}
}
}
printf("%s", available_character);
}
int main(){
char result[30];
letters("arpstxgoieyu", result);
}
Example from code:
letters("arpstxgoieyu", result);
This letters are used and prgram should print this letters:
bcdfhjklmnqvwz
But my program print this:
%bcd#fPhajklmn q
Your bug is inside this snippet:
...
if(counter == gussed_character_lenght){
available_character[i] = alphabet[i];
}
...
When you determine that indeed, gussed_character contains alphabet[i], you try to add that character to the available_character array. However, you put alphabet[i] at position i in available_character. This means that the character inside alphabet at position i is copied to that same position in available_character. Notice that the output string contains the not used characters in the same position as in alphabet:
"a b c d e f g h i j k l m n o p q r s t u v w x y z" // alpabet
| | | | | | | | | |
V V V V V V V V V V
"% b c d # f P h a j k l m n q" // output string
Then the skipped characters are undefined, since you don't write anything to there (meaning it will take the value of whatever happens to be at that memory location at that time, making it random).
Instead of positioning the available character at position i, place it at the end of available_character. You can use a variable to keep track of the end of the available_character string at position alphabet[i] there.
I took your requirements and also implemented it myself, since I see some points where the code could also be improved (besides the bug):
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
void letters(const char* used_characters, char* available_characters){
const char* alphabet = "abcdefghijklmnopqrstuvwxyz";
unsigned int available_character_index = 0;
for (const char* alphabet_letter = alphabet; *alphabet_letter != '\0'; alphabet_letter++) {
bool character_is_used = false;
for (const char* used_character = used_characters; *used_character != '\0'; used_character++) {
if (*used_character == *alphabet_letter) {
character_is_used = true;
break;
}
}
if (!character_is_used) {
available_characters[available_character_index++] = *alphabet_letter;
}
}
available_characters[available_character_index] = '\0';
printf("%s", available_characters);
}
int main(){
char result[30];
letters("arpstxgoieyu", result);
return 0;
}
Main takeaways are:
Obvious one is the bug fix. I now use a variable available_character_index to keep track of the end of the available_characters string and position any available characters there, also taking care to update available_character_index whenever I add a character.
You forgot to terminate the available_characters string. This could lead to the terminal going haywire when you print the available_characters string.
I think it's conceptually easier to iterate through a string by having a char pointer that starts at the beginning of the string and works on the array till it hits \0 (the null character). So, I changed the for-loops to work with them instead of an integer index.
I find your use of the counter variable a bit confusing. From what I gather, you're incrementing it only when alphabet[i] != gussed_character[j], so at the end if gussed_characters contains some character in aphabet, it should no longer be equal to strlen(gussed_characters). That condition does work, but it's quite confusing. In this case, a boolean is more appropriate (simple == better).
in Caesar (CS50) it says that i need to convert an ASCII character to alphabetical index in one of the steps. what does that mean? i saw a video that said that i "need to find the relationship between a number's ASCII value and its actual index in the alphabet", but i haven't really understood how I might implement this* and *what exactly is the relationship.
please elaborate in your answer because I'm new to this.
string plaintext = get_string("plaintext;");
As you may or may not know ASCII characters are encoded as 8-bit values and character constants, in reallity, have int type in C.
Using this knowledge you can perform character arithmetic as if they are regular numbers, take the following example:
printf("%d\n", 'a');
This prints 'a''s int value which is 97.
Now this:
printf("%d\n", 'g' - 'a');
This will print 6 which is the result of 103 - 97.
Now your string:
const char* plaintext = "plaintext";
for(size_t i = 0; i < strlen(plaintext); i++){
printf("%c - %d\n",plaintext[i], plaintext[i] - 'a' + 1);
}
The result:
p - 16
l - 12
a - 1
i - 9
n - 14
t - 20
e - 5
x - 24
t - 20
As you can see the printed results are the indexes of the letters in the alphabet 1...26, I added 1 to the result because, as you know, in C indexing starts at 0 and you would have 0...25.
So the bottom line is that you can use this character arithmetic to find the indexes of characters, this also aplies to caps, but you can't mix both.
Note that there are other character encodings that do not allow for this kind of arithmetic because the alphabetic characters are not in sequencial order, like, for example, EBCDIC.
It means that a single char variable is nothing but an integer containing an ASCII code, such as 65 for 'A'. It might be more convenient for an algorithm to work with the interval 0 to 25 than 65 to 90.
Generally, if you know that a char is an upper-case letter, you can do a naive conversion to alphabetical index by subtracting the letter 'A' from it. Naive, because strictly speaking the letters in the symbol (ASCII) table need not be located adjacently. For a beginner-level program, it should be ok though:
char str[] = "ABC";
for(int i=0; i<3; i++)
printf("%d ", str[i] - 'A'); // prints 0 1 2
Wheras a 100% portable converter function might look something like this:
int ascii_to_int (char ch)
{
const char LOOKUP_TABLE [128] =
{
['A'] = 0,
['B'] = 1,
...
};
return LOOKUP_TABLE[ch];
}
Here you have an example. It is portable as it does not depend if the char encoding.
const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";
int getIndex(const char *alphabet, int c)
{
int result = -1;
const char *res;
res = strchr(alphabet, c);
if(res)
{
result = res - alphabet;
}
return result;
}
int main(void)
{
char *str = "Hello World!!!";
while(*str)
{
printf("Index of %c is %d\n", *str, getIndex(alphabet, *str));
str++;
}
}
https://godbolt.org/z/rw2PK9
Disclaimer: Whatever is below, it's related to Affine Cipher. For whomever doesn't know it, it's a encrypting method that uses a mathematical function Ax+B to shift each letter in a given plaintext according to the letter's index in the alphabet.
I've written a code that encrypts and decrypts a given plaintext or ciphered text using Affine Cipher. It consists of these three functions:
char *encryption(char Plaintext[MAXSIZE], int A, int B);
int modularinverse(int number, int modulo);
char *decryption(char Ciphered[MAXSIZE], int A, int B, int inverse);
The part that concerns me sites in the decryption function. Around three or four letters are miss-calculated.
Let's consider the following plaintext: "a b c d e"
Using the encryption function:
char *encryption(char Plaintext[MAXSIZE], int A, int B) {
static char Ciphered[MAXSIZE];
int i;
int y;
int index;
for (i = 0; i < strlen(Plaintext) - 1; i++) {
if (Plaintext[i] == ' ') {
Ciphered[i] = ' ';
} else {
index = (int)Plaintext[i] - 'a';
y = (A * index + B) % 26;
Ciphered[i] = (char)y + 97;
}
}
return Ciphered;
}
it turns the plaintext into: "f m t a h". Which is correct.
Decrypting the plaintext should obviously give: "a b c d e". But instead, it gives: "a b c J e".
char *decryption(char Ciphered[MAXSIZE], int A, int B, int inverse) {
static char NewPlaintext[MAXSIZE];
int i;
unsigned int x;
int y;
int index;
for (i = 0; i < strlen(Ciphered); i++) {
if (Ciphered[i] == ' ') {
NewPlaintext[i] = ' ';
} else {
index = (int)Ciphered[i] - 'a';
x = inverse * (index - B) % 26;
NewPlaintext[i] = (char)x + 97;
}
}
return NewPlaintext;
}
The letter d is miss-calculated for a reason I don't know. Printing the values of variables index, inverse, B and x for each one of the characters f m t a h will respectively return this:
5 15 5 0
12 15 5 1
19 15 5 2
0 15 5 -23
7 15 5 4
First column represents indexes of the letters f m t a h.
Second column represents the inverse of A=7, which is 15. (Totally harmful, you may ignore it).
Third column represents B which is a constant for now (You may ignore it).
Fourth column represents x which is the result of inverse*(index-B) % 26. Adding 97 (ASCII number of 'a') to each of number in this column will result to the ASCII number of each letter.
i.e 0+97 = 97 which is 'a'. By consequence Decryption(f)=a.
But if you can notice. the result of x for the letter 'a' is -23. -23+97=74 which is J in ASCII. It should rather be 100 as it's the ASCII number for d. Therefore the result of x should rather be 3, not -23.
The reason behind this miss-calculation is buzzing me and I haven't figured out what's causing it.
Your code has few issues which are causing this strange behavior;
Don't use int type if you are dealing with character. Use char
In decryption() handle if the value of x is negative.
you can modify your decryption() like this.
char *decryption(char Ciphered[MAXSIZE],int A, int B, int inverse)
{
static char NewPlaintext[MAXSIZE];
char x;
char index;
for(int i=0;i<strlen(Ciphered);i++)
{
if(Ciphered[i]==' ')
{
NewPlaintext[i]=' ';
}
else
{
index=(int)Ciphered[i] - 'a';
x=inverse*(index-B) % 26;
if(x < 0)
{
// add 26 to take care of negative values; since you are using %
x += 26;
}
NewPlaintext[i]=(char)x+97;
}
}
return NewPlaintext;
}
I tested it few entries and it works fine.
Hope this helps.
Your code has several problems:
you stop before the end of the string: i<strlen(Plaintext)-1
you do not null terminate the destination strings.
your return a pointer to static storage: only one string can be encrypted/decyphered at a time.
depending on the values, you may take the modulo of negative numbers, which will be negative too. Use this instead: x = ((inverse * (index - B) % 26) + 26) % 26;
I have written a function below to take a char array and manipulate its values (namely, convert the char to an int if it is a number). However, I have a question with how the char array is managed. When I look at input[i], it is the correct value (the value that was placed in the array. However, &input[i] gives a capital letter, and I don't know why it does that. For example, if I enter "11" and trace the variables, I might get the following result:
input[0] is 1
&input[0] is D
input[1] is 1
&input[1] is E
On to my code, if I try to use input[i], I get the error of "passing argument makes pointer from integer without cast". If I use &input[i], the code compiles but I get the wrong result. What's going on with this, and how do I access the value I'm trying to get?
Below is my code:
void myFunction(char *input) {
Queue* numberQueue = queue_new();
Queue* opQueue = queue_new();
int i = 0;
int j;
for (j = 0; j < strlen(input); j++) {
printf("input[%d] is %c\n", i, input[i]);
printf("&input[%d] is %c\n", i, &input[i]);
int number = (int)input[i];
/* queue_push_tail(queue, data) */
queue_push_tail(numQueue, number); /* ERROR */
/* rest of code omitted */
i++;
}
}
If I understand that you want to push each digit in the input character string into queue_push_tail, as an integer value then you want your loop to do something like this:
for (j = 0; j < strlen(input); j++) {
if ( input[j] >= '0' && input[j] <= '9')
{
number = input[j] - '0';
/* queue_push_tail(queue, data) */
queue_push_tail(numQueue, number); /* ERROR - FIXED*/
/* rest of code omitted */
}
}
Recall, ASCII characters are themselves unsigned integers. You simply need to adjust the value for each character by subtracting the value of ASCII '0'. If you need to collect all numbers from the string into a single number (e.g. ac7f9gh3 => 793) then simply store the values unadjusted in a temp string, and then call atoi (temp).
I am like 3 weeks new at writing c code, so I am a newbie just trying some examples from a Harvard course video hosted online. I am trying to write some code that will encrypt a file based on the keyword.
The point is each letter of the alphabet will be assigned a numerical value from 0 to 25, so 'A' and 'a' will be 0, and likewise 'z' and 'Z' will be 25. If the keyword is 'abc' for example, I need to be able to convert it to its numerical form which is '012'. The approach I am trying to take (having learned nothing yet about many c functions) is to assign the alphabet list in an array. I think in the lecture he hinted at a multidimensional array but not sure how to implement that. The problem is, if the alphabet is stored as an array then the letters will be the actual values of the array and I'd need to know how to search an array based on the value, which I don't know how to do (so far I've just been returning values based on the index). I'd like some pseudo code help so I can figure this out. Thanks
In C, a char is an 8-bit integer, so, assuming your letters are in order, you can actually use the char value to get the index by using the first letter (a) as an offset:
char offset = 'a';
char value = 'b';
int index = value - offset; /* index = 1 */
This is hard to answer, not knowing what you've learned so far, but here's a hint to what I would do: the chars representing letters are bytes representing their ASCII values, and occur sequentially, from a to z and A to Z though they don't start at zero. You can cast them to ints and get the ascii values out.
Here's the pseudo code for how I'd write it:
Cast the character to a number
IF it's between the ascii values of A and Z, subtract it from A
ELSE Subtract it from the ASCII value of a or A
Output the result.
For what it's worth, I don't see an obvious solution to the problem that involves multidimensional arrays.
char '0' is the value 48
char 'A' is the value 65
char 'a' is the value 97
You said you want to learn how to search in the array:
char foo[26]; //your character array
...
...
//here is initialization of the array
for(int biz=0;biz<26;biz++)
{
foo[biz]=65+biz; // capital alphabet
}
...
...
//here is searching 1 by 1 iteration(low-yield)
char baz=67; //means we will find 'C'
for(int bar=0;bar<26;bar++)
{
if(foo[bar]==baz) {printf("we found C at the index: %i ",bar);break;}
}
//since this is a soted-array, you can use more-yield search algortihms.
Binary search algortihm(you may use on later chapters):
http://en.wikipedia.org/wiki/Binary_search_algorithm
The use of a multidimensional array is to store both the lower case and upper case alphabets in an array so that they can be mapped. An efficient way is using their ASCII code, but since you are a beginner, I guess this example will introduce you to handle for loops and multidimensional arrays, which I think is the plan of the instructor as well.
Let us first set up the array for the alphabets. We will have two rows with 26 alphabets in each row:
alphabetsEnglish[26][2] = {{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'},
{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}};
Now we can map elements of both cases.
int main()
{
int c,i,j;
char word[10];
printf("Enter a word:");
scanf("%s",word);
c=strlen(word);
printf("Your word has %d letters ", c);
for (i = 0; i < c; i++) //loop for the length of your word
{
for (j = 0; j <= 25; j++) //second loop to go through your alphabet list
{
if (word[i] == alphabetsEnglish[0][j] || word[i] == alphabetsEnglish[1][j]) //check for both cases of your alphabet
{
printf("Your alphabet %c translates to %d: ", word[i], j);
}
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *conv(char* str){
static const char* table = "abcdefghijklmnopqrstuvwxyz";
int size, *ret, *p;
if(NULL==str || *str == '\0') return NULL;
size = strlen(str);
ret=p=(int*)malloc(size*sizeof(int));
while(*str){
char *pos;
pos=strchr(table, tolower(*str++));
*p++ = pos == NULL ? -1 : pos - table;
}
return ret;
}
int main(void){
char *word = "abc";
int i, size = strlen(word), *result;
result = conv(word);
for(i=0;i<size;++i){
printf("%d ", result[i]);//0 1 2
}
free(result);
return 0;
}