Please help...........

S

Steve Clay

I have a small C program for a college course. It is meant to encrypt
and decrypt lower case letters and leave spaces as spaces. I can't
get it to run properly as I think I have a problem in the While
construct area. It is driving me mad trying to sort it out - can
someone please help.

The program is:

/*
* Program to encrypt a message using the Turbo C random
* number generator. Only lower case letters and the space
* character can be used in the message.
*/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>

#define SEED 1

unsigned char encrypt(unsigned char);
unsigned char decrypt(unsigned char);
void wait(void);


main()

{
unsigned char c;
char type;

/*
* initialise the random number generator
*/
srand(SEED);

/*
* display user headings and prompts
*/
clrscr();
cprintf("T223 encryption program\r\n\r\n");
cprintf("Type d to decode a message or any other character to encode
");
type = getch(); /* input the user option */
cprintf("\r\nNow type in the message, use only lower case letters "
"or space.\r\nEnd with any other character.\r\n\r\n");


c = (unsigned char)getchar(); /* read in first character */

/*
* main encryption/decryption loop
* loop while characters are lower case letters or spaces
*/
while ((c>='a') && (c<='z') && (c=' '));
{
if (c==' ')
{
switch (type)
{
case '64':
c = decrypt (c) ;
break;

default:
c = encrypt (c) ;
break;
}
}
putchar('c'); /* display encrypted/decrypted character */
c = (unsigned char)getchar(); /* get next character */
}
/*
* end of main while loop
*/
wait();
}

/*
* end of main() function
*/


/*
* function encrypt()
* ==================
* encrypts a single character
*/
unsigned char encrypt(unsigned char letter)
{
unsigned char r;
r = (unsigned char)random(26);
letter = letter + r;
if (letter>'z')
{
letter = letter - 26;
}
return(letter);
}
/*
* end of encrypt()
*/


/*
* function decrypt()
* ==================
* decrypts a single character
*/
unsigned char decrypt(unsigned char letter)
{
unsigned char r;
r = (unsigned char)random(26);
letter = letter - r;
if (letter<'a')
{
letter = letter + 26;
}
return(letter);
}
/*
* end of decrypt()
*/


/*
* function wait()
* ===============
* waits for a keypress
*/

void wait(void)
{
fflush(stdin);
cprintf("\r\nPress return to terminate");
getchar();
}
/*
* end of wait()
*/


/*
* end of program
*/
 
P

Peter Ammon

Steve said:
I have a small C program for a college course. It is meant to encrypt
and decrypt lower case letters and leave spaces as spaces. I can't
get it to run properly as I think I have a problem in the While
construct area. It is driving me mad trying to sort it out - can
someone please help.

The program is:

/*
* Program to encrypt a message using the Turbo C random
* number generator. Only lower case letters and the space
* character can be used in the message.
*/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>

Nonstandard headers, etc.
#define SEED 1

unsigned char encrypt(unsigned char);
unsigned char decrypt(unsigned char);
void wait(void);


main()

{
unsigned char c;
char type;

/*
* initialise the random number generator
*/
srand(SEED);

/*
* display user headings and prompts
*/
clrscr();
cprintf("T223 encryption program\r\n\r\n");
cprintf("Type d to decode a message or any other character to encode
");
type = getch(); /* input the user option */
cprintf("\r\nNow type in the message, use only lower case letters "
"or space.\r\nEnd with any other character.\r\n\r\n");

Nonstandard functions, etc.
c = (unsigned char)getchar(); /* read in first character */

What if getchar() returns EOF?
/*
* main encryption/decryption loop
* loop while characters are lower case letters or spaces
*/
while ((c>='a') && (c<='z') && (c=' '));

c=' ' assigns space to c, which always evaluates to nonzero (true) and
leaves c as a space.
Spurious semicolon at the end of the above statement.

{
if (c==' ')
{
switch (type)
{
case '64':

'64' is two characters in a single character literal; it's
implementation defined what this means. Why not just use 'd'?
c = decrypt (c) ;
break;

default:
c = encrypt (c) ;
break;
}
}
putchar('c'); /* display encrypted/decrypted character */

You mean putchar(c);
c = (unsigned char)getchar(); /* get next character */
}
/*
* end of main while loop
*/
wait();
}

/*
* end of main() function
*/


/*
* function encrypt()
* ==================
* encrypts a single character
*/
unsigned char encrypt(unsigned char letter)
{
unsigned char r;
r = (unsigned char)random(26);
letter = letter + r;
if (letter>'z')
{
letter = letter - 26;
}
return(letter);
}
/*
* end of encrypt()
*/


/*
* function decrypt()
* ==================
* decrypts a single character
*/
unsigned char decrypt(unsigned char letter)
{
unsigned char r;
r = (unsigned char)random(26);

You mean rand().
letter = letter - r;
if (letter<'a')
{
letter = letter + 26;
}
return(letter);
}
/*
* end of decrypt()
*/


/*
* function wait()
* ===============
* waits for a keypress
*/

void wait(void)
{
fflush(stdin);

Undefined behavior here.
 
M

Michael

Hi Steve,
Peter already pointed out some problems
in your program (more I ever found). I
just want to add s.th. according your
while condition:
while ((c>='a') && (c<='z') && (c=' '));

Isn't it
> while ((c>='a') && (c<='z') || (c==' '))
a character 'or' space?

Regards
Michael
 
R

Richard Heathfield

Michael said:
Hi Steve,
Peter already pointed out some problems
in your program (more I ever found). I
just want to add s.th. according your
while condition:


Isn't it

a character 'or' space?

Well, that's certainly an improvement, since no character can be a letter
/and/ a space. But this:

while(islower((unsigned char)c) || (c == ' '))

is better still, since it doesn't rely on lower case letters being
contiguous and in alphabetical order.
 
P

pete

Richard said:
Well, that's certainly an improvement, since no character can be a letter
/and/ a space. But this:

while(islower((unsigned char)c) || (c == ' '))

is better still, since it doesn't rely on lower case letters being
contiguous and in alphabetical order.

How would you write islower in C,
if you didn't care about the consequences of undefined behavior ?

I've got this:

#include <limits.h>
#include <string.h>

#define LOWER "abcdefghijklmnopqrstuvwxyz"

int islower(int c)
{
return CHAR_MAX >= c && c > '\0' && strchr(LOWER, c) != NULL;
}
 
D

Dan Pop

In said:
How would you write islower in C,
if you didn't care about the consequences of undefined behavior ?

I've got this:

#include <limits.h>
#include <string.h>

#define LOWER "abcdefghijklmnopqrstuvwxyz"

int islower(int c)
{
return CHAR_MAX >= c && c > '\0' && strchr(LOWER, c) != NULL;
}

The idea is that some programs make intensive use of the <ctype.h> stuff,
so you want them to be as fast as possible. They're usually implemented
using a lookup table defining a number of attributes (as binary flags)
for each character. Each function simply gets the flags value associated
with the corresponding character and ANDs it with a mask preserving only
the relevant bit(s).

A change of locale simply means using another lookup table. OTOH,
<wctype.h> stuff may need to be handled differently...

Have a look at Plauger's book.

Dan
 
D

Darklight

Below is a program taken from a book that does the same thing
you are trying to do hope it helps!

/* Program: Coder.c
* Usage: Coder [filename] [action]
* where filename = filename for/with coded data
* where action = D for decode anything else for
* coding
*--------------------------------------------------------------*/

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

int encode_character( int ch, int val );
int decode_character( int ch, int val );

int main( int argc, char *argv[])
{
FILE *fh; /* file handle */
int rv = 1; /* return value */
int ch = 0; /* variable to hold a character */
unsigned int ctr = 0; /* counter */
int val = 5; /* value to code with */
char buffer[256]; /* buffer */

if( argc != 3 )
{
printf("\nError: Wrong number of parameters..." );
printf("\n\nUsage:\n %s filename action", argv[0]);
printf("\n\n Where:");
printf("\n filename = name of file to code or decode");
printf("\n action = D for decode or C for encode\n\n");
rv = -1; /* set return error value */
}
else
if(( argv[2][0] == 'D') || (argv [2][0] == 'd' )) /* to decode */
{
fh = fopen(argv[1], "r"); /* open the file */
if( fh <= 0 ) /* check for error */
{
printf( "\n\nError opening file..." );
rv = -2; /* set return error value */
}
else
{
ch = getc( fh ); /* get a character */
while( !feof( fh ) ) /* check for end of file */
{
ch = decode_character( ch, val );
putchar(ch); /* write the character to screen */
ch = getc( fh);
}

fclose(fh);
printf( "\n\nFile decoded to screen.\n" );
}
}
else /* assume coding to file. */
{

fh = fopen(argv[1], "w");
if( fh <= 0 )
{
printf( "\n\nError creating file..." );
rv = -3; /* set return value */
}
else
{
printf("\n\nEnter text to be coded. ");
printf("Enter a blank line to end.\n\n");

while( fgets(buffer, 256, stdin) != NULL )
{
if( strlen (buffer) <= 1 )
break;

for( ctr = 0; ctr < strlen(buffer); ctr++ )
{
ch = encode_character( buffer[ctr], val );
ch = fputc(ch, fh); /* write the character to file */
}
}
printf( "\n\nFile encoded to file.\n" );
fclose(fh);
}

}
return rv;
}

int encode_character( int ch, int val )
{
ch = ch + val;
return ch;
}

int decode_character( int ch, int val )
{
ch = ch - val;
return ch;
}
 
T

The Real OS/2 Guy

I've got this:

#include <limits.h>
#include <string.h>

#define LOWER "abcdefghijklmnopqrstuvwxyz"

int islower(int c)
{
return CHAR_MAX >= c && c > '\0' && strchr(LOWER, c) != NULL;
}

try to test the strings


"MÄHMASCHINE"
"mähen"
"büßen"
.......

fails miserably on characters used by french, italian, german,
norways, .........
The world is not US only.

islower() works correctly on them when LC_LOCALE is set correctly.
 
P

pete

The said:
try to test the strings

"MÄHMASCHINE"
"mähen"
"büßen"
......

fails miserably on characters used by french, italian, german,
norways, .........
The world is not US only.

islower() works correctly on them when LC_LOCALE is set correctly.

I don't have LC_LOCALE in my version of N869.

Is it possible for a conforming implementation to only support
the "C" locale ?
 
P

pete

Dan said:
The idea is that some programs make intensive use
of the <ctype.h> stuff,
so you want them to be as fast as possible.

I'm interested in simple portable ways of expressing
standard library functions, minimally, for academic reasons.
 
T

The Real OS/2 Guy

I don't have LC_LOCALE in my version of N869.

Is it possible for a conforming implementation to only support
the "C" locale ?
Yes - but that limits you to be unable to NOT use national language
support and makes your program userunfriendly.
 
D

Dave Thompson

Well, that's certainly an improvement, since no character can be a letter
/and/ a space. But this:
Plus it (quietly) fixes the spurious null loop body.
while(islower((unsigned char)c) || (c == ' '))
Although in general the cast is advisable, in the OP's code c is
(already) uchar, plus set from getchar which except for EOF (not
checked for) produces only uchar *values* though not uchar type.
is better still, since it doesn't rely on lower case letters being
contiguous and in alphabetical order.

Although the encrypt and decrypt functions, which you snipped, do.
Plus they rely on the codes for lowercase letters not being within 26
of either end of the range of unsigned char. Which does happen to be
the case for ASCII. And even for EBCDIC, which already failed the
contiguous criterion anyway, and doesn't satisfy that for *upper*case.

- David.Thompson1 at worldnet.att.net
 

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

Members online

No members online now.

Forum statistics

Threads
473,888
Messages
2,569,964
Members
46,293
Latest member
BonnieHamb

Latest Threads

Top