So, wanting to learn at least the basics of C before I continue with C++, I'm writing some small programs to understand it better. (And soon, a small Text-Based Adventure Game, for the purpose of learning how to cope without Objects! LOL)
Anyway, I just want code critique, as I have never used the C input functions (I admit, I have used and like printf()printf()! Even I even made my own sprintf()sprintf(), compatible with the C++ string class.)
I hope my code is good. I tend to get code to work properly, completely ignoring formatting and performance, then later once it works I make it look nice. (Andand run nicenicely.)
Here it is! Hope I did well :)caesar.c
UPDATE: Fixed a couple minor bugs
#include <string.h> /* for strlen() */
#include "caesar.h"
char *getCipherText(char *src, int key) {
int len = strlen(src);
int i = 0;
int ch = 0;
/* Loop over each char in src */
for (i = 0; i < len; i++) {
ch = (int)src[i]; /* Convert the char to int to prevent many uneccecary casts */
if (ch >= 65 && ch <= 90) { /* If the char is uppercase */
ch += key; /* add the key */
if (ch > 90) ch -= 26; /* if the char is higher than the highest uppercase char, sub 26 */
if (ch < 65) ch += 26; /* if the char is lower than the lowest uppercase char, add 26 */
src[i] = (char)ch; /* set the current char in src to the char value of ch */
} else if (ch >= 97 && ch <= 122) { /* else if it's lowercase */
ch += key; /* add the key */
if (ch > 122) ch -= 26; /* if the char is higher than the highest lowercase char, sub 26 */
if (ch < 97) ch += 26; /* if the char is lower than the lowest lowercase char, add 26 */
src[i] = (char)ch; /* set the current char in src to the char value of ch */
}
/* an else case is not needed, since we are modifying the original. */
}
/* Return a pointer to the char array passed to us */
return src;
}
char *getPlainText(char *src, int key) {
/* Since getCipherText adds the key to each char, adding a negative key
* is equivalent to subtracting a positive key. Easier than re-implementing.
*/
return getCipherText(src, -key);
}
UPDATE 2: Improved code syntax - Thanks for the pointer about char pointers! :)caesar.h
UPDATE 3: Total reconstruction of the syntax, minimizing the code size - Thanks!!!!
char *getCipherText(char *src, int key);
char *getPlainText(char *src, int key);
main.cmain.c
#include <stdio.h> /* for printf(), sscanf(), fgetc() and fgets() */
#include <stdio<stdlib.h>
/* for malloc() and free() */
#include <stdlib<string.h>
/* for strlen() */
#include <ctype"caesar.h>h"
/* Size of text intbuffer encodeto read into */
#define BUFS 1024
/* Size of buffer for reading misc. items, i.e. for the get_int(int) chfunction */
#define TBUFS 128
/* Get char, no new lines */
int keygetc_nnl() {
int ch = '\n';
/* While ch is ifa (islowernewline or carriage return, read another char */
while (ch == '\n' || ch == '\r')
ch = fgetc(stdin);
{
/* Return the char, promoted to an integer */
return ch;
}
/* Get an integer */
int get_int() {
char ch*s = (ch-'a'char*)malloc(TBUFS); +s[0] key)= %'\0';
26 + 'a'; int i = 0;
/* Read a string, and later parse the int in case there are no ints to chread +=*/
while (chstrlen(s) <<= 'a'1) ?
26 : 0; fgets(s, TBUFS, stdin);
/* Parse the int. }Using sscanf because scanf on stdin leaves the file caret at a unknown position. */
sscanf(s, "%d", &i);
else /* Return the int - if (isuppersscanf found nothing, it's already 0 */
return i;
}
int main(ch)int argc, char *argv[]) {
char *text = NULL;
int key = 0;
int ch = (ch-'A'0;
+ key while(1) %{ 26 +/* 'A';Forever loop, until we break; out */
/* Prompt for an option */
ch += printf(ch"Encrypt, <Decrypt, 'A')or Quit? 26 :(e/d/q) 0;");
ch = getc_nnl();
}
/* Make sure they returngave ch;
us a valid option - }
if not, keep prompting! */
int decode while (intch != 'e' && ch, int!= key'E' && ch != 'd' && ch != 'D' && ch != 'q' && ch != 'Q') {
returnprintf("Invalid encodeoption. Encrypt, Decrypt, or Quit? (e/d/q) ");
ch, -key= getc_nnl();
}
int main(int argc, char **argv)/* {If the user wants to quit... */
if (ch == 'q' int|| ch;ch == 'Q')
intbreak; key;/* ...then break out of the loop */
/* Allocate buffer for iftext (argcI <set 2text[0] to a null-terminator due to later strlen() {calls) */
text = (char*)malloc(BUFS); text[0] = '\0';
printf("USAGE: cipher
<integer key> <encode | decode>\n");
/* Get the text to encrypt - If user entered nothing,
* or printffgets("Then) is reading only a newline (from the fgetc calls), justkeep typereading.
your text and it will automatically output the en*/de
crypted text! printf("Please enter your text:)\n" ");
while (strlen(text) <= 1)
fgets(text, returnBUFS, 1;stdin);
}
/* Get the integer key =to atoiencrypt/decrypt with. If it's invalid, keep prompting! :) */
printf(argv[1]"Ok, now what key should I use? (1 - 25) ");
key = get_int();
if while (key < 1 || key > 25) {
printf("Invalid key. Please enter a number between 1 and 25: ");
printf("Key is invalid, or out of range. Valid keys are integers 1key through= 25.\n"get_int();
}
return 1;
/* Ok, we have our data - now, did }
they say encrypt or decrypt? */
int (*f)if (int,ch int)== ='e' (argv[2][0]|| ch == 'd''E') ? {
/* Encrypt, and print the result */
decode :
getCipherText(text, key);
encode;
printf("Ok. Here's your encrypted text: %s\n", text);
while (EOF != (ch=getchar} else if ())ch == 'd' || ch == 'D') {
/* Decrypt, and print the result */
putchar(f getPlainText(chtext, key);
printf("Ok. Here's your decrypted text: %s\n", text);
}
return 0; /* Free our malloc, so we don't have a memory overrun */
free(text);
}
return 0;
}