string *parse(string str,int from){
int i=0,n=0,j,k;
i=j=from;
string *data=new string[6];
while(str[i]){
if(str[i]==' '){
for(k=0;k<(i-j-1);k++){
data[n][k]=str[j+k]; << Error takes place here
}
data[n][k]='\0';
j=i;
n++;
}
i++;
}
return data;
}
Thanks for your help. I tried to debug but without success, what am I missing?
The problem is that elements data[i] of the data array all have the length of zero. That is why the assignment data[n][k] is always outside of data[n]'s range.
One way of fixing this would be using concatenation:
data[n] += str[j+k];
A better approach would be eliminating the loop altogether, and using substr member function of std::string instead: it lets you cut out a portion of str knowing the desired length and the starting position.
In addition, you are returning a pointer to a local array, which is undefined behavior. You should replace an array with a vector<string>, and add items to it using push_back.
Finally, you need to push the final word when the str does not end in a space.
Here is your modified program that uses the above suggestions:
vector<string> parse(string str,int from){
int i=from, j=from;
vector<string> data;
while(str[i]){
if(str[i]==' '){
data.push_back(str.substr(j, i-j+1));
j=i+1;
}
i++;
}
if (j != str.size()) {
data.push_back(str.substr(j));
}
return data;
}
Here is a demo on ideone.
data starts with 0 length, data[n][k] out of boundry. data[n][k]='\0' is not correct way of using C++ string and string * is considered of bad practice.
To separate a string by space, try:
#include <string>
#include <vector>
#include <sstream>
std::string data("hi hi hi hi hi");
std::stringstream ss(data);
std::string word;
std::vector<std::string> v;
while(std::getline(ss, word, ' '))
{
v.push_back(word);
}
Related
I want to store words separated by spaces into single string elements in a vector.
The input is a string that may end or may not end in a symbol( comma, period, etc.)
All symbols will be separated by spaces too.
I created this function but it doesn't return me a vector of words.
vector<string> single_words(string sentence)
{
vector<string> word_vector;
string result_word;
for (size_t character = 0; character < sentence.size(); ++character)
{
if (sentence[character] == ' ' && result_word.size() != 0)
{
word_vector.push_back(result_word);
result_word = "";
}
else
result_word += character;
}
return word_vector;
}
What did I do wrong?
Your problem has already been resolved by answers and comments.
I would like to give you the additional information that such functionality is already existing in C++.
You could take advantage of the fact that the extractor operator extracts space separated tokens from a stream. Because a std::string is not a stream, we can put the string first into an std::istringstream and then extract from this stream vie the std:::istream_iterator.
We could life make even more easier.
Since roundabout 10 years we have a dedicated, special C++ functionality for splitting strings into tokens, explicitely designed for this purpose. The std::sregex_token_iterator. And because we have such a dedicated function, we should simply use it.
The idea behind it is the iterator concept. In C++ we have many containers and always iterators, to iterate over the similar elements in these containers. And a string, with similar elements (tokens), separated by a delimiter, can also be seen as such a container. And with the std::sregex:token_iterator, we can iterate over the elements/tokens/substrings of the string, splitting it up effectively.
This iterator is very powerfull and you can do really much much more fancy stuff with it. But that is too much for here. Important is that splitting up a string into tokens is a one-liner. For example a variable definition using a range constructor for iterating over the tokens.
See some examples below:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <regex>
const std::regex delimiter{ " " };
const std::regex reWord{ "(\\w+)" };
int main() {
// Some debug print function
auto print = [](const std::vector<std::string>& sv) -> void {
std::copy(sv.begin(), sv.end(), std::ostream_iterator<std::string>(std::cout, "\n")); std::cout << "\n"; };
// The test string
std::string test{ "word1 word2 word3 word4." };
//-----------------------------------------------------------------------------------------
// Solution 1: use istringstream and then extract from there
std::istringstream iss1(test);
// Define a vector (CTAD), use its range constructor and, the std::istream_iterator as iterator
std::vector words1(std::istream_iterator<std::string>(iss1), {});
print(words1); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 2: directly use dedicated function sregex_token iterator
std::vector<std::string> words2(std::sregex_token_iterator(test.begin(), test.end(), delimiter, -1), {});
print(words2); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 3: directly use dedicated function sregex_token iterator and look for words only
std::vector<std::string> words3(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {});
print(words3); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 4: Use such iterator in an algorithm, to copy data to a vector
std::vector<std::string> words4{};
std::copy(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {}, std::back_inserter(words4));
print(words4); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 5: Use such iterator in an algorithm for direct output
std::copy(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {}, std::ostream_iterator<std::string>(std::cout,"\n"));
return 0;
}
You added the index instead of the character:
vector<string> single_words(string sentence)
{
vector<string> word_vector;
string result_word;
for (size_t i = 0; i < sentence.size(); ++i)
{
char character = sentence[i];
if (character == ' ' && result_word.size() != 0)
{
word_vector.push_back(result_word);
result_word = "";
}
else
result_word += character;
}
return word_vector;
}
Since your mistake was only due to the reason, that you named your iterator variable character even though it is actually not a character, but rather an iterator or index, I would like to suggest to use a ranged-base loop here, since it avoids this kind of confusion. The clean solution is obviously to do what #ArminMontigny said, but I assume you are prohibited to use stringstreams. The code would look like this:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> single_words(string sentence)
{
vector<string> word_vector;
string result_word;
for (char& character: sentence) // Now `character` is actually a character.
{
if (character==' ' && result_word.size() != 0)
{
word_vector.push_back(result_word);
result_word = "";
}
else
result_word += character;
}
word_vector.push_back(result_word); // In your solution, you forgot to push the last word into the vector.
return word_vector;
}
int main() {
string sentence="Maybe try range based loops";
vector<string> result= single_words(sentence);
for(string& word: result)
cout<<word<<" ";
return 0;
}
This is the code for removing consecutive words:
std::string unstretch(std::string word)
{
std::string s;
int k=0;
for(int i=0;i<word.length();k++,i++)
{
if(word[i]!=word[i+1])
{
s[k]=word[i];
}
else
k--;
}
s[k]='\0';
return s;
}
This code works if we replace string s with char s[50]. Can someone explain why this happens?
s is an empty string. You cannot use operator[] on an index that doesn't exist.
The problem is you are treating string as a char array. Its not just a char array. So,
You don't need to keep an index to append
You don't need the null terminator
I think what your program does is remove the duplicate characters. This is how you would probably do it:
std::string unstretch(std::string word)
{
std::string s;
for(int i=0;i<word.length();i++)
{
if(word[i]!=word[i+1])
{
s += word[i];
}
}
return s;
}
I wrote a program to remove spaces from string in c++. But when i compile this program i got two errors. They are error: initializer fails to determine size of ‘str1’ and error: array must be initialized with a brace-enclosed initializer.
Can any one show me the error of my code. I am new for C++. I mentioned my code below
#include <stack>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
char *delSpaces(char *str)
{
int i = 0, j = 0;
while (str[i])
{
if (str[i] != ' ')
str[j++] = str[i];
i++;
}
str[j] = '\0';
return str;
}
int main(){
string s;
cin >> s;
char str1[]=s;
cout << delSpaces(str1);
}
char str1[]=s;
is not valid C++.
I recommend changing your function to take a string argument by reference.
But if you can't do that, then one way to get read/write access to the char buffer of non-const s, since C++11, is
&s[0]
Since C++17 you can also use s.data().
However, note that your delSpaces creates a zero-terminated string in the supplied buffer, without knowing anything about a string. Since a string can hold any binary data s.length() would be unaffected by the call to delSpaces. You could fix that by adding a call to s.resize(), but again, a better approach is to express delSpaces with a string& argument.
You can't initialize a char[] buffer with a std::string object, that is why you are getting errors.
You would have to do something more like this instead:
char *str1 = new char[s.size()+1];
std::copy(s.begin(), s.end(), str1);
str1[s.size()] = '\0';
std::cout << delSpaces(str1);
delete[] str1;
A better option would be to change the delSpaces() function to take a std::string by reference instead:
void delSpaces(std::string &str) {
size_t j = 0;
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] != ' ')
str[j++] = str[i];
}
str.resize(j);
}
...
std::string s;
std::cin >> s;
delSpaces(s);
You can even let the STL remove the space characters for you:
void delSpaces(std::string &str) {
str.erase(
std::remove(str.begin(), str.end(), ' '),
str.end()
);
}
That being said, note that by default, when operator>> is reading character data, it ignores leading whitespace and then stops reading when it encounters whitespace, so your use of operator>> in this situation will never return a std::string that has spaces in it, thus your delSpaces() function is pretty useless as shown. Use std::getline() instead, which reads until it encounters a line break, and thus can return a string with spaces in it:
std::getline(std::cin, s);
I'm trying to build a function that goes through a while or for-loop and finds where the space is, outputs everything before the space, and then erases everything before the space including the space, and then repeats this again.
Any help is much appreciated.
int sentence()
{
string enteredSentence="";
getline(cin,enteredSentence);
string sentenceString(enteredSentence);
int sentenceLength=enteredSentence.size();
cout<<"size of sentence"<<sentenceLength<<endl;
int stringSize=sentenceString.size();
while(stringSize>0)
{
int spaceLoc = enteredSentence.find(" ");
cout<<spaceLoc;
cout<<sentenceString.substr(0,spaceLoc)<<endl;
sentenceString.substr(0,spaceLoc);
cout<<"string before string eraced"<<sentenceString<<endl;
sentenceString.erase (0,spaceLoc);
cout<<"string after string eraced"<<sentenceString<<endl;
stringSize=sentenceString.size();
cout<<"string size is"<<stringSize<<endl;
}
This is how I fixed your code:
#include <iostream>
using namespace std;
int main()
{
string enteredSentence="";
getline(cin,enteredSentence);
string sentenceString(enteredSentence);
int sentenceLength = enteredSentence.size();
cout<<"size of sentence:"<<sentenceLength<<endl;
string::size_type stringSize = sentenceString.size();
while(stringSize > 0)
{
int spaceLoc = sentenceString.find(" "); //there was incorrect var
cout<<spaceLoc<<endl;
if(spaceLoc == string::npos){
cout<<"last part:"<<sentenceString<<endl;
break;
}//check if there are no spaces left
cout<<sentenceString.substr(0,spaceLoc)<<endl;
//the substr line here was redundant
cout<<"string before string erased:"<<sentenceString<<endl;
sentenceString.erase(0, spaceLoc + 1);//also delete the space
cout<<"string after string erased:"<<sentenceString<<endl;
stringSize=sentenceString.size();
cout<<"string size:"<<stringSize<<endl<<endl;
}
return 0;
}
You could use a stringstream.
#include <sstream>
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
string enteredSentence; // It's initialized to "" by default, by the way
getline(cin,enteredSentence);
cout<<"size of sentence: "<<enteredSentence.length()<<endl;
istringstream str_in(enteredSentence);
string word;
while(str_in >> word) {
// Do stuff with word
// I believe str_in.str() will also give you the portion that hasn't yet been processed.
}
return 0;
}
I'm not 100% sure that I understand what you want to achieve. But I can help you with find:
It has a second parameter that specifies from where on in the string the search will start:
size_t pos = 0;
while ((pos = str.find(' ', pos)) != std::string::npos) {
std::cout << "Found a space at " << pos << std::endl;
++pos;
}
Reference
With more information on what you actually want your code to do (show example input plus wanted output) I can help you clear the rest of your code.
Currently your description suggests that you want to output the entire string, but in pieces (separated by spaces).
Your code makes a (needless?) copy of your input, generates substrings only to throw them away and doesn't return an int as said in the function declaration.
If you want to tokenize your input then this question has some answers for you.
Here's part my code:
#include <stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main(){
FILE *in=fopen("C.in","r");
//freopen("C.out","w",stdout);
int maxl=0;
int i;
string word;
vector<string> words;
while(!feof(in)){
fscanf(in,"%s ",word.c_str());
int t=strlen(word.c_str());
if(t>maxl){
maxl=t;
words.clear();
words.insert(words.end(),word);
}else if (t==maxl){
words.insert(words.end(),word);
}
}
the problem occurs at
words.insert(words.end,word)
while
word
contains the word from my file, the vector item
words[i]
contains an empty string.
How is this possible?
fscanf(in,"%s ",word.c_str());
That's never going to work. c_str() is a const pointer to the string's current contents, which you mustn't modify. Even if you do subvert const (using a cast or, in this case, a nasty C-style variadic function), writing beyond the end of that memory won't change the length of the string - it will just give undefined behaviour.
Why not use C++ style I/O, reading into a string so that it automatically grows to the correct size?
std::ifstream in(filename);
std::string word;
while (in >> word) {
if (word.size() > maxl) {
maxl = word.size();
words.clear();
words.push_back(word);
} else if (word.size() == maxl) {
words.push_back(word);
}
}