Adding a char into a temporaryChar outputting garbage - c++

I'm doing a method in which I load a notepad file with random data in it, and I have to read character by character. Then I check whether this character is a Digit or a Letter and so on and so forth.
I invented a method called isDigit (ch) in which it accepts the character that is being loaded and checks whether it is between 0 and 9. If it is a Digit it is added to a newly created char tempString.
The Problem is that whenever I add to this char tempString the first number comes out OK but the rest (in my dummy file I have from 1 - 5) it comes out as garbage.
What could be the reason please? Down below you have the code and the output
Coding
Token Lexer::getNextToken()
{
char ch;
char tempString;
std::ifstream input("dummyData.txt");
while (input)
{
input.get(ch);
if(isDigit(ch))
{
tempString += ch;
cout << tempString << endl;
Col++;
}
else if (ch == '\n')
{
cout << "\nNew Line\n" << endl;
Row++;
Col = 1;
}
else
{
cout << "Error" << endl;
}
Offset ++;
cout << " Row " << Row << " Column " << Col << " Offset: " << Offset << endl;
}
return Token::tkDigit;
}

You declare tempString as a single character, rather than a string. Adding a character to it doesn't turn it into a string and append the character; it adds the ASCII value of ch to the value already in tempString, producing some other character value.
Try std::string tempString;

You use char tempString as a buffer, but instead to store data in it you increment its value which results as a rubbish. Notice that char which presents a digit is not a digit value you expect. This way you go outside printable string boundary.

tempString is defined as a char. I believe you want it to be a std::string.
In addition you should use standard functions instead of rewriting from scratch. See std::isdigit.

Related

C++ How to check if string starts with char from input

So I want to make a console application that asks you one letter, and a word, and to see if word starts with that letter.
cout<<"Player 1: "<<endl;
cin>> letter;
cin>> word1;
std::string s(word1);
if (s.find(letter) == 0){
std::cout << "String starts with "<< letter<< endl;
}
You need to access first element of the string:
std::string someString = "foo"; // for example purposes
char someChar = 'f';
if (someString[0] == someChar)
std::cout << "First character of this string is " << someChar << "!";
Be careful though, if you fail to read string, you can try to access the first element (with index 0) but it may not exist. Do it like this:
if (someString.length() > 0)
{
// string is not empty. You can use also !someString.empty()
}

I need to know how to copy a c-string from one varible to another in order to get a third function to work in my program

I'm trying to write three functions for an assignment
changeUp changes a string to uppercase
changeDown changes a string to lowercase
changeRev reverses the case of each character
Each function must accept a pointer to a string or C-string as an argument and must make the changes above by iterating over each character in the input string.
When entering AbCd, the first function should return ABCD; the second function should return abcd; and the reverse function should return aBcD.
I cannot figure out how to get the last function to work - it just returns all uppercase letters.
I have tried copying the input to a variable to save it - you can see my commented out areas where I tried to do this, but I really don't know what I'm doing, I'll just be honest. I got all kinds of errors when trying to copy (line, line2).
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
void changeUp(char *line)//Change to upper case
{
for (int i = 0; line[i]; i++)
{
if (islower(line[i])) line[i] = toupper(line[i]);
}
}
void changeDown(char *line)//Change to lower case
{
for (int i = 0; line[i]; i++)
{
if (isupper(line[i])) line[i] = tolower(line[i]);
}
}
void changeRev(char *line)//Reverse the cases
{
for (int i = 0; line[i]; i++)
{
if (isupper(line[i])) line[i] = tolower(line[i]);
else if (islower(line[i])) line[i] = toupper(line[i]);
}
}
void main()
{
const int SIZE = 81; //For character space
char line[SIZE], line2[SIZE];//Character array
cout << "Enter a string of characters :" <<endl;//Takestring input from user
cin.getline(line, SIZE);
//strcpy_s(line, line2);
changeUp(line);
cout << "Changed to Upper Case " << line << endl;//Output string in all caps
//strcpy_s(line, line2);
changeDown(line);
cout << "Changed to Lower Case " << line << endl;//Output string in lower case
//strcpy_s(line, line2);
changeRev(line);
cout << "The rverse of the characters is " << line << endl;//Output reverse of string entered
system("pause");
return;
}
it is bad practice to include: "using namespace std", it is better to use std::cout and that goes for all functions from that namespace. Also you were sending a pointer to function so each time each function was modifying the string, therefore before your reverse condition you were passing all lowercase therefore that is why you were getting all caps. I think something like the solution bellow would be better approach.
#include <iostream>
#include <string>
using namespace std;
string changeUp(string line)//Change to upper case
{
for (int i = 0; line[i]; i++)
{
if (islower(line[i])) line[i] = toupper(line[i]);
}
return line;
}
string changeDown(string line)//Change to lower case
{
for (int i = 0; line[i]; i++)
{
if (isupper(line[i])) line[i] = tolower(line[i]);
}
return line;
}
string changeRev(string line)//Reverse the cases
{
for (int i = 0; line[i]; i++)
{
if (isupper(line[i])) line[i] = tolower(line[i]);
else if (islower(line[i])) line[i] = toupper(line[i]);
}
return line;
}
void main()
{
const int SIZE = 81; //For character space
char line[SIZE], line2[SIZE];//Character array
cout << "Enter a string of characters :" << endl;//Takestring input from user
cin.getline(line, SIZE);
//strcpy_s(line, line2);
cout << "Changed to Upper Case " << changeUp(line) << endl;//Output string in all caps
//strcpy_s(line, line2);
cout << "Changed to Lower Case " << changeDown(line) << endl;//Output string in lower case
//strcpy_s(line, line2);
cout << "The rverse of the characters is " << changeRev(line) << endl;//Output reverse of string entered
system("pause");
return;
}
You're almost there. The problem is that you are operating on the same variable and are overwriting the input line each time you run your functions on it. When you run changeRev you are "reversing" the result of the input string after you have just modified it to lowercase using changeDown. Reversing this string naturally makes it all uppercase.
Creating a copy is the right thing to do, but you have have just gotten the order of the arguments wrong. The destination is first, the source second. Then make sure to only operate on the copy, line2 so that the user's original input remains unmodified in the line variable so that you can use it again later.
strcpy_s(line2, line);
changeUp(line2);
cout << "Changed to Upper Case " << line2 << endl;/
strcpy_s(line2, line);
changeDown(line2);
cout << "Changed to Lower Case " << line2 << endl;
strcpy_s(line2, line);
changeRev(line2);
cout << "The reverse of the characters is " << line2 << endl;
The reason is that the functions are modifying the string in-place. Hence the string goes from AbCd => ABCD => abcd => ABCD. You lose the original string in the first call.
The solution is to make a copy of the string every time and call the function on the copy.

Creating an encryption program with a choice of three methods! It has issues I am not sure how to fix

#include <iostream>
#include <string.h>
#include <string>
#include <fstream>
using namespace std;
int get_ascii_int(char ch);
int get_offset_ascii(char ch2, int offset);
//int print_string_ints(string test_string);
int method3_substitution_abc();
//above are the function declarations
int main()
{
string test_string;//input of string
char ch = 0;//used in method1
char ch2 = 0;//used in method2
int index1 = 0;//used in for loop method1
int index2 = 0;//used in for loop method2
int offset = 0;//input of how much to offset
int new_ascii = 0;//the new ascii with offset
int ascii_value1 = 0;//the ascii value of the char
int option;//the menu choice of encryption method
int decision;//the decision to save or display
ofstream method1;//method 1 text file
ofstream method2;//method 2 text file
ofstream method3;//method 3 text file
string test_string_copy;//copy of string method 2
//Below is a description of the methods of encryption
cout << "There are three methods of encryption, listed below, to choose from: " << endl;
cout << "1. Converting characters into the corresponding ASCII values. " << endl;
cout << "2. Shifting characters right/left using the ASCII value of the characters ";
cout << "and a set offset amount. " << endl;
cout << "3. Using a reverse alphabet, so each letter will be replaced with the letter ";
cout << "on the opposite end of the alphabet. For example, A would become Z. " << endl;
cout << "Which encryption method would you like to use, 1, 2, 3? ";
cin >> option;
switch (option)
{
case '1':
method1.open("method1.txt");
cout << "Input a word or name: ";
getline(cin, test_string);
for (; index1 < test_string.size(); index1++);
{
ascii_value1 = get_ascii_int(test_string[index1]);
}
cout << "Would you like to display the file or save it, enter 1 for display or 2 for save?";
cin >> decision;
if (decision == '1')
{
cout << "The encrypted code is " << ascii_value1 << endl;
}
else
{
if (method1.is_open())
{
method1 << "The encrpyted code is " << ascii_value1 << endl;
method1.close();
}
else
cout << "Unable to open file." << endl;
}
break;
case '2':
method2.open("method2.txt");
cout << "Input a word or name: ";
getline(cin, test_string);
test_string_copy = test_string;
for (; index2 < test_string_copy.size(); index2++);
{
new_ascii = get_offset_ascii(test_string_copy[index2], ch2);
}
cout << "Would you like to display the file or save it, enter 1 for display or 2 for save?";
cin >> decision;
if (decision == '1')
{
cout << "The encrypted code is " << new_ascii << endl;
}
else
{
if (method2.is_open())
{
method2 << "The encrypted code is " << new_ascii << endl;
method2.close();
}
else
cout << "Unable to open file." << endl;
}
break;
case '3':
method3.open("method3.txt");
method3_substitution_abc();
break;
}
return 0;
}
//listed below are the function definitions
int get_ascii_int(char ch)
{
return ((int)ch);
}
int get_offset_ascii(char ch2, int offset)
{
int new_offset_value;//the value after adding the determined offset to the ascii value of the letter
new_offset_value = (int)ch2 + offset;
(char)new_offset_value;
return (new_offset_value);
}
//int print_string_ints(string test_string)
//{
//for (int i = 0; i < test_string.size(); i++)
//{
//(int)test_string[i++];
//}
//return 0;
//}
int method3_substitution_abc()
{
char test_string[100];
cout << "Enter a name or phrase: ";
cin >> test_string;
if (isupper((int)test_string))
{
int stalpha = 65;//start of alphabet
int endalpha = 90;//end of alphabet
char b[100];//array to reverse the alphabet
for (int i = 0; test_string[i] != '\0'; i++)
{
b[i] = endalpha - (test_string[i] - 65);
}
}
else if (islower((int)test_string))
int stalpha = 97;//start of alphabet
int endalpha = 122;//end of alphabet
char b[100];//array to reverse the alphabet
for (int i = 0; test_string[i] != '\0'; i++)
{
b[i] = endalpha - (test_string[i] - 97);
}
return 0;
}
I am trying to write this encryption program. And I am just getting really confused on why it won't run.
For example the switch statement is not running correctly, it will go to the correct case and then skip the input of the string?
This is my first experience with C++ so I struggle to debug.
I am having issues with saving the file to a text file after the user chooses to save or display? It has to be done after every case in the switch statement.
I also know the for loops I am using are not correct for method 1 and 2? Could someone check those out and tell me what the issue is. I am pretty sure it has to do with the parameters for the for loop.
And I don't know if I should use a string or an array for this? (In the part where the user inputs a string
At least the first problem you've identified (with the switch statement) is pretty simple and clear.
You've defined option as an int, so when you read it it's read as an integer. That means if the user enters 1, it'll have the value 1, which is different from the value '1'. '1' is a character that will (for example) print as 1, but its value is actually 49 in most character sets.
You have two obvious choices: either change option to be a char, so it'll be read as a character instead of an integer, or else change the values in the switch statement from '1', '2', etc., to just 1, 2, etc.
At a guess, the problem you're seeing from getline is a fairly common one when you mix a string extractor (e.g., cin >> my_string;) with std::getline. The string extractor extracts a string from the stream, but leaves the new-line character in the stream buffer. Then when you call std::getline, it reads that new-line as an empty string, so it doesn't wait for you to enter more input.
If you really have to mix the two this way, you probably want to add a call to std::cin.ignore to read and ignore any data up to and including the new-line character. Then when you call std::getline, it'll actually read some data.

NOTE:(getline was not the issue) C++ getline() stops working in user defined function but works in main function

NOTE: SOLVED, problem was not getline() but find function with an
Improperly filled array!
I've looked up several questions before posting my own, but I could not find an answer for my problem. This is my first question posted, but I did do some research and tried other solutions from other questions before posting my own. So I am not entirely sure this isn't a duplicate. My apologies! Thank you for understanding in advance!
I am trying to use getline() (c++) to get user input. It works fine in my main, but does not in my user defined function. I thought it might have to do with the buffer, so i used cin.ignore() as suggested in:
C++ getline method not working
and i checked:
How does getline work with cin?
to make sure I properly understood getline(). However my program still does not work correctly.
My program takes English Text as a string from user input (console input) and converts it into Morse Code and outputs result as a string (console output).
basically my problem is this:
getline works in my main function for both strings and strings with spaces ex: "This" and "This Code".
However, in my user defined function, it ONLY works for strings without spaces ex: "This".
Thanks for the help! Code snippets below!
#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;
using namespace std;
string textToMorse(const string alphabet, const string morseAlphabet[]);
int main()
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
..",".---","-.-",".-..","--","-.","---",".--.",
"--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
"...--","....-",".....",
"-....","--...","---..","----.",".-.-.-","--..--","..--.."};
int userSelection;
string resultString;
cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
cout << "Please select an option by typing the integer shown: " << endl << endl;
cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
cin >> userSelection;
while(userSelection == 1 || userSelection == 2)
{
if(userSelection == 1)
{
resultString = textToMorse(alphabet, morseAlphabet); // function where I use
// getline() but does not work
cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
cout << resultString << endl << endl << endl << endl;
}
}
return 0;
}
// does not work
string textToMorse(const string alphabet, const string morseAlphabet[])
{
string userInput;
cout << endl << "Enter English text to encode to Morse code,
with only a space between words: " << endl << endl;
cin.ignore();
getline(cin,userInput); //code works with strings without spaces,
//but breaks with others. ex: "This" works as input
//but "This code" breaks and the console seems to freeze
// then crashes out
cin.clear();
// rest of code, but program breaks before this.
string encodedEnglishText = "";
for(int i = 0; i < userInput.length(); i++)
{
userInput[i] = toupper(userInput[i]);
}
for(int i = 0; i < userInput.length(); i++)
{
encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
encodedEnglishText += " "; // extra spacing added for output clarity
if(userInput[i] == ' ')
{
encodedEnglishText += " "; // extra spacing added for output clarity
}
}
return encodedEnglishText;
}
However if I edit my code and get the input from my main and pass it in as a parameter, it works.
#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;
using namespace std;
string textToMorse(const string alphabet, const string morseAlphabet[], string userInput);
int main()
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
..",".---","-.-",".-..","--","-.","---",".--.",
"--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
"...--","....-",".....",
"-....","--...","---..","----.",".-.-.-","--..--","..--.."};
int userSelection;
string resultString;
cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
cout << "Please select an option by typing the integer shown: " << endl << endl;
cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
cin >> userSelection;
while(userSelection == 1 || userSelection == 2)
{
if(userSelection == 1)
{
string userInput;
cout << endl << "Enter English text to encode to Morse code,
with only a space between words: " << endl << endl;
cin.ignore();
getline(cin,userInput); //code works with both "This" and "This code"
cin.clear();
resultString = textToMorse(alphabet, morseAlphabet, userInput); //function modified
//to take one more
//parameter
cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
cout << resultString << endl << endl << endl << endl;
}
}
return 0;
}
string textToMorse(const string alphabet, const string morseAlphabet[], string userInput)
{
//code, but program works.
string encodedEnglishText = "";
for(int i = 0; i < userInput.length(); i++)
{
userInput[i] = toupper(userInput[i]);
}
for(int i = 0; i < userInput.length(); i++)
{
encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
encodedEnglishText += " "; // extra spacing added for output clarity
if(userInput[i] == ' ')
{
encodedEnglishText += " "; // extra spacing added for output clarity
}
}
return encodedEnglishText;
}
I didn't include all of the code, just the parts I felt were relevant to the question.
by works I mean:
getline successfully takes input. getline successfully assigns a string such as "this" and "this code" to the variable userInput when used in main function.
it only successfully assigns strings without spaces such as "this" when used in my user defined function. In that function, for some reason it does not work when I enter a string like "this code" or any string with a space inbetween.
note: program is not finished, as I plan to add other methods to do the reverse (as seen in code with
extra user options, but these are not yet implemented or defined, code still runs and compiles for problem I am facing.
The problem is that there is no morse code for a space.
Make a verification:
int n = alphabet.find(userInput[i]);
encodedEnglishText += (n == string::npos) ? " ": morseAlphabet[n];
Then it will work.
When you are looking for your input character in the alphabet string you won't find ' ' and std::string::find() return std::string::npos (normally -1 converted to the type std::string::size_type but the value isn't guaranteed). Using this value to index morseAlphabet won't do you much good: it is undefined behavior. This problem does not arise when you enter just one string as all characters are found in alphabet.
The proper way to deal with the situation is to look for the character and capture the result. Before using the result, you'd test the input, e.g.:
std::string::size_type pos(alphabet.find(userInput[i]));
if (pos == std::string::npos) {
// deal with the character not being part of the alphabet
}
else {
encodedEnglishText += morseAlphabet[pos];
}
Note that there are a few other things wrong with your program:
The selection of options should be inside the loop! The way it is implemented entering, e.g. 2 results in an infinite loop.
Using std::toupper() with a char can also result in undefined behavior! The problem is that std::toupper() expects a non-negative value of the value EOF but char may be signed. To avoid this problem you should use any of the functions from <cctype> or <ctype.h> with unsigned char:
userInput[i] = toupper[static_cast<unsigned char>(userInput[i]));
If the user doesn't enter an integer but, e.g., foo reading userSelection will fail and stream will get into failure state where it won't do anything until std::cin.clear() is entered. The best approach to deal with this situation is to test the result of reading the value before doing anything. If the input failed you can recover from the situation by clearing the status and skipping the offending character, e.g.:
if (std::cin >> userSelection) {
// use the selection
}
else {
std::cout << "ignoring invalid input\n";
std::cin.clear();
std::cin.ignore();
}
Note that your use of std::cin.clear() should be needed. Also, you should verify that the input you read with std::getline() is successful: in general, all user inputs should be tested for success.
If you enter a space character after the integer when reading userSelection, your call to std::cin.ignore() will ignore this space not the newline! To avoid this problem you could either read all charactors up to the first newline or skip all whitespace prior to the non-whitespace character:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // all till newline
std::cin >> std::ws; // skip all whitespace to first non-whitespace character
Do not use std::endl! It does not only create a newline but it also flushes the stream. This can easily create a performance problem.
You should probably pass std::string arguments by reference rather than by value. Passing the argument alphabet by value creates a copy with is inefficient (the morseAlphabet argument is passed by pointer although it looks like an array).
Some string literals seem to be split across multiple lines. Doing so is illegal (I guess, however, that this problem was introduced when pasting the code to the question above at some point).

Unable to recognize colon in String C++

This snippet of code include the string I want to display and a helper method that's sole function is to display the string, entering the text on a new line when it finds a colon. However, it is only doing that for the last colon, not the other colons
string list = ":hello:chris:";
void displayEntry(){char *colon = ":";
for (int i = 0; i<list.length(); i++) {
char *letter = &list.at(i);
if (strcmp(letter, colon) != 0) {
cout << list[i];
continue;
}
cout << "\n";
}
cout << "\n";
}
It's because strcmp is not used for comparing single characters, it compares a whole string up until it finds a NUL character.
You don't actually need char* for any of this, just use char and ==.
if (list.at(i) != ':')