Basic C++: convert from char to string - c++

I'm a little confused by the class code. Here's what I'm trying to do:
//Program takes "string text" and compares it to "string remove". Any letters in
//common between the two get deleted and the remaining string gets returned.
#include <string>
#include "genlib.h"
string CensorString1(string text, string remove);
int main() {
CensorString1("abcdef", "abc");
return 0;
}
string CensorString1(string text, string remove) {
for (int i = 0; text[i]; i++){
for (int n = 0; remove[n]; n++){
if (i != n){
string outputString = ' '; //to store non repeated chars in,
//forming my return string
outputString += i;
}
}
}
return outputString;
}
I'm getting an error on the "outputString += 1" saying: "cannot convert from "char" to
std::basic_string
I'm also getting an error on the "return outputString" saying: undeclared identifier
???????
I get that I'm putting a "char" on a "string" variable but what if shortly that "char" will soon be a string? Is there a way to pass this?
I'm always forgetting libraries. Can someone recommend a couple of standard/basic libraries I should always think about? Right now I'm thinking , "genlib.h" (from class).
C++ is kicking my ass. I can't get around constant little errors. Tell me it's going to get better.

There are many errors in your code:
Your outputString needs to be in the outer scope (syntax)
You compare i to n instead of text[i] to remove[n] (semantic)
You are adding i to the output instead of text[i] (semantic)
You ignore the return of CensorString1 (semantic)
Here is your modified code:
string CensorString1(string text, string remove) {
string outputString;
for (int i = 0; text[i] ; i++){
for (int n = 0; remove[n] ; n++){
if (text[i] != remove[n]){
outputString += text[i];
}
}
}
return outputString;
}
This has some remaining issues. For example, using text[i] and remove[n] for termination conditions. It is also very inefficient, but it should be a decent start.

At any rate, strings are always double-quoted in C and C++. Single-quoted constants are char constants. Fix that and you should probably be all right.
Also, look at this SO question: How do you append an int to a string in C++?
Good luck at Stanford!

There are some problems there:
string outputString = ' '; will try to construct a string from a char, which you can't do. You can assign a char to a string though, so this should be valid:
string outputString;
outputString = ' ';
Then, outputString is only visible within your if, so it won't act as an accumulator but rather be created and destroyed.
You're also trying to add character indices to the string, instead of characters, which is not what I think you want to be doing. It seems like you're mixing up C and C++.
For example, if you want to print the characters of a string, you could do something like:
string s("Test");
for (int i=0;i<s.length();i++)
cout << s[i];
Finally, I'd say that if you want to remove characters in text that also appear in remove, you'd need to make sure that none of the characters in remove match your current character, before you add it to the output string.

This is an implementation of what I think you want, your code has multiple problems which just showed up described in multiple other answers.
std::string CensorString1(std::string text, std::string remove) {
std::string result;
for (int i = 0; i<text.length(); i++) {
const char ch = text[i];
if(remove.find(ch) == -1)
result.append(1,ch);
}
return result;
}

Related

Why isn't the return working as Expected Giving some Random string

So the Problem was given a String Which is a Name like Sam Harris you have to output it's abbreviation what i did was find the space in the string and then taking a string otp which will add str[0] first letter of name str[pos+1] letter after position and also added a . in between but the return statement is returning some random value.Which is not expected.
#include
std::string abbrev(std::string str)
{
int pos{0};
for(int i=0;i<str.length();++i)
{
if(str[i]==' ')
{
pos=i;
break;
}
}
std::string otp=str[0]+"."+str[pos+1];
return otp;
}
int main()
{
std::string str="Sam Harris";
std::cout<<abbrev(str)<<"\n";
return 0;
}
The problem is that this here:
str[0]+"."+str[pos+1];
Isn't constructing a string. It's adding a char* to some chars, effectively performing some invalid pointer arithmetic. Fix it like this:
std::string otp = str[0] + std::string(".") + str[pos + 1];
Now std::string(".") correctly makes a std::string and appends those chars as intended using std::string's operator+.
str[0] and str[pos+1] returns a character at that position with type char. You cannot added a char variable to a constant string "." (double quoted). Overall I think it added up the constant string memory address with char values of each position and assign it to otp. For example, looking at your case, assume constant string "." have an address value 1000. The str[0] will return 'S' with ascii value 83 and str[pos+1] is expected to return 'H' with ascii value 72. Then opt will assigned with a memory address 1155 (83+1000+72), which will be an unknown program memory with junk value, which will be returned by the function. Use stringstream to concatnate string as following:
std::string abbrev(std::string str)
{
int pos{0};
for(int i=0;i<str.length();++i)
{
if(str[i]==' ')
{
pos=i;
break;
}
}
std::stringstream otp;
otp << str[0] << "." << str[pos+1];
return otp.str();
}
So you want the first letter, presumably capitalized, for each separate word in the string? Something like this should work.
std::string input = "Sam Harris";
std::string output = "";
auto n = input.find(" ");
while (n++ != input.npos)
{
output += std::to_upper(input[0]);
input = input.substr(n, input.size() - n);
n = input.find(" ");
}
Not a c++ guy, but I can give this a shot. I suspect, you're getting random stuff because you're overflowing the bounds of arrays for some inputs. Fixing that may fix your bug (example below, assuming your syntax is correct).
std::string abbrev(std::string str) {
for(int i=0;i<str.length()-1;++i) {
if(str[i]==' ') {
return str[0] + '.' + str[i +1];
}
return '';
}
Obviously you'll have to generalize for arbitrary number of spaces.

Cannot use string class to assign characters but works with char array in C++

I'm trying to assign some characters from a string to another string as follows:
string s2;
int ind = -1;
for(int i = 0; i < ch; i++)
{
s2[++ind] = s[i];
}
s2[++ind] = '\0';
Now when I try to print s2 using
cout << s2 << endl;
It prints nothing on the black screen. But when I use char array in place of string declaration for s2, then s2 gets printed successfully. I think both a string and char array's characters can be accessed in the same way. Cannot understand why this happened. Some info about this?
You cannot access the ++indd element of an empty string. Use string's operator += to append a char to the string.
Your code contains Undefined Behavior!
At the beginning your string size is zero and you do not resize it. As a result required memory is not allocated and proper information in string is not updated.
Small string optimization probably prevents a crash which should happen.
Two ways to fix it:
// crappy solution - to match your pattern
string s2;
for(int i=0;i<ch;i++)
{
s2.push_back(s[i]);
}
// a good one
string s2(s, s + strlen(s));

Delete repeated characters from a random word

I'm making a class to delete repeated character from a random word. For example if the input is "aabbccddeeff", it should output "abcdef". However my output contains strange characters after "abcdef". The main.cpp file already exists as the requirements for creating the class. Please see the following codes:
main.ccp
#include <iostream>
#include "repeatdeletion.h"
using namespace std;
int main()
{
char* noRepeats;
int length;
string s;
cout<<"Enter a random word with repeating characters: ";
cin>>s;
RepeatDeletion d;
length=s.length();
noRepeats=d.deleteRepeats(s, length);
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
delete [] noRepeats;
noRepeats=NULL;
return 0;
}
repeatdeletion.h
#ifndef REPEATDELETION_H
#define REPEATDELETION_H
#include <iostream>
using namespace std;
class RepeatDeletion
{
char* c;
char arr[128]={};
bool repeated;
bool isRepeated(char);
public:
RepeatDeletion();
~RepeatDeletion();
char* deleteRepeats(string, int);
};
#endif // REPEATDELETION_H
repeatdeletion.cpp
#include "repeatdeletion.h"
RepeatDeletion::RepeatDeletion()
{
repeated=false;
}
RepeatDeletion::~RepeatDeletion()
{
delete [] c;
c=NULL;
}
bool RepeatDeletion::isRepeated(char c){
bool repeated=false;
if (arr[c]>=1){
repeated=true;
arr[c]++;
}else{
arr[c]++;
}
return repeated;
}
char* RepeatDeletion::deleteRepeats(string str, int len){
c=new char[len];
int j=0;
for (int i=0; i<len; i++){
if (isRepeated(str[i])==false){
c[j]=str[i];
j++;
}
}
return c;
}
Your return character array is not null terminated.
The length function of string does not include \0.
You have two choices
Add null at the end of returned character array, and std::cout the char array directly (instead of char by char)
Output the final length of your char array, and use that as range to print it char by char
Your printing loop loops using the old and unmodified string length. That means you will go outside the characters you added to memory returned by deleteRepeats.
The easiest solution to handle this is to terminate the data as a proper string, and check for the terminator in the loop.
If you want to use a C-string array, they have a null terminator at the end. That means you'll want to (in deleteRepeats) define your character array one character larger than the length:
c=new char[len+1];
And, after the for loop, ensure you put that null terminator in:
c[j] = '\0';
Then, in your calling function, you can just do:
cout << noRepeats;
Even if you don't want to use C strings, you'll need to communicate the new length back to the caller somehow (currently, you're using the original length). The easiest way to do that is (IMNSHO) still using a C-style string and using strlen to get the new length (a).
Otherwise, you're going to need something like a reference parameter for the new length, populated by the function and used by the caller.
(a) But I'd suggest rethinking the way you do things. If you want to be a C++ coder, be a C++ coder. In other words, use std::string for strings since it avoids the vast majority of problems people seem to have with C strings.
That's because in your code you write the following:
cout<<"Your word without any repeating characters: ";
for (int k=0; k<length; k++){
cout<<noRepeats[k];
}
cout<<endl;
Here, length refers to the length of the original string (which you, by the way shouldn't pass to your deleteRepeats method). I would suggest you make deleteRepeats return a string and write something like this:
std::string noRepeats = d.deleteRepeats(s);
std::cout << "Your word without any repeating characters: ";
std::cout << noRepeats << std::endl;
C-style string (char *, if you insist) follow the convention that the last character is '\0', indicating that the string ends. You could also change deleteRepeats by appending '\0', i.e.
char* RepeatDeletion::deleteRepeats(string str){
c = new char[str.size() + 1];
int j = 0;
for (int i = 0; i < str.size(); i++){
if(isRepeated(str[i]) == false){
c[j] = str[i];
j++;
}
}
c[j] = '\0';
return c;
}
and in your main
std::cout << noRepeats << std::endl;
instead of the for loop. But really, you should use std::string, and if possible not mix it with char *. Hope that helps.
for(k=0;k<length;k++)
Here length should be the exact length of noRepeats, but not of s
so :
char* RepeatDeletion::deleteRepeats(string str, int len)
should return the length-after too
use std::unique it does what you want:
std::string s{};
std::cin>>s;
auto it = std::unique(std::begin(s), std::end(s));
s.resize(std::distance(std::begin(s),it));
std::cout << s;
the way it works is to go through the range begin to end and move all the remaining elements forward if the current element is equal to the next. It returns the position of the end of the new string (it in this example) but does not actually shorten the string so on the next line we shorten the string to the length equal to the distance of begin() to it.
see live at http://ideone.com/0CeaHW

How to empty a string in Arduino c language

I wrote the below in arduino code language (c or c++ ?)
And i got puzled, i'm not sure if this is a limitation from C or C++.
My function should split a text string and return word number x
In my function i need to clean a string variable, that resets its contend until X is reached
For readability X is called wordcount.
How do i clean the string Wordsample make it empty again ?
On a side note, if the word isnt found then this function should also return nothing
As the results are used to make other strings from.
String GetSubString (String A,int Wordcount) //for readability start counting B from 1
{ int CounterX;
String WordSampleN;
String result ;
for (int i = 0; i < A.length(); i++)
{ // split string
WordSampleN = WordSampleN + A[i];
if ((A[i] == ' ') || (A[i] =='\n'))
{ CounterX++;
if (CounterX == Wordcount)
{ result = WordSampleN;
}
if (CounterX <> WordCount)
{ WordSampleN = ''; // <== ERROR IS HERE
}
}
}
return result;}
On a side note, if possible I would like to keep use strings of any size, not fixed strings.
There is no concept of an 'empty character'. You cannot initialize your String (object) this way. Instead, use an empty (small-"s") string "";
WordSampleN = "";
This will call the String constructor that takes a c-style string, and initialize your String object with the empty string.

creating a string split function in C++ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Splitting a string in C++
Im trying to create a function that mimics the behavior of the getline() function, with the option to use a delimiter to split the string into tokens.
The function accepts 2 strings (the second is being passed by reference) and a char type for the delimiter. It loops through each character of the first string, copying it to the second string and stops looping when it reaches the delimiter. It returns true if the first string have more characters after the delimiter and false otherwise. The position of the last character is being saved in a static variable.
for some reason the the program is going into an infinite loop and is not executing anything:
const int LINE_SIZE = 160;
bool strSplit(string sFirst, string & sLast, char cDelim) {
static int iCount = 0;
for(int i = iCount; i < LINE_SIZE; i++) {
if(sFirst[i] != cDelim)
sLast[i-iCount] = sFirst[i];
else {
iCount = i+1;
return true;
}
}
return false;
}
The function is used in the following way:
while(strSplit(sLine, sToken, '|')) {
cout << sToken << endl;
}
Why is it going into an infinite loop, and why is it not working?
I should add that i'm interested in a solution without using istringstream, if that's possible.
It is not exactly what you asked for, but have you considered std::istringstream and std::getline?
// UNTESTED
std::istringstream iss(sLine);
while(std::getline(iss, sToken, '|')) {
std::cout << sToken << "\n";
}
EDIT:
Why is it going into an infinite loop, and why is it not working?
We can't know, you didn't provide enough information. Try to create an SSCCE and post that.
I can tell you that the following line is very suspicious:
sLast[i-iCount] = sFirst[i];
This line will result in undefined behavior (including, perhaps, what you have seen) in any of the following conditions:
i >= sFirst.size()
i-iCount >= sLast.size()
i-iCount < 0
It appears to me likely that all of those conditions are true. If the passed-in string is, for example, shorter than 160 lines, or if iCount ever grows to be bigger than the offset of the first delimiter, then you'll get undefined behavior.
LINE_SIZE is probably larger than the number of characters in the string object, so the code runs off the end of the string's storage, and pretty much anything can happen.
Instead of rolling your own, string::find does what you need.
std::string::size_type pos = 0;
std::string::size_type new_pos = sFirst.find('|', pos);
The call to find finds the first occurrence of '|' that's at or after the position 'pos'. If it succeeds, it returns the index of the '|' that it found. If it fails, it returns std::string::npos. Use it in a loop, and after each match, copy the text from [pos, new_pos) into the target string, and update pos to new_pos + 1.
are you sure it's the strSplit() function that doesn't return or is it your caller while loop that's infinite?
Shouldn't your caller loop be something like:
while(strSplit(sLine, sToken, '|')) {
cout << sToken << endl;
cin >> sLine >> endl;
}
-- edit --
if value of sLine is such that it makes strSplit() to return true then the while loop becomes infinite.. so do something to change the value of sLine for each iteration of the loop.. e.g. put in a cin..
Check this out
std::vector<std::string> spliString(const std::string &str,
const std::string &separator)
{
vector<string> ret;
string::size_type strLen = str.length();
char *buff;
char *pch;
buff = new char[strLen + 1];
buff[strLen] = '\0';
std::copy(str.begin(), str.end(), buff);
pch = strtok(buff, separator.c_str());
while(pch != NULL)
{
ret.push_back(string(pch));
pch = strtok(NULL, separator.c_str());
}
delete[] buff;
return ret;
}