-2
#include <stdio.h>
#include <string.h>

int main()
{
    int key;
    char line[500];
    char ch = '\0';
    int i = 0;

    printf("Enter key: ");
    scanf("%d", &key);
    getchar();

    printf("Enter line: ");

    while(ch != '\n')
    {
        ch = getchar();
        line[i] = ch;
        i++;    
    }

    int length = i; 
    int k = 0;
    char temp[length];

    for(i = 0; i < length; i++)
    {

        if((int)line[i] >= 65 && (int)line[i] <= 90)
        {           
                temp[k++] = (int)line[i] + key;
        } else if((int)line[i] >= 97 && (int)line[i] <= 122){
                temp[k++] = (int)line[i] + key;
        } else {
            temp[k++] = line[i];
        }
    }

    printf("\n");

    for(i = 0; i < length; i++)
    {
        printf("%c", temp[i]);
    }
}

What I have done so far is to convert characters into another one. For example, if I input "abc ABC" and the adding value(int key) is 3, then it should print out "def DEF".

This works fine, but what I want to achieve further is to rewind the character if it`s out of bound. For example, if I input "XYZ" and the adding value is 3, it should print out "ABC", not "[]". Can I please get any help or an advice of how to solve this problem? Thanks..

seung
  • 53
  • 1
  • 7

1 Answers1

1

First of all, when I see

if((int)line[i] >= 65 && (int)line[i] <= 90)

my first reaction is, "What do 65 and 90 mean?" Well, I know, but still, those numbers were an unnecessary nuisance for you to figure out and they're an unnecessary nuisance for the reader to read. So just say

if(line[i] >= 'A' && line[i] <= 'Z')

instead. In C, the value of a character constant like 'A' is the value of the character in the machine's character set, or 65 in ASCII. (I got rid of some unnecessary casts, also.)

Next, one sort of brute-force way of fixing your problem would be to just check for overflow:

if(line[i] >= 'A' && line[i] <= 'Z')
{
    temp[k] = line[i] + key;
    if(temp[k] > 'Z')
        temp[k] -= 26;
    k++;
}

Since I had to do several things with temp[k] before I was finished with it, I moved the k++ to the end.

You would use similar code for the a-z case.

If you want to make the program more general, there is also the possibility that key might be negative. In that case, you have to worry about letters "less than" A, also. You could extend the code like this:

if(line[i] >= 'A' && line[i] <= 'Z')
{
    temp[k] = line[i] + key;
    if(temp[k] > 'Z')
        temp[k] -= 26;
    else if(temp[k] < 'A')
        temp[k] += 26;
    k++;
}

Again, you'd repeat this for the a-z case.

Now, the non-brute-force way of doing this is to recognize that the "wraparound" arithmetic we're doing here is what's also called "modulus" arithmetic, because it's related to the "modulus" or "remainder" operator, %. So, if you understand how % works, you can write code like this:

if(line[i] >= 'A' && line[i] <= 'Z')
{
    int c = line[i] - 'A';
    c = (c + key) % 26;
    temp[k++] = c + 'A';
}

It's still not perfectly straightforward, because we have to go from a letter like 'Y', to its 0-based position in the alphabet (25), to its shifted value (28, assuming a key of 3), to its "modulo" value {2}, and then finally back to a letter like 'B'.

Or, in more detail, what's going on is that the capital letters are, in ASCII, 65 to 90. So we subtract 65 to get numbers in the range 0-25. Once we're in the range 0-25, we can use modulus arithmetic, because % 26 basically means, "only integers in the range 0 - 25". Finally, when we're done with our modulus arithmetic, we add 65 again, to get back up to the 65-90 range of actual letters. (And instead of subtracting and adding 65, we subtract and add 'A', because it's the same value, but clearer.)

And, again, I'm still only showing the code for the capital letters; you'd have to repeat this code for the a-z case, too.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • 1
    What happens if the offset is 300? hint - it's not going to work. – RoiHatam Jun 11 '17 at 17:03
  • @RoiHatam Sure. But (a) he's not going to do that (or not going to expect it to work), and (b) we're building up to `%` by easy stages. – Steve Summit Jun 11 '17 at 17:09
  • If I use this case, I lose my '(space)' How should I avoid losing it? – seung Jun 11 '17 at 17:33
  • @seung The code fragments I've posted shouldn't alter space characters at all -- they should alter upper-case letters only, and the analogous cases should alter lower-case letters only. So I'm not sure why you're saying you're losing your spaces. Do you understand how the code I've posted is supposed to work? – Steve Summit Jun 11 '17 at 17:48