C++ reading string segmentation fault - c++

I am writing a program that will input an alphabetic message, and use the class to build the morse code string, and then output the string. I have written all the method and the program compiles fine. However when I enter the temp string and hit return. I am given a segmentation fault. I can't seem to find the problem. If anyone can see what the problem is I would greatly appreciate your help. Thanks.
#include <string>
#include <vector>
#include <fstream>
using namespace std;
class Code
{
public:
Code(); // Default constructor - loads and uses morse code
string decode(vector< string> message); // decodes a message
string encode(vector<char> message); // encodes a message
private:
vector<string> codewords; // this is a codeword vector parallel to A-Z
vector<char> alpha; // this is the vector for A-Z
vector<char> alphacode(); // function builds the vector alpha - A B C etc.
vector<string> morsecode(); // function builds the vector codewords containing morse code
char decode(string c); //returns the character for the codeword c.
string encode(char c);
};
Code::Code() {
alpha = alphacode();
codewords = morsecode();
}
string Code::decode(vector< string> message) {
string temp;
for (int i=0; i < message.size(); i++) {
temp += decode(message[i]);
}
return temp;
}
string Code::encode(vector<char> message)
{
string temp;
for (int i=0; i<message.size(); i++)
{
temp+=encode(message[i]);
}
return temp;
}
vector<string> Code::morsecode()
{ // This function returns a vector containing the morse code
vector<string> temp(28);
temp[0] =".-";
temp[1] ="-...";
temp[2] ="-.-.";
temp[3] ="-..";
temp[4] =".";
temp[5] ="..-.";
temp[6] ="--.";
temp[7] ="....";
temp[8] ="..";
temp[9] =".---";
temp[10] ="-.-";
temp[11] =".-..";
temp[12] ="--";
temp[13] ="-.";
temp[14] ="---";
temp[15] =".--.";
temp[16] ="--.--";
temp[17] =".-.";
temp[18] ="...";
temp[19] ="-";
temp[20] ="..-";
temp[21] ="...-";
temp[22] =".--";
temp[23] ="-..-";
temp[24] ="-.--";
temp[25] ="--..";
temp[26] =".......";
temp[27] ="x";
return temp;
}
vector<char> Code::alphacode()
{// This returns a vector containing the alphabet a-z and " "
vector<char> temp;
for (char c='A'; c<='Z'; c++)
temp.push_back(c);
temp.push_back(' ');
temp.push_back('.');
return temp;
}
char Code::decode(string c)
{
for (int i = 0; i < alpha.size(); i++) {
if(c == codewords[i]) {
return alpha[i];
}
}
}
string Code::encode(char c)
{
for (int i=0;i<codewords.size();i++)
{
if (c==alpha[i])
{
return codewords[i];
}
}
}
int main()
{
vector<char> message;
string temp;
getline(cin, temp);
for (int i=0; i <temp.length(); i++)
{
message.push_back(temp[i]);
}
Code C;
cout << C.encode(message) << endl;
}

Your alphacodes and morsecodes are only for Capital letters, so this function returns null resulting in problems.
string Code::encode(char c)
{
for (int i=0;i<codewords.size();i++)
{
if (c==alpha[i])
{
return codewords[i];
}
}
}
Your check for c==alpha[i] should either check ignoring the case or your alpha codes should have small alphabet codes as well. Your morsecodes should have the codes for small alphabets as well and your checks where you map A-Z to 0-28 should accommodate small letters.
Remember, small letters have different ASCII codes than Capital letters.

The following function does not have a return statement at the end.
string Code::encode(char c)
{
for (int i=0;i<codewords.size();i++)
{
if (c==alpha[i])
{
return codewords[i];
}
}
// What should happen if execution gets to this line?
}
If, per chance, your code reaches the end of the function, you will run into undefined behavior. That could be the source of your problem.

Related

C++ reverse a string but printing numbers first

I was given a project in class and almost have it finished, I am required to take a string of numbers and letters and return that string with the numbers printed first followed by the letters in reverse order (ex. abc123 should return 123cba). As of now my code returns a string with the numbers first and the original order of the letters (ex. abc123 returns 123abc). I would be able to do this with two loops however the assignment asks that my code only iterates though the initial string one time. Here is the code I have so far...
#include <iostream>
#include <string>
#include "QueType.h"
#include "StackType.h"
using namespace std;
int main ()
{
QueType<char> myQueue;
StackType<char> myStack;
string myString="hello there123";
char curchar;
string numbers, letters;
for (int i = 0; i < myString.length(); i++) {
if (isdigit(myString.at(i))) {
myQueue.Enqueue(myString.at(i));
myQueue.Dequeue(curchar);
numbers += curchar;
//cout<<numbers<<endl;
}
else if (islower(myString.at(i))) {
myStack.Push(myString.at(i));
curchar = myStack.Peek();
myStack.Pop();
letters += curchar;
//cout<<curchar<<endl;
}
}
cout<<(myString = numbers + letters)<<endl;
}
In my code, I have two .h files that set up a stack and a queue. With the given string, the code loops through the string looking to see if it sees a letter or number. With a number the spot in the string is then saved to a queue, and with a letter it is saved to the stack.
The only other way i can think of reversing the order of the letters is in the if else statement instead of having char = myStack.Peek() every loop, change it to char += myStack.Peek() however I get weird lettering when that happens.
since you already got the string with letters you can basically reverse it and that's it.
//emplace version:
void reverse_str(std::string& in)
{
std::reverse(in.begin(), in.end());
}
//copy version
std::string reverse_str(std::string in)
{
std::reverse(in.begin(), in.end());
return in;
}
in your case the emplace version would be the best match.
in other cases (e.g. when you want to preserve the original string) the copy version is preferred.
adding an example to make it as clean as possible.
int main()
{
std::string inputstr = "123abc";
std::string numbers{};
std::string letters{};
for(auto c : inputstr)
{
if(isdigit(c))
numbers += c;
else
letters += c;
}
reverse_str(letters); //using the emplace version
std::cout << numbers + letters;
}
Here's my take. It only loops through the string once. I don't have your types, so I'm just using the std versions.
std::string output;
output.reserve( myString.size() );
std::stack<char> stack;
for ( char c : myString ) {
if ( std::isdigit( c ) ) // if it's a number, just add it to the output
output.push_back( c );
else // otherwise, add the character to the stack
stack.push( c );
}
// string is done being processed, so use the stack to get the
// other characters in reverse order
while ( !stack.empty() ) {
output.push_back( stack.top() );
stack.pop();
}
std::cout << output;
working example: https://godbolt.org/z/eMazcGsMf
Note: wasn't sure from your description how to handle characters other than letters and numbers, so treated them the same as letters.
One way to do this is as follows:
Version 1
#include <iostream>
#include <string>
int main() {
std::string s = "abc123";
std::string output;
output.resize(s.size());
int i = output.length() - 1;
int j = 0;
for(char &c: s)
{
if(!std::isdigit(c))
{
output.at(i) = c;
--i;
}
else
{
output.at(j) = c;
++j;
}
}
std::cout<<output<<std::endl;
}
You can also use iterators in the above program to obtain the desired result as shown in version 2.
Version 2
#include <iostream>
#include <string>
int main() {
std::string s = "abfsc13423";
std::string output;
output.resize(s.size());
std::string::reverse_iterator iter = output.rbegin();
std::string::iterator begin = output.begin();
for(char &c: s)
{
if(!std::isdigit(c))
{
*iter = c;
++iter;
}
else
{
*begin = c;
++begin;
}
}
std::cout<<output<<std::endl;
}

C++: English to Pig Latin

I am receiving an error from the following code when I try to dynamically allocate the array (seen after my attempt to incrementing through each letter in the users array using the bool function). This is the error:
main.cpp: In function ‘Word* splitSentene(std::string, int&)’:
main.cpp:81:32: error: cannot convert ‘std::string* {aka std::basic_string*}’ to ‘Word*’ in assignment
words = new string[i];
I am trying to count how many words the user inputs and dynamically allocate an array for the string of words. This is my code thus far:
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
struct Word
{
string english; // English sentence
string piglatin; // Pig latin sentence
};
// PT 1. Function prototype
Word * splitSentence(const string words, int &size){};
int main()
{
string userSentence;
int size;
// Get the users sentence to convert to pig latin
cout << "Please enter a string to convert to pig latin:\n";
getline(cin, userSentence);
// Directs to Word * splitSentence function
Word* tempptr = splitSentence(userSentence, size);
delete [] tempptr;
return 0;
}
//PT 1. Analyze the sentence
Word * splitSentene(const string words, int &size)
{
bool flag = true;
int num = 0;
for (int i = 0; i < words.length() + 1; i++)
{
//test for white space, then when you hit the first alphabetical character after a space,
//increment up the size of the array
if (isspace(words[i]))
flag = true;
if (isalpha(words[i]));
{
if (flag == true)
{
flag = false;
cout << words[i++];
}
}
// Dynamically allocate the array for the words
Word *sentence = nullptr;
sentence = new string[i];
}
}
Here are the pt 1 instructions for further clarification:
PT. 1) Write a function that takes in an English sentence as one string. This function should first calculate how many “words” are in the sentence (words being substrings separated by whitespace). It should then allocate a dynamic array of size equal to the number of words. The array contains Word structures (i.e. array of type Word). The function would then store each word of that sentence to the english field of the corresponding structure. The function should then return this array to the calling function using the return statement, along with the array size using a reference parameter.
This function should also remove all capitalization and special characters other than letters. Implement the function with the following prototype:
Word * splitSentence(const string words, int &size);
This is my first post here, so I will appreciate any input on how to dynamically allocate the array and format it (if I have successfully coded how to count the words in the sentence the user inputs). If more information needs to be provided, let me know!
The compiler error is because you are trying to assign a string[] array to a Word* pointer. You need to allocate a Word[] array instead.
You also have other errors in your code:
You have an erroneous {} at the end of the declaration of splitSentence().
You misspelled splitSentene in the defintion of splitSentence().
You have an erroneous ; on if (isalpha(words[i]));
You are not return'ing the array that you allocate.
In fact, you are not even following the instructions properly at all. You are not "calculating how many words are in the sentence" BEFORE allocating the array (you tried, but you are doing the allocation in the wrong place), and you are not filling the array at all, let alone "removing all capitalization and special characters other than letters".
Try something more like this:
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
struct Word
{
string english; // English sentence
string piglatin; // Pig latin sentence
};
// PT 1. Function prototype
Word* splitSentence(const string words, int &size);
int main()
{
string userSentence;
int size;
// Get the users sentence to convert to pig latin
cout << "Please enter a string to convert to pig latin:\n";
getline(cin, userSentence);
// Directs to Word * splitSentence function
Word* tempptr = splitSentence(userSentence, size);
delete [] tempptr;
return 0;
}
//PT 1. Analyze the sentence
Word* splitSentence(const string words, int &size)
{
bool flag = true;
int num = 0;
char ch;
for (int i = 0; i < words.length(); ++i)
{
ch = words[i];
if (isalpha(ch))
{
if (flag)
{
flag = false;
++num;
}
}
else if (isspace(ch))
{
flag = true;
}
}
Word *sentence = new Word[num];
int index = -1;
flag = true;
num = 0;
for (int i = 0; i < words.length(); ++i)
{
ch = words[i];
if (isalpha(ch))
{
if (flag)
{
flag = false;
++num;
++index;
}
if (isupper(ch))
{
ch = tolower(ch);
}
sentence[index].english += ch;
}
else if (isspace(ch))
{
flag = true;
}
}
size = num;
return sentence;
}
Live Demo
That being said, this will be much easier to implement splitSentence() if you could use std::istringstream and std::vector and other C++ idioms, instead of using C idioms, eg:
#include <iostream>
#include <sstream>
#include <cctype>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct Word
{
string english; // English sentence
string piglatin; // Pig latin sentence
};
// PT 1. Function prototype
Word* splitSentence(const string words, int &size);
int main()
{
string userSentence;
int size;
// Get the users sentence to convert to pig latin
cout << "Please enter a string to convert to pig latin:\n";
getline(cin, userSentence);
// Directs to Word * splitSentence function
Word* tempptr = splitSentence(userSentence, size);
delete [] tempptr;
return 0;
}
//PT 1. Analyze the sentence
Word* splitSentence(const string words, int &size)
{
istringstream iss(words);
vector<string> vec;
string s;
while (iss >> s)
{
remove_if(s.begin(), s.end(),
[](unsigned char ch){ return !isalpha(ch); });
if (!s.empty())
{
transform(s.begin(), s.end(), s.begin(),
[](unsigned char ch){ return tolower(ch); });
vec.push_back(s);
}
}
Word *sentence = new Word[vec.size()];
transform(vec.begin(), vec.end(), sentence,
[](const string &s){
Word w;
w.english = s;
return w;
}
);
size = vec.size();
return sentence;
}
Live Demo

Adding the next character on a string C++

I did get the next character on a string (hello-->ifmmp) but in the case of hello* i want to be able to still display the * as the exception, it can be also a number but i guess it does not matter because is not in the alphabet.
this is my code, Where should be the else if?
There is another option but i dont find it optimized, it is to add inside the first for loop this:
string other="123456789!##$%^&*()";
for(int z=0;z<other.length();z++)
{
if(str[i]==other[z])
str2+=other[z];
}
Then this is the main code;
int main()
{
string str = "hello*";
string str2="";
string alphabet = "abcdefghijklmnopqrstuvwxyz";
for(int i=0;i<str.length();i++)
{
for(int j=0;j<alphabet.length();j++)
{
if(str[i]==alphabet[j])
{
str2+=alphabet[j+1];
}
}
}
cout<<str2<<endl;
return 0;
}
I like functions. They solve a lot of problems. For example, if you take the code you already have, paste it into a function, and give it a little tweak
char findreplacement(char ch, const std::string & alphabet)
{
for (int j = 0; j < alphabet.length(); j++)
{
if (ch == alphabet[j])
{
return alphabet[(j+1) % alphabet.length()];
// return the replacement character
// using modulo, %, to handle wrap around z->a
}
}
return ch; // found no replacement. Return original character.
}
you can call the function
for (int i = 0; i < str.length(); i++)
{
str2 += findreplacement(str[i], alphabet);
}
to build str2. Consider using a range-based for here:
for (char ch: str)
{
str2 += findreplacement(ch, alphabet);
}
It's cleaner and a lot harder to screw up.
There is a function isalpha in the standard library which is very useful for classification.
You could do something like this.
(This kind of exercise usually assumes the ASCII encoding of the English alphabet, and this is a very ASCII-specific solution. If you want a different alphabet or a different character encoding, you need to handle that yourself.)
#include <cctype>
#include <string>
#include <iostream>
int main()
{
std::string str = "Hello*Zzz?";
std::string str2;
for (char c: str)
{
if (std::isalpha(c))
{
c += 1;
if (!std::isalpha(c))
{
// Went too far; wrap around to 'a' or 'A'.
c -= 26;
}
}
str2 += c;
}
std::cout << str2 << std::endl;
}
Output:
Ifmmp*Aaa?

c++ Undefined Reference to Code::morsecode() and Undefined Reference to Code::alphacode()

Getting this error
Undefined Reference to Code::morsecode()
Undefined Reference to Code::alphacode()
collect2: error: ld returned 1 exit status
I compiled using c++ morsecode.cpp. I am unable to figure out what the problem is?? Tried looking through my code to see where the problem lies but I am unable to figure out what the issue is.
Any help is appreciated. Thanks
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class Code
{
public:
Code(); //Default Constructor
string decode(vector<string> message); //Decodes message
private:
vector<string> codewords; //codeword vector parallel to A-Z
vector<char> alpha; //this is the vector for A-Z
vector<char> alphacode(); //Function that builds the vector alpha -A B C...
vector<string> morsecode(); //function builds the vector codewords containing morsecode
char decode(string c); //returns the character for the codeword c.
};
Code::Code()
{
codewords = morsecode();
alpha = alphacode();
}
string Code::decode(vector<string> message)
{
string temp;
for(int i = 0; i < message.size(); i++)
{
temp += decode(message[i]);
}
return temp;
}
char Code::decode(string c)
{
for(int i = 0; i < alpha.size(); i++)
{
if(c == codewords[i])
{
return alpha[i];
}
}
}
// This function returns a vector containing the morse code
vector<string> morsecode()
{
vector<string> temp(28);
temp[0] =".-";
temp[1] ="-...";
temp[2] ="-.-.";
temp[3] ="-..";
temp[4] =".";
temp[5] ="..-.";
temp[6] ="--.";
temp[7] ="....";
temp[8] ="..";
temp[9] =".---";
temp[10] ="-.-";
temp[11] =".-..";
temp[12] ="--";
temp[13] ="-.";
temp[14] ="---";
temp[15] =".--.";
temp[16] ="--.--";
temp[17] =".-.";
temp[18] ="...";
temp[19] ="-";
temp[20] ="..-";
temp[21] ="...-";
temp[22] =".--";
temp[23] ="-..-";
temp[24] ="-.--";
temp[25] ="--..";
temp[26] =".......";
temp[27] ="x";
return temp;
}
// This returns a vector containing the alphabet a-z and " "
vector<char> alphacode()
{
vector<char> temp;
for (char c='A'; c<='Z'; c++)
temp.push_back(c);
temp.push_back(' ');
temp.push_back('.');
return temp;
}
//Main Program
int main()
{
vector<string> message;
string temp;
Code c;
cin >> temp;
while (cin.good())
{
message.push_back(temp);
cin >> temp;
}
cout << c.decode(message) << endl;
return 0;
}
The defined standalone function vector<string> morsecode() is not the desired vector<string> Code::morsecode().

Using isalpha function with string pointers

Hey I'm quite new to programming and I'm having trouble using the isalpha function in my programme. This a part of the code for a palindrome class. What I'm trying to do is remove all the non alphabetic characters from the input. So if the user inputs "Hi, How are you" I need to first count the size of the array of just the letters then in my removeNonLetters subclass, I need to get rid of the non alphabetical characters. Can someone please help me with this. Thank you so much!
#include <iostream>
#include <string>
#include <stdio.h>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <ctype.h>
using namespace std;
class palindrome
{
private:
int only_letters_size;
string input_phrase;
string* only_letters;
public:
string inputPhrase();
string removeNonLetters();
string* new_Array;
int size_new_Array;
};
string palindrome::inputPhrase()
{
cout << "Input phrase: "; //asks the user for the input
getline(cin,input_phrase);
size_new_Array = input_phrase.length(); //creating a dynamic array to store
the input phrase
new_Array = new string[size_new_Array];
int i;
for (i=0; i<size_new_Array; i++)
{
new_Array[i]=input_phrase[i];
}
only_letters_size = 0;
while(new_Array[i])
{
if (isalpha(new_Array[i])) //PROBLEM OCCURS HERE
{
only_letters_size=only_letters_size+1;
}
}
cout << only_letters_size << endl;
return new_Array;
}
string palindrome::removeNonLetters()
{
int j=0;
int str_length = new_Array.length(); //string length
only_letters = new string[only_letters_size];
for (int i=0;i<size_new_Array;i++) //PROBLEM OCCURS HERE AS WELL
{
if (isalpha(new_Array[i]))//a command that checks for characters
{
only_letters[j] = new_Array[i];//word without non alphabetical c
characters is stored to new variable
j++;
}
}
cout << only_letters << endl;
return only_letters;
}
I've found the best way to determine if a string is a palindrome is to walk toward the center from both sides. In your case I would just opt to skip non-alpha characters like so.
bool is_palindrome(string mystring)
{
int start = 0, end = mystring.length() - 1;
while (start < end)
{
// Skip over non-alpha characters
while (!isalpha(mystring[start]))
{
start++;
}
while (!isalpha(mystring[end]))
{
end--;
}
if (tolower(mystring[start]) != tolower(mystring[end]))
{
return false;
}
else
{
start++;
end--;
}
}
return true;
}
If you must save the input first and remove nonalpha characters, I would do it like this.
string remove_non_alpha(string mystring)
{
string ret_string = "";
for (int i = 0; i < mystring.length(); i++)
{
if (isalpha(mystring[i]))
{
ret_string += tolower(mystring[i]);
}
}
return ret_string;
}
And then feed the result into the above function.
Sorry for being hard, but your trying far too much copying around. You can achieve all this with one single loop after retrieving your data and all on one single string object (unless you want to keep the original input for some other purposes):
getline(cin,input_phrase);
std::string::iterator pos = input_phrase.begin();
for(char c : input_phrase)
{
if(isalpha(c))
{
*pos++ = tolower(c);
}
}
input_phrase.erase(pos, input_phrase.end());
After that, your string is ready to use...
Explanation:
std::string::iterator pos = input_phrase.begin();
An iterator something similar than a pointer to the internal data of the string. We keep the position to move the alpha only characters to, skipping the non-alpha ones.
for(char c : input_phrase)
Simply iterating over all characters...
if(isalpha(c))
The essential check, is the current character an alpha one?
*pos++ = tolower(c);
If so, convert it to lower case immediately. Assign it to the current string position, and advance the "pointer" (iterator!).
input_phrase.erase(pos, input_phrase.end());
And at very last, drop the remaining part of the string occupied with surplus characters. You might note that there might be some characters you wanted to keep within, but you copied these to a position more to the left already...