user6217340
user6217340

Reputation:

How to shift chars w/pointers

I'm trying to write a function in C which shifts each letter of a char *, so 'a' becomes 'z' and 'b' becomes 'y'. In the if statements below, it's my understanding that (*p - 'a') is the letter p points to, but I'm not sure how to shift the char to achieve the desired result. Any guidance would be greatly appreciated.

void encode(char *s1, char *s2) {
    char *p, *q;

    q = s2;
    for (p = s1; p < p + p[STR_LEN]; p++, q++) {
        if (*p >= 'a' && *p <= 'z') {
            *q = (*p - 'a');
        } else
        if (*p >= 'A' && *p <= 'Z') {
            *q = (*p - 'A');
        }
    }
}

EDIT Thanks for all the help! It looks like the best algorithm was *q = 'A' + 'Z' - (*p), but for some reason it's only encoding the first and second word, with this ▒ as a space. The problem is obviously the rest of my code so I'll get to work. Thanks again!

EDIT2

I had to add the code below to account for a space character. Thanks again!

else if (*p == ' ')
            {
                    *q = ' ';
            }

Upvotes: 2

Views: 1427

Answers (4)

Pushan Gupta
Pushan Gupta

Reputation: 3825

The problem is this *q = (*p - 'a');

Look whats happening! Imagine *p is 'c'. *q then becomes 99-97=2 i.e. character value of ASCII 2. Instead it should have ASCII value of 120 i.e. x.

So use plain Arithmetic with ASCII values. This would result in

*q='a'+'z'-(*p);//97+122-99=120 for *p='c'

Similarly for A-Z range

*q='A'+'Z'-(*p);

So the code would look like this:

void encode(char *s1, char *s2) {
    char *p, *q;

    q = s2;
    p=s1;
    int i;
    for (i=0; i<STR_LEN; i++) {// I am assuming that STR_LEN is a macro or global value.
        if (*p >= 'a' && *p <= 'z') {
            *q='a'+'z'-(*p);
        } else if (*p >= 'A' && *p <= 'Z') {
            *q='A'+'Z'-(*p);
        }else {
            *q=*p;
        }
        p++;
        q++;
    }
}

Upvotes: 1

pks
pks

Reputation: 1

See the following code. It shifts all the letters as per your need. 'a' becomes 'z', 'A' becomes 'Z', 'b' becomes 'y' and 'B' becomes 'Y' etc...

Note: here I am assuming s1 is the letter to be shift and result goes in s2.

void encode(char *s1, char *s2) {
    if ((*s1 >= 'a') && (*s1 <= 'z')) {
        *s2 = 'z' - (*s1 - 'a');
    } else if ((*s1 >= 'A') && (*s2 <= 'Z')) {
        *s2 = 'Z' - (*s1 - 'A');
    }
}

Upvotes: 0

chqrlie
chqrlie

Reputation: 144770

Your formulae are incorrect:

  • your test for end of string is bizarre, you should probably just check for the '\0' terminator.
  • you must subtract the difference from the character to a, from z.
  • you should also copy the characters that are not letters.
  • you should set a null terminator at the end of the destination string.

Here is a modified version:

void encode(char *s1, char *s2) {
    char *p, *q;

    for (p = s1, q = s2; *p != '\0'; p++, q++) {
        if (*p >= 'a' && *p <= 'z') {
            *q = 'z' - (*p - 'a');
        } else
        if (*p >= 'A' && *p <= 'Z') {
            *q = 'Z' - (*p - 'A');
        } else {
            *q = *p;
        }
    }
    *q = '\0';
}

Note that this programs assumes that all lowercase and uppercase characters are consecutive, which is true for ASCII but false for EBCDIC.

Here is a alternate version that performs a generic substitution, for all character sets:

char const source_set[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
char const mirror_set[] = "zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA";

void encode(const char *src, char *dest) {
    for (; *src; src++, dest++) {
        const char *p = strchr(source_set, *src);
        *dest = p ? mirror_set[p - source_set] : *src;
    }
    *dest = '\0';
}

Note that the order of the arguments is inconsistent with common practice, rooted in the standard library examples: strcpy, memcpy and many others pass the destination before the source arrays.

Here is another solution for 8-bit characters that requires an initialization step but produces a very efficient encoding function:

char const source_set[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
char const mirror_set[] = "zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA";
char encode_array[256];

void encode_initialize(void) {
    for (int i = 0; i < 256; i++) {
        encode_array[i] = (char)i;
    }
    for (int i = 0; source_set[i]; i++) {
        encode_array[(unsigned char)source_set[i]] = mirror_set[i];
    }
}

void encode(const char *src, char *dest) {
    while ((*dest++ = encode_array[(unsigned char)*src++]) != '\0')
        continue;
}

Upvotes: 1

Cwift
Cwift

Reputation: 310

*q = ('z' - *p) + 'a';

It likes number 0 becomes number 25 and number 25 becomes number 0.

Upvotes: 1

Related Questions