#include <stdio.h>
void caesar (char cipher[], int shift);
int main ()
{
char cipher[200];
int shift;
printf("Enter text to be encrypted (in small letter): ");
gets(cipher);
printf("Number of shift to right? : ");
scanf("%d", &shift);
caesar (cipher, shift);
return 0;
}
void caesar (char cipher[], int shift)
{
int i = 0;
while (cipher[i] != '\0')
{
if ((cipher[i] + shift) >= 97 && (cipher[i] + shift) <= 122)
{
cipher[i] += (shift);
}
else
{
cipher[i] += (shift - 25);
}
i++;
}
printf("%s", cipher);
}
How can I ignore the operation of spaces? I mean, I want to add spaces in my converted/decrypted string. While I running this program it vanishes the spaces from the encrypted string. How can I do this? Suppose that, "this is a pen" is would become: "uijt jt b qfo" if right shift by 1.
You should check whether a character is a letter before shifting. Your code shifts everything and checks only whether a character is a valid letter afterwards to detect wrapping. (It also doesn't make the puctuation and spaces vanish, it converts them to non-printable characters with ASCII values below 32.)
You could also enforce correct wrapping by using the modulo operator:
void caesar(char cipher[], int shift)
{
char *p = cipher;
while (*p)
{
if ('a' <= *p && *p <= 'z') {
*p = 'a' + (*p - 'a' + shift) % 26;
}
p++;
}
}
If you want to auto-detect the shift, just use brute force for all 26 possible shifts and check for common expected substrings:
int autocaesar(char cipher[])
{
int shift = 0;
while (shift < 26) {
if (strstr(cipher, "the")) return shift;
if (strstr(cipher, "this")) return shift;
if (strstr(cipher, "that")) return shift;
caesar(cipher, 1);
shift++;
}
return -1;
}
The function strstr is in <string.h> and finds a substring in an string. This is done very crudely here: It is not enforced that "the" is a word of its own. Also, the check is case sensitive.
Note that the cipher is shifted by one character at a time, because the original string will be shifted continuously. If nothing os found, it will have wrapped over to contain the original string.
Related
I need to build a function that gets an input and capitalizes only the first letter, doesn't print numbers, capitalizes after a . for a new sentence, and capitalizes all words between a double quotation marks ".
This is what I got until now:
#include <stdio.h>
#define MAX 100
int main()
{
char str[MAX] = { 0 };
int i;
//input string
printf("Enter a string: ");
scanf("%[^\n]s", str); //read string with spaces
//capitalize first character of words
for (i = 0; str[i] != '\0'; i++)
{
//check first character is lowercase alphabet
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
if (str[i] == '.')//check dot
{
//if dot is found, check next character
++i;
//check next character is lowercase alphabet
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
}
else
{
//all other uppercase characters should be in lowercase
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32; //subtract 32 to make it small/lowercase
}
}
printf("Capitalize string is: %s\n", str);
return 0;
}
I cant find a way to remove all numbers from input and convert all lowercase to uppercase inside a " plus code for not printing numbers if user input them.
if I input
I am young. You are young. All of us are young.
"I think we need some help. Please" HELP. NO, NO NO,
I DO NOT
NEED HELP
WHATSOEVER.
"Today’s date is
15/2/2021"...
I am 18 years old, are you 20 years old? Maybe 30 years?
output:
I am young. You are young. All of us are young.
"I THINK WE NEED SOME HELP. PLEASE" help. No, no no,
i do not
need help
whatsoever.
"TODAY’S DATE IS
//"...
I am years old, are you years old? maybe years?
The C standard library provides a set of functions, in ctype.h, that will help you
Of particular interest, would be:
isdigit() - returns true if digit
isalpha() - returns true if alphabet character
isalnum() - returns true if alpha/numeric character
islower() - returns true if lower case character
isupper() - returns true if upper case character
tolower() - converts character to lower case
toupper() - converts character to upper case
So, for example, you could replace the test/modify with:
if ( islower( str[i] ) )
{
str[i] = toupper( str[i] );
}
Pedantically, islower() and toupper() return an unsigned int but that's a separate matter...
You can remove letters from a string if you keep two indices, one for reading and one for writing. The following loop will remove all digits from a string:
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (!isdigit(c)) str[j++] = c;
}
str[j] = '\0';
(I've used to character classification functions from <ctype.h> mentioned in Andrew' answer.)
This is safe, because j will always be smaller or equal to i. Don't forget to mark the end of the filtered string with the nullterminator, '\0'. You can combine this filtering with your already existing code for replacing characters.
In your code, you capitalize letters only if they are directly behind a full stop. That's usually not the case, there's a space between full stop and the next word. It's better to establish a context:
shift: capitalize the next letter (beginning or after full stop.)
lock: capitalize all letters (inside quotation marks.)
When you read a letter, decide whether to capitalize it or not depending of these two states.
Putting the filtering and the "shift context§ together:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "one. two. THREE. 4, 5, 6. \"seven\", eight!";
int shift = 1; // Capitalize next letter
int lock = 0; // Capitalize all letters
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (isdigit(c)) continue;
if (isalpha(c)) {
if (shift || lock) {
str[j++] = toupper(c);
shift = 0;
} else {
str[j++] = tolower(c);
}
} else {
if (c == '"') lock = !lock;
if (c == '.') shift = 1;
str[j++] = c;
}
}
str[j] = '\0';
puts(str);
printf("(length: %d)\n", j);
return 0;
}
In order to remove some characters, you should use 2 index variables: one for reading and one for writing back to the same array.
If you are allowed to use <ctype.h>, it is a much more portable and efficient way to test character types.
Also do not use scanf() with protection against buffer overflow. It is as bad as using gets(). Given the difficulty in specifying the maximum number of bytes to store into str, you should use fgets() instead of scanf().
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#define MAX 100
int main() {
char str[MAX];
int i, j;
unsigned char last, inquote;
//input string
printf("Enter a string: ");
if (!fgets(str, sizeof str, stdin)) { //read string with spaces
// empty file
return 1;
}
last = '.'; // force conversion of first character
inquote = 0;
//capitalize first character of words
for (i = j = 0; str[i] != '\0'; i++) {
unsigned char c = str[i];
//discard digits
if (isdigit(c)) {
continue;
}
//handle double quotes:
if (c == '"') {
inquote ^= 1;
}
//upper case letters after . and inside double quotes
if (last == '.' || inquote) {
str[j++] = toupper(c);
} else {
str[j++] = tolower(c);
}
if (!isspace(c) && c != '"') {
// ignore spaces and quotes for the dot rule
last = c;
}
}
str[j] = '\0'; // set the null terminator in case characters were removed
printf("Capitalized string is: %s", str);
return 0;
}
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
// two arguments
if (argc != 2)
{
printf("Give two arguments\n");
return 1;
}
printf("plaintext: ");
string plaintext = get_string();
printf("ciphertext: ");
string key = argv[1];
for (int i = 0, t = 0, n = strlen(plaintext); i < n; i++, t++)
{
// if it's no letter, then:
if (!isalpha(plaintext[i]) && plaintext[i] != ' ')
{
printf("False");
return 1;
}
int number = 0;
if (isalpha(plaintext[i]))
{
number += 1;
}
if (strlen(key) > number)
{
number = 0;
}
if (isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] - 65) + key[number]) % 26) + 65);
}
//if it is lowercase
else if (islower(plaintext[i]))
{
printf("%c", (((plaintext[i] - 97) + key[number]) % 26) + 97);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
So there's something missing with my code. When I do ./vigenere baz and then type as plaintext: Hello, world!, I get ciphertext: ByffiFalse. I should be getting iekmo, vprke! Also, when I type ./vigenere hello, and then type bye as the plaintext, I get ciphertext bye too while it should be icp. Can someone figure out what's missing or wrong with my code?
The biggest two problems with your code are the calculating the correct key differential value (you're not), and key advancement. I'll talk about them in reverse order.
Key advancement should start with the first key character, then advance one by one with each plain text being processed. When the key position reaches end-of-string, it is restarted. The most basic pseudo code for that would be
char *keyp = argv[1];
for (loop through plainttext)
{
if (*keyp == 0) // reached the terminator ?
keyp = argv[1]; // then reset to beginning.
//... process the current plain text character, using *keyp
//... as the next key character to use.
// advance key to next position (possibly conditionally)
++keyp;
}
But your code doesn't do that. Rather, it advances the key immediately, meaning you're starting with the second character onward.
int number = 0;
if (isalpha(plaintext[i]))
{
number += 1; // HERE. first pass will use key[1]. it should be key[0]
}
if (strlen(key) > number) // this is backward
{
number = 0;
}
Secondly, and probably more important, the whole point if a Vigenere cipher is effectively using a square shading table. See this link for a picture of that. The point of the algorithm you're coding is to act like that table exists using math. The offsets are the important part.When you do this calculation:
(((plaintext[i] - 65) + key[number]) % 26) + 65
which in reality should look like this:
(((plaintext[i] - 'A') + key[number]) % 26) + 'A'
consider what that key character addition is doing. Take your example:
key: baz
plaintext: Hello, World!
The first ciphertext character by your calculation will be:
((('H' - 'A') + 'a') % 26) + 'A'
Note: the 'a' is there because your first-pass is broken by one, remember?
That crunches down as follows
(((7) + 97) % 26) + 'A'
((105) % 26) + 'A'
(1 % 26) + 'A'
1 + 'A'
'B'
And that's exactly what you're getting. But its wrong. Its wrong because this is wrong:
(((plaintext[i] - 'A') + key[number]) % 26) + 'A'
^^^^^^^^^^^
That's the raw ascii value of the input character. What it should be is a calculated value between 1..26. In short, you're not adjusting your key input correctly.
Assumptive Solution
The following assumes the key will always be lower-case. It also fixes your first-skip logic, and decouples using cs50.h (which, frankly, I think does more harm than good). Finally it uses a `char* to track which key character is being used next. I leave the task of supporting mixed case input keys to you:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
// two arguments
if (argc != 2)
{
printf("Give two arguments\n");
return 1;
}
printf("plaintext: ");
char pt[256] = { 0 };
if (fgets(pt, sizeof pt, stdin))
{
// get the plaintext length
size_t ptlen = strlen(pt);
// remove trailing newline if present, and adjust ptlen
if (ptlen > 0 && pt[ptlen - 1] == '\n')
pt[--ptlen] = 0;
// the key we're using. intially at the start
char *key = argv[1];
for (size_t i = 0; i < ptlen; ++i)
{
// reset key if prior iteration landed on terminator
if (!*key)
key = argv[1];
if (isalpha((unsigned char)pt[i]))
{
if (isupper((unsigned char)pt[i]))
{
printf("%c", (((pt[i] - 'A') + (*key-'a')) % 26) + 'A');
++key;
}
//if it is lowercase
else if (islower((unsigned char)pt[i]))
{
printf("%c", (((pt[i] - 'a') + (*key-'a')) % 26) + 'a');
++key;
}
else
{
fputc(pt[i], stdout);
}
}
else
{
fputc(pt[i], stdout);
}
}
fputc('\n', stdout);
}
else
{
perror("Failed to read string");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Output from ./progname baz
plaintext: Hello, World!
Iekmo, Vprke!
All non-alpha characters (not spaces only) should be skipped without encoding. Do not print "False" and return on, for example ',' symbol in "Hello, world!" string. Also, you can encode string in-place. Thus, main loop may looks like
printf("plaintext: ");
string s = GetString();
if (s == NULL)
return 1;
for (int i = 0, len = strlen(s); i < len; ++i) {
if (isalpha(s[i])) {
/* encode s[i] in-place,
* all non-alpha characters left as is
*/
}
}
printf("ciphertext: %s\n", s);
Key characters should also be "shifted". For example, for uppercase letters
s[i] = ((s[i] - 'A') + (key[n] - 'A') % 26) + 'A';
if (++n >= keylen)
n = 0;
I suggest to normalize key before main loop, so that you will be able to use (key[n] - 'A') both for lower and upper characters from input string:
string key = argv[1];
strupper(k);
int keylen = strlen(key);
int n = 0;
Although I don't want provide full code because this is your courses, I think it would be better if you do it by yourself. But… some pieces:
strupper function:
void strupper(string s)
{
for (int i = 0, n = strlen(s); i < n; ++i)
s[i] = toupper(s[i]);
}
Compact main loop:
for (int i = 0, n = strlen(s); i < n; ++i) {
if (isalpha(s[i])) {
char ref = isupper(s[i]) ? 'A' : 'a';
int shift = k[j] - 'A';
s[i] = ref + (s[i] - ref + shift) % 26;
if (++j >= klen) j = 0;
}
}
p.s. You use the same key character for all input characters because of int number = 0; defined and zeroed inside for loop.
I've searched the web quite long for a simple caesar chiper/encryption algorithm in C language.
I found one but is wasn't perfect so I already changed the code.
Still having problems, because a friend said that the programm should be able to handle big key's, too.
For example text "Hello World" with a Key: 50... And if I do that I get the following: (Console output)
This tiny application encodes plain text to the Caesar Encryption
Type in some text to decode: Hello World
Type in the key/shifting of the letters:
50
`}ääç oçèä|
Which is wrong.... And maybe the problem is the char/array - I don't know...So I would be happy if you could help me with that :)
Here is the source code(with some comments):
#include <stdio.h>
#include <conio.h>
#include <wchar.h>
int main()
{
unsigned char array[100], shifting; //creating 2 arrays for the encryption
//I changed it to unsigned char because otherwise Z with key 6/7 dosen't work
int z; //This is our key
printf("This tiny application encodes plain text to the Caesar Encryption\n");
printf("Type in some text to decode :");
fgets(array, 100, stdin); //because gets() is bad I'am using fgets()
printf("Type in the key/shifting of the letters:\n");
scanf("%d", &z);
for (int i = 0; array[i] != '\0'; i++)
{
shifting = array[i]; //overgive values from array to shifting
if (shifting >= 'a' && shifting <= 'z') { //check the containing lowercase letters
shifting = shifting + z;
if (shifting > 'z') {
shifting = shifting - 'z' + 'a' - 1; // if go outside the ascii alphabeth this will be done
}
array[i] = shifting;
}
else if (shifting >= 'A' && shifting <= 'Z') { //the same for uppercase letters
shifting = shifting + z;
if (shifting > 'Z') {
shifting = shifting - 'Z' + 'A' - 1;
}
array[i] = shifting;
}
}
printf("%s\n", array);
return 0;
}
The source of your problem is here:
if (shifting > 'z') {
shifting = shifting - 'z' + 'a' - 1; // if go outside the ascii alphabeth this will be done
}
What's the length of the English alphabet? It's 26.
If you give z greater than 26, a single decrement by the alphabet length does not suffice. You should either make sure z does not exceed the length of alphabet, of repeat decrementing until the result fits the alphabet range.
Solution 1:
int asciiAlphabetLength = 'z' - 'a' + 1;
printf("Type in the key/shifting of the letters:\n");
scanf("%d", &z);
z %= asciiAlphabetLength;
Solution 2:
shifting += z;
while (shifting > 'z') {
shifting -= asciiAlphabetLength; // while outside the ascii alphabeth reduce
}
Hi I am stuck while trying to cipher and decipher string using pointer. i need to shift the alphabet by +1.
example: Hello will be Ifmmp. And i also need to eliminate other characters such as $%^^. so when the string is 'z' +1 would give me 'a'
Here is my code.
char *cipher(char *s) {
int i =0;
int shift = 1;
while(*(s+i)!= '\0') {
if (*(s+i)) {
*(s+i)+= (shift);
}
i++;
}
}
char *decipher(char *s) {
int i =0;
int shift = -1;
while(*(s+i)!= '\0') {
if (*(s+i) +shift) {
*(s+i)+= (shift);
}
i++;
}
}
my current output is:
To cipher: abcxyz -> bcdyz{
To decipher: bcdyz{ -> abcxyz
Thanks
First of all, change the while to For-Loop, if you increase itearator at the for loop and its your condition the best readable code is For-Loop
Second, you need to add condtion-
If the letter is 'z' assign 'a'
else do the same thing
Third if you want to avoide another letters you need to add condition:
if((*s+i)<'a' || (*s+i)>'z'){
do what you want
} else {
avoide
} /// it will work if you use character encoding that the alphebet is by order and continuous
I add the code with change at chipher function, you will add the same to the next function
char *cipher(char *s){
int shift = 1;
for(int i=0; *(s+i)!= '\0'; i++){
if (*(s+i)){
//i add that condtion for 'z' you need to add the same condition to the next function
if(*(s+i)=='z'){
*(s+i)='a';
}else{
*(s+i)+= (shift);
}
}
}
}
char *decipher(char *s){
int shift = -1;
for(int i=0 ;*(s+i)!= '\0'; i++){
if (*(s+i) +shift){
*(s+i)+= (shift);
}
}
}
i need to shift the alphabet by +1
Shift only characters a-z. So code must detect those
char *shift_AZ(char *s, int shift) {
// Bring shift into 0-25 range
shift %= 26;
if (shift < 0) shift += 26;
// loop until at end of string
// while(*(s+i)!= '\0') {
while(*s) {
// Assuming ASCII, detect select characters
if ((*s >= 'a') && (*s <= 'z')) {
// Do the shift, wrap around via %26
*s = (*s - 'a' + shift)%26 + 'a';
}
s++; // next chraracter
}
char *cipher(char *s) {
return shift_AZ(s, 1);
}
char *decipher(char *s) {
return shift_AZ(s, -1);
}
Is there a quick way to retrieve given character's position in the english alphabet in C?
Something like:
int position = get_position('g');
int position = 'g' - 'a' + 1;
In C, char values are convertible to int values and take on their ASCII values. In this case, 'a' is the same as 97 and 'g' is 103. Since the alphabet is contiguous within the ASCII character set, subtracting 'a' from your value gives its relative position. Add 1 if you consider 'a' to be the first (instead of zeroth) position.
You should also probably take into account upper/lower case. In my expereince, counting from 1, is often dangerous because it can lead to off-by-one bugs. As a rule of thumb I always convert to a 1-based index only when interacting with the user, and use 0-based counting internally, to avoid confusion.
int GetPosition(char c)
{
if (c >= 'a' && c <= 'z') {
return c - 'a';
}
else if (c >= 'A' && c <= 'Z') {
return c - 'A';
}
else {
// Indicate that it isn't a letter.
return -1;
}
}
This will work with EBCDIC and is case-insensitive:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int getpos (char c)
{
int pos;
const char * alphabet = "abcdefghijklmnopqrstuvwxyz";
const char * found;
c = tolower ((unsigned char)c);
found = strchr (alphabet, c);
pos = found - alphabet;
if (!found)
pos = 0;
else if (pos == 26)
pos = 0;
else
pos++;
return pos;
}
int main ()
{
char tests[] = {'A', '%', 'a', 'z', 'M', 0};
char * c;
for (c = tests; *c; c++) {
printf ("%d\n", *c - 'a' + 1);
printf ("%d\n", getpos (*c));
}
return 0;
}
See http://codepad.org/5u5uO5ZR if you want to run it.
Take the input of the alphabet:
scanf("%c",ch);
Just subtract 96 from the ascii value of the character. This can be done within the printf argument:
printf("%d",ch-96);