ASCII ROT13 cipher results in incorrect characters - c

I have been trying to learn C and decided to do an encryption project. I want to use ROT 13 encryption for the project but I have been getting an error. The code is supposed to check the value of a char at index position words[i] and compare its value. If it's in the range of 97-122 ('a' - 'z'), run the code and add the encryption. I learned, however, that when I want to replace a letter like 'z' and move it 6 positions, it doesn't work. Moving it 5 positions does work. Please see the code below:
#include <stdio.h>
#include <string.h>
int main(){
char words[25]= "ABC MNO XYZ";
printf("%s \n", words);
printf("size of 'words' is %d \n", strlen(words));
int size_t = strlen(words);
for (int i=0; i < size_t; i++){
printf("%c \n", words[i]);
}
printf("unencrypted ends here... \n\nStarts the cipher\n");
//converts array to lowercase for ascii purposes
for (int i=0; i < size_t; i++){
words[i]= tolower(words[i]);
}
for (int i=0; i < size_t; i++)
{
char res = 'z';
if(words[i]>=97 && words[i]<=122)
{
words[i] = words[i]+6;
while(words[i] > 122)
{
res = words[i]-res;
printf("The value of res is: %d\n", res);
words[i]=96;
words[i]= words[i]+res;
}
}
//'res' ascii value equals 122
//if words[i] is more than 122 (z), subtract 122 from it and store it in res
//restart words[i] at position before 'a', then add res
//not sure why but after 122 + 6 or more positions, does not reset to a char before 'a'
//gives those weird chars at 128+ ascii locations
printf("%c \n", words[i]);
}
return 0;
}

#user3386109 has already commented a solution to your problem:
Subtract 'a' from the letter. Add 13 (for rot13), and then subtract 26
if the result is >= 26. Then add 'a' to get the final result.
But here's an explanation of why adding 5 to words[i] works but 6 doesn't:
The main reason adding 5 to words[i] works but adding 6 doesn't is because in your case char is signed (range -128 to 127) so if words[i] (a char) is equal to 122, adding 6 to it (128) overflows the range of signed char.
Since words[i] will never be negative, try using unsigned char instead of char.
Last but not the least, size_t is a datatype in C, try to avoid using it as a variable name.

The problem is that a char may have a range of [-128, 127], which is why adding 5 works, but adding 6 causes an out-of-range assignment. One solution is to first convert the char to a larger type, for example an int, but there is something better:
for (int i=0; i < size_t; i++)
{
if (islower(words[i]))
words[i] = (words[i] - 'a' + 13) % 26 + 'a';
printf("%c \n", words[i]);
}
This takes the character, makes it a value between 0 and 25, applies the shift, takes the remainder to handle the wrapping around the alphabet, and finally adds 'a' again to convert the value back to the ASCII 'a' to 'z' range.
This will still implicitly convert the char to an int type, as 'a' and 13 are ints, but now we no longer need an if-statement and it expresses clearly that we are using values modulo 26.
For more information on the range of char and type promotions, see here. Note that assigning an out-of-range value to a signed integer is actually implementation-defined behavior.
Some additional advice:
The typical signature for main, using no parameters, is int main(void).
To use tolower, include the ctype.h header.
Do not use an identifier called size_t. This is a type used in C and is typedef'd in many commonly used headers.
Using 'a' and 'z' makes the code easier to understand than using 97 and 122. For checking if a char is lowercase, use islower.
The strlen function returns a value of the type size_t. The correct format specifier for this is not %d, but %zu.

Related

C Programming: how to get normal value of int without using value - 48?

So i have this loop the check user input:
int ch, num;
while ((ch = getchar()) != '\n')
{
if (isdigit(ch))
{
num = ch - 48;
}
}
So according this table:
Character Decimal Value
0 48
1 49
2 50
3 51
4 52
5 53
6 54
7 55
8 56
9 57
I am using this way to get my number: num = ch - 48;
And if for example i want to multiple my number by 10 ?
how to get normal value of int without using value - 48?
Like this:
num = ch - '0';
Read more in How to convert char to integer in C?
In both cases, you then just do:
num *= 10;
since num is of type int.
Warning: Others suggest int atoi (const char * str); to get the number, which expects as an input a string, not a character! So if you pass a character to that function (thus a non-null-terminated string, you will invoke Undefined Behavior).
You should always use the idiomatic
num = ch - '0';
The reason being that this works for any encoding supported by C: C mandates that the digits 0 to 9 appear contiguously and in ascending order. If you hardcode the value of '0' to 48 say, you are not, strictly speaking, writing portable C.
Note that the expression ch - '0' is an int type in C due to the rules of argument promotion ('0' is an int type in C). You are therefore free to multiply this by 10 in the same way as you would apply arithmetic operations to any int type.
Here's the best way to read input from user till the new line. I'm posting one example you can go through it and implement your code as you need.
This example will read for user input in integer untill newLine(\n).
Make sure you are not giving space at last.
Sample Code:
#include <stdio.h>
int main(void) {
int i=0,size,arr[10000];
char temp;
do{
scanf("%d%c", &arr[i], &temp);
i++;
} while(temp!= '\n');
size=i;
for(i=0;i<size;i++){
printf("%d ",arr[i]);
}
return 0;
}
You can use atoi() function here.You are getting ch as input from user.
You can convert it into string as follows-
char number[2] ="";
number[0]=ch;
number[1]='\0'
num = atoi(number);
This will solve your problem.

Storage of ASCII values of a string in an integral array in C [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
How can i store ASCII values of a string in an integral array and not print them in C?
For example: I input "ABab" and i have an array of a[4] then how can i store a[0]=67, a[1]=66, a[2]=97, a[3]=98?
It's already stored as you mention: a string is an array of char and a char is an integer.
I guess you know that computers work on "binary digits (bits)", so did you already ask yourself how the computer would store a character at all?
The answer is: That's what character encodings like ASCII are meant for: They assign a unique number to every character and the number is what gets stored!
As C should work on virtually any machine/system/OS, it doesn't specify which encoding is used for the characters, it just specifies a few properties this encoding must fulfill. ASCII only consists of 128 different codes (the amount that can be represented by 7 bits), so nowadays, larger encodings than ASCII are used, but with a probability very close to 1, your system uses an encoding that includes ASCII (very often this would be UTF-8).
So, as already commented, when you read characters in an array of char, you already end up with the ASCII values stored there. char is the smallest integer type in C and corresponds to a byte -- and a byte is exactly the amount of bits needed to store the representation of a character. This is almost always 8 bits, but larger values are allowed by the C standard.
If you want to print a number, you have to convert it to decimal places and convert these to the (ASCII) codes of the characters 0 to 9. Of course, C already has a function doing this for you: printf() with a suitable format string. To print the decimal value of a byte/char, you can simply do:
char c = 'A';
printf("%hhu", (unsigned char)c);
u is the conversion specifier for an unsigned integer, hh modifies the length of the argument to char, and you cast your char to unsigned char because C allows char to be either signed or unsigned.
You can use a loop to copy elements of a string into an array of the type int.
For example
#include <stdio.h?
int main( void )
{
char *s = "ABab";
int a[4];
const size_t N = sizeof(a) / sizeof(*a);
size_t i = 0;
for (; i < N && s[i] != '\0'; i++) a[i] = s[i];
while (i != N) a[i] = 0;
for (i = 0; i < N; i++) printf("%d ", a[i]);
putchar('\n');
return 0;
}
The program output is
65 66 97 98
If you need to output a character array as integers instead of their symbol representations then you can just write
#include <stdio.h?
int main( void )
{
char *s = "ABab";
for ( size_t i = 0; s[i] != '\0'; i++) printf("%d ", s[i]);
putchar('\n');
return 0;
}
Take into account that the type char can behave either as the type signed char or unsigned char. If you want to store or output characters as unsigned values you should write in the first program
for (; i < N && s[i] != '\0'; i++) a[i] = ( unsigned char )s[i];
and in the second program
for ( size_t i = 0; s[i] != '\0'; i++) printf("%d ", ( unsigned char )s[i]);
That is you need to cast explicitly char to unsigned char.

Turning a string character into an int

Basically, I have this really long string full of digits:
char *number = "insert really long number";
Now I want to perform math operations on individual digits contained in this string, let's say the following (summing two consecutive digits in this string aka array of chars):
sum = number[i] + number[i+1];
However, this does not produce the correct result, it returns a garbage value. I know how to extract a single value with printf for example:
printf("%c", number[i]);
But how can I get this %c to use in computations as above? I tried with atoi, but I get "error: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'; take the address with &".
1) atoi accept string rather than single character
2) If you want to convert just one ACSII char 0 - 9 just use following code:
if(rChar >= '0' && rChar <= '9')
val = rChar - '0';
You probably want this:
char *number = "123";
int n = 0;
char c;
for (int i = 0; c = number[i]; i++)
{
n += number[i] - '0';
}
printf("n = %d\n", n);
For any number which is represented as a datatype char, you can subtract that number from '0' to get that number in integer type.
For example:
char a = '5';
int num = a - '0';
//num will store 5
Why this works?
Because if you check the ASCII value for '5', it is 53 and for '0' it is 48. So the difference is 5. This will work for converting any number in character form to integer.
The ASCII value for '0' is 48, for '1' it is 49 and so on. So the subtraction from '0' results in giving us the difference of ASCII values.
Here is a link to ASCII values: http://www.asciitable.com/
atoi convert string (const char*) to int, if you give it a char it will not work. A solution to convert a char to an int is to use the ASCII table:
char c = '9'
int v = c - '0'; // v == 9

Can i assign a integer to a character pointer array?

int k=5;
char* result = (char *)malloc(100 * sizeof(char));
result[count] = k;
Considering the above code, if I print the contents of result[count] it prints smiley symbols. I tried like below,but of no use.
result[count]=(char)k;
Can anyone help me?
I am percepting that malloc(100*sizeof(char)) will create 100 blocks each of size of character contiguously. Please correct me if I am wrong?
I'll disregard all the fluff about arrays and malloc as it is irrelevant to the problem you describe. You seem to essentially be asking "What will this code print:"
char c = 5;
printf("%c", c);
It will print the symbol 5 in your symbol table, most likely a non-printable character. When encountering non-printable characters, some implementations choose to print non-standard symbols, such as smileys.
If you want to print the number 5, you have to use a character literal:
char c = '5';
printf("%c", c);
or alternatively use poor style with "magic numbers":
char c = 53; // don't write code like this
printf("%c", c);
It is a problem of character representation. Let's begin by the opposite first. A char can be promoted to an int, but if you do you get the representation of the character (its code). Assuming you use ASCII:
char c = '5';
int i = c; // i is now 0x35 or 53 ASCII code for '5'
Your example is the opposite, 5 can be represented by a char, so result[count] = k is defined (even if you should have got a warning for possible truncation), but ASCII char for code 5 is control code ENQ and will be printed as ♣ on a windows system using code page 850 or 437.
A half portable (not specified, but is known to work on all common architectures) way to do the conversion (int) 5 -> (char) '5' is to remember that code '0' to '9' are consecutive (as are 'A' to 'Z' and 'a to 'z'), so I think that what you want is:
result[count] = '0' + k;
First, let's clean up your code a bit:
int k=5;
char* result = malloc(100);
result[count] = k;
sizeof(char) is always equal to 1 under any platform and you don't need to cast the return of malloc() in C.
This said, as long as your count variable contains a value between 0 and 99, you're not doing anything wrong. If you want to print the actual character '5', then you have to assign the ASCII value of that character (53), not just the number 5. Also, remember that if that array of chars has to be interpreted as a string, you need to terminate it with '\0':
int k=5, i;
char* result = malloc(100);
for (i=0; i<98; i++) {
result[i] = ' ';
}
result[98] = 53;
result[99] = '\0';
printf("%s\n", result);
The elements in the array you're trying to allocate are all the size of a char, 1 byte. An int is 4 bytes thus your issues. If you want to store ints in an array you could do:
int result[100];
Followed by storing the value, but honestly from the way your questioned is posed I don't know if that's actually what you're trying to do. Try rephrasing the post with what you're trying to accomplish.
Are you trying to store 5 as a character?

Store an integer in a char array

I am trying to store an integer in a char array. How can I do that? This is my approach (by casting it the int to a char) but it does not work. What am I missing?
#include <stdio.h>
int main(int argc, char** argv)
{
char cArray[10] = {};
// Store a character in the char array
cArray[5] = 'c';
printf("%c\n", cArray[5]);
// Store an integer in the char array
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
printf("%c\n", cArray[6]);
}
Let's start with the basics.
For x86 architecture(assuming you use it) a char variable is stored in 1 byte and an int variable is stored in 4 bytes.
It is IMPOSSIBLE to store a random integer value in a char variable unless you have some compression schema and know that some integer values will not occur(no random!) in your program. No exceptions.
In your case, you want to store integers in a char array. There are four options:
1.If you want to store a random integer in this char array, then you should get the pointer to the index that you want to store the integer and cast it to an integer pointer and use it like that.
char mychars[10];
int * intlocation = (int*)(&mychar[5]);
*intlocation = 3632; // stores 3632
Beware that this will write to 4 bytes(4 char locations in your array) starting from the index you have specified. You should always check you are not going out of array.Also you should do the same casting for retrieving the value when needed.
2.If your values are between [0,255] or [-128,127] you can safely store your integers in a char since these ranges can be represented using a byte. Beware that char being signed or unsigned is implementation-dependent. Check this out!
mychars[5] = 54;
3.If your integer is just a digit, you can use the char representation of the digit.
mychars[5] = your_digit + 48; // 48 is the ascii code for '0'
4.If you want to store the string representation of your integer, then you should use itoa() and write each char of the resulting string to your array one by one. In that case, you should always check that you are not going out of array.
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
printf("%c\n", cArray[6]);
This code attempts to print a character with the encoding 0; assuming ASCII, nothing will get displayed because there is no printable character associated with that code.
If you intend to store the ASCII code for the character '0' and print it, then you need to write
cArray[6] = 48; // same as writing cArray[6] = '0' (ASCII)
printf( "%c\n", cArray[6] );
This will print 0 to your console.
If, on the other hand, you want to store any arbitrary integer value1 to cArray[6] and display that value, then you need to use the %d conversion specifier:
cArray[6];
printf( "%d\n", cArray[6] );
1. That is, any integer that fits into the range of char, anyway
Normally, a computer exactly does what you tell it. The instruction DWIM (do what I mean) hasn't been invented yet.
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
sets the index position 6, but
printf("%c\n", cArray[5]);
prints the index position 5.
I would like to add on to Seçkin Savaşçı's answer (in which you cast a char* pointer to somewhere in the char array to an int* pointer, allowing you to write an integer to the array by dereferencing the pointer).
You can also use bit-shifting:
#include <stdio.h>
int main() {
int first_int = 4892; // number larger than 127 (max. value of char)
int second_int = 99584; // same
// char array to hold two integers:
char array[8]; // ...assuming an integer size of 4 and char size of 1
// Now, assuming you are on a little endian system (in which the least
// significant bytes come first), you can add the two above integers to the
// array like so:
array[0] = first_int; // assigns first_int's least significant byte
array[1] = first_int >> 8; // assigns first_int's 2nd least significant byte
array[2] = first_int >> 16; // assigns first_int's 2nd most significant byte
array[3] = first_int >> 24; // assigns first_int's most significant byte
// repeat for second_int:
array[4] = second_int;
array[5] = second_int >> 8;
array[6] = second_int >> 16;
array[7] = second_int >> 24;
// You can now prove that this char array holds the two integers like this:
printf("First integer: %d\n", *((int *) array));
printf("Second integer: %d\n", *((int *) (array + 4)));
return 0;
}
On a big endian system you would first assign the most significant byte, and move on to the least significant bytes.
Replace
cArray[6] = (char) 0; // WHY DOES THIS NOT WORK???
printf("%c\n", cArray[5]);
By
cArray[6] = (char)51;
printf("%c\n", cArray[6]);
Should display '3'
I think you will understand your mistake... 0 as int does not represent the printable character '0', but the NULL termination string
51 as int represent the character '3'
You may use itoa(0,&cArry[6],10).
Use the correctly desired format specifier.
cArray[6] = (char) 0; does store an integer 0 into array element cArray[6]. Its the printf() that is fooling OP into thinking that did not work.
Using %c says OP wants the character that is encoded with a 0. (It usually not visible). Use %d to print the integer value of cArray[6].
printf("%d\n", cArray[6]);
You can add the ASCII value of 0 to the value you want to store digit into the character array.
For example if you want to store 0,1,...,9 into the character array A[10], you may use the following code.
for(j = 0; j<k; j++)
{
A[j] = j + '0'; // Same effect if you use A[j] = j + 0x30
}
This works only if the integer you want to store is less than 10. Otherwise you will have to extract the digits using modulo operator and store.

Resources