c++ input character or check length of string is 1? - c++

So I was originally using cin to have the user input a character. Then if this character isn't a, b, or c, it continues to loop and prints an error message. However, if the user enters multiple characters, it prints the error message multiple times. So now I'm using scanf to take in a string and check if the length is 1. This is straight up just not working at all.
string enterLetter() {
string n;
scanf("%s", &n);
return n;
}
void main() {
string ch = "";
cout << "Type a, b, or c: ";
while (ch != "a" && ch != "b" && ch != "c"){
while (ch.length() != 1) {
ch = enterLetter();
cout << ch.length();
}
ch = tolower((char)ch.c_str());
cout << "\n" << ch;
}

You can't use scanf("%s") with std::string like you are attempting. scanf("%s") expects a pre-allocated char[] instead. If you want to read a std::string, use std::cin.operator>>() or std::getline() instead:
char enterLetter() {
string n;
do {
std::getline(std::cin, n);
}
while (n.length() != 1);
return n[0];
}
int main() {
char ch;
do {
std::cout << "Type a, b, or c: ";
ch = enterLetter();
}
while ((ch != 'a') && (ch != 'b') && (ch != 'c'));
std::cout << ch;
return 0;
}

You don't need to, nor should you use a string for this. Using a char with scanf works better.
int main() {
char ch;
cout << "Type a, b, or c: ";
scanf("%c", &ch);
while ((ch > 'C' && ch < 'a') || ch > 'c' || ch < 'A' ) {
if (ch >= 'A' && ch <= 'Z')
ch += ('a' - 'A');
cout << endl << ch;
cout << endl << "Enter a, b, or c: ";
scanf("%c", &ch);
}
}
This uses scanf to get a char ch. It loops while the char is not a, b, c or A, B, C (as you seemed to want an uppercase use case). If the char is uppercase it gets converted to lower case and then outputs the char.

You could use cin.getline() to read a whole line of user input terminated by the Enter key.
char str[64];
cin.getline(str, sizeof(str));
if the strlen(str) is not equal to 1, an error can be thrown. Otherwise, str[0] can be compared with a, b or c.
If you scanfa string in a loop, it will return the first set of characters terminated by a whitespace (space-bar or new-line char). In the next iteration it will read the next string and so. If a user enters something like "abc def\n", scanf will first return abc followed by def. If you use cin.getline(), all the characters entered until the newline, i.e. "abc def" will be returned in the first call to cin.getline().

Related

Text to Caesar Cipher

I am a beginner and i made a code in C++ to convert 3 characters to caesar cipher but my problem is that i can print only characters to a - w. How can i print x, y ,z using only if else statement. I have tried else if and many other things but it prints for x,y,z {|} which is +3 i know i need to do -23 but i cant get it to work pls help. This is my code for only to a - w. Edit : i still don’t get how to go from x,y,z to a,b,c if some1 has an code example i would appreciate it cus im trying but it for some reason keeps printing {|} which is ch = ch + 3; and not ch = ch - 23; which is the one i want to do with else if statement
char ch1;
char ch2;
char ch3;
cout << "Insert three characters: " << endl;
cin >> ch1;
cin >> ch2;
cin >> ch3;
if (ch1 >= '97' && ch1 <= '119' || ch2 <= '97' && ch2 <= '119' || ch3 >= '97' && ch3 <= '119') {
ch1 = ch1 + 3;
ch2 = ch2 + 3;
ch3 = ch3 + 3;
cout << "Caesar Cipher: " << ch1 << ch2 << ch3 << endl;
}
To wrap your characters around, you need the modulo operator, %. But first you must transform the letter to a zero-based value. After that, you have a number in the range [0, 25] and you can offset it. You then take the modulo to wrap the new value to the same range and finally transform it back to an alphabet character.
Example:
ch1 = 'a' + (ch1 - 'a' + 3) % 26;
Notice I'm using a character literal here. You should always avoid hard-coding character values, as that just makes your code more difficult to read and less portable. To test if a value is lowercase, there's a standard library function std::islower (and a corresponding std::isupper) found in the header <cctype>.
Fixing your code up a bit, it becomes:
if (std::islower(ch1)) ch1 = 'a' + (ch1 - 'a' + 3) % 26;
if (std::islower(ch2)) ch2 = 'a' + (ch2 - 'a' + 3) % 26;
if (std::islower(ch3)) ch3 = 'a' + (ch3 - 'a' + 3) % 26;
cout << "Caesar Cipher: " << ch1 << ch2 << ch3 << endl;
But look at all the code duplication! What if you want to change the key, or use more or less characters, or change the encoding algorithm completely? That's where a function comes in handy:
char EncodeChar(char c, int key)
{
if (std::islower(c))
c = 'a' + (c - 'a' + key) % 26;
return c;
}
Now you can use it like this:
const int key = 3;
ch1 = EncodeChar(ch1, key);
ch2 = EncodeChar(ch2, key);
ch3 = EncodeChar(ch3, key);
Even better, read your characters into a std::string and encode it in-place. You're no longer restricted to exactly three characters:
void CaesarEncode(std::string& s, int key)
{
for (char& c : s) c = EncodeChar(c, key);
}
Call that like this:
std::string text = "Hello, world!";
CaesarEncode(text, 3);
std::cout << text << "\n";
Now, this will work for positive offsets, but not negatives. If you need to apply a negative offset, you need to add an additional 26 before modulo which ensures you never go below zero. It's useful to support both, because you probably want to decode the ciphertext at some point. You can use the same function but make the key negative.
One way to approach this is to modify a negative key at the last minute with a recursive call in your CaesarEncode function:
void CaesarEncode(std::string& s, int key)
{
if (key < 0)
{
CaesarEncode(s, 26 - (-key % 26));
return;
}
for (char& c : s) c = CaesarEncode(c, key);
}
Let's continue. What about capital letters? You can handle those too:
char EncodeChar(char c, int key)
{
if (std::isalpha(c))
{
char base = std::islower(c) ? 'a' : 'A';
c = base + (c - base + key) % 26;
}
return c;
}
As you can see, using functions makes life much easier, because you don't need to create a mess when beefing up your encoding method. You just change the core logic in one place.
Rolling this all together, and with a few extra helpers from the standard library, you get a reasonably compact program that can encode and decode:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
#include <string>
std::string CaesarEncode(const std::string& s, int key)
{
if (key < 0)
{
return CaesarEncode(s, 26 - (-key % 26));
}
auto fnEncodeChar = [key](unsigned char c) -> unsigned char
{
if (std::isalpha(c))
{
char base = std::islower(c) ? 'a' : 'A';
c = base + (c - base + key) % 26;
}
return c;
};
std::string encoded;
std::transform(s.begin(), s.end(), std::back_inserter(encoded), fnEncodeChar);
return encoded;
}
std::string CaesarDecode(const std::string& s, int key)
{
return CaesarEncode(s, -key);
}
int main()
{
const int KEY = 3;
std::string line;
while (std::getline(std::cin, line))
{
std::string encoded = CaesarEncode(line, KEY);
std::string decoded = CaesarDecode(encoded, KEY);
std::cout << "Original : " << line << "\n";
std::cout << "Encoded : " << encoded << "\n";
std::cout << "Decoded : " << decoded << "\n";
}
}
Input:
This is a test.
Output:
Original : This is a test.
Encoded : Wklv lv d whvw.
Decoded : This is a test.

C++ Can't print certain words from Char array

Not sure how to phrase the question, but I'm making a program for an assignment, which we're not allowed to use pre-existing libraries besides input/output. We also can only use primitive data-types. I have to read a text file with words, remove all punctuation from the word, and then store those words in a 2D array of characters.
This problem seems to be that when a word starts with a non-alphabetic character, the whole word doesn't output when using cout << stack[top] but when I output each individual character with cout << stack[top][i], it produces the expected output.
'stack' is a 2D array which contains characters to make up words.
'top' is a variable to represent the length of stack
Code:
#include <iostream>
#include <fstream>
using namespace std;
// Function Prototypes
void push(char word[]);
char formatCharacter(char letter);
bool isAlphabet(char letter);
char toLowercase(char letter);
// Global Variables
const int STACK_SIZE = 50000;
const int WORD_SIZE = 30;
char stack[STACK_SIZE][WORD_SIZE];
int top = 0;
int words = 0;
int wordCount[STACK_SIZE];
int main(){
// Local Variables
char filename[20];
ifstream fin;
char word[WORD_SIZE];
// Get file input
cerr << "Please enter the name of the input file: ";
cin >> filename;
// Open file
fin.open(filename);
// Print error if file doesn't open, then quit the program.
if (!fin) {
cerr << "Error opening file " << filename << ". Program will exit." << endl;
return 0;
}
// Read the file into the stack
while (fin >> word) {
push(word);
}
// Close file
fin.close();
}
void push(char word[]){
if (top == STACK_SIZE) return;
int i = 0;
int j = 0;
do {
if (isAlphabet(word[i])){
word[i] = formatCharacter(word[i]);
stack[top][i] = word[i];
cout << stack[top][i]; // Output fine
j++;
}
i++;
} while (word[i]);
wordCount[words] = j;
//cout << stack[top] << ": " << wordCount[words] << endl; // Output incorrect
cout << endl;
top++;
words++;
return;
}
bool isAlphabet(char letter){
if ((letter < 'A' || letter > 'Z') && (letter < 'a' || letter > 'z')){
return false;
}
else{
return true;
}
}
char formatCharacter(char letter){
if ((letter < 'A' || letter > 'Z') && (letter < 'a' || letter > 'z')){
letter = '\0';
}
else{
if (letter >= 'A' && letter <= 'Z'){
letter = toLowercase(letter);
}
}
return letter;
}
char toLowercase(char letter){
letter = letter + 32;
return letter;
}
isAlphabet() just checks if it's an alphabetic character
formatCharacter() removes any punctuation by replacing the character with '\0', and also changes uppercase to lowercase.
Input:
Jabberwocky
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
Output when using cout << stack[top][i]:
jabberwocky
twas
brillig
and
the
slithy
toves
did
gyre
and
gimble
in
the
wabe
all
mimsy
were
the
borogoves
and
the
mome
raths
outgrabe
Output when using cout << stack[top]:
jabberwocky: 11
: 4
brillig: 7
and: 3
the: 3
slithy: 6
toves: 5
did: 3
gyre: 4
and: 3
gimble: 6
in: 2
the: 3
wabe: 4
all: 3
mimsy: 5
were: 4
the: 3
borogoves: 9
and: 3
the: 3
mome: 4
raths: 5
outgrabe: 8
Notice the word 'twas' is missing. I'd rather not loop through each character of each word to get the output I need. I'd appreciate any advice, thanks!
The simplest fix is to change:
stack[top][i] = word[i];
To:
stack[top][j] = word[i];
^ j not i here
This will ensure that the 'Twas ends up as twas and not \0twas.
Also, formatCharacter() should call isAlphabet() rather than repeat the condition.

RE: Why am I getting the wrong value of vowels from this counter?... original code

Instructions:
using a value returning function
Write a program that prompts the user to input a sequence of characters and outputs the number of vowels.
This is the problem given by the instructor..
#include <iostream>
using namespace std;
bool isVowel(char ch);
int main() {
char ch;
cout << "Enter a character: ";
cin >> ch;
cout << ch << " is a vowel: " << isVowel(ch) << endl;
return 0;
}
bool isVowel(char ch){
if (ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U' ||
ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u'){
return true;
} else
return false;
}
char is a single character, not a sentence. For a sentence use a string.
string s;
cout << "Enter a sentence: ";
cin >> s;
Then use a loop to loop through each character of the sentence
for (char ch : s)
{
...
}
Then use isVowel to test a single character, and increment the count if found. The clue is in the name isVowel, not countVowels, so isVowel should test a single vowel and return true or false, not count the number of vowels.
int vowels = 0;
for (char ch : s)
{
if (isVowel(ch))
vowels++;
}
finally write isVowel to test a single character.
bool isVowel(char ch)
{
return ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U' ||
ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u';
}
There are several problems here.
Firstly, you don't initialize vowels. You presumably mean int vowels = 0; or int vowels {0};.
Secondly, you are reading a single character with cin >> ch;. I suspect you mean to loop over an input string.
Thirdly, your signature for isVowel is bool isVowel(int vowels, char ch);, which returns a bool. But you have written your function as thought it is manipulating an integer total of vowels. This inconsistency doesn't make sense.
Fourthly, you assign the result of isVowel to a character in ch = isVowel(vowels,ch);. Then you call isVowel again with this updated ch in cout << isVowel(vowels, ch) << .... I'm not sure what you're attempting to do here, but this also doesn't make any sense.
You need to revisit all of this code. You probably want isVowel to actually return a boolean. You probably want to iterate over an entire input string, and adjust the value of vowels appropriately (after initializing it).
Your program is running an undefined behavior; you are using vowels without being initialized.
You can make function that takes the counter of vowels as a reference to an integer for example.
void isVowel(int& counter, char ch) {
std::string vowels{ "AaEeIiOoUu" };
for (auto c : vowels)
if(ch == c)
counter++;
}
int main(){
char ch;
int counter{};
while (std::cin >> ch)
isVowel(counter, ch);
std::cout << counter << endl << " vowels in this sentence." << endl;
}
#include <iostream>
using namespace std;
bool isVowel(int vowels, char ch);
So isVowel returns a bool. That would make sense if its purpose was to tell us whether a single character was a vowel or not. For some reason, we pass an integer called vowels to it. That doesn't seem to make any sense. What would it do with an integer value?
int main() {
char ch;
So ch is a single character. Okay.
int vowels;
And vowels is an integer with no particular value.
cout << "Enter a sentence: ";
cin >> ch;
Uh oh. We ask the user to enter a sentence but then we read in a single character. Remember, ch was a char.
ch = isVowel(vowels,ch);
Uh oh. We didn't assign vowels any particular value, so we've passed no particular value to isVowel. Also, we took the boolean value returned and assigned to a variable of type char. Why would we do that?
cout << isVowel(vowels, ch) << " vowels in this sentence." << endl;
Then for some reason we call isVowel again. That doesn't make much sense. Also, isVowel returned a bool (a yes or no). Why are we outputting that as if it was the number of vowels?
return 0;
}
// build a string counter and make it callable
bool isVowel(int vowels, char ch){
Okay, so isVowel returns a boolean and takes as input an integer and a character.
for (int i = 0; i < ch; i++){
if (ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U' ||
ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u'){
vowels++;
}
We are looping from zero to the value of the single character? That doesn't make sense.
}
return vowels;
}
Lots of problems here. Because there are so many fundamental problems with this code, it seems you've attempted a problem that's way beyond your C++ knowledge and you should attempt something much simpler first, such as accepting a sentence as input and repeating it back to the user without using any additional functions.

Recognizing Space character in C++ Program

#include<iostream.h>
#include<conio.h>
void main()
{
char ch;
cout<<"Enter a character:";
cin>>ch;
if(ch==32)
cout<<"space";
else if(ch>=65 && ch<=90)
cout<<"upper case letter";
else if(ch>=97 && ch<=122)
cout<<"lower case letter";
else
cout<<"special character entered";
getch();
}
I need to check whether character entered is lower or upper case letter,special character, digit or space character. 32 is code for space but as I am entering space as ' ' on the console, its not recognizing ' ' as space.
Spaces are ignored by default, use noskipws
#include<iostream>
using namespace std;
int main()
{
char ch;
cout<<"Enter a character:";
cin>>noskipws>>ch;
if(ch==32)
cout<<"space";
else if(ch>=65 && ch<=90)
cout<<"upper case letter";
else if(ch>=97 && ch<=122)
cout<<"lower case letter";
else
cout<<"special character entered";
getchar();
return 0;
}
Also, if you're adding '' to the space then keep in mind that only the first character is being recognized.
The problem
cin >> ch discards whitespaces (including space, \t, \n, etc.) The correct way is to use get(ch):
cin.get(ch);
(noskipws is another option mentioned in #Samuel's answer, but get may be easier here for a single character.)
Other problems
Use <iostream> instead of <iostream.h>. <iostream.h> is not standard C++.
Use <cstdio>* instead of <conio.h>. <conio.h> is not standard C++.
Use int main() instead of void main(). void main() is not standard C++.
Use indentation instead of left-justifying. Left-justifying is less readable.
Use ch == ' ' instead of ch == 32. ch == 32 is not portable.
Use isupper(ch) instead of ch >= 65 && ch <= 90. ch >= 65 && ch <= 90 is not portable.
Use islower(ch) instead of ch >= 97 && ch <= 122. ch >= 97 && ch <= 122 is not portable.
Fixed code:
#include <iostream>
#include <cctype>
int main()
{
char ch;
std::cout << "Enter a character:";
std::cin.get(ch);
if (ch == ' ')
std::cout << "space";
else if (std::isupper(ch))
std::cout << "upper case letter";
else if (std::islower(ch))
std::cout << "lower case letter";
else
std::cout << "special character entered";
// std::cin >> ch; // only if you really demand it
}
* Even <cstdio> shouldn't be used in this case. If you do want to hold the window open, use getchar() or std::cin >> ch instead of getch(). The better way is to invoke it in a console.
Use characters themselves instead of their codes.
#include<iostream.h>
#include<conio.h>
void main()
{
char ch;
cout << "Enter a character:";
cin >> ch;
if (ch == ' ')
cout << "space";
else if (ch >= 'A' && ch <= 'Z')
cout << "upper case letter";
else if(ch >= 'a' && ch <= 'z')
cout << "lower case letter";
else
cout << "special character entered";
getch();
}

Delimiter matching simple program won't work

I have looked over this for hours it seems like. This program will compile, it just can't detect errors correctly. And for some reason it will work when I type in hey [) or hey {], etc. But it won't work for hey[) or hey{]. Obviously in all cases it should detect an error but for some reason the space after 'hey' makes a difference.
#include<iostream>
#include <stack>
using namespace std;
bool delimiterMatching(char *file){
stack<char> x;
int count = 0;
char ch, onTop, check;
while(ch != '\0'){
ch = file[count];
if (ch == '(' || ch == '[' || ch == '{')
x.push(ch);
else if (ch == ')' || ch == ']' || ch == '}') {
onTop == x.top();
x.pop();
if((ch==')' && onTop!='(') || (ch==']' && onTop!='[') || (ch=='}' &&
onTop!= '{'))
return false;
}
count++;
}
if (x.empty())
return true;
else
return false;
}
int main()
{
char *test = new char();
cout << "enter sentence: ";
cin >> test;
if (delimiterMatching(test))
cout << "success" << endl;
else
cout << "error" << endl;
return 1;
}
With cin >> test you don't get a whole sentence, but only a string until cin encounters whitespace. So if you type (hey ), thest would be (hey and the closing brace would only be read by the next >>, whereas (hey) would work as expected.
You have a second issue with your test allocation, which might be too short for reasonable input.
Change main() as follows:
char *test = new char[256]; // enough space. COnsider also string
cout << "enter sentence: ";
cin.getline(test, 256); // full line input.
...
You have also two nasty bugs in delimiterMatching().
First you use an uninitialized ch in your while condition. Either initialise ch to a non nul char, or use while (file[count]).
And did you notice onTop == x.top(); ? Shouldn't it be onTop = x.top();?