about strings in c++ - c++

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;
}

Related

Why am I getting string reversal wrong with a trailing space character?

I am unable to get why there is a space and it is getting me wrong.
Below is the code I wrote for the solution
Why there is blank space char at the end of the string at the end even after reversing my string.
Question
class Solution {
public:
string minRemoveToMakeValid(string s) {
string str = "";
int n = s.length();
int open=0;
for(int i=0;i<n;i++){
if(s[i]=='('){
open++;
}else if(s[i]==')'){
open--;
if(open<0){
open=0;
continue;
}
}
str+=s[i];
}
open=0;
string s2="";
for(int i=n-1;i>=0;i--){
if(str[i]==')'){
open++;
}else if(str[i]=='('){
open--;
if(open<0){
open=0;
continue;
}
}
s2=s2+str[i];
}
reverse(s2.begin(),s2.end());
return s2;
}
};
Leetcode Submission getting wrong
The length of str may be less than one of s, but you are using the length of s while iterating within str. You must use correct length.
string s2="";
n = str.length(); // add this
for(int i=n-1;i>=0;i--){

Debug my reimplementation of strtok and split

I'm supposed to be writing code that takes a string of comma separated values without spaces (ex. my,name,is,jack). First we had to write a function
string nextstring(string str, int start_index)
that returns a single "value" from your initial string depending on the start index. The second part of the problem was to write a function
int split(string str, string a[], int max_size)
that will identify all the values in the initial string and put them in a string array and then return the total number of values stored in the array; i.e. if you had initially input my,name,is it would return 3.
My function never returns the correct value and whatever it returns changes depending on what the length of the words are.
#include <iostream>
#include <string>
using namespace std;
string nextstring(string str, int start_index);
int split(string str, string a[], int max_size);
int main()
{
string str;
int cnt;
string a[100];
cout<< "what is your string" << endl;
getline(cin, str);
cnt= split(str, a, 100);
cout << "There are " << cnt << " values in this string" << endl;
for(int i=0; i<cnt; i++)
{
cout << a[i] << endl;
}
return 0;
}
string nextstring(string str, int start_index)
{
string ans;
if(str[start_index] == ',' || str[start_index] == '\0')
{
ans=" ";
}
else{
ans=str[start_index]+nextstring(str, start_index+1);
}
return ans;
}
int split(string str, string a[], int max_size)
{
int j=0;
int ans=0;
double k=0;
while(j<max_size)
{
a[j]= nextstring(str,k);
string check=a[j];
if(isalpha(check[0])!= 0)
{
ans++;
}
k=k+a[j].length();
j++;
}
return ans;
}
It seems that your problem is that while(j<max_size){...} leads to j being incremented up to max_size. The line a[j]= nextstring(str,k); is at some points reading values that are outside your string which is really bad!
Replacing while(j<max_size){...} by while(j<max_size && k<str.length()){...} seems to be enough to make your code work!
Apart from that:
k has no reason to be a double! It should be an int (or something similar).
Since you are already using string, you should also learn to use vector. split is better written as:
int split(string str, vector<string> &a, int max_size)
{
int ans=0;
int k=0;
while(k<str.length())
{
string next = nextstring(str,k);
if(isalpha(next[0])!= 0)
{
ans++;
a.append(next);
}
k += next.length();
}
return ans;
}
The problem in your approach is to identify the end of the string, as there is no null terminator in a c++ string. Consider to update nextstring() to look for the end of string in a different manner:
string nextstring(string str, int start_index)
{
...
if(start_index == str.size() || str[start_index] == ',' ) //<===
{
ans=" ";
}
...
}
online demo
Additional recommendation
Note that it is not very nice to return a blank string when in reality it should be empty to reflect its real value (e.g. ",,"). You have no choice because otherwise you would have no mean in the calling function, to determine that the end of string was reached. But the consequence is thar all your strings have a trailing blank.
When you call recursively the function adding char to build the return string, you risk to have a considerable overhead. You could consider avoiding this, by replacing the else part:
ans=str.substr(start_index, str.find(',', start_index+1)-start_index);
However, as you have no trailing blank anymore, you need to adapt split() so to adapt its way to count the total number of chars parsed:
k=k+a[j].length()+1; // +1 because there's no longer a trailing blank.
Online demo

String pointer manipulation

I have this assignment at school. A string pointer is passed to the function and returns 2 const strings to a different functions.
The 2 new strings divide the original string into 2 parts based on a space.
Example:
Input
str = 05/12 Hello
Desired output
key = 05/12
satData = Hello
This is the code I wrote but its giving me errors. Please help
void RBapp::processInsert(string &str)
{
string *key = new string();
string *satData = new string();
int i = 0, j =0;
while(str[i]!=" ")
{
key[j] = str[i];
i++;
j++;
}
j = 0;
while(str[i]!='\0')
{
satData[j] = str[i];
i++;
j++;
}
myRBT.rbInsert(key, satData);
}
Using stringstream
void RBapp::processInsert(const std::string &str)
{
std::stringstream ss(str);
std::string key;
std::string satData;
ss >> key;
ss >> satData;
myRBT.rbInsert(key, satData);
}
Your program is subject to undefined behavior since you are accessing memory that is not valid.
When you use:
string *key = new string();
string *satData = new string();
You have two pointers that point to empty strings.
key[j] = str[i];
is wrong if j > 0 since that points to invalid memory.
Based on the description of what you are trying to do, what you need is something along the lines of:
void RBapp::processInsert(string &str)
{
// There is no need to use new string.
// Just use two string objects.
string key;
string satData;
int i = 0;
while(str[i]!=" ")
{
// Add the character to key
key.push_back(str[i]);
i++;
}
// Increment i here if you want the space to be excluded from
// satData. If you want to include the space character in satData,
// then, there is no need to increment i
++i;
while(str[i]!='\0')
{
// Add the character to satData
satData.push_back(str[i]);
i++;
}
myRBT.rbInsert(key, satData);
}
You say you receive a string pointer - what I see is you receive a string. In C++ you would try to avoid hand-written loops as much as possible - std::string has a lot of stuff you need.
void process(const string &str) {
auto firstSpace = str.find_first_of(' ');
auto key = str.substr(0, firstSpace);
auto value = str.substr(firstSpace, string::npos);
myRBT.rbInsert(key, value);
}

C++ string library error: string subscript out of range

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);
}

Value returned by strtok() for tokens of length 0?

I have the following piece of C++ code:
string dots="...";
char *points=(char *)malloc(sizeof(char)*20);
strcpy(points,dots.c_str());
points=strtok(points,".");
while(points!=NULL)
{
cout<<points<<endl;
points=strtok(NULL,".");
}
The cout statement prints nothing. What is this character that cout returns for 0 length token match? I have tried to check for '\0' but does not work. Please Help.
EDIT: Complete Program to Validate IP Addresses
#include<iostream>
#include<cstring>
#include<stdlib.h>
using namespace std;
int validateIP(string);
int main()
{
string IP;
cin>>IP;
int result=validateIP(IP);
if(result==0)
cout<<"Invalid IP"<<endl;
if(result==1)
cout<<"Valid IP"<<endl;
return 0;
}
//function definition validateIP(string)
int validateIP(string IP)
{
char ip[16];
int dotCount=0;
strcpy(ip,IP.c_str());
//check number of dots
for(int i=0;i<strlen(ip);++i)
{
if(ip[i]=='.')
{
dotCount++;
}
}
if(dotCount!=3)
return 0;
//check range
char *numToken;
numToken = strtok (ip,".");
while (numToken!= NULL)
{
int number;
if(numToken!=NULL) //check for token of length 0(e.g. case: ...)
number=atoi(numToken); //i also checked for (numToken[0]!='\O')
else return 0;
if(number<0 or number>255)
return 0;
numToken=strtok (NULL,".");
}
return 1;
}
The program prints ValidIP for input: ...
Your code has undefined behavior, you haven't allocate memory for points, accessing it invokes UB.
Update, I might write validateIP by using string and STL functions only if I could. Mix C/C++ is not good for maintenance.
#include <sstream>
int to_int(const std::string& s)
{
int i(0);
std::stringstream ss(s);
ss >> i;
return i;
}
bool isValidIp(const std::string& IP)
{
if (std::count(IP.begin(), IP.end(), '.') != 3)
{
return false;
}
std:stringstream ss(IP);
int token;
std::string s;
while(std::getline(ss, s, '.'))
{
int token = to_int(s);
if (token < 0 || token > 255)
{
return false;
}
}
return true;
}
Then you call it:
if (isValidIp(IP))
{
std::cout << "Valid IP" << std::endl;
}
else
{
std::cout << "Invalid IP" << std::endl;
}
The strtok function returns sub-string of the given string delimited by the given character. IMO (to be tested) if your string only contains delimiting characters, the strtok function will return NULL (no more tokens) at the first call.
Moreover in your code snippet, you copy the string to an uninitialized pointer. Replace your call to strcpy by a call to strdup for the underlying memory to be allocated before copying. Edit: you modified your question as I were answering
strtok is used to tokenize the string. Say, i have a string "abc.def.ghi.jkl" then we can use strtok to get the tokens besed on the delimiter.
char a[]="abc.def.ghi.jkl";
char tmp=strtok(a, ".");
if (tmp != NULL) //Required because strtok will return null if it failes find the delimiter
printf("\n value is [%s]", tmp); //out put is abc
So, in your case "..." is the string and '.' is the delimiter which result in empty string because there is no characters between first character and the delimiter '.'
your code will return empty string say "" as an output. for all the sttok function call.
Second you have to allocate memory to the points variable like
char points[dots.length()+1];
If the string only contains delimiting characters, strok return NULL
You probably want this:
int main()
{
string dots=". . ."; //Notice space
char *points=(char *)malloc(sizeof(char)*20);
char *p; // Use a char pointer
strcpy(points,dots.c_str());
p=strtok(points,".");
while(p!=NULL)
{
cout<<points<<endl;
p=strtok(NULL,".");
}
/* Free Memory */
free(points);
}