Manipulating array of chars - c

I'm writing a code in C programming language that receives a string (of chars) as input and each letter advances 3 in the alphabet. E.g. If user types "abc", the program should return "def". The problem is that if the user types 'z' (e.g.), the program returns some char, instead of my goal (which would be this case the letter 'c'). My current algorithm includes this if statement:
if ((text[i]>='a' && text[i]<='w')||(text[i]>='A' && text[i]<='W'))
text[i] = (text[i]) + 3;
But this forces me to write all this lines:
else if (text[i]=='x') text[i]='a';
else if (text[i]=='X') text[i]='A';
else if (text[i]=='y') text[i]='b';
else if (text[i]=='Y') text[i]='B';
else if (text[i]=='z') text[i]='c';
else if (text[i]=='Z') text[i]='C';
How can I optimize my code?

Your problem can be addressed with simple arithmetic logic. The range of char ranges from 0 - 255. Each value corresponds to a separate character. The letters 'A-Z' and 'a-z' range from 65 - 90 and 97 - 122 respectively. So for your problem there are two ranges. You can check with the standard library function that your character falls in upper case or lower case range. then you can set the base for your range. Next you will find the offset of your character from base, add 3 in it. the new value can be made circular using % operator. each range has maximum of 26 characters so you can make your range circular by taking a mod from 26. Now add the resulting value (offset) to the base to get the desired character.
#include <ctype.h>
...
...
...
char c = text[i];
char base = isupper(c)? 'A' : 'a';
text[i] = base + (((c - base) + 3) % 26); // New Desired Character

Related

Convert single characters of a string to elements of an integer array

So I'm a newcomer to C and I've just learned about string after array. Now I'm trying to write a program that convert a string which consists of only integer numbers into an integer array.
For example let's say I have this string og[] and use fgets to get the input: og = 123456
Then I want to convert this '012345678' string into an array, let's say mod[] which be like:
mod[0] = 1;
mod[1] = 2;
mod[2] = 3;
mod[3] = 4;
mod[4] = 5;
mod[5] = 6;
Is there any method to achieve this quickly with a function? If no, how could I write a function to convert this?
Thank you in advance.
Use ASCII difference method in order to get required outcome:
For example let you are converting (char)1 to (int)1. So Subtract
ASCII value of 1 by 0:
ie,'1'-'0'(since, 49-48=1 here 49 is ASCII value of '1' and 48 is of '0').
And at the end store it into integer variable.
By using above concept you code will be:
int i=0;
char str []="123456789";
int strsize=(sizeof(str)/sizeof(char))-1;
int *arr=(int * )malloc(strsize*sizeof(int));
// YOUR ANSWER STARTS HERE
while(str[i]!='\0'){
arr[i]=str[i]-'0';
i++;
}
here size of str string is 10 thus subtracting 1 from it in order to get 9.
here while loop moving till end of string (i.e '\0')
If you are using an ASCII-based system (very likely) and you are only concerned with single digits, this is quite simple:
int main(void)
{
char og[] = "123456";
int *mod = calloc(strlen(og),sizeof(*mod));
for (int i = 0; og[i]; ++i) {
mod[i] = og[i] - '0';
}
// then whatever you want to do with this
}
This works because in ASCII, decimal digits are sequential and when the character is '0' and you subtract '0' (which is 48 in ASCII), you get the numerical value of 0; when the character is '1' (which is 49 in ASCII), you get the numerical value 1; and so on.

I am trying to perform a Caesar shift on the character z (ASCII 122). How do I give it "more room" to prevent it from overflowing past 127?

In the CS50 2019 Caesar assignment, I am supposed to perform Caesar shifts on characters by a given number of letters (key).
To do this, I add the value of key to each letter, as such:
for each character in plaintext:
plaintext[character] += key
Since I want z to loop back to a, I then wrote:
while (ciphered_character > 122)
{
ciphered_character -= 26;
}
Running the program with plaintext of z and a key of 26 causes 26 to be added to z (which is represented by 122). This causes plaintext[character] to overflow (past 127, I presume) and become negative before the while loop even kicks in. This gives a garbage output.
I know I can check for potential overflows beforehand and subtract 26 first, but that complicates my code. Can I give the variable 'more room' to prevent it from overflowing?
Do I use a different data type? What is the best practice here?
If you only care about lower case then this will work for you:
for each character in plaintext:
plaintext[character] = (plaintext[character] - 'a' + key) % 26 + 'a'
Subtracting 'a' to give you a value of 0-25, then add the key. If there is a overflow the modulo will give you the updated value in the 0-25 range which is added back to 'a' to get the correct character.
If you do need to handle both upper and lower case then you will need two different cases - one using 'a' and the other using 'A'. Select the the correct case for each character by checking isupper(plaintext[character])
Fun project;
I did it like this, assuming ASCII and using the full range of printable characters, from Space to ~
void caeser_shift(char* text, int key)
{ while (*text) { *text++ = ((*text-' ') + key) %('~'-' ') + ' '; } }
int main(void)
{
char plaintext[] = "Hello World; This is a test.";
caeser_shift(plaintext, 26);
printf("%s\n", plaintext);
return 0;
}
Output
Success #stdin #stdout 0s 4520KB
b!((+:q+.( U:n$%/:%/:{:0!/0H

How do I use modulo arithmetic to implement caesar cipher

I am trying to perform a wrap around of the ASCII alphabet characters in order to perform a shift from a key. For example, if the key is 2 then shift the letter A to become C. But, how do I wrap around Z in order to get to B using modulus arithmetic?
I am trying to implement the following formula:
ci = (pi + key) % 26;
Where ci is the ith ciphered letter and pi is the ith letter to be ciphered.
I believe you need to work with "relative" values, rather than absolute values.
Use something like
ci = ((pi - 'A' + key) % 26 ) + 'A';
Character integer constants stores the encoded values, in this case, ASCII. Here, 'A' starts from an offset (decimal value of 65), not from 0. So, before you can wrap the result using a % 26 operation, you need to get that offset out. Once the calculation is done, add the offset back to get the proper ASCII representation.
Others have already shown the basic concept of subtracting the offset of ASCII letters, but you have to be careful in when crossing from capital to non capital letters, as there are some symbols in between which I guess you want to avoid. I have added some logic that enables negative shifts and keeps the letter within capital letter or non capital letter space and tests whether it is a letter at all.
#include <stdio.h>
#define ASCII_CAP_LETTER_OFFS 65
#define ASCII_LETTER_OFFS 97
#define NUM_OF_LETTERS 26
char shift_letter (char letter, short shift)
{
char ci;
short shift_lcl = shift % NUM_OF_LETTERS;
if (shift_lcl >= 0)
{ // shift in positive direction
}
else
{ // shift in negative direction
shift_lcl = NUM_OF_LETTERS + shift_lcl;
}
if (letter >= ASCII_CAP_LETTER_OFFS && letter < ASCII_CAP_LETTER_OFFS + NUM_OF_LETTERS)
{// its a capital letter
ci =
(letter + shift_lcl - ASCII_CAP_LETTER_OFFS) % NUM_OF_LETTERS +
ASCII_CAP_LETTER_OFFS;
}
else if (letter >= ASCII_LETTER_OFFS && letter < ASCII_LETTER_OFFS + NUM_OF_LETTERS)
{// its a non capital letter
ci =
(letter + shift_lcl - ASCII_LETTER_OFFS) % NUM_OF_LETTERS +
ASCII_LETTER_OFFS;
}
else
{
printf ("This was not a letter!\n");
ci = 0;
}
return ci;
}
int main ()
{
char test_letter = 'a';
short test_shift = -53;
char shifted_letter = 0;
shifted_letter = shift_letter (test_letter, test_shift);
printf("%c + %d = %c", test_letter, test_shift, shifted_letter);
}
Deeper
ci = ((pi - 'A' + key) % 26) + 'A';
as well answered by #Sourav Ghosh generates the expected encoded A-Z when key is non-negative and not too large. It reduces pi with - 'A' so the value is in the [0...25] range and the re-offsets it after the % calculation.
To work for the full int range of key takes a little more code.
Reduce key range [INT_MIN...INT_MAX] with the functional equivalent range of [-25 ... 25] with key % 26. This step is important to prevent intoverflow with pi - 'A' + key. This can be done once if a number of letters need encoding.
Add 26. This insures negative keys are moved to positive ones.
ci = ((pi - 'A' + key%26 + 26) % 26 ) + 'A';
Note: In C, % is not the mod operator, but the remainder operator. Functional differences occur with a%b when a and/or b are negative. ref

I don't understand atoi function in K&R C book?

#include <stdio.h>
#include <string.h>
int main(void)
{
char s[]= "9";
printf("atoi = %d",atoi(s));
system("pause");
return 0;
}
int atoi(char s[])
{
int i=0,n=0;
for(i;s[i]>='0' && s[i]<='9';i++)
n=10*n + (s[i]-'0');
return n;
}
In above program it gave me result 9 as per program it should print ascii value for 9
and I don't understand what this for loop does.
for(i;s[i]>='0' && s[i]<='9';i++)
n = 10*n + (s[i]-'0');
Lets break this down:
for (i;
This creates a for loop, with the loop variable i. This is not necessary, but more of a coding style.
s[i] >= '0' && s[i] <= '9'
This checks to make sure that the character at that index is inside the range for a decimal character (0 - 9), and if it is not, it exits the loop, then returns the number.
i++
After the loop runs, this increases the index you are checking in the string by one.
n = 10 * n
This adds an extra digit to 'n' by multiplying by 10, because you know that if you have one more character in your number, it must be multiplied by ten (say I start parsing 100, I read the first two strings, and have 10, there is one more character, so I multiply by ten to get 100.
+ (s[i]-'0');
This adds the next digit to 'n', the result, which is determined by subtracting the character at the current index by '0', which, when in the range of 0 - 9, returns the integer for that number (if this confuses you, take a look at an ASCII Chart.
Hopefully this helped you understand.
this converts string representation to number like "329" to 329
It takes 3 first then 3*10+2=32
then 32*10 + 9 =329
for(i;s[i]>='0' && s[i]<='9';i++) /* loop over just the digits, in L->R order */
n = 10*n + (s[i]-'0'); /* Take value so far, "shift" a 10's place left,
and add in value of latest digit
(diff between ASCII of digit & ASCII of zero) */

Converting Letters to Numbers in C

I'm trying to write a code that would convert letters into numbers. For example
A ==> 0
B ==> 1
C ==> 2
and so on. Im thinking of writing 26 if statements. I'm wondering if there's a better way to do this...
Thank you!
This is a way that I feel is better than the switch method, and yet is standards compliant (does not assume ASCII):
#include <string.h>
#include <ctype.h>
/* returns -1 if c is not an alphabetic character */
int c_to_n(char c)
{
int n = -1;
static const char * const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *p = strchr(alphabet, toupper((unsigned char)c));
if (p)
{
n = p - alphabet;
}
return n;
}
If you need to deal with upper-case and lower-case then you may want to do something like:
if (letter >= 'A' && letter <= 'Z')
num = letter - 'A';
else if (letter >= 'a' && letter <= 'z')
num = letter - 'a';
If you want to display these, then you will want to convert the number into an ascii value by adding a '0' to it:
asciinumber = num + '0';
The C standard does not guarantee that the characters of the alphabet will be numbered sequentially. Hence, portable code cannot assume, for example, that 'B'-'A' is equal to 1.
The relevant section of the C specification is section 5.2.1 which describes the character sets:
3 Both the basic source and basic execution character sets shall have
the following members: the 26 uppercase letters of the Latin
alphabet
ABCDEFGHIJKLM
NOPQRSTUVWXYZ
the 26 lowercase letters of the Latin alphabet
abcdefghijklm
nopqrstuvwxyz
the 10 decimal digits
0123456789
the following 29 graphic characters
!"#%&'()*+,-./:
;<=>?[\]^_{|}~
the space character, and control characters representing horizontal
tab, vertical tab, and form feed. The
representation of each member of the source and execution basic
character sets shall fit in a byte. In both the source and execution
basic character sets, the value of each character after 0 in the above
list of decimal digits shall be one greater than the value of the
previous.
So the specification only guarantees that the digits will have sequential encodings. There is absolutely no restriction on how the alphabetic characters are encoded.
Fortunately, there is an easy and efficient way to convert A to 0, B to 1, etc. Here's the code
char letter = 'E'; // could be any upper or lower case letter
char str[2] = { letter }; // make a string out of the letter
int num = strtol( str, NULL, 36 ) - 10; // convert the letter to a number
The reason this works can be found in the man page for strtol which states:
(In bases above 10, the letter 'A' in either upper or lower case
represents 10, 'B' represents 11, and so forth, with 'Z' representing
35.)
So passing 36 to strtol as the base tells strtol to convert 'A' or 'a' to 10, 'B' or 'b' to 11, and so on. All you need to do is subtract 10 to get the final answer.
Another, far worse (but still better than 26 if statements) alternative is to use switch/case:
switch(letter)
{
case 'A':
case 'a': // don't use this line if you want only capital letters
num = 0;
break;
case 'B':
case 'b': // same as above about 'a'
num = 1;
break;
/* and so on and so on */
default:
fprintf(stderr, "WTF?\n");
}
Consider this only if there is absolutely no relationship between the letter and its code. Since there is a clear sequential relationship between the letter and the code in your case, using this is rather silly and going to be awful to maintain, but if you had to encode random characters to random values, this would be the way to avoid writing a zillion if()/else if()/else if()/else statements.
There is a much better way.
In ASCII (www.asciitable.com) you can know the numerical values of these characters.
'A' is 0x41.
So you can simply minus 0x41 from them, to get the numbers. I don't know c very well, but something like:
int num = 'A' - 0x41;
should work.
In most programming and scripting languages there is a means to get the "ordinal" value of any character. (Think of it as an offset from the beginning of the character set).
Thus you can usually do something like:
for ch in somestring:
if lowercase(ch):
n = ord(ch) - ord ('a')
elif uppercase(ch):
n = ord(ch) - ord('A')
else:
n = -1 # Sentinel error value
# (or raise an exception as appropriate to your programming
# environment and to the assignment specification)
Of course this wouldn't work for an EBCDIC based system (and might not work for some other exotic character sets). I suppose a reasonable sanity check would be to test of this function returned monotonically increasing values in the range 0..26 for the strings "abc...xzy" and "ABC...XYZ").
A whole different approach would be to create an associative array (dictionary, table, hash) of your letters and their values (one or two simple loops). Then use that. (Most modern programming languages include support for associative arrays.
Naturally I'm not "doing your homework." You'll have to do that for yourself. I'm simply explaining that those are the obvious approaches that would be used by any professional programmer. (Okay, an assembly language hack might also just mask out one bit for each byte, too).
Since the char data type is treated similar to an int data type in C and C++, you could go with some thing like:
char c = 'A'; // just some character
int urValue = c - 65;
If you are worried about case senstivity:
#include <ctype.h> // if using C++ #include <cctype>
int urValue = toupper(c) - 65;
Aww if you had C++
For unicode
definition of how to map characters to values
typedef std::map<wchar_t, int> WCharValueMap;
WCharValueMap myConversion = fillMap();
WCharValueMap fillMap() {
WCharValueMap result;
result[L'A']=0;
result[L'Â']=0;
result[L'B']=1;
result[L'C']=2;
return result;
}
usage
int value = myConversion[L'Â'];
I wrote this bit of code for a project, and I was wondering how naive this approach was.
The benefit here is that is seems to be adherent to the standard, and my guess is that the runtime is approx. O(k) where k is the size of the alphabet.
int ctoi(char c)
{
int index;
char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
c = toupper(c);
// avoid doing strlen here to juice some efficiency.
for(index = 0; index != 26; index++)
{
if(c == alphabet[index])
{
return index;
}
}
return -1;
}
#include<stdio.h>
#include<ctype.h>
int val(char a);
int main()
{
char r;
scanf("%c",&r);
printf("\n%d\n",val(r));
}
int val(char a)
{
int i=0;
char k;
for(k='A';k<=toupper(a);k++)
i++;
return i;
}//enter code here

Resources