Function To Count occurrence of given string - c++

#include<iostream>
using namespace std;
void check_exist_get_count(string str,char ch)
{
int counter=0;
for(int x=0;x<str.length();x++)
{
if(str[x]==ch)
counter++;
}
cout<<ch<<" : "<<counter;
}
int main ()
{
string str;
cin>>str;
for(int x=0;x<str.length();x++)
{
check_exist_get_count(str,str[x]);
}
return 0;
}
Without built in function i need to to count the occurence of letter but i have problem what condition i should use to check which make for loop not sending letter more than one time
example:in my code i get
input
aaabbc
output
a : 3 a : 3 a : 3 b : 2 b : 2 c : 1
but Required answer should be
a : 3 b : 2 c : 1

You're just iterating over the string once in your main function, and for every character in that string, again go over the whole string and count how many characters like that are in there.
What you don't do is track which characters you already have counted, that's why you count them multiple times. Don't nest loops (calling your function inside the first loop), but tear those things apart:
One option would be to do a first pass over the string, in which you just build a list of characters that are in the string, something like this:
std::set<char> chars;
for (char c: str)
{
chars.insert(c); // a set doesn't allow duplicate entries
// so you don't have to check yourself if it's already in there
}
Then you could, in a second loop, call count for each of the characters in the set. That would still be inefficient, though; you can use a map for keeping track what characters are as well as their count so far. Something like this:
Code to compute the histogram of character frequencies then could look something like this:
#include <iostream>
#include <map>
#include <string>
int main ()
{
std::string str("aaabbc");
std::map<char, size_t> charHistogram;
for (char c: str)
{
// if c not contained in map yet, it's automatically initialized to 0
++charHistogram[c];
}
for (auto const & p: charHistogram)
{
std::cout << p.first << " : " << p.second << " ";
}
return 0;
}
See code in cpp.sh

Another option to add to #codeling's answer. Same idea, but different implementation:
You can use an array to count the used letters.
First array position will tell you number of appearances for 'a', second position for 'b' and so on.
You could extend it to count uppercase and symbols.
You could also change the std::array for a size_t counts[26] array.
[Demo]
#include <array>
#include <iostream> // cout
#include <string>
int main()
{
const std::string s{"aaabbc"};
std::array<size_t, 26> counts{};
for (auto&& ch : s)
{
if (ch >='a' and ch <= 'z')
{
counts[ch - 'a']++;
}
}
for (char i{0}; i < counts.size(); ++i)
{
if (counts[i])
{
std::cout << static_cast<char>('a' + i) << ": " << counts[i] << "\n";
}
}
}

Related

Duplicate character in a string in array c++. It is throwing garbage please help me out [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 months ago.
Improve this question
I have created a program for finding the duplicate character in a string. It is throwing garbage please help me to find the error and also find out its solution. I have created two arrays array a and b array a is a character array and array b is a integer array. array a is storing the characyeer that occurred in the string and array b for storing their frequency. please help me to find out the error
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
string s;
int i,j,k,l,m,n=0;
cout<<"Enter a string:";
cin>>s;
while (s[i]!='\0')
{
j++;
i++;
}
char *a=(char *)malloc(j*sizeof(char));
int *b = (int *)malloc(j*sizeof(int));
for (i=0;i<j;i++)
{
b[i]=0;
}
for (i=0;i<j;i++)
{
l=0;
for (k=0;k<i;k++)
{
if (s[i]==a[k])
{
b[k]++;
}
else
{
l++;
}
}
if (l+1==i)
{
a[i]=s[i];
b[i]++;
n++;
}
}
i=0;
while (a[i]!='\0')
{
m++;
i++;
cout<<a[i];
}
for (i=0;i<m;i++)
{
if (b[i]>1)
{
cout<<a[i]<<"occurs "<<b[i]<<" times";
}
}
return 0;
}
Let's actually use C++:
#include <cctype>
#include <iostream>
#include <string>
#include <unordered_map>
int main() {
std::string sample{"rat cat bat"};
std::unordered_map<char, int> letterFrequencies;
for (auto c : sample) {
if (std::isalpha(c)) {
++letterFrequencies[c];
}
}
for (auto entry : letterFrequencies) {
if (entry.second > 1) {
std::cout << "'" << entry.first << "' occurs " << entry.second
<< " times.\n";
}
}
}
Output:
❯ ./a.out
't' occurs 3 times.
'a' occurs 3 times.
Analyzing your code is difficult, as it seems to do far more than what's necessary. What it's doing unnecessarily is difficult to determine as your variable names are awful. Even if I wanted to use your two array method, I wouldn't. This can be done manually with a single array.
I don't know what the point of the nested loops are at all. All you need to do is count, and then analyze. That doesn't require nesting. It's two distinct loops.
You sized a wrong. It should be the size of the alphabet, not the size of your string that might have repeated characters that you are trying to count. But like I said, this array is unnecessary.
Shortcomings of the example above are that upper case and lower case letters are treated as different letters. It's an easy enough fix using another function from <cctype>.
It also explicitly only lists letters that were repeated.
std::unordered_map is a key-value data structure (similar to a python dictionary), usually implemented as a hash-map, meaning that lookups are very fast. Our keys are the letters of the string, the value is the count. The other key property is that when using operator[], if the key doesn't exist, it will be created for us.
Here is a different program that doesn't use a map.
#include <array>
#include <cctype>
#include <iostream>
#include <string>
int main() {
std::string sample{"rat cat bat"};
std::array<int, 26> letterFrequencies{0};
for (auto c : sample) {
if (std::isalpha(c)) {
++letterFrequencies[std::toupper(c) - 'A'];
}
}
for (std::size_t entry = 0; entry < letterFrequencies.size(); ++entry) {
if (letterFrequencies[entry] > 1) {
std::cout << "'" << static_cast<char>(entry + 'A') << "' occurs "
<< letterFrequencies[entry] << " times.\n";
}
}
}
Output:
❯ ./a.out
'A' occurs 3 times.
'T' occurs 3 times.
This program treats upper case and lower letters as the same.

Process exited prematurely with a SIGSEGV signal

This code shows this SIGSEGV error, which I understand, is a segmentation error. Can someone please help!
The code returns the count of distinct case-insensitive alphabetic characters and numeric digits that occur more than once in the input string.
I am using this on a programming challenge so this is only a function.
So, If I input "aabcdef" it should return 2 because 'a' occurs twice. Input can contain alphabets as well as numerics.
int duplicateCount(const char* in)
{
int a[39]={0},b=0;
for(int i=0;i<strlen(in);i++)
{
if(in == NULL)
return 0;
if((int)in[i] < 97)
{
a[(int)in[i]]++;
}
a[tolower(in[i])-'a'+1]++;
}
for(int i=0;i<39;i++)
{
if(a[i]>1)
b++;
}
return b;
}
Problem is here
if((int)in[i] < 97)
{
a[(int)in[i]]++;
}
a[tolower(in[i])-'a'+1]++;
you may write outside of bounds which, as we know, has UB.
Fix
First you have to check if character is letter with isalpha(c)
Then you have to transform character to lower via tolower(c)
And sub the first low case letter in alphabet c - 'a'
Then you can index an array and increment its value.
Here is fixed code
Since we are in c++, you may use std::map
#include <iostream>
#include <map>
int main()
{
std::string text("aabbc");
std::map<char, int> letterCounter;
for(auto& it : text)
{
letterCounter[it]++;
}
for (auto& it : letterCounter)
{
if (it.second > 1)
{
std::cout << "Character " << it.first << " has appeared "
<< it.second << " times." << std::endl;
}
}
return 0;
}
Output
Character a has appeared 2 times.
Character b has appeared 2 times.

How do I look for a word in a string of randomly generated letters i C++?

I'm trying to make a program that contiues to randomly generate a string of letters, but stop when it has generated a word the user have entered.
I have made it generate the letters but I don't know how to make it recognize a word from it.
for (int i = 1; i < 1000; i++) {
int n = rand() % 26;
char c = (char)(n + 65);
cout << c;
}
return 0;
I'm gonna change the for loop to a while loop when I know how to make it find the users input.
I'm very new to programming so the solution is most likely obvious.
As one of the comments suggests, you need to create a string from your chars. After that, I would suggest looking at:
http://www.cplusplus.com/reference/string/string/find/
its a search function for strings used on other strings... which is exactly what you're looking for.
One of the comments also suggest using == to compare the string you created from chars and the user input string, but there isn't much use in doing it this way when the string::find function does the exact same thing but more efficently
A Modern C++ solution.
The interesting part in the main function which is below.
#include <random>
#include <iostream>
#include <algorithm>
#include <list>
#include <sstream>
void NotFoundMessage(std::list<char>& randomSequence);
void FoundMessage(long long iterationCount);
// Seed with a real random value, if available
std::random_device r;
std::default_random_engine e1(r());
// A random character between 'A' and 'Z'
std::uniform_int_distribution<int> uniform_dist('A', 'Z');
char nextRandomCharacter()
{
return static_cast<char>(uniform_dist(e1));
}
int main()
{
std::string input;
std::cin >> input;
// <--- NEEDS CHECKS IF INPUT IS CORRECT!!!!
std::list< char > randomSequence;
// Fill randomSequence with initial data
for ( const auto& c : input )
{
randomSequence.push_back( nextRandomCharacter() );
}
long long iterationCount = 1;
while ( !std::equal( input.begin(), input.end(),
randomSequence.begin() ) )
{
NotFoundMessage( randomSequence );
// remove character from front and add random char at end.
randomSequence.pop_front();
randomSequence.push_back( nextRandomCharacter() );
iterationCount++;
}
FoundMessage(iterationCount);
}
void NotFoundMessage(std::list<char>& randomSequence)
{
std::cout << "Not found in: ";
for ( const auto& c : randomSequence )
std::cout << c << ' ';
std::cout << '\n';
}
void FoundMessage(long long iterationCount)
{
std::cout << "Found after "
<< iterationCount
<< " iterations."
<< std::endl;
}

How to compare two arrays and return non matching values in C++

I would like to parse through two vectors of strings and find the strings that match each other and the ones that do not.
Example of what I want get:
input vector 1 would look like: [string1, string2, string3]
input vector 2 would look like: [string2, string3, string4]
Ideal output:
string1: No Match
string2: Match
string3: Match
string4: No Match
At the moment I use this code:
vector<string> function(vector<string> sequences, vector<string> second_sequences){
for(vector<string>::size_type i = 0; i != sequences.size(); i++) {
for(vector<string>::size_type j = 0; j != second_sequences.size(); j++){
if (sequences[i] == second_sequences[j]){
cout << "Match: " << sequences[i];
}else{
cout << "No Match: " << sequences[i];
cout << "No Match: " << second_sequences[j];
}
}
}
}
It works great for the ones that match, but iterates over everything so many times,
and the ones that do not match get printed a large number of times.
How can I improve this?
The best code is the code that you did not have to write.
If you take a (STL) map container it will take care for you of sorting and memorizing the different strings you encounter.
So let the container works for us.
I propose a small code quickly written. You need for this syntax to enable at least the C++ 2011 option of your compiler ( -std=c++11 on gcc for example ). The syntax that should be used before C++11 is much more verbose (but should be known from a scholar point of view ).
You have only a single loop.
This is only a hint for you ( my code does not take into account that in the second vector string4 could be present more than once, but I let you arrange it to your exact needs)
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
vector<string> v1 { "string1","string2","string3"};
vector<string> v2 { "string2","string3","string4"};
//ordered map will take care of "alphabetical" ordering
//The key are the strings
//the value is a counter ( or could be any object of your own
//containing more information )
map<string,int> my_map;
int main()
{
cout << "Hello world!" << endl;
//The first vector feeds the map before comparison with
//The second vector
for ( const auto & cstr_ref:v1)
my_map[cstr_ref] = 0;
//We will look into the second vector ( it could also be the third,
//the fourth... )
for ( const auto & cstr_ref:v2)
{
auto iterpair = my_map.equal_range(cstr_ref);
if ( my_map.end() != iterpair.first )
{
//if the element already exist we increment the counter
iterpair.first->second += 1;
}
else
{
//otherwise we put the string inside the map
my_map[cstr_ref] = 0;
}
}
for ( const auto & map_iter: my_map)
{
if ( 0 < map_iter.second )
{
cout << "Match :";
}
else
{
cout << "No Match :" ;
}
cout << map_iter.first << endl;
}
return 0;
}
Output:
No Match :string1
Match :string2
Match :string3
No Match :string4
std::sort(std::begin(v1), std::end(v1));
std::sort(std::begin(v2), std::end(v2));
std::vector<std::string> common_elements;
std::set_intersection(std::begin(v1), std::end(v1)
, std::begin(v2), std::end(v2)
, std::back_inserter(common_elements));
for(auto const& s : common_elements)
{
std::cout<<s<<std::endl;
}

How to use string.substr() function?

I want to make a program that will read some number in string format and output it like this: if the number is 12345 it should then output 12 23 34 45 . I tried using the substr() function from the c++ string library, but it gives me strange results - it outputs 1 23 345 45 instead of the expected result. Why ?
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main(void)
{
string a;
cin >> a;
string b;
int c;
for(int i=0;i<a.size()-1;++i)
{
b = a.substr(i,i+1);
c = atoi(b.c_str());
cout << c << " ";
}
cout << endl;
return 0;
}
If I am correct, the second parameter of substr() should be the length of the substring. How about
b = a.substr(i,2);
?
As shown here, the second argument to substr is the length, not the ending position:
string substr ( size_t pos = 0, size_t n = npos ) const;
Generate substring
Returns a string object with its contents initialized to a substring of the current object. This substring is the character sequence that starts at character position pos and has a length of n characters.
Your line b = a.substr(i,i+1); will generate, for values of i:
substr(0,1) = 1
substr(1,2) = 23
substr(2,3) = 345
substr(3,4) = 45 (since your string stops there).
What you need is b = a.substr(i,2);
You should also be aware that your output will look funny for a number like 12045. You'll get 12 20 4 45 due to the fact that you're using atoi() on the string section and outputting that integer. You might want to try just outputing the string itself which will be two characters long:
b = a.substr(i,2);
cout << b << " ";
In fact, the entire thing could be more simply written as:
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string a;
cin >> a;
for (int i = 0; i < a.size() - 1; i++)
cout << a.substr(i,2) << " ";
cout << endl;
return 0;
}
Another interesting variant question can be:
How would you make "12345" as "12 23 34 45" without using another string?
Will following do?
for(int i=0; i < a.size()-1; ++i)
{
//b = a.substr(i, 2);
c = atoi((a.substr(i, 2)).c_str());
cout << c << " ";
}
substr(i,j) means that you start from the index i (assuming the first index to be 0) and take next j chars.
It does not mean going up to the index j.
You can get the above output using following code in c
#include<stdio.h>
#include<conio.h>
#include<string.h>
int main()
{
char *str;
clrscr();
printf("\n Enter the string");
gets(str);
for(int i=0;i<strlen(str)-1;i++)
{
for(int j=i;j<=i+1;j++)
printf("%c",str[j]);
printf("\t");
}
getch();
return 0;
}
Possible solution without using substr()
#include<iostream>
#include<string>
using namespace std;
int main() {
string c="12345";
int p=0;
for(int i=0;i<c.length();i++) {
cout<<c[i];
p++;
if (p % 2 == 0 && i != c.length()-1) {
cout<<" "<<c[i];
p++;
}
}
}
Possible solution with string_view
void do_it_with_string_view( void )
{
std::string a { "12345" };
for ( std::string_view v { a }; v.size() - 1; v.remove_prefix( 1 ) )
std::cout << v.substr( 0, 2 ) << " ";
std::cout << std::endl;
}
The string constructor can be used to get a copy of a substring.
string(const string& str, size_t pos, size_t n)
For example...
b = string(a, i, 2); // substring of a from position i, including 2 characters
This differs from substr in that the length n cannot be omitted. I offer this only as an alternative, not as an improvement.