Is this code a portable?

  • Thread starter Robert Bachmann
  • Start date
R

Robert Bachmann

Two years I wrote a simple cesar encryption program, it worked but it
relied on ASCII.
So today I tried to make an portable cesar encryption.
Please tell me if the code below is really protable.

Thanks in advance.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>

char
letters_a_z[] = "zabcdefghijklmnopqrstuvwxy",
letters_A_Z[] = "ZABCDEFGHIJKLMNOPQRSTUVWXY",
letters_a_z_rot[] = "abcdefghijklmnopqrstuvwxyz",
letters_A_Z_rot[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

int main (void)
{
int ch;

setlocale (LC_CTYPE, "C");

while ((ch = getc (stdin)) != EOF)
{
if (isupper (ch))
ch = letters_A_Z_rot[strchr (letters_A_Z, ch) - letters_A_Z];
else if (islower (ch))
ch = letters_a_z_rot[strchr (letters_a_z, ch) - letters_a_z];

putc (ch, stdout);
}

return 0;
}
 
G

Gianni Mariani

Robert said:
Two years I wrote a simple cesar encryption program, it worked but it
relied on ASCII.
So today I tried to make an portable cesar encryption.
Please tell me if the code below is really protable.

Thanks in advance.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>

char
letters_a_z[] = "zabcdefghijklmnopqrstuvwxy",
letters_A_Z[] = "ZABCDEFGHIJKLMNOPQRSTUVWXY",
letters_a_z_rot[] = "abcdefghijklmnopqrstuvwxyz",
letters_A_Z_rot[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

int main (void)
{
int ch;

setlocale (LC_CTYPE, "C");

while ((ch = getc (stdin)) != EOF)
{
if (isupper (ch))
ch = letters_A_Z_rot[strchr (letters_A_Z, ch) - letters_A_Z];
else if (islower (ch))
ch = letters_a_z_rot[strchr (letters_a_z, ch) - letters_a_z];

putc (ch, stdout);
}

return 0;
}

For 8 bit character sets it is OK, you might need to check for SJIS and
Big5 characters sets.

This might be a tad faster but it relies on 8 bit character sets as well.

#include <stdio.h>

char key_array[256] = {
['A']='Z',
['B']='Y',
['C']='X',
['D']='W',
['E']='V',
['F']='U',
['G']='T',
['H']='S',
['I']='R',
['J']='Q',
['K']='P',
['L']='O',
['M']='N',
['N']='M',
['O']='L',
['P']='K',
['Q']='J',
['R']='I',
['S']='H',
['T']='G',
['U']='F',
['V']='E',
['W']='D',
['X']='C',
['Y']='B',
['Z']='A',
['a']='z',
['b']='y',
['c']='x',
['d']='w',
['e']='v',
['f']='u',
['g']='t',
['h']='s',
['i']='r',
['j']='q',
['k']='p',
['l']='o',
['m']='n',
['n']='m',
['o']='l',
['p']='k',
['q']='j',
['r']='i',
['s']='h',
['t']='g',
['u']='f',
['v']='e',
['w']='d',
['x']='c',
['y']='b',
['z']='a',
};

int main (void)
{
int ch;

while ( (ch = getc (stdin)) != EOF)
{

int ch2;

ch = ( ch2 = key_array[ ch & 0xff ] ) ? ch2 : ch;

putc (ch, stdout);


}

return 0;
}
 
E

Eric Sosman

Robert said:
Two years I wrote a simple cesar encryption program, it worked but it
relied on ASCII.
So today I tried to make an portable cesar encryption.
Please tell me if the code below is really protable.

Thanks in advance.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>

char
letters_a_z[] = "zabcdefghijklmnopqrstuvwxy",
letters_A_Z[] = "ZABCDEFGHIJKLMNOPQRSTUVWXY",
letters_a_z_rot[] = "abcdefghijklmnopqrstuvwxyz",
letters_A_Z_rot[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

int main (void)
{
int ch;

setlocale (LC_CTYPE, "C");

while ((ch = getc (stdin)) != EOF)
{
if (isupper (ch))
ch = letters_A_Z_rot[strchr (letters_A_Z, ch) - letters_A_Z];
else if (islower (ch))
ch = letters_a_z_rot[strchr (letters_a_z, ch) - letters_a_z];

putc (ch, stdout);
}

return 0;
}

This should work, because the setlocale() causes the
isupper() and islower() functions to consider only the
fifty-two letters A-Z and a-z as alphabetic. (However,
the setlocale() call should be unnecessary: according to
the Standard, every program begins in the "C" locale.)

You might want to consider some improvements, though;
it's almost always better to achieve a goal with less code
instead of more. One suggestion is to handle both upper-
and lower-case in a single operation:

char alpha[] = "abc...xyzABC...XYZ";
char coded[] = "bcd...yzaBCD...YZA";
...
if (isalpha(ch))
ch = coded[ strchr(alpha, ch) - alpha ];

Another possibility is to do away with the isalpha()
test by using the alpha[] array itself to define the
characters that are subject to change. With the arrays
as above you could write

char *p;
...
p = strchr(alpha, ch);
if (p != NULL)
ch = coded[p - alpha];

This may not look like a big improvement and it may in
fact be just a hair slower than the prior version, but it
has an advantage: it generalizes to let you encode non-
alphabetic characters as well. For example, you could
scramble digits as well as letters, or spaces and other
puncutation, just by changing the two arrays.

Finally, on machines with "normal" character sets of
256 or so distinct codes, there's a technique that is even
more general and (after some initial setup) probably faster.
The idea is to build a table giving the coded equivalent of
every possible character; this will be the identity mapping
for many characters, but will be something else for the
enciphered characters. You'd set the table up like this:

#include <limits.h> /* for UCHAR_MAX */

char caesar[1+UCHAR_MAX];
int i;
for (i = 0; i <= UCHAR_MAX; ++i)
caesar = i; /* the identity mapping */
for (i = 0; alpha != '\0'; ++i)
caesar[ alpha ] = coded;

Once the table is built, the actual processing reduces to

while ((ch = getc(stdin)) != EOF)
putc (caesar[ch], stdout);

.... which is almost as simple as one can get. Of course,
this technique is viable only for "normal" character sets;
on machines with (for example) 32-bit characters, the table
would become unwieldy and `i' might not work as a plain `int'.
 
R

Robert Bachmann

Gianni said:
Robert Bachmann wrote:
[code snipped]
For 8 bit character sets it is OK, you might need to check for SJIS and
Big5 characters sets.
I think it should be OK also for n bit character sets.
(Where n is >= 8)
Of course it wouldn't encode other characters then
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ". (without " of
course)
This might be a tad faster but it relies on 8 bit character sets as well.

#include <stdio.h>

char key_array[256] = {
['A']='Z',
['B']='Y',
['C']='X', [...]
['Y']='B',
['Z']='A',
['a']='z',
['b']='y',
[...]
['y']='b',
['z']='a',
The key should be
['A']='B',
['B']='C',
['C']='D',
....
['Y']='Z',
['Z']='A',
etc.

[snipped]
 
I

Irrwahn Grausewitz

Francois Grieu said:
char k[1]={[0]=0};

Is this C?

Designated initializers are a new feature of C99, providing
a mechanism for initializing "sparse" aggregates.
See: C99 6.7.8 Initialization

Regards
 
R

Robert Bachmann

Eric said:
Robert Bachmann wrote: [...]
You might want to consider some improvements, though;
it's almost always better to achieve a goal with less code
instead of more. One suggestion is to handle both upper-
and lower-case in a single operation:

char alpha[] = "abc...xyzABC...XYZ";
char coded[] = "bcd...yzaBCD...YZA";
...
if (isalpha(ch))
ch = coded[ strchr(alpha, ch) - alpha ];

Another possibility is to do away with the isalpha()
test by using the alpha[] array itself to define the
characters that are subject to change. With the arrays
as above you could write

char *p;
...
p = strchr(alpha, ch);
if (p != NULL)
ch = coded[p - alpha];
Thanks for that advice, that will make things a little bit simpler.

P.S:
I just realized that the subject line should have been "Is this code a
portable one?" or "Is this code portable?".
 
F

Francois Grieu

Irrwahn Grausewitz said:
Francois Grieu said:
char k[1]={[0]=0};

Is this C?

Designated initializers are a new feature of C99, providing
a mechanism for initializing "sparse" aggregates.
See: C99 6.7.8 Initialization

Wow ! Thanks for pointing this out. Can be usefull for
conpile-time-initialized sparse arrays.


Francois Grieu
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top