Program producing funky output - c++

I am writing a program that takes in an input stream from std::cin and then fills a map container with all of the words(after removing all punctuation and making them lowercase) from the input along with their frequency.
here is my code...
#include "prog4.h"
void clean_entry(const string& s1, string& s2) {
for (int i = 0; i < s2.size(); i++) {//loop through the string
s2[i] = tolower(s2[i]);
}
}
void get_words(map < string, int >& map1) {
string input;
getline(cin, input);
string s1;
for (int i = 0; i < input.size(); i++ , s1 = "") {//loop through
entire input
if (isalnum(input[i]) == 0) {//if its a alphanumeric char
for (int d = i; isalnum(input[d]) == 0;d++) {//make s1 the
next set of characters between punctuation
s1 += input[d];
if (isalnum(input[d]) != 0)//update i to the next non
alfanumeric character position
i = d;
}
}
clean_entry(s1, s1);
map1[s1]++;
}
}
void print_words(const map < string, int >& m1) {
map<string, int>::const_iterator it;
cout << "Number of non-empty words: " << m1.size() << '\n';
int count = 0;
for (it = m1.begin(); it != m1.end(); it++) {
if (it->second == 1)
count++;
}
cout << "Number of distinct words: " << count << '\n';
it = m1.begin();
for (int y = 0; it != m1.end(); it++,y++) {
if (y % 3 == 0) {
cout << '\n';
}
cout << setw(20) << it->first << setw(10) << it->second;
}
}
int main() {
map <string, int> m1;
get_words(m1);
print_words(m1);
return 0;
}
I have tested the print and clean methods and they both work as expected. The problem I am getting is when I use the get_words method undoubtedly.
As an example when I use the input "Huge Muge Cuge luge" this is what I get as an output...
Number of non-empty words: 2
Number of distinct words: 0
16 3
I'm not sure what is causing this to happen and after reviewing the code I cant seem to find the problem which is why i'm posting here

Let me list out few problems which I can observe in your code.
The isalnum function returns non-zero value for alphanumeric characters.
That means the statement
if (isalnum(input[i]) == 0) { in function get_words should be changed to
if (isalnum(input[i]) != 0) {
Also, statement for (int d = i; isalnum(input[d]) == 0;d++) { should be changed to for (int d = i; isalnum(input[d]) != 0;d++) {
Another problem is that statement i = d; will not be executed as when for loop break it will skip those lines since conditions are just opposite. You can fix that by moving declaration of d out of for loop. The modified function should be:
=>
void get_words(map < string, int >& map1)
{
string input;
getline(cin, input);
string s1;
for (int i = 0; i < input.size(); i++ , s1 = "")
{
if (isalnum(input[i]) != 0)
{//if its a alphanumeric char
int d;
for (d = i; isalnum(input[d]) != 0;d++)
{
s1 += input[d];
}
if (isalnum(input[d]) == 0)
i = d;
}
clean_entry(s1, s1);
map1[s1]++;
}
}

Related

Getting "Exited with return code -11(SIGSEGV)" when attempting to run my code

#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> separate(string str){
string build = "";
vector<string> temp;
for(int i = 0;i < str.size(); i++){
if(str[i] != ' '){
build += str[i];
} else if(str[i] == ' '){
temp.push_back(build);
build = "";
}
}
return temp;
}
int main() {
int count;
string sentence;
vector<int> numTimes;
getline(cin, sentence);
vector<string> words = separate(sentence);
for(int i = 0; i < words.size(); i++){
for(int j = 0; j < words.size(); i++){
if(words[i] == words[j]){
count++;
}
}
numTimes.push_back(count);
}
for(int k = 0; k < words.size(); k++){
cout << words[k] << " - " << numTimes[k] << endl;
}
return 0;
}
The code is supposed to receive a string, separate it into the individual words, place those words into a vector and finally output the number of times the word occurs in the sentence. However when running my code, I get a message saying that the program was exited with code -11. I have looked a bit online but do not fully understand what this means or where it is occurring in my code.
Changed signed counter variables (i, j) to unsigned (size_t) as you compare the two. In separate(..) changed if-else-if to just if-else, and fixed the loop per #user4581301 to use the right loop variable. Also fixed last word not being added. Minor reformat to use tab/8 space for indent.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> separate(string str) {
string build = "";
vector<string> temp;
for(size_t i = 0; i < str.size(); i++) {
if(str[i] == ' ') {
temp.push_back(build);
build = "";
} else {
build += str[i];
}
}
if(build.size()) {
temp.push_back(build);
}
return temp;
}
int main() {
int count = 0;
string sentence;
vector<int> numTimes;
getline(cin, sentence);
vector<string> words = separate(sentence);
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < words.size(); j++) {
if(words[i] == words[j]) {
count++;
}
}
numTimes.push_back(count);
}
for(size_t k = 0; k < words.size(); k++) {
cout << words[k] << " - " << numTimes[k] << endl;
}
return 0;
}
This seems to fix the segfault which answers question posed.
You haven't provided sample input and output but the counts clearly seems wrong. What do you mean with sentence? There is no notion of English sentences ending with '.' or whatever:
./a.out
a bc d
a - 1
bc - 2
d - 3
./a.out
a a b
a - 2
a - 4
b - 5
Suggest you work on that and open new question if you need further help.
#Allan Wind is right, but to offer an alternate solution using the C++17 standard.
Iterating
Rather than use indexes, let's use a more modern for loop.
for (const char &ch : s)
Rather than:
for (size_t i = 0; i < str.size(); i++)
After all, the index is not important in this situation.
Dealing with multiple spaces
Right now, both the OP's code and Allan's will push an empty string onto the output vector whenever they encounter more than one contiguous space. We can correct that by resetting the string to empty when a space is encountered, but when a space is encountered and the string is empty, don't take any action.
We also need to check if the string is non-empty when the loop is finished. If so, we need to push that onto the output vector. We may not get a trailing space to trigger pushing that last word.
vector<string> separate(string s) {
vector<string> output;
string current = "";
for (const char &ch : s) {
if (current != "" && ch == ' ') {
output.push_back(current);
current = "";
}
else if (ch == ' ') {
// Do nothing!
}
else {
current += ch;
}
}
if (current != "") {
output.push_back(current);
}
return output;
}
Putting it together so far
#include <string>
#include <vector>
#include <iostream>
using namespace std;
vector<string> separate(string s);
int main() {
auto v = separate("hello world foo");
for (auto i : v) {
cout << i << endl;
}
}
vector<string> separate(string s) {
vector<string> output;
string current = "";
for (const char &ch : s) {
if (current != "" && ch == ' ') {
output.push_back(current);
current = "";
}
else if (ch == ' ') {
// Do nothing!
}
else {
current += ch;
}
}
if (current != "") {
output.push_back(current);
}
return output;
}
Counting words
We can use a map to count the occurrences of words. We use a map<string, int> where each word is the key, and the val is the occurrences. As we iterate over the words, if the word already exists as a key in the map, we increment it by `. If not, we set it to 1.
int main() {
auto v = separate("hello world hello world foo");
map<string, int> m;
for (auto i : v) {
if (m[i]) {
m[i] += 1;
}
else {
m[i] = 1;
}
}
for (auto const& [key, val] : m) {
cout << "The word \"" << key << "\" occurs "
<< val << " times." << endl;
}
}

Inserted in set and received Segmentation fault

I created code to convert graph representation (A list of edges -> the adjacency list)
How can i fix error?
I have Segmentation fault in line res[cur.first - 1].insert(cur.second);for input
4 3
3 2
2 1
4 2
My code
#include <bits/stdc++.h>
using namespace std;
pair<int, int> strToSotredPair(const string& s) {
int a = 0, b = 0;
int pos = 0;
while (s[pos] != ' ') {
a = a * 10 + s[pos] - '0';
++pos;
}
while (pos < s.size()) {
b = b * 10 + s[pos] - '0';
++pos;
}
return {min(a, b), max(a, b)};
}
int main() {
int n, m;
string input;
cin >> n;
cin >> m;
vector<set<int>> res(n, set<int>());
for (int i = 0; i < m; ++i) {
cin >> input;
auto cur = strToSotredPair(input);
res[cur.first - 1].insert(cur.second); // error in this line
}
for (int i = 0; i < res.size(); ++i) {
cout << res[i].size() << ' ';
for (auto item : res[i]) {
cout << item << ' ';
}
cout << endl;
}
}
There are a couple of error's in your code because of which you were getting that error.
You wanted the graph edges as strings. So you need to take edge inputs as strings. For that, you would be required to use getline(cin,input) and cin.ignore().
(My suggestion: Do not take inputs as strings because as it is you are converting them to integers afterwards. By default if you just write cin<<node1<<node2; the two nodes of an edge would have come as integers and function strToSotredPair would not be needed).
In function strToSotredPair after you get the integer a, pos variable is pointing to the space. So you need to increase it by 1 to point to the starting position to 2nd number. Hence a pos++ was needed.
#include <bits/stdc++.h>
using namespace std;
pair<int, int> strToSotredPair(const string& s) {
int a = 0, b = 0;
int pos = 0;
while (s[pos] != ' ') {
a = a * 10 + s[pos] - '0';
++pos;
}
pos++;
while (pos < s.size()) {
b = b * 10 + s[pos] - '0';
++pos;
}
return {min(a, b), max(a, b)};
}
int main() {
int n, m;
string input;
cin >> n;
cin >> m;
vector<set<int>> res(n, set<int>());
cin.ignore(); // To clear the input buffer
for (int i = 0; i < m; ++i) {
getline(cin, input); // to get line by line string inputs
auto cur = strToSotredPair(input);
res[cur.first - 1].insert(cur.second);
}
for (int i = 0; i < res.size(); ++i) {
cout << res[i].size() << ' ';
for (auto item : res[i]) {
cout << item << ' ';
}
cout << endl;
}
}

How to get a substring by deleting minimum number of characters?

In this question, we take 2 strings as input say s1 and s2.
Now, first we need to check if s2 is a subsequence of s1. If not, print no.
But if it is, we need to print the minimum number of characters to be deleted from s1 to get s2.
Eg- thistext text
Here, text can be directly found without deleting any characters so the answer is 0.
Eg- cutefriendship crisp
In this case, the answer is 9.
What I've done so far,
#include <bits/stdc++.h>
using namespace std;
int checkIfSub(string s1, string s2, int m, int n)
{
int j = 0;
for(int i = 0; i < m && j < n; i++)
if(s1[i] == s2[j])
j++;
if(j == n)
return 0;
else
return 1;
}
int check(string s1, string s2)
{
int count = 0; string s3;
if(checkIfSub(s1, s2, s1.length(), s2.length()) == 1 || s2.length() > s1.length())
{
cout << "NO\n"; return 0;
}
int j = 0;
for(int i = 0; i < s1.length(); i++)
{
if(s1[i] == s2[j])
{
s3[j] = s1[j];
j++; continue;
}
count++;
}
cout << "YES " << count << "\n";
return 0;
}
int main() {
string s1, s2;
cin >> s1 >> s2;
check(s1, s2);
return 0;
}
My code works well for the second example, but fails the first case.
(This was a question asked in some interview I read online.)
Try something like this:
#include <iostream>
#include <string>
using namespace std;
bool check(const string &s1, const string &s2, int &minToDelete)
{
minToDelete = 0;
bool anySubSeqFound = false;
if (s2.empty())
return false;
string::size_type first = 0;
while ((first = s1.find(s2[0], first)) != string::npos)
{
int numDeleted = 0;
bool isSubSeq = true;
string::size_type next = first + 1;
for(string::size_type j = 1; j < s2.size(); ++j)
{
string::size_type found = s1.find(s2[j], next);
if (found == string::npos)
{
isSubSeq = false;
break;
}
numDeleted += (found - next);
next = found + 1;
}
if (isSubSeq)
{
if (anySubSeqFound)
{
if (numDeleted < minToDelete)
minToDelete = numDeleted;
}
else
{
anySubSeqFound = true;
minToDelete = numDeleted;
}
}
++first;
}
return anySubSeqFound;
}
int main()
{
int minToDelete;
if (check("thistext", "text", minToDelete))
cout << "yes, delete " << minToDelete << endl;
else
cout << "no" << endl;
if (check("cutefriendship", "crisp", minToDelete))
cout << "yes, delete " << minToDelete << endl;
else
cout << "no" << endl;
}
Live Demo

map giving some ambiguous value

The output expected is "2a3b3c4d3l4z" but
i'm getting:12a3b3c4d3l4z.
Why the extra "1" is coming in the output?
char ipstr[] = "aabbbcccddddzzzzlll";
cout<<"size of string:"<<sizeof(ipstr)<<endl;
num = 0;
map<char, int> ms;
for(int i = 0; i<sizeof(ipstr);i++){
if(ipstr[i] == ipstr[i+1])
num++;
else{
ms[ipstr[i]] = num+1;
num = 0;
}
}
for(auto it = ms.begin();it != ms.end();it++){
cout<<it->second<<it->first;
}
cout<<endl;
The extra 1 is the printout of the entry {'\0', 1} caused by taking the trailing '\0' into the loop. The \0 is not printable, therefore you see only 1.
You evaluated your string length including '\0' character (it can be ambigious that string ends with this one). Then in a for loop you added '\0' to the map. But what does it mean to print null character. That's why you have 1 and a whitespace at the beginning.
char ipstr[] = "aabbbcccddddzzzzlll";
int n = strlen(ipstr);
cout << "size of string:" << n << endl;
int num = 0;
map<char, int> ms;
for (int i = 0; i < n - 1; i++) {
if (ipstr[i] == ipstr[i + 1])
num++;
else {
ms[ipstr[i]] = num + 1;
num = 0;
}
}
for (auto it = ms.begin(); it != ms.end(); it++) {
cout << it->second << it->first;
}
cout << endl;

How do I make Palindrome function reverse more than one word

My palindrome function's supposed to find a word (or more than one word) in string, compare it with a bunch of other strings in the container, and if it finds one that's the same, reverse it, and stick them together. E.g. palindrome -> palindromeemordnilap, or if it's a more than one word: two words > two wordssdrow owt.
Mine's working for only one word, and also, for some reason, fails to correctly reverse the last one in the sentence. What should I, if even possible, change to accomplish the above?
#include <iostream>
#include <vector>
#include <string>
typedef std::vector<std::string> StringVektor;
std::string ReverseString(std::string s1)
{
std::string to_return(s1);
char temp(0);
for (int i(0); i < vrati.size() / 2; i++)
{
temp = to_return.at(i);
to_return.at(i) = to_return.at(to_return.length() - 1 - i);
to_return.at(to_return.length() - 1 - i) = temp;
}
return to_return;
}
std::string CreatePalindrome(String s, StringVektor v)
{
std::string compare;
for (int i(0); i < s.size(); i++)
{
if (s.at(i) != ' ')
compare += s.at(i);
if (s.at(i) == ' ' || i == s.length() - 1)
{
for (int j(0); j < v.size(); j++)
{
if (compare == v.at(j))
{
std::string put_in;
put_in = ReverseString(v.at(j));
s.insert(i, put_in);
}
}
compare.clear();
}
}
std::string to_return;
to_return = s;
return to_return;
}
int main ()
{
std::string sentence, phrase;
StringVektor v1;
std::cout << "Enter your sentence: ";
std::getline(std::cin, sentence);
std::cout << "Enter phrases: ";
for ( ;;)
{
std::getline(std::cin, phrase);
if(!fraza.empty())
v1.push_back(phrase);
if(std::cin.peek() == '\n')
break;
}
std::cout << "Your sentence after the transformation: " <<
CreatePalindrome(sentence, v1);
return 0;
}