Errors in ROT13 code (C) - c

My program should take in a char, and encode it using ROT13 if it is a letter, and otherwise leave it the same, and then print the result.
My code below works for all lowercase letters, and uppercase letters A-M, but fails on uppercase letters N-Z, and other symbols/numbers. Any help appreciated :)
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#define TRUE 1
#define FALSE 0
#define UPPER_START 65
#define UPPER_END 90
#define LOWER_START 97
#define LOWER_END 122
#define UPPER_MID 77
#define LOWER_MID 109
void testEncode (void); int isValid (char cipherChar); char encode (char letter);
int main (int argc, char* argv[]) {
char cipherChar;
scanf("%c", &cipherChar);
if (isValid(cipherChar) == TRUE) {
printf("%c", encode (cipherChar));
} else if (isValid(cipherChar) == FALSE) {
printf("%c", cipherChar);
}
return EXIT_SUCCESS;
}
int isValid (char cipherChar) {
int valid;
if ((cipherChar >= UPPER_START) &&
(cipherChar <= UPPER_END)) {
valid = TRUE;
} else if ((cipherChar >= LOWER_START) &&
(cipherChar <= LOWER_END)) {
valid = TRUE;
} else {
valid = FALSE;
}
return valid;
}
char encode (char letter) {
if ((letter <= UPPER_MID) || (letter <= LOWER_MID)) {
letter = letter + 13;
} else {
letter = (letter - 13);
}
return letter;
}

ROT13 generally doesn't affect characters other than [A-Za-z], so I'd say just ignore those. unless you have some reason to rotate them as well. For example, sometimes 0-9 are treated with ROT5.
In any case, your if statement with the clause (letter <= UPPER_MID) || (letter <= LOWER_MID) basically says, "any character before 'a' gets 13 added to it", so that's why [N-Z] aren't working correctly. Instead, try breaking out the upper- and lower-case logic and handling the wrap-around per-case, like this:
if (letter >= UPPER_START && letter <= UPPER_END) {
letter = letter + 13;
if (letter > UPPER_END) {
letter -= 13;
}
} else if (letter >= LOWER_START && letter <= LOWER_END) {
letter = (letter + 13);
if (letter > LOWER_END) {
letter -= 13;
}
}

Related

Kernighan and Ritchie - exercise 3.3 (expand function)

I have solved the exercises 3.3 from the K&R book. The solution I have implemented seems to work, but is a bit verbose and there could be smarter way to write this code. I wanted to ask if there could be problems with the solution I implemented and if there were easier way to write it:
Write a function expand(s1,s2) that expands shorthand notations like
a-z in the string s1 into the equivalent complete list abc...xyz in
s2. Allow for letters of either case and digits, and be prepared to
handle cases like a-b-c and a-z0-9 and -a-z. Arrange that a leading or
trailing - is taken literally
My code is this one:
#include <stdio.h>
void expand(char s1[],char s2[]){
int j=0,i=0;
while(s1[j] != '\0'){
if (s1[j]>= 'a' && s1[j] <= 'z' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= 'a' && s1[j+2] <= 'z' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (s1[j]>= 'A' && s1[j] <= 'Z' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= 'A' && s1[j+2] <= 'Z' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (s1[j]>= '0' && s1[j] <= '9' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= '0' && s1[j+2] <= '9' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (j!= 0 && s1[j] == '-' && (s1[j-1] < s1[j+1])){
int z = s1[j+1]-(1+s1[j-1]);
int c;
for (c=0;c<=z;c++){
s2[i]= c+(s1[j-1]+1);
i++;
}
j=j+2;
}
else if ( s1[j]>= 32 && s1[j] <= 127 && (s1[j+1] != '-' || s1[j+1]>= 32 && s1[j+1] <= 127 )){
s2[i] = s1[j];
j++;
i++;
}
}
s2[i]='\n';
i++;
s2[i]='\0';
}
int main() {
int c;
char s2[100];
expand("-a-c,a-c-g,A-Z0-9--", s2);
printf("%s",s2);
}
The code works in this way:
First it check if there is a triplet of the kind "x-y" where x<y. Then if gives to the array the values from x to y included and jump to the next character after the triplet "x-y". The same is done for upper case letters and for numbers in further if conditions.
the condition else if (j!= 0 && s1[j] == '-' && (s1[j-1] < s1[j+1])) is used to check for cases like "a-c-d1". The code I have implemented in this example will work like this:
Since we start with the 0-th character in "a-c-d" and the pattern "x-y" is present, "abc" will be assigned to the array. then we will directly jump to the second - in "a-c-f". Since this second - is preceded by a letter "c" and followed by a letter "f", and "c"<"f", then the characters between "c" and "f" will be assigned to the array, excluding the initial "c". Then the index for the string will jump of two and reach 1.
Some other way :
you only to know the last char before - and if it is the same type as current one (lower or upper case letter or digit)
when you get a - and previous char is a letter or digit you know you may have to make expansion
if you have a letter or digit after - and it is corresponding to letter/digit before - you know you can expand from char before / to current one.
you do need to look forward but only save previous char and char before -
you do same kind of processing for each different char type (letter/digit)
You can find an example after :
#include <stdio.h>
// handle different char type
typedef enum E_chartype {
LowerCaseLetter,
UpperCaseLetter,
Digit09,
OtherChar
} E_chartype;
// save if we may have a posdible expansion
typedef enum E_states {
NothingStarted,
StartedExpansion
} E_states;
// find type of a char
E_chartype getCharType(char c) {
if ((c >= 'a') && (c <= 'z'))
return LowerCaseLetter;
if (( c >= 'A') && (c <= 'Z'))
return UpperCaseLetter;
if ((c >= '0') && (c <= '9'))
return Digit09;
return OtherChar;
}
void expandopt(char *inS, char *outS) {
// init output string to null string
outS[0] = 0;
char *endS = outS;
E_states automat = NothingStarted;
char savedChar = 0;
int currentIndex;
E_chartype prevCType=OtherChar,savedCType=OtherChar;
char savedC = 0,prevC=0;
// loop on input string
for (currentIndex = 0; inS[currentIndex] != 0;currentIndex++) {
// save current char in variable c for shorter writting
char c = inS[currentIndex];
printf("%c : ",c);
// save type of current char
E_chartype currentCType = getCharType(c);
switch (automat) {
// genersl case notjing yet started
case NothingStarted:
// possibkee expansion if previous chsr is letter or digit and current char is -
if ((prevCType != OtherChar) && (c == '-')) {
printf("start rep\n");
automat = StartedExpansion;
// save the previous char and its type as it eill br the reference fircexpansion
savedCType = prevCType;
savedC = prevC;
} else {
// reset and cooy current char to iutput
automat = NothingStarted;
printf("nothing\n");
*endS++ = c;
}
break;
case StartedExpansion:
// we make ecpansion only if still same char type and letter/digit is strictly after saved one
if ((currentCType == savedCType) && (c > savedC)){
printf("expansion ");
for (char newC
= savedC+1;newC <= c;newC++) {
*endS++ = newC;
}
// save char in case thrre id a - after, which mean nee expansion
savedC = c;
} else {
// save current chsrcsnd its type
savedCType = currentCType;
savedC = c;
// copy previous char (= -) whch was not vopief in case of expansion
*endS++ = prevC;
*endS++ = c;
}
automat = NothingStarted;
break;
}
// save current chsr and type
prevCType = currentCType;
prevC = c;
}
// add 0 at end of string
*endS = 0;
}
int main() {
expandopt("-a-c,a-c-g,A-Z0-9–",s2);
printf("%s\n",s2);
}
Sorry for the code formatting, I did not find good code editor on phone.

String character check

i should realize two very similar functions but i am having problems.
I have to read the string "username", this string can only contain letters (upper and lower case) and spaces.
I have to read the string "key", this string can only contain letters (upper and lower case) and numbers.
If the guidelines are not followed, the user must be able to retrieve the input.
Unfortunately, I cannot use special libraries (only stdio and stdlib).
I realized this:
void checkString(char *i){
int cont;
do {
scanf("%s", i);
if (checkStrLen(6, 6, i) != 0) { //function that controls the size of the string (min,max,string)
for(cont=0; cont<6;){
if((i[cont]>='0' && i[cont]<='9')||
(i[cont]>='A' && i[cont]<='Z')||
(i[cont]>='a' && i[cont]<='z')){
cont++;
}else{
printf("Not valid character");
printf("Try again");
}
}
}else{
printf("\nToo large string");
printf("\nTry again");
}
}while(1);
}
I was thinking of doing something similar.
For the first problem I would replace (i[cont]>='0' && i[cont]<='9') with (i[cont]==' ').
the problem is that I don't understand how to get out of the for if I find a forbidden character during the loop.
I was thinking of using a break, but that would get me out of the whole function.
any advice?
PS how does the function look like? can it be okay or is it completely wrong?
I think the do while loop is not necessary here. do the scanf and get user input first then call checkString. Inside checkString keep your if else statement.
char checkString(char *i){
int cont;
if (checkStrLen(6, 6, i) != 0) { //function that controls the size of the string (min,max,string)
for(cont=0; cont<6;){
if((i[cont]>='0' && i[cont]<='9')||
(i[cont]>='A' && i[cont]<='Z')||
(i[cont]>='a' && i[cont]<='z')){
cont++;
}else{
printf("Not valid character");
printf("Try again");
return i;
}
}
}
else{
printf("\nToo large string");
printf("\nTry again");
}
}
#include <stdio.h>
#define MAXSIZE 100
#define SIZELIM 6
#define true 1
#define false 0
// Returns length of string
// If possible, use strlen() from <string.h> instead
int strlen(char *str) {
char i;
for (i = 0; str[i] != 0 && str[i] != '\n'; i++);
return i;
}
// Returns 1 if strings are equal
// If possible, use strcmp() from <string.h> instead
int streq(const char *x, const char *y) {
char chrx = 1, chry = 1, i;
for (i = 0;
chrx != 0 && chry != 0 && chrx == chry;
chrx = x[i], chry = y[i], i++);
return chrx == chry;
}
// Returns 1 if chr is number or letter
// If possible, use isalnum() from <ctype.h> instead
int isalnum(const char chr) {
return (chr >= '0' && chr <= '9' ||
chr >= 'A' && chr <= 'Z' ||
chr >= 'a' && chr <= 'z');
}
// Checks if string contains numbers and letters only
int isvalid(const char *str) {
int valid = true;
for (int i = 0; str[i] != 0 && str[i] != '\n'; i++) {
if (!isalnum(str[i])) {
valid = false;
break;
}
}
return valid;
}
// Main
int main(void) {
char str[MAXSIZE];
for (;;) {
printf("> ");
fgets(str, MAXSIZE, stdin);
if (streq(str, "quit\n"))
break;
if (strlen(str) > SIZELIM || !isvalid(str)) {
if (strlen(str) > SIZELIM)
puts("String too large");
else if (!isvalid(str))
puts("Not a valid string");
puts("Try again"); }
}
return 0;
}
You can code those functions that you cannot import:
int letters_and_spaces(char c)
{
return c == ' ' || C >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
int letters_and_numbers(char c)
{
return c >= '0' && c <= '9' || C >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
And to use scanf to read spaces you can't use %s. You could change to:
scanf("%100[^\n]*c", i);
BE CAREFUL: I've put 100, supposing i has enough space for that. It will read up to 100 characters (or as many as the number you put there) or until find the \n.

Hello. My program keeps failing to create the string output I expect. Can you notice a flaw?

This function is meant to fill a second string with the filtered results of the first. the filter should remove all special characters and only print lower case permutations of all letters written
I've tried changing the nature of the "ModifyText" loop, and I've done it with pointers+while loop and with for loops both with the condition of ending when the iterator reaches a character \0.
These are the methods I've already tried, both continue to only return the lowercase "the" of the first word in the string, not the entire string with only lowercase alphabet letters
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//
//int ModifyText(char Stringboy[], char output[])
//{
// for(int i=0; Stringboy[i] != '\0'; i++)
// {
// if(Stringboy[i] >= 'A' && Stringboy[i] <= 'Z')
// {
// output[i] = Stringboy[i] + 32;
//
// }
// else if(Stringboy[i] >= 'a' && Stringboy[i] <= 'z')
// {
// output[i] = Stringboy[i];
// }
//}}
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
}
int main(void){
char samplearray[] = {"THE quick Brown Fox jumps over the Lazy Dog!***!"};
char dummy[83];
printf("Original Text: \n %s\n", samplearray);
ModifyText(samplearray, dummy);
printf("Modified Text: \n %s\n", dummy);
//letterCounter(dummy); //these two bottom functions have their prints written into them, so they need only be called
//wordCounter(dummy);
printf("length of sample array is %d", strlen(samplearray));
}
This code is only returning a string "the" when it should be returning a string "the quick brown fox jumps over the lazy dog" in the string entitled dummy
When *Stringboy is a space then you do not set *output since neither if condition is true. However, you do increment output. As a result the character after "the" in output will be random data (in your case is is probably NULL) which is why the string ends.
Change the code to this:
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
*output = '\0';
That way the spaces will be written to the output string.
In your original code, you increment the output pointer also when you didn't copy a letter. You either should write something (e.g. a space) or not increment the output pointer. If you increment the output pointer without writing something, whatever character was there before will stay there. If you're lucky that character is a zero (terminating your string), but it can also be any weird character, including character 7 (a bell sound).
Also, don't forget that your output string needs a terminating zero. Otherwise, weird uninitialized characters might pop up at the end of your string.
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
++output;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
++output;
}
++Stringboy;
}
*output = '\0'; // make sure the output gets a terminating zero
}
Here is a more fancy version, that outputs spaces to replace non-letters. To not get the output flooded with spaces, a boolean variable checks to maximally output one space between the words.
int ModifyText(char *Stringboy, char *output)
{
bool previousWasLetter = false;
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
++output;
previousWasLetter = true;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
++output;
previousWasLetter = true;
}
else if (previousWasLetter)
{
*output = ' ';
++output;
previousWasLetter = false;
}
++Stringboy;
}
*output = '\0'; // make sure the output gets a terminating zero
}
You have several mistakes:
You copy characters to a new string only if character is an uppercase letter or if the character is lowercase... but you don't copy anything, when it's not either. As you feed the function with an array allocated in the stack (recently allocated, so probably you got a new page zero filled) the character there could be a \0 char and so, delimited the string. You need to copy the character untouched in case it's not an uppercase character... not only if it is lowercase. This will allow you to copy the spaces (which are neither) for example. Resulting in this code:
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else // if(*Stringboy >= 'a' && *Stringboy <= 'z') // not needed
{
*output = *Stringboy;
}
you dont finalize the output string, putting a \0 character at the end. You should do it past the end of the loop, as the output pointer has been left pointing to the next output char, just add
*output = '\0';
next to the loop.
Some other minor changes (these cannot be considered mistakes, but will silence some warnings got from the compiler on some permitted language inconsistencies you made), like adding a return 0; statement to nonvoid returning functions (this should be a mistake in case you planned to return something from it), change the %d length format for a more portable %zd format string (if you have strlen() returning a long value and int and long are different size, this could lead to problems in some machines), and adding a new line \n character, so the shell prompt gets printed in the next line (and not just after the string length).
So, the code finally should be something like:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//
//int ModifyText(char Stringboy[], char output[])
//{
// for(int i=0; Stringboy[i] != '\0'; i++)
// {
// if(Stringboy[i] >= 'A' && Stringboy[i] <= 'Z')
// {
// output[i] = Stringboy[i] + 32;
//
// }
// else if(Stringboy[i] >= 'a' && Stringboy[i] <= 'z')
// {
// output[i] = Stringboy[i];
// }
//}}
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else // if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
*output = '\0';
return 0;
}
int main(void){
char samplearray[] = "THE quick Brown Fox jumps over the Lazy Dog!***!"; // braces unneeded.
char dummy[83];
printf("Original Text: \n %s\n", samplearray);
ModifyText(samplearray, dummy);
printf("Modified Text: \n %s\n", dummy);
//letterCounter(dummy); //these two bottom functions have their prints written into them, so they need only be called
//wordCounter(dummy);
printf("length of sample array is %zd\n", strlen(samplearray));
return 0;
}

Palindrome C program convert capital letters to small letters [duplicate]

This question already has answers here:
Implementation of ToLower function in C
(4 answers)
Closed 5 years ago.
At school Im working on a palindrome C program. I'm almost done, but I would like my program to mark both 'Anna' and 'anna' as a palindrome. I tried some stuff out but nothing really worked.
My code :
#include <stdio.h>
#include <string.h>
int main() {
char palindroom[50],a;
int lengte, i;
int woord = 0;
printf("This program checks if your word is a palindrome.\n");
printf("Enter your word:\t");
scanf("%s", palindroom);
lengte = strlen(palindroom);
for (i = 0; i < lengte; i++) {
if (palindroom[i] != palindroom[lengte - i - 1]) {
woord = 1;
break;
}
}
if (woord) {
printf("Unfortunately, %s is not palindrome\n\n", palindroom);
}
else {
printf("%s is a palindrome!\n\n", palindroom);
}
getchar();
return 0;
}
I've seen some people using tolower from ctype.h but I'd like to avoid that.
So my question is : how do I convert all uppers to lowers in a string?
[ps. some words I may code might seem odd, but that's Dutch. Just erase an o and you'll understand]
Thanks.
the difference between uppercase and lowercase in ASCII table is 32 so you can add 32 if an uppercase letter is in the input to convert it to lowercase ( http://www.asciitable.com/ ) :
if ((currentletter > 64) && (currentletter < 91))
{
char newletter;
newletter = currentletter + 32;
str[i] = newletter;
}
else
{
str[i] = currentletter;
}
modified program :
#include <stdio.h>
#include <string.h>
int main() {
char palindroom[50],a;
int lengte, i;
int woord = 0;
printf("This program checks if your word is a palindrome.\n");
printf("Enter your word:\t");
scanf("%s", palindroom);
lengte = strlen(palindroom);
for (i = 0; i < lengte; i++)
{
if (palindroom[i] > 64 && palindroom[i] < 91)
{
palindroom[i] = palindroom[i] + 32;
}
if (palindroom[i] != palindroom[lengte - i - 1]) {
woord = 1;
break;
}
}
if (woord) {
printf("Unfortunately, %s is not palindrome\n\n", palindroom);
}
else {
printf("%s is a palindrome!\n\n", palindroom);
}
getchar();
return 0;
}
65 is the decimal representation of A in the ASCII table, 90 is the decimal representation of Z while a is 97 ( = 65 +32 ) and z is 122 ( = 90 +32 )
If you want don't want to use tolower or toupper you can do this:
// tolower
char c = 'U';
char lower_u = c | 0x20
// toupper
char c = 'u';
char upper_u = c & 0xdf
In ASCII the difference between a lower and an upper character is the 5th bit.
When The 5th bit is 0, you get an upper character, when the 5th bit is 1, you get a lower character.

Translating user input program in C error

I am trying out a program which translates user input based on the below rules:
If the character is a letter, it must be printed in upper case.
If the character is a number (0-9), an asterisk (*) must be printed instead.
If the character is a double quote ("), a single quote (') must be printed instead.
If the character is the backslash "\" then it is skipped (not printed), and the next character is printed without any modifications.
Otherwise, the character is printed as-is.
MyCode
#include <stdio.h>
void lowertoupper(char lower)
{
char upper;
if(lower >= 'a' && lower <= 'z'){
upper = ('A' + lower - 'a');
}
else{
upper = lower;
}
printf("%c",upper);
}
int main(void) {
char chara;
printf("please enter");
while(scanf(" %c", &chara)!= EOF) {
if ((chara>='a' && chara<='z')||(chara>='A' && chara<='Z'))
{
lowertoupper(chara);
}
else if (chara>=0 && chara<=9)
{
printf("*");
}
else if (chara=='"')
{
printf("'");
}
else if (chara=="\\")
{
}
else {
printf("%c",chara);
}
}
}
My questions
This doesn't as expected. What conditions am I missing here.
How can I satisfy the condition 4 without using any built in function.
int noChange = 0; /* Added */
while(scanf(" %c", &chara) == 1) { /* Modified */
if(noChange == 1) { /* Added */
printf("%c",chara); /* Added */
noChange = 0; /* Added */
} /* Added */
else if ((chara>='a' && chara<='z')||(chara>='A' && chara<='Z')) /* Modified */
{
lowertoupper(chara);
}
else if (chara >= '0' && chara <= '9') /* Modified */
{
printf("*");
}
else if (chara=='"')
{
printf("'");
}
else if (chara=='\\') /* Modified */
{
noChange = 1; /* Added */
}
else {
printf("%c",chara);
}
}
Working demo here
This also works, comparing chara stores the ascii value, so ascii value of '0' is not 0.
#include <stdio.h>
int main() {
char chara = '\0';
while(scanf("%c", &chara) == 1) {
if ( chara>='a' && chara<='z' ) printf("%c",'A' + (chara - 'a'));
else if (chara >= '0' && chara <= '9') printf("%c",'*');
else if (chara=='"') printf("%c",'\'');
else if (chara=='\\') ;
else printf("%c",chara);
}
}
Your test for digits is problem. The digit characters are '0' through '1', whose actual value depends on the local charset but are never 0 through 9.

Resources