I am working on some code for a class that requires me to output duplicates in a string. This string can have any ascii character but the output needs to show only the repeated character and the total number of times it repeats.
Here are some sample inputs and outputs
mom, m:2
taco, No duplicates
good job, o:3
tacocat, t:2 c:2 a:2
My code works for all but the last test case, the t:2 and a:2 appears twice, Now I have come to the conclusion that I need to store duplicated characters somewhere and run a check on that list to see if that duplicate has already been printed so I tried using a vector.
My method is to push the character into the vector as the duplicates are printed and if a character is already in the vector then it is skipped in the printing. But I have not been able to find a way to this. I tried to use the find() from #include<algorithm> but got a syntax error that I am unable to fix. Is there a function that I can apply for this? Or am I going about this in a bad way?
I found the implementation of find() here & I looked here but they don't match and it breaks my code completely when I try to apply it.
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
vector <char> alreadyprintedcharacters;
void findrepeats(string const&);
int main()
{
string input;
cout << "Enter the input : ";
getline(cin, input);
findrepeats(input);
return 0;
}
void findrepeats(string const &in)
{
int trackerOfDuplicates = 0;
int asciiArray[256];
char ch;
int charconv;
for (int i = 0; i < 256; i++) // creates my refference array for the comparison and sets all the values equal to zero
asciiArray[i] = 0;
for (unsigned int i = 0; i < in.length(); i++)
{
ch = in[i];
charconv = static_cast<int>(ch);
if (asciiArray[charconv] == 0)
{
asciiArray[charconv] = 1;
}
else if (asciiArray[charconv] > 0)
{
asciiArray[charconv] = asciiArray[charconv]++;
}
}
bool trip = false;
for (unsigned int i = 0; i < in.length(); i++)
{
char static alreadyprinted;
char ch = in[i];
if ((asciiArray[ch] > 1) && (ch != alreadyprinted) && (find(alreadyprintedcharacters.begin(), alreadyprintedcharacters.end(), ch)!= alreadyprintedcharacters.end()))// change reflected HERE
{
cout << in[i] << " : " << asciiArray[ch] << endl;//???? maybe a nested loop
trip = true;
alreadyprinted = ch;
alreadyprintedcharacters.push_back(alreadyprinted);
}
}
if (trip == false)
cout << "No repeated characters were found.\n";
}
Your code works fine for me (gives the correct output for tacocat) if you fix the error related to std::find:
std::find doesn't return a bool, it returns an iterator (in your case, a std::vector<char>::iterator). If you want to check if std::find found something, you should compare it to alreadyprintedcharacters.end(), because that's what std::find returns if it didn't find something.
You can create an integer array of 256 and initialize it to 0 at first. Then loop over characters in the string and increment each index that corresponds to that letter. In the end, you can print out letters that have values greater than 1. Just change your findrepeats function to the following:
void findrepeats(string const &in)
{
int asciiArray[256];
char ch;
int charconv;
bool foundAny = false;
for (int i = 0; i < 256; i++) asciiArray[i] = 0;
for (unsigned int i = 0; i < in.length(); i++)
{
ch = in[i];
charconv = static_cast<int>(ch);
asciiArray[charconv]++;
}
for (unsigned int i = 0; i < 256; i++)
{
char static alreadyprinted;
if (asciiArray[i] > 1)
{
foundAny = true;
cout << static_cast<char>(i) << " : " << asciiArray[i] << endl;
}
}
if (!foundAny)
cout << "No repeated characters were found.\n";
}
You have to make following changes in your code
change the loop body where you are updating the reference array for the comparison and sets all the values like this:
//your code
else if (asciiArray[charconv] > 0)
{
asciiArray[charconv] = asciiArray[charconv]++;
}
in the above code the value of asciiArray[charconv] doesn't change because it is a post increment asciiArray[charconv]++; , either change it to a pre increment ++asciiArray[charconv]; or write asciiArray[charconv] = asciiArray[charconv]+1;
Here is a link to this why it doesn't increment.
Also you can change the loop like this,more simplified:
for (unsigned int i = 0; i < in.length(); i++)
{
ch = in[i];
charconv = static_cast<int>(ch);
asciiArray[charconv]++;
}
change the type of found to std::vector<char>::iterator coz find returns an iterator to the first element in the range that compares equal to val & if no elements match, the function returns last.
std::vector<char>::iterator found = find(alreadyprintedcharacters.begin(), alreadyprintedcharacters.end(), ch);
Then your condition should be like
if((asciiArray[ch] > 1) && (ch!=alreadyprinted) && (found == alreadyprintedcharacters.end()))
I don't quite get why you need all of that code (given you stated you can't use std::map).
You declared an array of 256 and set each item to 0, which is OK:
for (int i = 0; i < 256; i++)
asciiArray[i] = 0;
Now the next step should be simple -- just go through the string, one character at a time, and increment the associated value in your array. You seem to start out this way, then go off on a tangent doing other things:
for (unsigned int i = 0; i < in.length(); i++)
{
ch = in[i]; // ok
asciiArray[ch]++;
We can set a boolean to true if we discover that the character count we just incremented is > 1:
bool dup = false;
for (unsigned int i = 0; i < in.length(); i++)
{
ch = in[i]; // ok
asciiArray[ch]++;
if ( asciiArray[ch] > 1 )
dup = true;
}
That is the entire loop to preprocess the string. Then you need a loop after this to print out the results.
As to printing, just go through your array only if there are duplicates, and you know this by just inspecting the dup value. If the array's value at character i is > 1, you print the information for that character, if not, skip to the next one.
I won't show the code for the last step, since this is homework.
Just met similar question last week, here is what I did, maybe not a best solution, but it did work well.
string str("aer08%&#&%$$gfdslh6FAKSFH");
vector<char> check;
vector<int> counter;
//subscript is the bridge between charcheck and count. counter[sbuscript] store the times that check[subscript] appeared
int subscript = 0;
bool charisincheck = false;
for (const auto cstr : str) //read every char in string
{
subscript = 0;
charisincheck = false;
for (const auto ccheck : check) // read every element in charcheck
{
if (cstr == ccheck)//check if the char get from the string had already existed in charcheck
{
charisincheck = true; //if exist, break the for loop
break;
}
subscript++;
}
if (charisincheck == true) //if the char in string, then the count +1
{
counter[subscript] += 1;
}
else //if not, add the new char to check, and also add a counter for this new char
{
check.push_back(cstr);
counter.push_back(1);
}
}
for (decltype(counter.size()) i = 0; i != counter.size(); i++)
{
cout << check[i] << ":" << counter[i] << endl;
}met
import java.util.*;
class dublicate{
public static void main(String arg[]){
Scanner sc =new Scanner(System.in);
String str=sc.nextLine();
int d[]=new int[256];
int count=0;
for(int i=0;i<256;i++){
d[i]=0;
}
for(int i=0;i<str.length();i++){
if(d[str.charAt(i)]==0)
for(int j=i+1;j<str.length();j++){
if(str.charAt(i)==str.charAt(j)){
d[str.charAt(i)]++;
}
}
}
for(char i=0;i<256;i++){
if(d[i]>0)
System.out.println(i+" :="+(d[i]+1));
}
}
}
//here simple code for duplicate characters in a string in C++
#include<iostream.h>
#include<conio.h>
#include<string.h>
void main(){
clrscr();
char str[100];
cin>>str;
int d[256];
int count=0;
for(int k=0;k<256;k++){
d[k]=0;
}
for(int i=0;i<strlen(str);i++){
if(d[str[i]]==0)
for(int j=i+1;j<strlen(str);j++){
if(str[i]==str[j]){
d[str[i]]++;
}
}
}
for(int c=0;c<256;c++){
if(d[c]>0)
cout<<(char)c<<" :="<<(d[c]+1)<<"\n";
}
getch();
}
Related
I am having problems with the following code once the string gets to around 24~ characters. It will run through the code just fine and calculate the correct amount of words in the string but it will error on strings containing more than a few words. You can try inputting your name in 3 or 4 times and it errors out for me. I ran the debug option and it shows the error at line 74 which is the last closing bracket for the main function.
#include <iostream>
using namespace std;
class WordCounter
{
private:
string tempInput;
int wordCount;
int arraySize;
char characterArray[];
public:
WordCounter()
{
tempInput = "";
wordCount = 0;
arraySize = 0;
}
void getCharString()
{
cout << "Enter the sentence you would like a word count for:\n";
getline(cin, tempInput);
}
void setArraySize()
{
arraySize = tempInput.length();
}
void convertStringToCharArray()
{
for(int counter = 0; counter < arraySize; counter++)
{
characterArray[counter] = tempInput[counter];
}
}
int countNumOfWords()
{
int charCount;
for(int counter = 0; counter < arraySize; counter++)
{
if(characterArray[counter] == '\n')
{
return 0;
}
if(characterArray[counter] == ' ')
{
charCount = 0;
}
else if(++charCount == 1)
{
wordCount++;
}
}
return wordCount;
}
};
int main()
{
WordCounter wordOne;
wordOne.getCharString();
wordOne.setArraySize();
wordOne.convertStringToCharArray();
int numberOfWords = wordOne.countNumOfWords();
cout << "The number of words in the sentence is " << numberOfWords << ".\n";
return 0;
}
If you want a function that count words in a string, where words are splited by whitespaces character, you can just use a regex :
#include <string>
#include <regex>
size_t countNumOfWords(std::string s) {
std::regex wordCountRegex("[^ ]+");
std::smatch matches;
size_t nb_words = 0;
while (std::regex_search(s, matches, wordCountRegex)) {
s = matches.suffix().str();
++nb_words;
}
return nb_words;
}
Or continue with the same code you had before :
int countNumOfWords(const std::string& s)
{
int charCount;
for(int counter = 0; counter < s.length(); counter++)
{
if(s[counter] == '\n')
{
return 0;
}
if(s[counter] == ' ')
{
charCount = 0;
}
else if(++charCount == 1)
{
wordCount++;
}
}
return wordCount;
}
However, if you want to continue using your code, you will have to make several modifications :
The field characterArray is never initialized, and no memory allocation is done. The value of characterArray ( which is a pointer to char ) is completely random, and accessing it through the subscript operator results in undefined behavior ( which means that the program could crash, or corrupt variables, or do nothing detectable, and that make debugging very hard ). You might want to add characterArray = new char[arraySize]; in the convertStringToCharArray() method
Speaking about converting std::string to char array, you might want to replace the code in the convertStringToCharArray() method by that : characterterArray = tempInput.c_str(). std::string::c_str() method return the internal value of the pointer in your std::string object, and points to the memory location where a char array has been allocated. You should not delete it
Based on the previous point, you might want to only use the std::string field, which has his own size information ( making arraySize field useless ) and his own char array ( making characterArray field useless ).
When trying to compile the code below I get three errors.
'iterator_category': is not a member of any direct or indirect base class of 'std::iterator_traits<_InIt>'
'_Iter_cat_t' : Failed to specialize alias template
type 'unknown-type' unexpected
I'm quite new to C++ and have gone over the code many times changing snippets but nothing helps. Any help deciphering these error messages is much appreciated.
#include "../../std_lib_facilities.h"
class Puzzle {
public:
vector<char> letters;
Puzzle(int my_size);
void generate(void);
void enter_letters(void);
void feedback(Puzzle puzzle);
private:
int size = 4;
};
Puzzle::Puzzle(int my_size)
{
size = my_size;
}
//Generate size unique letters for the letters array.
void Puzzle::generate(void)
{
for (int i = 0; i < size; ++i) {
char rand = randint(26) - 1 + 'a';
while ((find(letters[0], letters[size], rand) != letters[size])) {
rand = randint(26) - 1 + 'a';
}
letters[i] = rand;
}
}
//Let the user enter size unique letters.
void Puzzle::enter_letters(void)
{
cout << "Enter four different letters seperated by spaces:\n";
for (int i = 0; i < size; ++i) {
char letter;
cin >> letter;
letters[i] = letter;
}
}
//Tell the user how many bulls and cows they got.
void Puzzle::feedback(Puzzle puzzle)
{
int cows = 0, bulls = 0;
for (int i = 0; i < size; i++) { //input
for (int j = 0; j < size; ++j) { //puzzle
if (i == j && letters[i] == puzzle.letters[j]) {
++bulls;
break;
}
else if (letters[i] == puzzle.letters[j]) {
++cows;
break;
}
}
}
cout << "Bulls: " << bulls << "\nCows: " << cows << "\n";
}
//Seed the random function.
void seed(void)
{
int sum = 0;
cout << "Enter a random string of characters:\n";
string str;
cin >> str;
for (char& c : str)
sum += c;
srand(sum);
}
int main()
{
constexpr int GAME_SIZE = 4;
seed();
Puzzle puzzle(GAME_SIZE);
puzzle.generate();
Puzzle input(GAME_SIZE);
input.enter_letters();
while (puzzle.letters != input.letters) {
input.feedback(puzzle);
input.enter_letters();
}
cout << "Congragulations, you did it!\n";
keep_window_open();
return 0;
}
You're using find() wrong.
find(letters[0], letters[size], rand)
Your letters is a std::vector. You're passing the first value in the vector, and the last value in the vector, to std::find.
This is actually undefined behavior, since size is not always the actual size of your letters vector. So, you'll be getting a random crash, as an extra bonus here in addition to your compilation error.
The first two parameters to std::find are iterators of a sequence to search, and not values.
This should be:
find(letters.begin(), letters.end(), rand)
Also, your overall algorithm is broken. Once letters reaches a certain size, your random number generating code will take ... a significant time to find some new letter to add to letters, that's not used already. Once letters manages to acquire all 26 characters of the alphabet, this will turn into an infinite loop. But that would be a different question...
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I was asked this question in an interview:
Given an array with the input string, display the output as shown below
Input
INDIA
Output
INDA
****
*
I iterated through the array and stored each character as a key in std::map with value as number of occurrence. Later I iterate the map and print the asteriks and reduce the value in the map for each character.
Initially, I was asked not to use any library. I gave a solution which needed lot of iterations. For every character, iterate the complete array till the index to find previous occurrences and so on.
Is there any better way, e.g. better complexity, such as faster operation, by which this can be achieved?
Essentially what you are asking is how to implement map without using the STL code, as using some kind of data structure which replicates the basic functionality of map is pretty much the most reasonable way of solving this problem.
There are a number of ways of doing this. If your keys (here the possible characters) come from a very large set where most elements of the set don't appear (such as the full Unicode character set), you would probably want to use either a tree or a hash table. Both of these data structures are very important with lots of variations and different ways of implementing them. There is lots of information and example code about the two structures around.
As #PeterG said in a comment, if the only characters you are going to see are from a set of 256 8-bit chars (eg ASCII or similar), or some other limited collection like the upper-case alphabet you should just use an array of 256 ints and store a count for each char in that.
here is another one:
You can see it working HERE
#include <stdio.h>
int main()
{
int i,j=0,f=1;
char input[50]={'I','N','D','I','A','N','A','N'};
char letters[256]={0};
int counter[256]={0};
for(i=0;i<50;i++)
{
if(input[i])
counter[input[i]]++;
if(counter[input[i]]==1)
{
putchar(input[i]);
letters[j]=input[i];
j++;
}
}
putchar('\n');
while(f)
{
f=0;
for(i=0;i<j;i++)
if(counter[letters[i]])
{
putchar('*');
counter[letters[i]]--;
f=1;
}
else
{
putchar(' ');
}
putchar('\n');
}
return 0;
}
If the alphabet under consideration is fixed, it can be done in two passes:
Create an integer array A with the size of the alphabet, initialized with all zeros.
Create a boolean array B with size of the input, initialize with all false.
Iterate the input; increase for every character the corresponding content of A.
Iterate the input; output a character if its value it B is false and set its value in B to true. Finally, output a carriage return.
Reset B.
Iterate input as in 4., but print a star if if the character's count in A is positive, then decrease this count; print a space otherwise.
Output a carriage return; loop to 5 as long as there are any stars in the output generated.
This is interesting. You shouldnt use a stl::map because that is not a hashmap. An stl map is a binary tree. An unordered_map is actually a hash map. In this case we dont need either. We can use a simple array for char counts.
void printAstr(std::string str){
int array[256] ;// assumining it is an ascii string
memset(array, 0, sizeof(array));
int astrCount = 0;
for(int i = 0; i < str.length()-1; i++){
array[(int) str[i]]++;
if(array[(int) str[i]] > 1) astrCount++;
}
std::cout << str << std::endl;
for(int i = 0; i < str.length()-1;i++) std::cout << "* ";
std::cout << std::endl;
while(astrCount != 0){
for(int i= 0; i< str.length() - 1;i++){
if(array[(int) str[i]] > 1){
std::cout << "* ";
array[(int) str[i]]--;
astrCount--;
}else{
std::cout << " ";
}
}
std::cout << std::endl;
}
}
pretty simple just add all values to the array, then print them out the number of times you seem them.
EDIT: sorry just made some logic changes. This works now.
The following code works correctly. I am assuming that you can't use std::string and take note that this doesn't take overflowing into account since I didn't use dynamic containers. This also assumes that the characters can be represented with a char.
#include <iostream>
int main()
{
char input[100];
unsigned int input_length = 0;
char letters[100];
unsigned int num_of_letters = 0;
std::cin >> input;
while (input[input_length] != '\0')
{
input_length += 1;
}
//This array acts like a hash map.
unsigned int occurrences[256] = {0};
unsigned int max_occurrences = 1;
for (int i = 0; i < input_length; ++i)
{
if ((occurrences[static_cast<unsigned char>(input[i])] += 1) == 1)
{
std::cout<< " " << (letters[num_of_letters] = input[i]) << " ";
num_of_letters += 1;
}
if (occurrences[static_cast<unsigned char>(input[i])] > max_occurrences)
{
max_occurrences = occurrences[static_cast<unsigned char>(input[i])];
}
}
std::cout << std::endl;
for (int row = 1; row <= max_occurrences; ++row)
{
for (int i = 0; i < num_of_letters; ++i)
{
if (occurrences[static_cast<unsigned char>(letters[i])] >= row)
{
std::cout << " * ";
}
else
{
std::cout << " ";
}
}
std::cout << std::endl;
}
return 0;
}
The question is marked as c++ but It seems to me that the answers not are all quite C++'ish, but could be quite difficult to achieve a good C++ code with a weird requirement like "not to use any library". In my approach I've used some cool C++11 features like in-class initialization or nullptr, here is the live demo and below the code:
struct letter_count
{
char letter = '\0';
int count = 0;
};
int add(letter_count *begin, letter_count *end, char letter)
{
while (begin != end)
{
if (begin->letter == letter)
{
return ++begin->count;
}
else if (begin->letter == '\0')
{
std::cout << letter; // Print the first appearance of each char
++begin->letter = letter;
return ++begin->count;
}
++begin;
}
return 0;
}
int max (int a, int b)
{
return a > b ? a : b;
}
letter_count *buffer = nullptr;
auto testString = "supergalifragilisticoespialidoso";
int len = 0, index = 0, greater = 0;
while (testString[index++])
++len;
buffer = new letter_count[len];
for (index = 0; index < len; ++index)
greater = max(add(buffer, buffer + len, testString[index]), greater);
std::cout << '\n';
for (int count = 0; count < greater; ++count)
{
for (index = 0; buffer[index].letter && index < len; ++index)
std::cout << (count < buffer[index].count ? '*' : ' ');
std::cout << '\n';
}
delete [] buffer;
Since "no libraries are allowed" (except for <iostream>?) I've avoided the use of std::pair<char, int> (which could have been the letter_count struct) and we have to code many utilities (such as max and strlen); the output of the program avobe is:
supergaliftcod
**************
* ******* *
* *** *
* *
*
*
My general solution would be to traverse the word and replace repeated characters with an unused nonsense character. A simple example is below, where I used an exclamation point (!) for the nonsense character (the input could be more robust, some character that is not easily typed, disallowing the nonsense character in the answer, error checking, etc). After traversal, the final step would be removing the nonsense character. The problem is keeping track of the asterisks while retaining the original positions they imply. For that I used a temp string to save the letters and a process string to create the final output string and the asterisks.
#include <iostream>
#include <string>
using namespace std;
int
main ()
{
string input = "";
string tempstring = "";
string process = "";
string output = "";
bool test = false;
cout << "Enter your word below: " << endl;
cin >> input;
for (unsigned int i = 0; i < input.length (); i++)
{ //for the traversed letter, traverse through subsequent letters
for (unsigned int z = i + 1; z < input.length (); z++)
{
//avoid analyzing nonsense characters
if (input[i] != '!')
{
if (input[i] == input[z])
{ //matched letter; replace with nonsense character
input[z] = '!';
test = true; //for string management later
}
}
}
if (test)
{
tempstring += input[i];
input[i] = '*';
test = false; //reset bool for subsequent loops
}
}
//remove garbage symbols and save to a processing string
for (unsigned int i = 0; i < input.size (); i++)
if (input[i] != '!')
process += input[i];
//create the modified output string
unsigned int temp = 0;
for (unsigned int i = 0; i < process.size (); i++)
if (process[i] == '*')
{ //replace asterisks with letters stored in tempstring
output += tempstring[temp];
temp++;
}
else
output += process[i];
//output word with no repeated letters
cout << output << endl;
//output asterisks equal to output.length
for (unsigned int a = 0; a < output.length (); a++)
cout << "*";
cout << endl;
//output asterisks for the letter instances removed
for (unsigned int i = 0; i < process.size (); i++)
if (process[i] != '*')
process[i] = ' ';
cout << process << endl << endl;
}
Sample output I received by running the code:
Enter your word below:
INDIA
INDA
****
*
Enter your word below:
abcdefgabchijklmnop
abcdefghijklmnop
****************
***
It is possible just using simple array to keep count of values.
#include<iostream>
#include<string>
using namespace std;
int main(){
string s;
char arr[10000];
cin>>s;
int count1[256]={0},count2[256]={0};
for(int i=0;i<s.size();++i){
count1[s[i]]++;
count2[s[i]]++;
}
long max=-1;
int j=0;
for(int i=0;i<s.size();++i){
if(count1[s[i]]==count2[s[i]]){ //check if not printing duplicate
cout<<s[i];
arr[j++]=s[i];
}
if(count2[s[i]]>max)
max=count2[s[i]];
--count1[s[i]];
}
cout<<endl;
for(int i =1; i<=max;++i){
for(int k=0;k<j;++k){
if(count2[arr[k]]){
cout<<"*";
count2[arr[k]]--;
}
else
cout<<" ";
}
cout<<endl;
}
}
Currently I am getting an runtime "assertation error"
Here is the error:
I'm reading words from a text file into dynamically allocated arrays.
this block of code is where I am filling the new arrays.
I know the problem is being caused by this block of code and something about my logic is off just can't see what it is.
//fill new arrays
for( int y = 0; y < new_numwords; y++)
{
for( int i = 0; i < NUM_WORDS; i++)
{
if (!strcmp(SentenceArry[i], EMPTY[0]) == 0)
{
New_SentenceArry[y] = SentenceArry[i];
New_WordCount[y] = WordCount[i];
y++;
}
}
}
Also how would I pass this dynamically allocated 2D array to a function? (the code really needs to be cleaned up as a whole)
char** SentenceArry = new char*[NUM_WORDS]; //declare pointer for the sentence
for( int i = 0; i < NUM_WORDS; i++)
{
SentenceArry[i] = new char[WORD_LENGTH];
}
Here is the full extent of the code.. help would be much appreciated!
Here is what is being read in:
and the current output (the output is how it's suppose to be ):
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
#include <iomanip>
using std::setw;
using std::left;
using std::cout;
using std::cin;
using std::endl;
using std::ifstream;
int main()
{
const int NUM_WORDS = 17;//constant for the elements of arrays
const int WORD_LENGTH = 50;//constant for the length of the cstrings (NEED TO GIVE THE VALUE ZERO STILL!)
short word_entry = 0; //declare counter
short new_numwords= 0; //declare new word count
char EMPTY[1][4]; //NULL ARRAY
EMPTY[0][0] = '\0';//define it as null
char** SentenceArry = new char*[NUM_WORDS]; //declare pointer for the sentence
for( int i = 0; i < NUM_WORDS; i++)
{
SentenceArry[i] = new char[WORD_LENGTH];
}
int WordCount[NUM_WORDS];//declare integer array for the word counter
for(int i = 0; i < NUM_WORDS; i++)//fill int array
{
WordCount[i] = 1;
}
int New_WordCount[NUM_WORDS] = {0};
ifstream read_text("DataFile.txt"); //read in our text file
if (read_text.is_open()) //check if the the file was opened
{
read_text >> SentenceArry[word_entry];
//REMOVE PUNCTUATION BEFORE BEING READ INTO THE ARRAY
while (!read_text.eof())
{
word_entry++; //increment counter
read_text >> SentenceArry[word_entry]; //read in single words of the text file into the array SentenceArry
char* ptr_ch;//declare our pointer that will find chars
ptr_ch = strstr( SentenceArry[word_entry], ",");//look for "," within the array
if (ptr_ch != NULL)//if true replace it with a null character
{
strncpy( ptr_ch, "\0" , 1);
}//end if
else
{
ptr_ch = strstr( SentenceArry[word_entry], ".");//look for "." within the array
if (ptr_ch != NULL)//if true replace it with a null character
{
strncpy( ptr_ch, "\0" , 1);
}//end if
}//end else
} //end while
}//end if
else
{
cout << "The file could not be opened!" << endl;//display error message if file doesn't open
}//end else
read_text.close(); //close the text file after eof
//WORD COUNT NESTED FOR LOOP
for(int y = 0; y < NUM_WORDS; y++)
{
for(int i = y+1; i < NUM_WORDS; i++)
{
if (strcmp(SentenceArry[y], EMPTY[0]) == 0)//check if the arrays match
{
y++;
}
else
{
if (strcmp(SentenceArry[y], SentenceArry[i]) == 0)//check if the arrays match
{
WordCount[y]++;
strncpy(SentenceArry[i], "\0" , 3);
}//end if
}//end if
}//end for
}//end for
//find how many arrays still contain chars
for(int i = 0; i < NUM_WORDS; i++)
{
if (!strcmp(SentenceArry[i], EMPTY[0]) == 0)
{
new_numwords++;
}
}
//new dynamic array
char** New_SentenceArry = new char*[new_numwords]; //declare pointer for the sentence
for( int i = 0; i < new_numwords; i++)
{
New_SentenceArry[i] = new char[new_numwords];
}
//fill new arrays
for( int y = 0; y < new_numwords; y++)
{
for( int i = 0; i < NUM_WORDS; i++)
{
if (!strcmp(SentenceArry[i], EMPTY[0]) == 0)
{
New_SentenceArry[y] = SentenceArry[i];
New_WordCount[y] = WordCount[i];
y++;
}
}
}
//DISPLAY REPORT
cout << left << setw(15) << "Words" << left << setw(9) << "Frequency" << endl;
for(int i = 0; i < new_numwords; i++) //compare i to the array constant NUM_WORDS
{
cout << left << setw(15) << New_SentenceArry[i] << left << setw(9) << New_WordCount[i] << endl; //display the contents of the array SentenceArry
}
//DEALLOCATION
for( int i = 0; i < NUM_WORDS; i++)//deallocate the words inside the arrays
{
delete [] SentenceArry[i];
}
for(int i = 0; i < new_numwords; i++)
{
delete [] New_SentenceArry[i];
}
delete [] SentenceArry; //deallocate the memory allocation made for the array SentenceArry
delete [] New_SentenceArry;//deallocate the memory allocation made for the array New_SentenceArry
}//end main
There are several issues with the code, not withstanding that this could be written using C++, not C with a sprinkling of C++ I/O..
Issue 1:
Since you're using c-style strings, any copying of string data will require function calls such as strcpy(), strncpy(), etc. You failed in following this advice in this code:
for( int y = 0; y < new_numwords; y++)
{
for( int i = 0; i < NUM_WORDS; i++)
{
if (!strcmp(SentenceArry[i], EMPTY[0]) == 0)
{
New_SentenceArry[y] = SentenceArry[i]; // This is wrong
New_WordCount[y] = WordCount[i];
y++;
}
}
}
You should be using strcpy(), not = to copy strings.
strcpy(New_SentenceArry[y], SentenceArry[i]);
Issue 2:
You should allocate WORD_LENGTH for both the original and new arrays. The length of the strings is independent of the number of strings.
char** New_SentenceArry = new char*[new_numwords]; //declare pointer for the sentence
for( int i = 0; i < new_numwords; i++)
{
New_SentenceArry[i] = new char[new_numwords];
}
This should be:
char** New_SentenceArry = new char*[new_numwords]; //declare pointer for the sentence
for( int i = 0; i < new_numwords; i++)
{
New_SentenceArry[i] = new char[WORD_LENGTH];
}
Issue 3:
Your loops do not check to see if the index is going out of bounds of your arrays.
It seems that you coded your program in accordance to the data that you're currently using, instead of writing code regardless of what the data will be. If you have limited yourself to 17 words, where is the check to see if the index goes above 16? Nowhere.
For example:
while (!read_text.eof() )
Should be:
while (!read_text.eof() && word_entry < NUM_WORDS)
Issue 4:
You don't process the first string found correctly:
read_text >> SentenceArry[word_entry]; // Here you read in the first word
while (!read_text.eof() )
{
word_entry++; //increment counter
read_text >> SentenceArry[word_entry]; // What about the first word you read in?
Summary:
Even with these changes, I can't guarantee that the program won't crash. Even it it doesn't crash with these changes, I can't guarantee it will work 100% of the time -- a guarantee would require further analysis.
The proper C++ solution, given what this assignment was about, is to use a std::map<std::string, int> to keep the word frequency. The map would automatically store similar words in one entry (given that you remove the junk from the word), and would bump up the count to 1 automatically, when the entry is inserted into the map.
Something like this:
#include <string>
#include <map>
#include <algorithm>
typedef std::map<std::string, int> StringMap;
using namespace std;
bool isCharacterGarbage(char ch)
{ return ch == ',' || ch == '.'; }
int main()
{
StringMap sentenceMap;
//...
std::string temp;
read_text >> temp;
temp.erase(std::remove_if(temp.begin(), temp.end(), isCharacterGarbage),temp.end());
sentenceMap[temp]++;
//...
}
That code alone does everything your original code did -- keep track of the strings, bumps up the word count, removes the junk characters from the word before being processed, etc. But best of all, no manual memory management. No calls to new[], delete[], nothing. The code just "works". That is effectively 5 lines of code that you would just need to write a "read" loop around.
I won't go through every detail, you can do that for yourself since the code is small, and there are vast amounts of resources available explaining std::map, remove_if(), etc.
Then printing out is merely going through the map and printing each entry (string and count). If you add the printing, that may be 4 lines of extra code. So in all, practically all of the assignment is done with effectively 10 or so lines of code.
Remove below code.
for(int i = 0; i < new_numwords; i++)
{
delete [] New_SentenceArry[i];
}
I am having a problem with my palindrome program. I am required to use arrays and show how a push and pop would work without .push or .pop. The trouble I am having is when I enter a 3 letter word it will say yes it is a palindrome but if I enter a word that is 4 or more characters it will say not a palindrome even if it is. ex. kayak. Dont see where I am going wrong.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char original[13];
int stkptr=-1;
int x = strlen(original)-1;
cout <<"Enter a character"<<endl;
for( ++stkptr ; stkptr<13;stkptr++)
//store user input into the array
{
cin>>original[stkptr];
if(original[stkptr]=='0')
break;
cout<<original[stkptr]<<" Stack pointer is: "<<stkptr<<endl;
}
//POP
for (--stkptr; stkptr>=0;stkptr--)
cout<<original[stkptr]<<" Stack pointer is: "<<stkptr<<endl;
for(int i = 0; i <= x; i++)
{
if (original[i] == original[x-i])
{
continue;
}
else
{
cout<<"\nNot a palidrome\n"<<endl;
system("pause");
return 0;
}
}
cout << "\nIndeed Palidrome\n"<<endl;
system("pause");
return 0;
}
Though you overly complicated the logic, I will tell what is wrong the current code.
you are going wrong with x. You initialize it to string length when there is no "string" (Also, your char array should have a \0 at the end for strlen() to work). Assign stkptr-1 to x before pop and remove pop.
And in your loop you should iterate only till half of the array, since you are comparing char-by-char from begin and end
for(int i = 0; i <= x/2; i++)
bool checkIsPalindrome(string s){
int nLength = s.length();
string s1, s2;
if(nLength & 1) // is Odd
nLength--;
nLength = nLength/2;
//take the first half
s1 = s.substr(0,nLength);
//pop off the last half of characters into the string
for(int i = s.length()-1; i > nLength; i--)
s2+= s.at(i);
if(s1 == s2)
return true;
else
return false;
}