Reputation:
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
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
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
Reputation: 144770
Your formulae are incorrect:
'\0'
terminator.a
, from z
.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
Reputation: 310
*q = ('z' - *p) + 'a';
It likes number 0 becomes number 25 and number 25 becomes number 0.
Upvotes: 1