How to write optimized constructor in a class > - c++

I wrote writing an email class, but I am not sure if this is the best way to write this... here's the code for it...
class email
{
string value;
string domain;
string com;
string username;
string encrypted;
bool state ;
public:
email(const string& val)
:value{ val}, state{false},com(),domain(),username(),encrypted()
{
for (int i = 0; i < value.size(); ++i)
{
if (value[i] == '#')
{
username = value.substr(0, i);
for (int j = i; j < value.size(); ++j)
{
if (value[j] == '.')
{
domain = value.substr(i, j);
com = value.substr(j+1, value.size()-1);
state = true;
}
}
}
}
if (state)
{
for (auto letter : value)
{
if (letter == ';' || letter == '\'' || letter == '[' || letter == ']')
{
state = false;
}
}
} else throw "invalid string";
if (state)
{
encrypted = username;
for (int i = 0; i < username.size() / 2; ++i)
{
swap(encrypted[i], encrypted[encrypted.size() - 1 - i]);
encrypted[i] = static_cast<char>(static_cast<int>(encrypted[i]) + 3);
}
}else throw "invalid charecters";
}
const string& get_domain() { return domain; }
const string& get_username() { return username; }
const string& get_com() { return com; }
const string& get_enc() { return encrypted; }
const bool good () const { return state; }
};
It's not completed yet, this is just a quick sketch from what I can remember because I don't have the actual code right now, my question is should I make another class to support the email class.. or is this the right way? I wrote a lot of code inside the constructor, that's what I am worried about.

You could break the for loops, if you have done your stuff.
First for: after you found '#' you do not have to loop to the end
Third for: after you found an error, you could throw immediatelly

Related

C++ program to count repeated words in a cstring

I've been working on a C++ program, I've made the logic but I'm unable to execute it. The question is:
Task: Write a program, using functions only, with the following features.
Program reads paragraph(s) from the file and stores in a string.
Then program counts the occurrence of each word in the paragraph(s) and stores all words with their number of occurrences.
If that word has appeared more than one time in whole string, it should store the word only once along its total occurrences.
The output described in above (in part 3) must be stored in a new file.
Sample input:
is the is and the is and the and is and only that is
Sample output:
is 5
the 3
and 4
only 1
that 1
I'll cut short to Occurrence program that I've written,
My logic is to store token into character array and then compare that array with main character array and do the increment:
void occurances() {
char* string = getInputFromFile();
char separators[] = ",.\n\t ";
char* token;
char* nextToken;
char* temp[100];
token = strtok_s(string, separators, &nextToken);
cout << temp;
int counter = 0;
int i = 0;
while ((token != NULL)) {
temp[i] = token;
i++;
for (int i = 0; i < strlen(string); i++) {
for (int j = 0; j < 100; j++) {
if ((strcmp(token, *temp)) == 0) {
counter++;
}
}
cout << temp << " : " << counter << endl;
}
if (token != NULL) {
token = strtok_s(NULL, separators, &nextToken);
}
}
}
This code is preposterous I know that, But please anyone be kind enough to give me a clue, actually I'm new to C++ . Thank you
If you store token into array this array should grow dynamically because the number of tokens is not known at the beginning. And according to the task description, you cannot use C++ standard containers, so, it is necessary to implement dynamic array manually, for example:
#include <iostream>
std::size_t increase_capacity_value(std::size_t capacity) {
if (capacity == 0) {
return 1;
}
else if (capacity < (SIZE_MAX / 2)) {
return capacity * 2;
}
return SIZE_MAX;
}
bool increase_array_capacity(char**& tokens_array, std::size_t*& tokens_count, std::size_t& capacity) {
const std::size_t new_capacity = increase_capacity_value(capacity);
if (new_capacity <= capacity) {
return false;
}
const std::size_t tokens_array_byte_size = new_capacity * sizeof(char*);
char** const new_tokens_array = static_cast<char**>(std::realloc(tokens_array, tokens_array_byte_size));
if (new_tokens_array == nullptr) {
return false;
}
tokens_array = new_tokens_array;
const std::size_t tokens_count_byte_size = new_capacity * sizeof(std::size_t);
std::size_t* const new_tokens_count = static_cast<std::size_t*>(std::realloc(tokens_count, tokens_count_byte_size));
if (new_tokens_count == nullptr) {
return false;
}
tokens_count = new_tokens_count;
capacity = new_capacity;
return true;
}
bool add_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
if (array_size == array_capacity) {
if (!increase_array_capacity(tokens_array, tokens_count, array_capacity)) {
return false;
}
}
tokens_array[array_size] = token;
tokens_count[array_size] = 1;
++array_size;
return true;
}
std::size_t* get_token_count_storage(char* token, char** tokens_array, std::size_t* tokens_count, std::size_t array_size) {
for (std::size_t i = 0; i < array_size; ++i) {
if (std::strcmp(token, tokens_array[i]) == 0) {
return tokens_count + i;
}
}
return nullptr;
}
bool process_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
std::size_t* token_count_ptr = get_token_count_storage(token, tokens_array, tokens_count, array_size);
if (token_count_ptr == nullptr) {
if (!add_token(token, tokens_array, tokens_count, array_size, array_capacity)) {
return false;
}
}
else {
++(*token_count_ptr);
}
return true;
}
int main() {
char string[] = "is the is and the is and the and is and only that is";
char separators[] = ",.\n\t ";
std::size_t token_array_capacity = 0;
std::size_t token_array_size = 0;
char** tokens_array = nullptr;
std::size_t* tokens_count = nullptr;
char* current_token = std::strtok(string, separators);
while (current_token != nullptr) {
if (!process_token(current_token, tokens_array, tokens_count, token_array_size, token_array_capacity)) {
break;
}
current_token = std::strtok(nullptr, separators);
}
// print the report only if all tokens were processed
if (current_token == nullptr) {
for (std::size_t i = 0; i < token_array_size; ++i) {
std::cout << tokens_array[i] << " : " << tokens_count[i] << std::endl;
}
}
std::free(tokens_array);
std::free(tokens_count);
}
godbolt.org
okay what if i want to store any token once, in an array and then replace it with new word while deleting duplicates in character array
It is also possible solution. But in general case, it is also necessary to allocate the memory dynamically for the current token. Because the lengths of tokens are also not known at the beginning:
void replace_chars(char* str, const char* chars_to_replace) {
while (str && *str != '\0') {
str = std::strpbrk(str, chars_to_replace);
if (str == nullptr) {
break;
}
const std::size_t number_of_delimiters = std::strspn(str, chars_to_replace);
for (std::size_t i = 0; i < number_of_delimiters; ++i) {
str[i] = '\0';
}
str += number_of_delimiters;
}
}
bool keep_token(char*& token_storage, const char* new_token) {
if (new_token == nullptr) {
return false;
}
const std::size_t current_token_len = token_storage ? std::strlen(token_storage) : 0;
const std::size_t requried_token_len = std::strlen(new_token);
if (token_storage == nullptr || current_token_len < requried_token_len) {
token_storage =
static_cast<char*>(std::realloc(token_storage, (requried_token_len + 1) * sizeof(char)));
if (token_storage == nullptr) {
return false;
}
}
std::strcpy(token_storage, new_token);
return true;
}
std::size_t count_tokens_and_replace(char* str, std::size_t str_len, const char* token) {
std::size_t number_of_tokens = 0;
std::size_t i = 0;
while (i < str_len) {
while (str[i] == '\0') ++i;
if (std::strcmp(str + i, token) == 0) {
replace_chars(str + i, token);
++number_of_tokens;
}
i += std::strlen(str + i);
}
return number_of_tokens;
}
int main() {
char string[] = "is the is and the is and the and is and only that is";
char separators[] = ",.\n\t ";
const std::size_t string_len = std::strlen(string);
replace_chars(string, separators);
std::size_t i = 0;
char* token = nullptr;
while (true) {
while (i < string_len && string[i] == '\0') ++i;
if (i == string_len || !keep_token(token, string + i)) break;
std::cout << token << " : " << count_tokens_and_replace(string + i, string_len - i, token) << std::endl;
}
std::free(token);
}
godbolt.org
But if it is known that the token length cannot be greater than N, it is possible to use the static array of chars to keep the current token. And it will allow to remove dynamic memory allocation from the code.

pattern matching (codejam round 1A previous year) solution not working

I am trying previous year's codejam question of round 1A
link to question
i have submitted this code(start reading from main method, for ease)-
#include <bits/stdc++.h>
using namespace std;
#define range(t) for (int i = 0; i < t; i++)
#define rangeG(i, t) for (i = 0; i < t; i++)
#define printVec(vec) \
for (auto c : vec) \
{ \
cout << c << endl; \
}
vector<string> separate(string s)
{
vector<string> result;
range(s.size())
{
if (s[i] == '*')
{
string temp = s.substr(0, i + 1);
if (temp.size() > 1)
{
result.push_back(temp);
}
s = s.substr(i, s.size());
i = 0;
}
else if (i == (s.size() - 1))
{
string temp = s.substr(0, i + 1);
result.push_back(temp);
s = s.substr(i, s.size());
}
}
return result;
}
void removeAsterisk(string &s)
{
s.erase(remove(s.begin(), s.end(), '*'), s.end());
}
bool setStart(string s, string &start)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), start.size()))
{
if (s[i] != start[i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= start.size())
{
start = s;
}
}
return possible;
}
bool setEnd(string s, string &end)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), end.size()))
{
if (s[s.size() - 1 - i] != end[end.size() - 1 - i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= end.size())
{
end = s;
}
}
return possible;
}
void solve()
{
int n;
cin >> n;
vector<string> allS;
bool possible = 1;
string start = "";
string end = "";
string middle = "";
string result = "";
while (n--)
{
string str;
cin >> str;
if (count(str.begin(), str.end(), '*') == 0)
{
result = str;
}
vector<string> temp = separate(str);
for (string s : temp)
{
if (s[0] != '*')
{
possible = setStart(s, start);
}
if (s[s.size() - 1] != '*')
{
possible = setEnd(s, end);
}
if (possible && count(s.begin(), s.end(), '*') == 0)
{
result = s;
break;
}
if (s[0] == '*' && s[s.size() - 1] == '*')
{
removeAsterisk(s);
middle += s;
}
}
}
if (possible)
{
if (result.size() == 0)
{
result = start + middle + end;
}
cout << result << "\n";
}
else
{
cout << "*\n";
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 0;
cin >> t;
range(t)
{
cout << "Case #" << i + 1 << ": ";
solve();
}
return 0;
}
it seems correct to me and i have tested many times for many examples, but it is losing in test set-1(exactly one * (asterisk) character and and always the first character of string). Can anyone tell what's wrong?
you can consider code of first ranked here (it has all solutions,check only for "pattern matching" task) for help. I know that the wrong answer is an edge case and if it passes test set 1 then it will pass others.

Recursion returning function without returning in special cases

I need to combine a given password by bruteforce. So I decided to use recursion function which returns string
string bruteforce(string password, string forcedPassword)
{
if (password.length() == forcedPassword.length())
{
if (password == forcedPassword)
{
return forcedPassword;
}
// What can I do here to return nothing and continue from the previous step?
}
for (int j = 32; j <= 126; j++)
{
forcedPassword += char(j);
bruteforce(password, forcedPassword);
}
}
int main()
{
...
cin >> password;
cout << bruteforce(password, "");
...
}
The problem is when I get password.length() == forcedPassword.length() but they are not the same. I need to exit only the last step of the recursion without any returning values. Is there any way to make it?
Assuming non empty password (else use optional), you may write:
std::string bruteforce(const std::string& password, const std::string& forcedPassword)
{
if (password.length() == forcedPassword.length())
{
if (password == forcedPassword)
{
return forcedPassword;
}
return "";
}
for (int j = 32; j <= 126; j++)
{
auto res = bruteforce(password, forcedPassword + char(j));
if (!res.empty()) {
return res;
}
}
return "";
}
I don't know if this will help you or not in your specific case:
std::string bruteforce( const std::string& enteredPassword, std::string& forcedPassword ) {
if ( enteredPassword.length() == forcedPassword.length() ) {
if ( enteredPassword == forcedPassword ) {
return forcedPassword;
}
return "";
}
static int j = 31;
while ( j <= 126 ) {
++j;
// Display forcedPassword to test it for each recursive iteration
std::cout << forcedPassword << "\n";
return bruteforce( enteredPassword, forcedPassword + char( j ) );
}
return "";
}
int main() {
std::string password;
std::string forcedPassword( "Hello" );
std::cout << "Enter the password\n";
std::cin >> password;
std::cout << bruteforce( password, forcedPassword );
std::cout << "\Press any key and enter to quit.\n";
char q;
std::cin >> q;
return 0;
}
But this does compile, build and run without errors, and there is no stack overflow here.
I made the enteredPassword a const ref since it will not be modified by this function. For the forcedPassword since you are showing that you are concatenating to this string I choose to make this a non const reference that will be modified. Instead of a for loop from [32,126], I choose to use a while loop using a static int counter. I initially set this value to 31 and check this loop while it is <= 126. Then within the loop I pre-increment the static counter, I then display the forcedPassword value for debugging purposes. Finally I return this recursive function passing in the original non modified enteredPassword along with the forcedPassword while updating it with char(j). For control paths where there are no operations to be made I simply just returned "";
Using bool function as suggested in comments you can do
#include <iostream>
using namespace std;
bool bruteforce(const string& password, string& forcedPassword, unsigned int length=0)
{
if (password.length() == length)
{
if (password == forcedPassword)
{
return true;
}
return false;
}
for (int j = 32; j <= 126; ++j)
{
forcedPassword[length] = char(j);
if ((bruteforce(password, forcedPassword, length+1)))
return true;
}
}
std::string findpassword(const string& password) {
std::string forcedPassword = "";
while (forcedPassword.length() < password.length())
forcedPassword.push_back('a');
if (bruteforce(password, forcedPassword))
return forcedPassword;
else
return "failed";
}
int main()
{
std::string password;
cin >> password;
cout << findpassword(password);
}

Can't find the frequency of the words C++

I'm trying to show how many times a word appears in a file. I'm not allowed to use third party libraries (c++ stl, boost etc.) Thats why im having a trouble. This is what i got so far;
I created an array list to store the words in the file. I got rid of the punctuations and numbers. Now i need to print all the words with their frequency and sort with respect to frequency like this;
Words: Frequency:
their 13
how 10
apple 9
is 5
arrayList.h
#include <iostream>
#include <string>
using namespace std;
class arrayList
{
public:
bool isEmpty() const;
bool isFull() const;
int listSize() const;
void print() const;
void insertAt(int location, const string& insertItem);
void removeAt(int location);
string retrieveAt(int location) const;
bool seqSearch(const string& item) const;
void insert(const string& insertItem);
void remove(const string& removeItem);
arrayList(int);
~arrayList();
private:
string *list;
int length;
int maxSize;
};
arrayList.cpp
#include "arrayList.h"
bool arrayList::isEmpty() const
{
return (length == 0);
}
bool arrayList::isFull() const
{
return (length == maxSize);
}
int arrayList::listSize() const
{
return length;
}
void arrayList::print() const
{
for (int i = 0; i < length; i++)
cout << list[i];
}
void arrayList::insertAt(int location, const string& insertItem)
{
list[location] = insertItem;
length++;
}
void arrayList::removeAt(int location)
{
for (int i = location; i < length - 1; i++)
list[i] = list[i+1];
length--;
}
string arrayList::retrieveAt(int location) const
{
return list[location];
}
bool arrayList::seqSearch(const string& item) const
{
int loc;
bool found = false;
for (loc = 0; loc < length; loc++)
if (list[loc] == item)
{
found = true;
break;
}
if (found)
return 1;
else
return 0;
}
void arrayList::insert(const string& insertItem)
{
list[length++] = insertItem;
}
void arrayList::remove(const string& removeItem)
{
int loc;
loc = seqSearch(removeItem);
removeAt(loc);
}
arrayList::arrayList(int size)
{
maxSize = size;
length = 0;
list = new string[maxSize];
}
arrayList::~arrayList(void)
{
delete [] list;
}
Source.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "arrayList.h"
#include <cctype>
using namespace std;
int wordCount(ifstream &file)
{
string word;;
int count=0;
while (file >> word)
{
count++;
}
file.clear();
file.seekg(0, ios::beg);
return count;
}
string removePunct(string word)
{
for (unsigned int i = 0; i < word.length(); i++)
{
if( word[i] == '.')
word[i] = ' ';
else if(word[i] == ',')
word[i] = ' ';
else if(word[i] == ';')
word[i] = ' ';
else if(word[i] == ':')
word[i] = ' ';
else if(word[i] == '?')
word[i] = ' ';
else if(word[i] == '-')
word[i] = ' ';
else if(word[i] == '[')
word[i] = ' ';
else if(word[i] == ']')
word[i] = ' ';
else if(word[i] == '(')
word[i] = ' ';
else if(word[i] == ')')
word[i] = ' ';
else if(word[i] == '!')
word[i] = ' ';
else if(word[i] == '\"')
word[i] = ' ';
else if(word[i] == '\'')
word[i] = ' ';
else if(word[i] == '_')
word[i] = ' ';
}
return word;
}
string makelower (string word)
{
for (unsigned int i = 0; i < word.length(); i++)
{
if ( isupper(word[i]) )
word[i] = tolower(word[i]);
}
return word;
}
int main ()
{
string fileName;
ifstream file;
cout << "Please enter the file name: ";
getline(cin,fileName);
file.open(fileName);
int listSize = wordCount(file);
arrayList list1(listSize*2);
string word, newWord;
int i = 0;
while (file >> word)
{
if (word[i] >= '1' && word[i]<= '9')
{
list1.insert(" ");
i++;
}
else
{
newWord = makelower(word);
list1.insert(removePunct(newWord));
list1.insert(" ");
}
}
/*int *counter = new int [listSize*2]; //I tried this but don't think its working
string item;
for (int i = 0; i < list1.listSize(); i++)
{
if( list1.retrieveAt(i) != " " )
{
string item = list1.retrieveAt(i);
while ( list1.seqSearch(item) )
counter[i]++;
}
}*/
system("pause");
return 0;
}
Any help is appreciated.
You have strange things going on in your code. But i think it doesn't effect your real problem.
The solution would be something like this:
class freqList
{
freqList(int size)
{
words = new string[size];
freqList = new int[size];
memset(freqList, 0, sizeof(int)*size); //set freqs to 0
length = 0;
}
int seqSearch(const string& item) const
{
...
return index_of_item; //-1 if you can't find it
}
void insertWord(string word)
{
int idx = searchSeq(word);
if(idx >= 0)
{//it already exists in the words list
freqs[idx]++;
}
else
{// new word, add to the end of the list
words[length] = word;
freqs[length]++;
length++;
}
}
...
string *words;
int *freqs; //same size of words
...
};
int wordCount(ifstream &file)
{
string word;;
int count=0;
while (file >> word)
{
word = removePunct(word);
word = wordToLower(word);
if(isWord(word))
count++;
}
file.clear();
file.seekg(0, ios::beg);
return count;
}
bool isWord(word)
{
//write a function which fills your constraints
}
Now, the main function should be like this:
int listSize = wordCount(file);
freqList freqs(listSize);
string word;
int i = 0;
while (file >> word)
{
word = removePunct(word);
word = wordToLower(word);
... // maybe you have other constraints
if (isWord(word))
{
freqs.insert(word);
}
}
After the while loop, you have freq list with words and freqs corresponding to each word.

Palindrome detector using stacks and queues C++

I am working on palindrome detector in C++ that reads in a file and marks the lines that are palindromes with the indicator "*". Here's what I have.
PalindromeDetector::PalindromeDetector(const string& iFile, const string& oFile) {
myInFile = iFile;
myOutFile = oFile;
}
void PalindromeDetector::detectPalindrome() {
ifstream fin(myInFile.data());
ofstream fout(myOutFile.data());
string nLine, palLine;
while (getline(fin, nLine)){
if (isPalindrome(nLine)){
fout << nLine << " ***";
} else {
fout << nLine;
}
}
fin.close();
fout.close();
}
bool PalindromeDetector::isPalindrome(const string& str) {
Stack<char> charStack(1);
ArrayQueue<char> charQueue(1);
char ch1, ch2;
for ( unsigned i = 0; i < str.size(); i++){
if (isalnum (str[i])){
tolower(str[i]);
try {
charStack.push(str[i]);
charQueue.append(str[i]);
} catch ( StackException& se ){
charStack.setCapacity(charStack.getCapacity() * 2);
charQueue.setCapacity(charQueue.getCapacity() * 2);
charStack.push(str[i]);
charQueue.append(str[i]);
}
} else {
while ( !charStack.isEmpty() || !charQueue.isEmpty() ){
ch1 = charStack.pop();
ch2 = charQueue.remove();
if ( ch1 != ch2 ){
return false;
}
}
}
}
return true;
}
I'm having 2 problems with this so far:
1. It isn't correctly outputting the file with the "*" at the end of the line; it's doing it at the front for some reason.
2. It only marks the first line in each block of the file, not the lines that are palindromes.
I would really appreciate some help on this.
Why are you making isPalidrome so complicated?
Could be done as thus
bool isPalidrome(const string &s) {
int left = 0;
int right = s.length() - 1;
while (left < right) {
if (s[left] != s[right]) return false;
left++; right--;
}
return true;
}
Of course you might what to add case-insensitivity
EDIT
Using the more silly way of stacks and queues
bool isPalidrome(const string &s) {
// Put everything on both
std::stack<char> lifo;
std::queue<char> fifo;
unsigned int loop;
for (loop = 0; loop < s.length); ++loop) {
lifo.push(s[loop]);
fifo.push(s[loop]);
}
// Note stack and queue the characters are in reverse order from each other
for (loop = 0; loop < s.length); ++loop) {
if (lifo.pop() != fifo.pop()) return false;
}
return true;
}