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.
Related
How to detect a alphabet if its a vowel or not with C? Here is my programme
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
int main(){
char input;
scanf("%c", &input);
if(isupper(input)){
printf("it's capital letter.\n");}
else{
printf("it's small letter.\n");}
int C = ((int)input); //Change C from a char to sacii code
int intarray[10] = {65, 69, 73, 79, 85, 97, 101, 105, 111, 117}; //array of vowel
for(int i = 0; i < 10; i++){
if(C == intarray[i]){ //cheaking if C is a vowel or not
printf("Yes\n"); //print if it is
break;}
else{
printf("No\n"); //print if not
break;}
}
INPUT
o
OUTPUT
it's a small letter.
No
You have a simple logic flow in your program.
The rules are:
It is a vowel if you found one element in your array that matches.
It is not a vowel if you do not find any matching value in your array.
That implies that you must search the whole array to find a vowel. Only after reaching the end of your array you can be sure it is not a vowel.
Besides that you should not use magic numbers if you want to store characters.
Try this:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
int main(void)
{
char input;
scanf("%c", &input);
if (isupper(input)) {
printf("it's capital letter.\n");
}
else {
printf("it's small letter.\n");}
static const char vowels[] = "aeiouAEIOU";
bool found = false;
for (int i = 0; i < 10; i++) {
if (C == vowels[i]) { //cheaking if C is a vowel or not
found = true;
break; // Do not continue search.
}
}
if (found == true) {
printf("Yes\n"); //print if it is a vowel
}
else {
printf("No\n"); // No vowel found.
}
}
}
I changed that vowel array to a string, i.e. I added space for nul-terminator.
That means you could use standard functions like strchr to check if a character is in that string.
That for loop would not be required then:
if (strchr(vowels, c) != NULL)
found = true; // We have a vowel
It is in your power to create your own lookup table that serves your needs.
Below is a LUT for 7-bit ASCII characters, populated to indicate the nature of the 128 ASCII values commonly used.
And there is a short bit of code that uses the LUT to determine the nature of a character (alpha or no, vowel or no) entered by the user.
#include <stdio.h>
char tbl[] =
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"Spppppppbbppppppddddddddddpppppp"
"pVCCCVCCCVCCCCCVCCCCCVCCCCCbpbpp"
"pvcccvcccvcccccvcccccvcccccbpbpp" ;
int main() {
int c = getchar();
int cX = tbl[ c ];
if( cX == 'C' || cX == 'V' )
printf( "%c is a capital letter\n", c );
else
if( cX == 'c' || cX == 'v' )
printf( "%c is a small letter\n", c );
else
printf( "%c is not a letter at all\n", c );
if( cX == 'V' || cX == 'v' )
printf( "%c is a vowel\n", c );
else
printf( "%c is not a vowel\n", c );
return 0;
}
There should be nothing difficult in the code above. The only difficulty is running the program over-and-over.
So, using 3 strings, we can exercise the table a little bit more.
#include <stdio.h>
char tbl[] = // the 'crafted' LUT
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"Spppppppbbppppppddddddddddpppppp"
"pVCCCVCCCVCCCCCVCCCCCVCCCCCbpbpp"
"pvcccvcccvcccccvcccccvcccccbpbpp" ;
int main() {
char *smpl[] = { // 3 sample strings of characters
"ABCDEFGHIJKLM01234NOPQRSTUVWXYZ(,=$)",
"abcdefghijklm01234nopqrstuvwxyz[,=$]",
"Twas BRILLIG and the Slithey toves...\t",
};
const int nNum = sizeof smpl/sizeof smpl[0]; // how many?
for( int i = 0; i < nNum; i++ ) {
puts( smpl[i] ); // show the string
// now replace each character with its 'nature' (digit, vowel, etc.)
for( int r = 0; smpl[i][r]; r++ )
smpl[i][r] = tbl[ smpl[i][r] ];
puts( smpl[i] ); // show transformed string
puts( "" ); // blank line separator
}
printf(
"Legend:\n"
"\tX - control char\n"
"\tS - SP(ace)\n"
"\tp - punctuation\n"
"\tb - bracket/brace\n"
"\td - digit\n"
"\tC - consonant\n"
"\tV - vowel\n"
);
return 0;
}
And the output of the 2nd version looks like...
ABCDEFGHIJKLM01234NOPQRSTUVWXYZ(,=$)
VCCCVCCCVCCCCdddddCVCCCCCVCCCCCbpppb
abcdefghijklm01234nopqrstuvwxyz[,=$]
vcccvcccvccccdddddcvcccccvcccccbpppb
Twas BRILLIG and the Slithey toves...
CcvcSCCVCCVCSvccSSccvSCcvccvcScvcvcpppX
Legend:
X - control char
S - SP(ace)
p - punctuation
b - bracket/brace
d - digit
C - consonant
V - vowel
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
string k = argv[1];
string s = GetString();
int l = strlen(k);
for(int i = 0, n = strlen(s); i < n; i++)
{
if(s[i] >= 65 && s[i] <= 90)
{
int i2 = ((s[i]-65) + (k[i%l]-97)) % 26;
printf("%c", i2+65);
} else if(s[i] >= 97 && s[i] <= 122)
{
int i2 = ((s[i]-97) + (k[i%l]-97)) % 26;
printf("%c", i2+97);
} else
{
printf("%c", s[i]);
}
}
printf("\n");
return 0;
}
I have removed as many parts as I can in order to make the code more relevant to the question. Basically why does this code work when "s" does not have any space(" ") in it and doesn't when "s" consists of space(" ")?
As most of you may know the idea is the argument entered at argv[1] is the "keyword" for the cipher. User then inputs a "plain-text" to cipher (s). It works when I try with various words or sentences if it doesn't include any space, " ". I just don't understand the logic behind this. Why does the cycle break if s[i] is not one of the first two conditions - I would have thought that "else" condition would work.
I would really appreciate it if someone can shed some light on this - many thanks in advance!
ps: I know there are some extra libraries at the top and the user input at argv[1] is not verified via isalpha(). I just want to understand the cycle process better for now, I have those checks in another file ready.
Here is code that implements the 'separate counters for string and key' comment that I made. It also uses the letter codes 'a' and 'A' (and avoids needing to use 'z' or 'Z') instead of using numbers. It does assume that you are dealing with a single-byte code set (not UTF-8 unless you're working in the ASCII range) where the lower-case and upper-case letters are each in a contiguous range (so it won't work reliably with EBCDIC, but will with most other code sets), and it also ignores accented characters. (It would have to do setlocale("") to get locale-specific interpretations of which characters are letters.)
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s key\n", argv[0]);
return 1;
}
string k = argv[1];
int l = strlen(k);
for (int i = 0; i < l; i++)
{
int c = k[i];
if (!isalpha(c))
{
fprintf(stderr, "%s: non-alpha character %c in key string\n", argv[0], c);
return 1;
}
k[i] = tolower(c);
}
printf("Enter a string to be encrypted:\n");
string s = GetString();
int n = strlen(s);
for (int i = 0, j = 0; i < n; i++)
{
int c = (unsigned char)s[i];
if (isupper(c))
c = ((c - 'A') + (k[j++ % l] - 'a')) % 26 + 'A';
else if (islower(c))
c = ((c - 'a') + (k[j++ % l] - 'a')) % 26 + 'a';
putchar(c);
}
putchar('\n');
return 0;
}
Here is a sample run that demonstrates the weakness of using 'a' as one of the letters in the key for this Vigenere cipher:
./vc caesArandAbrAcaDabRa
Enter a string to be encrypted:
It is reported that Caesar said "Veni, vidi, vici" when he conquered Britain.
Kt mk rvpbutfu tjaw Cbvscr wsiu "Vrqi, wzdk, vlcj" nhgn lw cfndxesvd Drltbzn.
I'm new to programming and I need some help in getting my program to work because I am kind of stuck at the moment. It's suppose to count the frequency of a letter and other characters for an input text file then print out the results but nothing happens when I do insert a file (but it does compile). This is what I have so far. I think its because I don't return the results of the array back into the main function so it can print out, but I am not sure how to do this. Would you need to use malloc (e.g. int *alphabetCount = (int *)malloc(sizeof(int)*ALPHABET_SIZE);) for the array then free it later?
Any help would be appreciated!
#include <stdio.h>
#include <stdlib.h>
#define ALPHABET_SIZE 26
#define FIRST_LC_LETTER 'a'
#define LAST_LC_LETTER 'z'
#define FIRST_UC_LETTER 'A'
#define LAST_UC_LETTER 'Z'
int freqAnalysis (int inputChar);
int main (int argc, char *argv[]) {
int inputChar = getchar();
int position = 0;
char alphabet [ALPHABET_SIZE] = {'a','b','c','d','e','f','g','h','i','j',
'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int alphabetCount [ALPHABET_SIZE];
freqAnalysis (inputChar);
while (position < ALPHABET_SIZE) {
printf ("Letter %c: %d\n",alphabet[position],alphabetCount[position]);
position++;
}
return EXIT_SUCCESS;
}
int freqAnalysis (int inputChar) {
int counter;
int numbers;
int spaces;
int specialChar;
int alphabetCount [ALPHABET_SIZE];
while (counter < ALPHABET_SIZE) {
counter = 0;
alphabetCount [counter] = 0;
counter ++;
}
while (inputChar != EOF) {
if (inputChar >= FIRST_LC_LETTER && inputChar <= LAST_LC_LETTER) {
alphabetCount [inputChar - FIRST_LC_LETTER] ++;
} else if (inputChar>=FIRST_UC_LETTER && inputChar<=LAST_UC_LETTER) {
alphabetCount [inputChar - FIRST_UC_LETTER] ++;
} else if (inputChar >= 0 && inputChar <= 9) {
numbers = 0;
numbers ++;
} else if (inputChar == ' ') {
spaces = 0;
spaces ++;
} else {
specialChar = 0;
specialChar ++;
}
}
printf ("Numbers: %d\nSpaces: %d\n Special characters: %d\n", numbers,
spaces, specialChar);
}
Here is a similar approach to consider. It has been written to remove dependencies from all libc header files except stdio.h. Rather than calling the character classification functions in ctype.h it relies on the ASCII values for each of the characters to set the alphabetCount indexes. Neither approach is better/worse than the other, they just illustrate different ways of approaching the same problem with the various tools available.
#include <stdio.h>
#define ALPHABET_SIZE 26
void freqAnalysis (FILE *fp, int *cnt);
int main (void)
{
int position = 0;
char *alphabet = "abcdefghijklmnopqrstuvwxyz";
int alphabetCount[ALPHABET_SIZE] = {0};
printf ("\nThe frequency analysis of the input characters:\n\n");
freqAnalysis (stdin, alphabetCount);
for (position = 0; position < ALPHABET_SIZE; position++)
printf (" %c/%c : %d\n", alphabet[position] - 32,
alphabet[position], alphabetCount[position]);
return 0;
}
void freqAnalysis (FILE *fp, int *cnt)
{
int c, numbers, spaces, specialChar;
c = numbers = spaces = specialChar = 0;
while ((c = fgetc (fp)) != '\n' && c != EOF)
{
if (c >= 'A' && c <= 'Z')
cnt[c - 'A']++;
else if (c >= 'a' && c <= 'z')
cnt[c - 'a']++;
else if (c >= '0' && c <= '9')
numbers++;
else if ( c == ' ' )
spaces++;
else
specialChar++;
}
printf (" Numbers : %d\n Spaces : %d\n Special : %d\n\n", numbers, spaces, specialChar);
}
Output
$ ./bin/charcount <<<"The Quick Brown Fox Jumps Over 1001 Lazy Dogs."
The frequency analysis of the input characters:
Numbers : 4
Spaces : 8
Special : 1
A/a : 1
B/b : 1
C/c : 1
D/d : 1
E/e : 2
F/f : 1
G/g : 1
H/h : 1
I/i : 1
J/j : 1
K/k : 1
L/l : 1
M/m : 1
N/n : 1
O/o : 4
P/p : 1
Q/q : 1
R/r : 2
S/s : 2
T/t : 1
U/u : 2
V/v : 1
W/w : 1
X/x : 1
Y/y : 1
Z/z : 1
policy of modified to be processed by passing a file handle and an secured array in main.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define ALPHABET_SIZE 26
#define FIRST_LC_LETTER 'a'
#define FIRST_UC_LETTER 'A'
void freqAnalysis(FILE *fin, int counter[]);
int main (int argc, char *argv[]) {
int position;
char alphabet[ALPHABET_SIZE] = {'a','b','c','d','e','f','g','h','i','j',
'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};//unused
int alphabetCount[ALPHABET_SIZE] = {0};
freqAnalysis(stdin, alphabetCount);
for (position = 0; position < ALPHABET_SIZE; position++){
printf ("Letter %c: %d\n", alphabet[position], alphabetCount[position]);
}
return EXIT_SUCCESS;
}
void freqAnalysis(FILE *fp, int alphabetCount[]) {
int inputChar;
int numbers , spaces, specialChar;
numbers = spaces = specialChar = 0;
while((inputChar=fgetc(fp)) != EOF) {
if(islower(inputChar)){
alphabetCount[inputChar - FIRST_LC_LETTER]++;
} else if(isupper(inputChar)) {
alphabetCount[inputChar - FIRST_UC_LETTER]++;//this relies on order of character codes.
} else if(isdigit(inputChar)) {
numbers++;
} else if(inputChar == ' ') {//isspace(inputChar)
spaces++;
} else {
specialChar ++;
}
}
printf("Numbers: %d\nSpaces: %d\nSpecial characters: %d\n", numbers,
spaces, specialChar);
}
I'm attempting to create a very simple encryption where a string is scanned, and the ascii code is increased by 5 (+5). When the letters reach the end of the alphabet it wraps back around to the beginning (same with numbers). punctuation and any other symbols are not encrypted. The encryption function seems to be working, however I'm having trouble passing the string back to the main function. What has gone wrong?
Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*function definitions */
char encrypt(char input_string[]);
int main(void)
{
char input_string[25];
char new_string[25];
char encrypted_string[25];
int i = 0;
// scan word
printf("Enter word: ");
scanf(" %[^\n]", input_string);
fflush(stdin);
//check input
printf("%s\n", input_string);
// call encrypt function
encrypted_string[25] = encrypt(input_string);
// print encrypted version
printf("encrypted: %s\n\n", encrypted_string);
return 0;
}
char encrypt(char input_string[])
{
char new_string;
static char str[25];
int i;
for(i = 0; i < 25; i++)
{
if (input_string[i] > 96 && input_string[i] < 118) // for a - u
{
new_string = (input_string[i] + 5);
}
else if (input_string[i] > 117 && input_string[i] < 123) // for v - z
{
new_string = (input_string[i] - 21);
}
else if (input_string[i] > 64 && input_string[i] < 86) // for A - U
{
new_string = (input_string[i] + 5);
}
else if (input_string[i] > 85 && input_string[i] < 91) // for V - Z
{
new_string = (input_string[i] - 21);
}
else if (input_string[i] > 47 && input_string[i] < 53) // for 0 - 4
{
new_string = (input_string[i] + 5);
}
else if (input_string[i] > 52 && input_string[i] < 58) // for 5 - 9
{
new_string = (input_string[i] - 5);
}
else
{
new_string = input_string[i];
}
str[i] = new_string;
}
printf("\n\n");
i=0;
//check asccii codes
while(str[i])
{
printf("%d ", str[i++]);
}
//print string
printf("\n\n%s\n\n", str);
//return string to main
return(str[25]);
}
return(str[25]); means you're trying to return the value of the 26th element,[which is out-of-bound access], not the address of the string.
encrypted_string[25] = encrypt(input_string);
No, you cannot assign a string return like that. It's wrong in many ways.
To correct, follow the below steps.
change char encrypt(char input_string[]) to char* encrypt(char input_string[])
use return(str); instead of return(str[25]);
instead of char encrypted_string[25];, write char * encrypted_string;
NOTE:
using static array will do the job, but IMO, a better approach will be allocating the array dynamically and return the pointer after populating from encrypt() function. You can later free() the pointer from main().
Your function:
char encrypt(char input_string[])
literally says that it accepts a long string as input, and returns just a single character as output.
That seems very dubious.
Don't you want it to return a string as output, not just one letter?
I'm trying to make a Vigenere cipher code in C and I have done something that is wrong and I can't fix it... How do understand that something goes wrong? Well I have some examples with keyword and result cipher with Vigenere cipher like
keyword: bacon
text: Meet me at the park at eleven am
correct result: Negh zf av huf pcfx bt gzrwep oz
my code result with same text and keyword: Tegh ne og tjs qaty bt syfvgb bm
Code:
int main(int argc, string argv[])
{
string keyWord;
if( argc != 2 )
{
printf("Wrong Argument");
return 1;
}
else
{
keyWord = argv[1];
//check if argument is
//only alphabetical characters
for(int i = 0; i < strlen(keyWord); i++)
{
char c = keyWord[i];
if( !isalpha(c) )
{
printf("Your Keyword Must Contain Only alphabetical characters\n");
return 1;
}
}
}
//todo
printf("Enter Plain Text\n");
string plainText = GetString();
for(int i = 0; i < strlen(plainText); i++)
{
char c = plainText[i];
int keyWordWrapper;
char keyC;
if(isalpha(c))
{
keyWordWrapper = i % strlen(keyWord);
keyC = keyWord[keyWordWrapper];
if(islower(c))
{
int key = keyC - 'a';
c = (c - 'a' + key) % 26 + 'a';
}
if(isupper(c))
{
int key = keyC - 'A';
c = (c - 'A' + key) % 26 + 'A';
}
}
printf("%c",c);
}
printf("\n");
return 0;
}
GetString() is declared in a header and defined in a library that I'm using (it's like scanf).
this is the updated code
int main(int argc, string argv[])
{
string keyWord;
if( argc != 2 )
{
printf("Wrong Argument");
return 1;
}
else
{
keyWord = argv[1];
//check if argument is
//only alphabetical characters
for(int i = 0; i < strlen(keyWord); i++)
{
char c = keyWord[i];
if( !isalpha(c) )
{
printf("Your Keyword Must Contain Only alphabetical characters\n");
return 1;
}
}
}
string plainText = GetString();
int j;
for(int i = 0; i < strlen(plainText); i++)
{
j++;
char c = plainText[i];
int keyWordWrapper;
char keyC;
if(j > strlen(keyWord))
j = 0;
if(isalpha(c))
{
keyWordWrapper = i % strlen(keyWord);
keyC = keyWord[keyWordWrapper];
int key;
tolower(c);
if(islower(keyC))
key = keyC - 'a';
if(isupper(keyC))
key = keyC - 'A';
c = (c - 'a' + key) % 26 + 'a';
}
printf("%c",c);
}
printf("\n");
return 0;
}
There are two problems in the code.
First is the treatment of upper case letters in the keyword. Note that in one case, the code subtracts a from keyC, and in the other A is subtracted. But that's based on the case of the plain text character. That subtraction needs to be based on the case of the letter in the keyword.
Second, the code advances to the next character in the keyword for every character in the plain text. The "correct result" doesn't advance to the next character of the keyword if the plain text character is a space character.
Here's an example of what I'm talking about for the second problem
text Meet me at
keyC baco nb ac
i 0123456789 i must always increment to the next char in plain text
k 0123 40 12 index into the keyword does not increment on non-alpha
Therefore k cannot be computed directly from i with the line
keyWordWrapper = i % strlen(keyWord);
Instead k needs to be initialized to 0 and then incremented only when the plain text contains an alpha character. The following line will compute the correct index into the keyword.
keyWordWrapper = k % strlen(keyWord);
The only difference is that i is replaced by k and k only increments when the plain text has an alpha character.
You should convert the key to all lower case (or all upper case) and then use the same expression in both shift blocks:
int key = keyC - 'a'; // Or 'A' if you convert to upper
You should remove the strlen(plainText) from the condition of the for loop; it converts a linear algorithm into a quadratic one.