I recently took an interest in encryption, then I came across this piece code, but I don't understand the meaning of the second "IF" statement.
#include<stdio.h>
int main()
{
char message[100], ch;
int i, key;
printf("Enter a message to encrypt: ");
gets(message);
printf("Enter key: ");
scanf("%d", &key);
for (i = 0; message[i] != '\0'; ++i) {
ch = message[i];
if (ch >= 'A' && ch <= 'Z') {
ch = ch + key;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
message[i] = ch;
}
}
printf("Encrypted message: %s", message);
return 0;
}
One of the fundamental things to understand for that code to make sense is that char represents both a character and a number at the same time.
That's because to a C program (and effectively all programs on all computers) characters are just numbers anyway.
When you say 'A' you could equivalently use 65 or 0x41 *.
You already make use of that property by adding key to ch to "shift up" the characters (i.e. if key is 1 then 'A' becomes 'B').
However, if you add 1 to 'Z' then the result is no longer an upper-case character (it will be [ in ASCII and compatible encodings).
The second if is responsible to wrap those results back down to 'A' by first subtracting 'Z' (which means the value is now "how many steps above Z were we) and then adding 'A' - 1 (which means that 1 step above Z will result in 'A').
* Assuming this is using ASCII or a compatible encoding, which will hold true on most modern operating systems
Let's rewrite the calculation that is performed if the expression of the if statement is true:
ch = ch - 'Z' + 'A' - 1;
to
ch = ch - ('Z' - 'A' + 1);
This should already make more sense. Now the part between parentheses of course never changes value, so lets introduce a constant:
#define APHABET_SIZE = ('Z' - 'A' + 1)
...
ch = ch - ALPHABET_SIZE;
Ah, so if the value of the character is higher than Z, the last letter of the alphabet, then subtract the alphabet size.
This is the kind of programming that you should not perform yourself; it performs all the functions at once instead of breaking them down, and trades briefness for readability.
The Caesar cipher performs modular addition to shift the characters by index. You should instead have a function int charToIndex(char), then perform the modular addition (or subtraction for decryption) using the % modulo operator and ALPHABET_SIZE, and then have a function char indexToChar(int) to convert it back.
Related
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
}
Hey guys I'm starting to learn C, and I was asked to code a program specifically, a caesar cipher (so, the idea is to replace any letter in the message by a letter three positions down the alphabet.)
My implementation should read a line of text and then either performs encryption or decryption, depending on the first character read. If the first character is $, then I'm supposed to encrypt the rest of the line, and precede the output by the character ?. If the first character is ?, then I'm supposed to decrypt the rest of the line, and precede my output by the character $.
So for example: ?Wr eh, ru qrw wr eh
the output should be: $To be, or not to be
and vice versa.
So this is my code so far:
#include <stdio.h>
int main(void){
char code[100], ch;
int i;
scanf("%s", &code);
if(code[0] == '$'){
for(i = 0; code[i] != '\0'; ++i){
ch = code[i];
if(ch >= 'a' && ch <= 'z'){
ch = ch + 3;
if(ch > 'z'){
ch = ch - 'z' + 'a' - 1;
}
code[i] = ch;
}
else if(ch >= 'A' && ch <= 'Z'){
ch = ch + 3;
if(ch > 'Z'){
ch = ch - 'Z' + 'A' - 1;
}
code[i] = ch;
}
}
printf("?%s\n", code);
return 0;
}
}
But the problem is, it returns the first character and stops whenever there are space.
Like for example I enter: $To be it outputs to: ?$To
Can someone please help me figure out what I'm doing wrong?
Here's a sample using getchar() to get you started:
#include <stdio.h>
int main() {
int ch; // Either EOF or one of the chars in 0-255
while ((ch = getchar()) != EOF) {
if ('A' <= ch && ch <= 'Z') {
int offset = ch - 'A';
printf("%c", 'a' + offset);
} else {
printf("%c", ch);
}
}
}
Now, this code isn't perfect in a lot of ways, but it does demonstrate how to use getchar(). Every time getchar() is called, it fetches the next char from standard input and returns it as an int. That's because when the input is over, it returns the special value EOF, which is outside the range of char.
The while loop here is a common idiom. When execution reaches the loop, it first has to call getchar(), whose result is stored into ch. Then it checks whether ch is EOF. If not, then the loop processes the character that was read. Otherwise, it exits and the program ends.
The body of the loop prints every character it sees, while converting the uppercase letters to lowercase.
#include <stdio.h>
int main()
{
int rotation, i=0;
char str[80]={0};
printf("Enter Text: ");
scanf("%[^\n]", str);
printf("\"");
printf("Enter Rotation: ");
scanf("%i", &rotation);
while(str[i])
{
if (str[i] >= 'a' && str[i] <= 'z')
printf("%c\n", 'a' + (str[i] - 'a' + rotation)%26);
else
printf("%c\n", str[i]);
i++;
}
return 0;
}
Have a hard time understanding this line of code (printf("%c\n", 'a' + (str[i] - 'a' + rotation)%26); )
Can anyone just write a brief explanation quickly it would help me
The program is taking the user's input text and on a per character basis rotating it through the alphabet based on the number entered. It works because of the ASCII table.
The line in question takes the character a user entered, offsets it by 'a' (which equals 91 in ASCII), adds in the rotation factor then performs modulo 26 on the result (how many characters are there in the alphabet again?) to make sure the result is still a lowercase character.
I bet you could find a good way to break this program :)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to create my personal atoi function but i doesn't work properly. I don't know why.
void ft_putchar(char c)
{
write(1, &c, 1);
}
int ft_atoi(const char *str)
{
int i;
i = 0;
while (str[i] == 9 || str[i] == 32 || str[i] == 43 || str[i] == 45)
i++;
while (str[i] > 48 && str[i] < 57)
{
ft_putchar(str[i]);
i++;
}
return (0);
}
int main(void)
{
printf("%d", atoi(" 2794ffafsaasf"));
printf("\n%d",ft_atoi(" 2794fsffsf"));
return(0);
}
I kinda works but it doesn't. It gives me a weird result where it even ignores '\n'.
The result it gives me is this.
272794 and a new line.
with only my function it gives me only the number 27.
EDIT:
I have created a new program. But it still doesn't work. It simply can't see digits.
int ft_atoi(const char *str)
{
int i;
int n;
i = 0;
while (str[i] == '\t' || str[i] == ' ' || str[i] == '+' || str[i] == '-')
++i;
n = i;
while (str[n] >= '0' && str[n] <= '9')
{
++n;
}
return(str[n]);
}
Your test for digits has the bounds set wrong. You're testing str[i] > 48 && str[i] < 57, but 48 is the ordinal for the 0 character, and 57 is the ordinal for 9. This means you only consider 1 through 8 inclusive to be numeric digits, and you stop parsing 2794fsffsf at the 9, not at the first f.
Changing the test to str[i] >= 48 && str[i] <= 57 would fix the bounds issue, but would still be less than self-documenting. To make it obvious what you're doing to people who don't have the ASCII tables memorized, you could do:
while ('0' <= str[i] && str[i] <= '9')
or possibly slightly slower but even more obviously with ctype.h:
while (isdigit(str[i]))
You could similarly replace the many non-obvious tests for whitespace ordinal values with isspace(str[i]).
First thing is to ignore leading whitespace. You can do that with i as you're doing, but it's easier to do it by shifting the start of the string forward. I'm guessing that you're reimplementing the standard C library as an exercise. I'm not, so I'm going to make use of the ctype.h functions. Adjust as you like, the basic code remains the same. You should probably write your own ft_isspace and ft_isdigit rather than hard coding the logic.
/* Move str to point at the first non-space character */
while( isspace(str[0]) ) {
str++;
}
Now there's no need for an i to hold your place, you can just work with str[0] and it will be the first non-whitespace character.
Next we need to find and add up our digits. Again, I'll use isdigit. Follow the advice in ShadowRanger's answer if you can't use that function.
The technique is to convert each character to a digit and add it to the total. Since we're reading a number left to right, each new digit multiplies the existing sum by 10. For example, if we had 1234 it would be... 1 then 10 + 2 then 120 + 3 then 1230 + 4.
int num = 0;
while( isdigit(str[0]) ) {
int digit = str[0] - '0';
num *= 10;
num += digit;
str++;
}
Once again I'm manipulating the pointer rather than using an index. This is just to save an integer, and to avoid mixing up two string iteration techniques in a single function.
And, finally, don't forget to return the number!
return num;
What about negative numbers? We need to look for a - before we check for digits, if it's there flip the sign. We also need to handle a + and ignore it.
/* Assume it's positive. */
short sign = 1;
/* Check for a sign. */
switch( str[0] ) {
case '-':
sign = -1;
str++;
break;
case '+':
str++;
break;
}
And then multiply by the sign to flip the result.
return sign * num;
Your code only writes out the numbers - and not all, as pointed out before me (because it excludes '0' and '9' and they should be included!) - to the file identified by 1 (what is maybe the standard output, I don't remember exactly...), and returns 0 as the parameter of the printf. It seems to me a little strange, you only had 27 printed out with your function, but it might be environment(?) specific. (I have not tested it, so it possibly not exactly work as I suppose...)
I've made my version of atoi, hoping I can show where to start / the way how you should do yours:
int nvi9_atoi(const char *s) {
int n = 0, valid = 0, prev = 0;
while(1) { // infinite loop
if (*s == '\0') break; // if it is the end of the string, finish further processing
if (*s >= '0' && *s <= '9') { // check whether the current character is an ascii number
n *= 10; // "move" all previous digits (eg. 1 -> 10, 43 -> 430); if n is 0, this has no effect
if (n >= 0) n += (*s - '0'); // if n is not negative, add the value of the last digit (here is ascii-number "conversion"!)
else n -= (*s - '0'); // if it is negative, the number should be substracted (note eg. if there was -10 so far, and the new number is 2, the new value should be -12, not -8)
if (n > 0 && !valid) { // if n not 0, and there was no digits before it, check if there was a minus sign before
valid = 1; // preventing more check
if (prev == '-') n *= -1; // makes n negative
}
} else if (valid) break; // if there was numbers processed, but the current character is not a number, finish loop
prev = *s; // store current character for minus sign checking of next loop
s++; // move string pointer to the next character
}
return n; // return the converted value
}
It is also untested, so fixes / corrections / improvements are welcome!
This function can even process strings like " sfg afg-65sd1g". In that case the returned value will be -65, because it looks for the first number, then returns.
I'm learning c language and I hit a wall, if you would like to help me I appreciate (here is the ex: "Write a program that reads characters from the standard input to end-of-file. For each character, have the program report whether it is a letter. If it is a letter, also report its numerical location in the alphabet and -1 otherwise." btw is not homework).The problem is with the \n i don't know how to make it an exception. I'm new around here please let me know if I omitted something. Thank you for your help.
int main(void)
{
char ch;
int order;
printf("Enter letters and it will tell you the location in the alphabet.\n");
while ((ch = getchar()) != EOF)
{
printf("%c", ch);
if (ch >= 'A' && ch <= 'Z')
{
order = ch - 'A' + 1;
printf(" %d \n", order);
}
if (ch >= 'a' && ch <= 'z')
{
order = ch - 'a' + 1;
printf(" %d \n", order);
}
if (order != (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
{
if (ch == '\n');
else if (order != (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
printf(" -1 \n");
}
}
system("pause");
}
You are talking about an "exception" which can be interpreted in other ways in programming.
I understand that you want that '\n' be "excepted" in the set of nonalphabetical characters, that is, that it doesn't generate the error value -1.
Since you are using console to run the program, a sequence of character is going to be read till ENTER key is pressed, which generates the character \n. So, I'm not pretty sure that the while() condition you used, that compares against EOF, it's a good decision of yours.
I would put there directly the comparisson against '\n'.
while ((ch = getchar()) != '\n')
To inform if ch is a letter or not, we could use string literals. The following use of string assignment would deserve more explanation, but I will omit it. It's valid with string literals:
char *info;
if (order != -1)
info = "is a letter";
else
info = "is not a letter";
You are assuming an encoding where the letters are in contiguous increasing order (as in ASCII).
By assuming that, it's enough to work with uppercase or lowercase letters, since you are only interested in the position that the letter occupy in the alphabet. So, you can choose to work with uppercase, for example, in this way:
if (ch >= 'a' && ch <= 'z')
ch = (ch - 'a' + 'A');
The effect of that line of code is that ch is converted to uppercase, only if ch is a lowercase letter. Another kind of character is not affected.
As a consequence, from now on, you only have uppercase letters, or nonalphabetical characters.
Then it's easy to code the remaining part:
if (ch >= 'A' && ch <= 'Z')
order = ch - 'A' + 1; // It brings no. position of letter in alphabet
else
order = -1; // This is the erroneous case
A printf() at the end of the loop could bring all the information about the character:
printf(" %16s: %4d \n", info, order);
The resulting code is shorter in more clear:
#include <stdio.h>
int main(void) {
char ch;
int order;
char *info;
while ((ch = getchar()) != '\n') {
printf("%c",ch);
if (ch >= 'a' && ch <= 'z') /* Converting all to uppercase */
ch = (ch - 'a' + 'A');
if (ch >= 'A' && ch <= 'Z')
order = ch - 'A' + 1; /* Position of letter in alphabet */
else
order = -1; /* Not in alphabet */
if (order != -1)
info = "is a letter";
else
info = "is not a letter";
printf(" %16s: %4d \n", info, order);
}
}
If you need to end the input by comparing against EOF, then the type of ch has to be changed to int instead of char, so you can be sure that the EOF value (that is an int) is properly held in ch.
Finally, this means that ch needs initialization now, for example to a neutral value in the program, as '\n'.
Finally, just for fun, I add my super-short version:
#include <stdio.h>
int main(void) {
int ch, order;
while ((ch = getchar()) != '\n') {
order = (ch>='a' && ch<='z')? ch-'a'+1:((ch>='A' && ch<='Z')? ch-'A'+1: -1);
printf("%c %8s a letter: %4d \n", ch, (order != -1)? "is":"is not", order);
}
}
The C language does not have exceptions. Exceptions were first introduced into programming in C++. You can do it manually in C using setjmp() and longjmp(), but it really isn't worth it.
The two most popular of doing error handling in C are:
Invalid return value. If you can return -1 or some other invalid value from a function to indicate 'there was an error', do it. This of course doesn't work for all situations. If all possible return values are valid, such as in a function which multiplies two numbers, you cannot use this method. This is what you want to do here - simply return -1.
Set some global error flag, and remember to check it later. Avoid this when possible. This method ends up resulting in code that looks similar to exception code, but has some serious problems. With exceptions, you must explicitly ignore them if you don't want to handle the error (by swallowing the exception). Otherwise, your program will crash and you can figure out what is wrong. With a global error flag, however, you must remember to check for them; and if you don't, your program will do the wrong thing and you will have no idea why.
First of all, you need to define what you mean by "exception"; do you want your program to actually throw an exception when it sees a newline, or do you simply want to handle a newline as a special case? C does not provide structured exception handling (you can kind-of sort-of fake it with with setjmp/longjmp and signal/raise, but it's messy and a pain in the ass).
Secondly, you will want to read up on the following library functions:
isalpha
tolower
as they will make this a lot simpler; your code basically becomes:
if ( isalpha( ch ) )
{
// this is an alphabetic character
int lc = tolower( ch ); // convert to lower case (no-op if ch is already lower case)
order = lc - 'a' + 1;
}
else
{
// this is a non-alphabetic character
order = -1;
}
As for handling the newline, do you want to just not count it at all, or treat it like any other non-alphabetic character? If the former, just skip past it:
// non-alphabetic character
if ( ch == '\n' )
continue; // immediately goes back to beginning of loop
order = -1;
If the latter, then you don't really have to do anything special.
If you really want to raise an honest-to-God exception when you see a newline, you can do something like the following (I honestly do not recommend it, though):
#include <setjmp.h>
...
jmp_buf try;
if ( setjmp( try ) == 0 ) // "try" block
{
while ( (ch = getchar() ) != EOF )
{
...
if ( ch == '\n' )
longjmp( try, 1 ); // "throw"
}
}
else
{
// "catch" block
}
I'm having hard time trying to understand why you even try to handle '\n' specifically.
You might be trying to implement something like this:
int main(void)
{
char ch;
int order;
printf("Enter letters and it will tell you the location in the alphabet.\n");
while ((ch = getchar()) != EOF)
{
printf("%c", ch);
if (ch >= 'A' && ch <= 'Z') {
order = ch - 'A' + 1;
printf(" %d \n", order);
} else if (ch >= 'a' && ch <= 'z') {
order = ch - 'a' + 1;
printf(" %d \n", order);
} else if (ch == '\n') { } else {
printf(" -1 \n");
}
}
system("pause");
}
While this is a good solution, I would recommend rewriting it in a more optimal way:
int main(void)
{
char ch;
printf("Enter letters and it will tell you the location in the alphabet.\n");
while ((ch = getchar()) != EOF)
{
int order;
if (ch != '\n'){
if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {
order = ch & 11111B;
printf("Letter %d\n", order);
} else {
order = -1;
printf("Not letter: %d\n", order);
}
}
}
system("pause");
}
This way the program relies on specific way letters coded in ASCII