As an assignment, I have to write a function in C++ that deletes a word in a sentence. We are given the sentence itself as a string std::string sentence and the number of a word to be deleted int place.
There can be multiple spaces between words and sentence can end and begin with spaces.
For example: DeleteWord("Fox jumped over lazy dog", 2) should return: "Fox over lazy dog".
The problem is that I can only use std::string size() and resize().
I also should delete only the word, not the spaces around it.
I've written some code, but the output is not right: I am putting all words in an array and then deleting the one in an argument but the whitespaces are a big problem as they are being put in the array as well, thus I am not being able to delete and print them correctly.
Do you have any ideas how to solve this problem? Thanks!
My code so far:
std::string DeleteWord(std::string sentence, int place){
std::string retvalue;
long long wordcounter = 0;
long long spacecounter = 0;
long long spacescounter = 0;
int i = 0;
int index = 0;
for(int i=0; i<sentence.size(); i++){
if((sentence[i]==' ') && (sentence[i+1]!=' ')) spacecounter++;
}
for(int i=0; i<sentence.size(); i++){
if(sentence[i]==' ') spacescounter++;
}
std::string words[spacescounter+1];
while(i<sentence.size()){
if(sentence[i]!=' '){
words[index] += sentence[i];
i++;
}
else{
index++;
i++;
}
}
sentence[place-1] = ' ';
for(int i=0; i<=index; i++){
retvalue+=words[i] + ' ';
}
return retvalue;
}
You don't have to count the spaces or words. You don't have to store the words in an array.
Iterate over the sentence and decrement place if the previous element is a space and the current is a non-space. If place is 0 you have to skip the word. Else copy the string into returned string. As I said in the comments it's as simple as one loop, one variable, 3 if conditions:
#include <iostream>
#include <string>
std::string DeleteWord(const std::string &sentence, int place){
if (sentence.empty()) {
return std::string();
}
auto isPreviousSpace = std::isspace(sentence[0]);
if (!isPreviousSpace) {
--place;
}
std::string retvalue;
for (const auto &c : sentence) {
if (isPreviousSpace && !std::isspace(c)) {
--place;
}
if (place != 0 || std::isspace(c)) {
retvalue += c;
}
isPreviousSpace = std::isspace(c);
}
return retvalue;
}
int main()
{
std::cout << DeleteWord("Fox jumped over lazy dog", 2);
// Output is: "Fox over lazy dog"
return 0;
}
A C++98 solution without std::isspace and without const ref argument:
#include <iostream>
#include <string>
std::string DeleteWord(std::string sentence, int place){
if (sentence.empty()) {
return std::string();
}
bool isPreviousSpace = sentence[0] == ' ';
if (!isPreviousSpace) {
--place;
}
std::string retvalue;
for (unsigned int index = 0; index < sentence.size(); ++index) {
if (isPreviousSpace && sentence[index] != ' ') {
--place;
}
if (place != 0 || sentence[index] == ' ') {
retvalue += sentence[index];
}
isPreviousSpace = sentence[index] == ' ';
}
return retvalue;
}
int main()
{
std::cout << DeleteWord("Fox jumped over lazy dog", 2);
// Output is: "Fox over lazy dog"
return 0;
}
I checked the words in the char array by checking the spaces and I delete the words by changing the '\0'(end string) position o by shifting the array
#include <string>
#include <iostream>
#include <string.h>
//#include <stdio.h>
using namespace std;
string DeleteWord(string a,int index)
{
int length=a.size();
int pos;
int word=1;
char* s;
s=new char[length];
strcpy(s,a.c_str());
for(int i=0; i<length; i++)
{
if(s[i]==' ' and i!=0 and s[i-1]!=' ')
word++;
}
if(index>word)
{
delete [] s;
return "error";
}
else
{
if(index==word)
{
pos=0;
for(int i=length-1; i>=0; i--)
{
if(s[i]==' ')
{
pos=i+1;
break;
}
}
s[pos]='\0';
}
else
{
int wl=0;
char pre=' ';
word=0;
pos=-1;
bool found=false;
for(int i=0; i<length; i++)
{
if(pre==' ' and s[i]!=' ')
{
word++;
if(word==index){
found=true;
pos=i;
}
}
if(found==true)
{
if(s[i]==' '){
break;
}
else
wl++;
}
pre=s[i];
}
for(int i=pos; i<length; i++)
s[i]=s[i+wl];
}
string f=string (s);
delete[] s;
return string(f);
}
}
int main()
{
string str="Fox jumped over lazy dog";
cout<<DeleteWord(str,4)<<endl;
return 0;
}
Find starting index and ending index of the word need to be deleted, i call it s and e respectively, the result will be: sentence[0:s-1] + sentence[e+1->sentence.size()-1]. I assume input value of place will be valid (greater than zero and equals to or less than number of words in the sentence). You can try with my code:
#include <iostream>
#include <string>
#include <map>
using namespace std;
pair<int,int> startAndEndIndexOfWord(string sentence, int place){
pair<int,int> startAndEnd;
int currentWordIndex = 0;
int startIndex = 0;
int endIndex = 0;
for(int i=0;i<sentence.size();i++){
//meet a word
if(sentence[i]!=' '){
currentWordIndex += 1;
if(currentWordIndex==place){//if it is the word need to be delete
startIndex = i;
//find ending index
endIndex = sentence.size()-1; //just a default value
for(int j=i+1;j<sentence.size();j++){
if(sentence[j]==' '){
endIndex = j-1;
break;
}
}
startAndEnd.first = startIndex;
startAndEnd.second = endIndex;
return startAndEnd;
}
else{
i+=1;
while(sentence[i]!=' ') i++; //ignore the current word
}
}
}
}
string deleteWord(string sentence, int place){
string result;
pair<int,int> startAndEndIndex = startAndEndIndexOfWord(sentence,place);
for(int i=0;i<startAndEndIndex.first;i++){
result+=sentence[i];
}
for(int i=startAndEndIndex.second+1;i<sentence.size();i++){
result+=sentence[i];
}
return result;
}
int main() {
int place = 5;
string sentence = "Fox jumped over lazy dog";
string result = deleteWord(sentence,place);
cout<<result;
return 0;
}
Related
#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;
}
}
I need to create a program that allows a user to input a string and my program will check to see if that string they entered is a palindrome (word that can be read the same backwards as it can forwards).
Note that reversing the whole string (either with the rbegin()/rend() range constructor or with std::reverse) and comparing it with the input would perform unnecessary work.
It's sufficient to compare the first half of the string with the latter half, in reverse:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string s;
std::cin >> s;
if( equal(s.begin(), s.begin() + s.size()/2, s.rbegin()) )
std::cout << "is a palindrome.\n";
else
std::cout << "is NOT a palindrome.\n";
}
demo: http://ideone.com/mq8qK
Just compare the string with itself reversed:
string input;
cout << "Please enter a string: ";
cin >> input;
if (input == string(input.rbegin(), input.rend())) {
cout << input << " is a palindrome";
}
This constructor of string takes a beginning and ending iterator and creates the string from the characters between those two iterators. Since rbegin() is the end of the string and incrementing it goes backwards through the string, the string we create will have the characters of input added to it in reverse, reversing the string.
Then you just compare it to input and if they are equal, it is a palindrome.
This does not take into account capitalisation or spaces, so you'll have to improve on it yourself.
bool IsPalindrome(const char* psz)
{
int i = 0;
int j;
if ((psz == NULL) || (psz[0] == '\0'))
{
return false;
}
j = strlen(psz) - 1;
while (i < j)
{
if (psz[i] != psz[j])
{
return false;
}
i++;
j--;
}
return true;
}
// STL string version:
bool IsPalindrome(const string& str)
{
if (str.empty())
return false;
int i = 0; // first characters
int j = str.length() - 1; // last character
while (i < j)
{
if (str[i] != str[j])
{
return false;
}
i++;
j--;
}
return true;
}
// The below C++ function checks for a palindrome and
// returns true if it is a palindrome and returns false otherwise
bool checkPalindrome ( string s )
{
// This calculates the length of the string
int n = s.length();
// the for loop iterates until the first half of the string
// and checks first element with the last element,
// second element with second last element and so on.
// if those two characters are not same, hence we return false because
// this string is not a palindrome
for ( int i = 0; i <= n/2; i++ )
{
if ( s[i] != s[n-1-i] )
return false;
}
// if the above for loop executes completely ,
// this implies that the string is palindrome,
// hence we return true and exit
return true;
}
#include <iostream>
#include <string>
bool isPalindrome(const std::string& str){
if(str.empty()) return true;
std::string::const_iterator itFirst = str.begin();
std::string::const_iterator itLast = str.end() - 1;
while(itFirst < itLast) {
if (*itFirst != *itLast)
return false;
++itFirst;
--itLast;
}
return true;
}
int main(){
while(1){
std::string input;
std::cout << "Eneter a string ...\n";
std::cin >> input;
if(isPalindrome(input)){
std::cout << input << " is palindrome.\n";
} else {
std::cout << input << " is not palindrome.\n";
}
}
return 0;
}
Check the string starting at each end and meet in the middle. Return false if there is a discrepancy.
#include <iostream>
bool palidromeCheck(std::string str) {
for (int i = 0, j = str.length()-1; i <= j; i++, j--)
if (str[i] != str[j])
return false;
return true;
}
int main(){
std::cout << palidromeCheck("mike");
std::cout << palidromeCheck("racecar");
}
Reverse the string and check if original string and reverse are same or not
I'm no c++ guy, but you should be able to get the gist from this.
public static string Reverse(string s) {
if (s == null || s.Length < 2) {
return s;
}
int length = s.Length;
int loop = (length >> 1) + 1;
int j;
char[] chars = new char[length];
for (int i = 0; i < loop; i++) {
j = length - i - 1;
chars[i] = s[j];
chars[j] = s[i];
}
return new string(chars);
}
when I was researching vectors, I noticed that size() is supposed to give the number of elements in the vector, right? So, when I found c++ does not have a string split() function built-in, I decided to make one. The problem is, vector.size() displays the same value as vector.capacity() as shown in the code:
#include <iostream>
#include <algorithm>
using namespace std;
void split(string input, char chr, vector<string> list) {
string add;
string conv;
int size = 0;
for (int i = 0; i <= input.size(); i++) {
if ((input[i] != char(chr)) && (input[i] != 0)) {
conv = input[i];
add += conv;
}
else {
cout << list.size() << endl;
if (size <= list.capacity()) {
list[size] = add;
add = "";
size++;
}
}
}
}
int main() {
vector<string> list(6);
split("test1,test2", ',', list);
for (int i = 0; i < 2; i++) {
cout << list[i] << endl;
}
}
The output is this:
6
6
<blank line>
<blank line>
whereas it SHOULD be this from my understanding:
1
2
test1
test2
Edit: if this is of any importance, I am compiling with -std=c++11
You initialize the vector with size 6, not capacity 6. It will be constructed with 6 empty elements inside and thus setting values 0 and 1 won't change that.
The reason why you see only blank lines is that you pass the vector by value instead of by reference to you split function.
#include <iostream>
#include <string>
#include <vector>
void split (const std::string& s, char sep, std::vector<std::string>& words)
{
if (s.empty()) return;
std::size_t beg = 0;
std::size_t end = s.find(sep, beg);
while (end != std::string::npos)
{
words.push_back(s.substr(beg, end - beg));
beg = end + 1;
end = s.find(sep, beg);
}
words.push_back(s.substr(beg));
}
int main() {
std::vector<std::string> words;
split("test1,test2", ',', words);
for (std::size_t i = 0; i != words.size(); ++i) {
std::cout << words[i] << std::endl;
}
return 0;
}
I need to create a program that allows a user to input a string and my program will check to see if that string they entered is a palindrome (word that can be read the same backwards as it can forwards).
Note that reversing the whole string (either with the rbegin()/rend() range constructor or with std::reverse) and comparing it with the input would perform unnecessary work.
It's sufficient to compare the first half of the string with the latter half, in reverse:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string s;
std::cin >> s;
if( equal(s.begin(), s.begin() + s.size()/2, s.rbegin()) )
std::cout << "is a palindrome.\n";
else
std::cout << "is NOT a palindrome.\n";
}
demo: http://ideone.com/mq8qK
Just compare the string with itself reversed:
string input;
cout << "Please enter a string: ";
cin >> input;
if (input == string(input.rbegin(), input.rend())) {
cout << input << " is a palindrome";
}
This constructor of string takes a beginning and ending iterator and creates the string from the characters between those two iterators. Since rbegin() is the end of the string and incrementing it goes backwards through the string, the string we create will have the characters of input added to it in reverse, reversing the string.
Then you just compare it to input and if they are equal, it is a palindrome.
This does not take into account capitalisation or spaces, so you'll have to improve on it yourself.
bool IsPalindrome(const char* psz)
{
int i = 0;
int j;
if ((psz == NULL) || (psz[0] == '\0'))
{
return false;
}
j = strlen(psz) - 1;
while (i < j)
{
if (psz[i] != psz[j])
{
return false;
}
i++;
j--;
}
return true;
}
// STL string version:
bool IsPalindrome(const string& str)
{
if (str.empty())
return false;
int i = 0; // first characters
int j = str.length() - 1; // last character
while (i < j)
{
if (str[i] != str[j])
{
return false;
}
i++;
j--;
}
return true;
}
// The below C++ function checks for a palindrome and
// returns true if it is a palindrome and returns false otherwise
bool checkPalindrome ( string s )
{
// This calculates the length of the string
int n = s.length();
// the for loop iterates until the first half of the string
// and checks first element with the last element,
// second element with second last element and so on.
// if those two characters are not same, hence we return false because
// this string is not a palindrome
for ( int i = 0; i <= n/2; i++ )
{
if ( s[i] != s[n-1-i] )
return false;
}
// if the above for loop executes completely ,
// this implies that the string is palindrome,
// hence we return true and exit
return true;
}
#include <iostream>
#include <string>
bool isPalindrome(const std::string& str){
if(str.empty()) return true;
std::string::const_iterator itFirst = str.begin();
std::string::const_iterator itLast = str.end() - 1;
while(itFirst < itLast) {
if (*itFirst != *itLast)
return false;
++itFirst;
--itLast;
}
return true;
}
int main(){
while(1){
std::string input;
std::cout << "Eneter a string ...\n";
std::cin >> input;
if(isPalindrome(input)){
std::cout << input << " is palindrome.\n";
} else {
std::cout << input << " is not palindrome.\n";
}
}
return 0;
}
Check the string starting at each end and meet in the middle. Return false if there is a discrepancy.
#include <iostream>
bool palidromeCheck(std::string str) {
for (int i = 0, j = str.length()-1; i <= j; i++, j--)
if (str[i] != str[j])
return false;
return true;
}
int main(){
std::cout << palidromeCheck("mike");
std::cout << palidromeCheck("racecar");
}
Reverse the string and check if original string and reverse are same or not
I'm no c++ guy, but you should be able to get the gist from this.
public static string Reverse(string s) {
if (s == null || s.Length < 2) {
return s;
}
int length = s.Length;
int loop = (length >> 1) + 1;
int j;
char[] chars = new char[length];
for (int i = 0; i < loop; i++) {
j = length - i - 1;
chars[i] = s[j];
chars[j] = s[i];
}
return new string(chars);
}
I am newbie programmer C/C++. Was learning pointers and character pointers and was trying to solve an exercise problem. Problem statement
Given a sentence " World is a great place to live in"
Problem description: Rearrange the given sentence based on the ascending order of its word length
output should be " A is in to live world great place"
I am trying my best and am pasting the code that I wrote, but not able to arrive at the answer. Can somebody point out the errors. I am sure there are lots.
#include <iostream>
#include <string.h>
using namespace std;
char* breakIntoWords(char *,char*pt);
int getwordcount(char* p)
{
int wc = 0;
while(*p == ' ')
{
p++;
}
while( 1) {
while( *p != ' ' && *p != '\0' && *p !='\n')
{
p++;
}
if(*p == ' ')
{
p++;
}
else{
break;
}
wc++;
}
wc++;
return wc;
}
int main()
{
char bsentence[120][5];
char sentence[120];
cout<<"Ent&er STring"<<endl;
char *p ;
p = "Test it again and welcome";
strcpy(sentence, p);
int wordcount =0;
wordcount=getwordcount(sentence);
char *pt = sentence;
for(int i =0; i <wordcount; i++)
{
pt = breakIntoWords(pt,bsentence[i]);
}
for(int i =0; i< wordcount; i++)
{
for(int j=i; j<i; j++)
{
int one = strlen(bsentence[i]);
int two = strlen(bsentence[i+1]);
if(one > two)
{
char temp[120];
strcpy(temp,bsentence[i]);
strcpy(bsentence[i+1],temp);
}
}
}
char sen2[12];
for(int i=0; i<wordcount; i++)
{
strcat(sen2,bsentence[i++]);
strcat(sen2, " ");
}
strcpy(sentence,sen2);
cout<<sentence;
}
char* breakIntoWords(char*p, char*pt)
{
int i = 0, j = 0;
while( *p != ' ')
{
pt[i] = *p++;
i++;
}
p++;
pt[i]='\0';
return p;
}
Without using String class.
I have solved it finally. Any inputs on improving it is welcome.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_WORD_SIZE 30
#define MAX_LINE_SIZE 100
using namespace std;
int getWordCount(char* s)
{
int wc = 0;
while(*s == ' ')
s++;
while(*s != '\n')
{
while(*s != ' ' && *s != '\n')
{
s++;
}
if(*s == ' ')
{
while(*s == ' ')
s++;
}
wc++;
}
return wc;
}
char* getWord(char* Source, char* word)
{
while(*Source == ' ')
Source++;
int i =0;
while(*Source != ' ' && *Source != '\n')
{
word[i] = *Source;
Source++;i++;
}
word[i]='\0';
if(*Source == ' ')
{
while(*Source == ' ')
Source++;
}
return Source;
}
void sortSentence(char* p[], int wc)
{
char *temp = new char[MAX_WORD_SIZE];
for(int i =0; i<wc; i++)
{
for(int j = i; j< (wc-1); j++)
{
if(strlen(p[j]) > strlen(p[j+1]))
{
strcpy(temp,p[j]);
strcpy(p[j],p[j+1]);
strcpy(p[j+1],temp);
}
}
}
delete[] temp;
}
int main()
{
char* string;
string = new char[MAX_LINE_SIZE];
cout<<"Enter Sentence"<<endl;
fgets(string,MAX_LINE_SIZE,stdin);
int wordCount = getWordCount(string);
char* pArrayOfPointers[30];
char* tempString = string;
for(int i =0; i< wordCount; i++)
{
char *ptemp;
ptemp =new char[MAX_WORD_SIZE];
pArrayOfPointers[i]= ptemp;
tempString = getWord(tempString,pArrayOfPointers[i]);
cout<<pArrayOfPointers[i]<<endl;
}
sortSentence(pArrayOfPointers, wordCount);
strcpy(string,pArrayOfPointers[0]);
strcat(string," ");
for(int i =1; i< wordCount; i++)
{
strcat(string,pArrayOfPointers[i]);
strcat(string," ");
}
cout<<string;
delete[] string;
}
Your code is vastly more complex than necessary because you’re not decomposing the problem into smaller tasks that would be easier to tackle.
Basically there are three steps:
Decompose sentence into an array of words.
Sort array of words by length.
Output words, separated by spaces.
Each of these tasks is trivial in C++ and doesn’t require pointers or anything like that (which is a good thing. Pointers have their place in C but only rarely in C++).
For example, the first step can be solved using C++ IO streams and the vector container:
std::vector<std::string> words;
std::string word;
while (cin >> word)
words.push_back(word);
This reads individual words from the standard input and stores them in a vector.
The second step can should be solved using the C++ standard library sort function.
The third step is a mere matter of iterating over the vector and pushing the words to the cout stream.
All in all, this shouldn’t take more than 15 lines of code.
If you don’t want to use a string class, your first step should be to write one. It doesn’t have to be fancy, but it should at least take care of the rudimentary mechanisms of handing the string’s memory, reading from input and writing to output.