ifstream file ("../file.csv");
string test;
unsigned counter = 0;
while(counter<10){
getline(file,test,'"');
cout<<test<<endl;
counter++;
}
I am essentially trying to recreate this in c++ but without using the string class. I am trying to figure out a way to not use the string class and still use this same function. Any thoughts?
For some clarification I will be delimeting with a '"' and then I will be a comma after that, so there is a text surrounded in '"', and a conclusion that is seperated from the text by a comma.
This is my custom class
class customString {
char* myStr;
int length;
public:
customString();
customString(char enb);
customString(const customString& source);
customString(customString&& source);
~customString(){delete myStr;}
};
customString::customString(){
str = new char[1];
str[0] = '\0';
}
customString::customString(char enb) {
length = 1;
myStr= new char(enb);
}
customString::customString(const customString &source) {
length = source.length;
myStr = new char[length];
for (int i = 0; i < length; i++){
myStr[i]=source.myStr[i];
}
}
customString::customString(const char* val){
if(val!= nullptr){
int counter = 0;
while(val[counter]!='\0')counter++; //Find length of the char array
length = counter;
myStr = new char[counter];
for(int i =0;i<counter;i++){
myStr[i]=val[i];
}
}else{
length = 1;
myStr = new char[length];
myStr[0] = '\0';
}
}
customString::~customString(){
delete[] myStr;
}```
you can use std::basic_istream<CharT,Traits>::getline:
basic_istream& getline( char_type* s, std::streamsize count, char_type delim );
There isn't much to your custom class, but as it is implemented, you need to define an assignment operator, otherwise an assignment could result in both a memory leak and a double free bug. Follow the Rule of Three.
If you must use a pointer, you should at least use a std::unique_ptr<char[]> instead of a bare pointer. However, it is simpler to use a std::vector<char> instead.
class customString {
std::vector<char> myStr;
friend std::ostream & operator << (std::ostream &ost, const customString &s) {
return ost.write(&s.myStr[0], s.myStr.size());
}
friend std::istream & getline (std::istream &ist, customString &s,
char delim = '\n') {
//...
return ist;
}
public:
customString() {}
customString(char enb) : myStr(enb) {}
customString(const char *val, int len = -1)
: myStr(val, val + (len < 0 ? strlen(val) : len))
{}
};
Note that your code was missing the const char * constructor. Also, since std::vector knows its length, the length member is no longer required. For convenience, I included a method to emit the contents into an std::ostream.
For your getline replacement, you could also implement that as a friend function inside your custom class, and I included a stub above. When you implement it, you have to pay attention to how std::getline is defined to make sure you follow all of its behaviors.
My advice is to actually extract one character at a time (e.g., with std::istream::get) and check it against the delimiter. Then, make sure you set failbit in the std::istream if you encounter one of the failure conditions.
str.max_size() characters have been stored
If no characters were extracted for whatever reason
Reference: cppreference.com
Good luck, and hope this helps!
Related
I want to learn how to copy the contents of one string into another, and I want to make sure my interpretation of my code is correct. The point of this exercise is learning, so I don't want to use STL implementations -- I want to learn the algorithms myself.
I have a class called CStudent that contains a private member variable named szName.
In my Main.cpp, I have some code that reads in a line of data using getLine, and extracts a certain amount of characters using a custom substr function.
I want to set the contents of szName to the result of the substr function, but every implementation I've tried thus far just results in only a single character being copied.
Here are the pertinent parts of code:
class CStudent
{
public:
void setName(char inName[]);
void setClass(char inClass[]);
void setGPA(float inFloat);
char getName();
char getClass();
float getGPA();
private:
char szName[20] = {};
char szClass[10] = {};
float fGPA{ -1.0f };
};
// Custom strcpy to enable use of setters in class
void strcpy(char inString[], char outString[], size_t outSize)
{
unsigned int i = 0;
for (; ((inString[i] != '\0') && (i < (outSize))); i++)
{
outString[i] = inString[i];
}
outString[i] = '\0';
}
void CStudent::setName(char inName[])
{
strcpy(inName, szName, 20);
}
// Custom substr to enable use of setters in class
void substr(char inString[], char outString[], size_t outSize, int startPos, int endPos)
{
int inStringPos = 0, outStringPos = 0;
//for (inStringPos = startPos, outStringPos = 0; outStringPos < outSize;)
for (inStringPos = startPos, outStringPos = 0; inStringPos < endPos;)
{
outString[outStringPos++] = inString[inStringPos++];
}
outString[outStringPos] = '\0';
}
Main excerpt:
int main()
{
CStudent students[25]{};
CStudent freshmen[25]{};
CStudent sophomores[25]{};
CStudent juniors[25]{};
CStudent seniors[25]{};
// Read in data
fstream inputFile;
inputFile.open("input.txt");
for (int i = 0; i < 25; i++)
{
char readLine[80] {};
inputFile.getline(readLine, 80);
char sName[20] {};
substr(readLine, sName, 20, 0, 19); // Only reading first character
students[i].setName(sName);
char sClass[10] {};
substr(readLine, sClass, 10, 20, 29);
students[i].setClass(sClass);
Where am I going wrong here?
I read the implementation of strcpy I've found in several locations and I can't seem to figure out where I went wrong.
Edit: In the code comments I mention that it's substr that's only returning 1 char, but it's actually the setter - setName.
I had incorrectly set the return type of getName to char instead of char*, which was rightfully only returning the first character of the array. Thanks #IgorTandetnik.
What is the proper c++11 way to extract a set of characters out of a stringstream without using boost?
I want to do it without copying, if possible, because where this is used is in a critical data loop. It seems, though, std::string does not allow direct access to the data.
For example, the code below performs a substring copy out of a stringstream:
inline std::string left(std::stringstream ss, uint32_t count) {
char* buffer = new char[count];
ss.get(buffer, count);
std::string str(buffer); // Second copy performed here
delete buffer;
return str;
}
Should I even be using char *buffer according to c++11?
How do I get around making a second copy?
My understanding is that vectors initialize every character, so I want to avoid that.
Also, this needs to be passed into a function which accepts const char *, so now after this runs I am forced to do a .c_str(). Does this also make a copy?
It would be nice to be able to pass back a const char *, but that seems to go against the "proper" c++11 style.
To understand what I am trying to do, here is "effectively" what I want to use it for:
fprintf( stderr, "Data: [%s]...", left(ststream, 255) );
But the c++11 forces:
fprintf( stderr, "Data: [%s]...", left(str_data, 255).c_str() );
How many copies of that string am I making here?
How can I reduce it to only a single copy out of the stringstream?
You could use something like described in this link: How to create a std::string directly from a char* array without copying?
Basically, create a string, call the resize() method on the string with the size that is passed to your function and then pass the pointer to the first character of the string to the stringstring.get() method. You will end up with only one copy.
inline std::string left(std::stringstream& ss, uint32_t count) {
std::string str;
str.resize(count);
ss.get(&str[0], count);
return str;
}
My suggestion:
Create the std::string to be returned by giving it the size.
Read the characters one by one from the stringstream and set the values in the std::string.
Here's what the function looks like:
inline std::string left(std::stringstream ss, uint32_t count) {
std::string str(count+1, '\0');
for (uint32_t i = 0; i < count; ++i )
{
int c = ss.getc();
if ( c != EOF )
{
str[i] = c;
}
else
{
break;
}
}
return str;
}
R Sahu, this I like! Obvious now that I see it done. ;-)
I do have one mod though (as well as passed a shared_ptr of stream which is what I actually had in my version):
In your initializer, you are filling with nulls. You only need to fill with the last one, so I propose a tweak of this:
inline std::string left(std::shared_ptr<std::stringstream> ss, uint32_t count) {
std::string str;
str.reserve(count + 1);
uint32_t i;
for(i = 0; i < count; ++i) {
int c = ss->get();
if(c != EOF) {
str[i] = c;
} else {
break;
}
}
str[i] = '\0';
return str;
}
Now, only initialized with nulls on a single character.
Thanks R Sahu!
If the purpose of this function is solely for passing to fprintf or another C-style stream, then you could avoid allocation completely by doing the following:
void left(FILE *out, std::stringstream &in, size_t count)
{
in.seekg(0);
char ch;
while ( count-- && in.get(ch) )
fputc(out, static_cast<unsigned char>(ch));
}
Usage:
fprintf( stderr, "Data: [" );
left(stderr, stream, 255);
fprintf( stderr, "] ...\n");
Bear in mind that another seekg will be required if you try to use the stream reading functions on the stringstream later; and it would not surprise me if this is the same speed or slower than the options involving str().
#include<iostream>
using namespace std;
class MyString{
private:
char *str=new char[10];
public:
MyString(){*str='\0';} //default constructor
MyString(char *s){ //parameterized constructor
str=s;
}
private:
int length(char* s){
int i=0;
while(s[i]!='\0')
i++;
return i;
}
char* delchar(char* s,int count,int start){
int i,j=0;
char *temp= new char[10];
for(i=start;i<start+count;i++){
s[i]=' ';
}
for(i=0;i<length(s);i++){
if(s[i]!=' ')
temp[j++]=s[i];
}
s=temp;
return s;
}
public:
MyString operator-(MyString s){
int i=0,j=0,count=0,start=-1;/* i to iterate the first string,j to iterate the second string*/
MyString temp; /* count to count the matched characters ,start to know the starting index*/
temp.str=str;
while(temp.str[i]!='\0'){
j=0;
start++;
while(s.str[j]!='\0'){
if(temp.str[i]==s.str[j]){
count++;
i++;
j++;
if(count==length(s.str)){//checks if the count
temp.str=delchar(temp.str,count,start);
i=i-count;
start=i-1;
count=0;
}
}
else{
i++;
count=0;
break;
}
}
}
return temp;
}
~MyString(){
delete str;
}
friend ostream &operator<<(ostream &stream,MyString& s){
stream<<s.str<<endl;
return stream;
}
};
int main(){
char *p= new char[20];
char *q= new char[10];
cin>>p;
cin>>q;
MyString s1(p);
MyString s2(q);
MyString s3;
s3=s1-s2;
cout<<s3;
delete p;
delete q;
return 0;
}
The above code overloads the - operator .It tries to subtract the substring from the main string for example input1:joshmathews input2:josh output:mathews. I am trying to store the output in a new MyString object s3. When I use a destructor as shown above,outputting s3
returns null. But when I don't use a destructor I get the expected output.Can anyone help?
The primary issue is that Operater- returns a local object which is copied by a default copy constructor -- that default copy constructor points s3 to the exact same memory/buffer of the temp MyString, and when that temp is destructed, it wipes out the memory s3 is using.
That is referred to as a dangling pointer. You can read more here: http://en.wikipedia.org/wiki/Dangling_pointer#Cause_of_wild_pointers
The code below is the changes I made to get your program executing and returning a valid result, while completing without error. To be clear though, there are issues with this altered version, runtime error or no runtime error, but this will help illuminate some important points.
When you define a type that allocates memory, you've really started to do somethings that don't come free. My altered version below completely got rid of the destructor, so actually it leaks memory up until the program ends. The destructor was invalid though, so removing it allowed the program the finish. But this would be one of those things that in general you shouldn't just accept.
I added a copy constructor and a copy assignment operator:
MyString(const MyString& s) {
strcpy_s(str, 10, s.str);
}
MyString& operator=(const MyString& s) {
strcpy_s(str, 10, s.str);
return *this;
}
Notice the strcpy_s in both of these. What is doing is copy the character string from the argument instead of just trying to point at the exact same string at the exact same address as the argument. If the argument gets destructed in your version, it wipes out some memory, so we can just accept default copy constructor and such since by default they are shallow copies that point to the same guts. That's one of the burdens of allocating memory -- you need to take care of that in both your destructor's ~and~ some of your constructors. This is referred to as "The Rule of Three":
If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.
Here's a wikipedia link about the rule of three: http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
You needed a destructor, so that's the clue you need the others. The reason is as I was saying -- by default you get a copy constructor for free, but it just makes everything point to the same guts if there are points are resources, but then you can't delete one without affecting everybody else.
Also, in delchar I added this line towards the bottom:
temp[j] = '\0';
Characters strings must always end at a null, and you copied only actual letter characters into temp, so without a null character, a strcpy doesn't know where to end.
If you remember I yanked out your destructor, then those are the changes I made.
The destructor also has an issue, in that if you use new to create an array, like
char* c = new char[10];
then you need to delete it in a way that indicates in was new'd as an array, like so:
delete [] c;
The next thing you should look into is how your MyString construction happens. If you step through, you'll see that the str member get new'd -- that means it holds a valid address into a buffer you can use -- but then if the MyString(char *s) constructor is used, it literally just takes this new address of s, and makes str hold that address instead -- which means the old address pointing to the valid buffer is lost, and that buffer of new'd memory cannot be freed. So that's a leak. You could use the strcpy_s strategy from the constructors I added to copy the contexts of what is pointed to by the s in MyString(char *s) into the new'd buffer. That would make a huge positive difference in the code.
And don't bother about all the elitists out there -- many of them were born doing headstands, so they can't see to relate to newbies giving things an honest effort.
Here's the full altered code:
#include<iostream>
using namespace std;
class MyString{
private:
char *str = new char[10];
public:
MyString(){ *str = '\0'; } //default constructor
MyString(char *s){ //parameterized constructor
str = s;
}
MyString(const MyString& s) {
strcpy_s(str, 10, s.str);
}
MyString& operator=(const MyString& s) {
strcpy_s(str, 10, s.str);
return *this;
}
private:
int length(char* s){
int i = 0;
while (s[i] != '\0')
i++;
return i;
}
char* delchar(char* s, int count, int start){
int i, j = 0;
char *temp = new char[10];
for (i = start; i<start + count; i++){
s[i] = ' ';
}
for (i = 0; i<length(s); i++){
if (s[i] != ' ')
temp[j++] = s[i];
}
temp[j] = '\0';
s = temp;
return s;
}
public:
MyString operator-(MyString s){
int i = 0, j = 0, count = 0, start = -1;/* i to iterate the first string,j to iterate the second string*/
MyString temp; /* count to count the matched characters ,start to know the starting index*/
temp.str = str;
while (temp.str[i] != '\0'){
j = 0;
start++;
while (s.str[j] != '\0'){
if (temp.str[i] == s.str[j]){
count++;
i++;
j++;
if (count == length(s.str)){//checks if the count
temp.str = delchar(temp.str, count, start);
i = i - count;
start = i - 1;
count = 0;
}
}
else{
i++;
count = 0;
break;
}
}
}
return temp;
}
~MyString(){
//delete str;
}
friend ostream &operator<<(ostream &stream, MyString& s){
stream << s.str << endl;
return stream;
}
};
int main(){
char *p = new char[20];
char *q = new char[10];
cin >> p;
cin >> q;
MyString s1(p);
MyString s2(q);
MyString s3;
s3 = s1 - s2;
cout << s3;
delete p;
delete q;
return 0;
}
I ran this through debug, and in the String Substring function, everything works up until the return statement.
'returnString', in the code below, has the correct value when at the return line. However, as soon as I go to next line (the closing bracket directly after), it changes to:
{Text=0x003ed0e0 "îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþ... }String
which I traced back to the destructor, is the value the String has when deleted.
Now, I would have thought that the value would be deleted only after it's passed, but it seems like it's getting deleted first. You guys know how to fix this? Like I said above, the function works perfectly (at least, it looks like it), there's just something wrong with how it's returning the value.
The line that calls on my string function: String LocalString((Address.Substring(0, atIndex))); (Address is declared a String under 'private' in the respective header file)
Substring is a little past halfway down, right after the index operator. If it seems like I'm missing a function or a file, ask for it. Thanks for reading and (I'm hoping) the help.
The String.h file:
#pragma once
#include <iostream>
#include <sstream>
using namespace std;
// C++ String class that encapsulates an ASCII C-string
class String
{
public:
// Default constructor
String()
{
Text = NULL;
}
// MUST HAVE: Copy-constructor that performs deep copy
String(const String& source)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = source;
}
// Init-constructor to initialize this String with a C-string
String(const char* text)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = text;
}
// Destructor
~String()
{
delete[] Text;
}
// Returns the count of characters in a C-string text; NULL-terminator is not counted
static int GetLength(const char* text)
{
int x = 0;
while(text[x] != '\0')
x++;
return x;
}
// Assignment operator to perform deep copy
String& operator = (const char* text)
{
// Ddispose of old Text
delete[] Text;
// +1 accounts for NULL-terminator
int trueLength = GetLength(text) + 1;
// Dynamically allocate characters on heap
Text = new char[trueLength];
// Copy all characters from source to Text; +1 accounts for NULL-terminator
for ( int i = 0; i < trueLength; i++ )
Text[i] = text[i];
return *this;
}
// if length is not specified, then the substring spans from startPosition until the end of this String
// throws an exception when startPosition is out of bounds
String Substring(int startPosition, int length=0) const
{
char * str = this->GetText();
int strLength = length;
int x = 0;
char* substring = new char[strLength];
while(x < strLength && str[x+startPosition]!='\0')
{
substring[x] = str[x + startPosition];
x++;
}
substring[x]='\0';
String returnString = substring;
return returnString;
}
// Returns the count of characters in the String; NULL-terminator is not counted
int GetLength() const
{
return GetLength(Text);
}
private:
// The encapsulated C-string
char* Text;
};
somewhere in main.cpp...
String LocalString((Address.Substring(0, atIndex)));
String DomainString((Address.Substring(atIndex + 1)));
// or, in simpler syntax:
/*
* String hell0 = String andGoodbye;
* String smile = String andWave;
*/
Despite the comment // Assignment operator to perform deep copy the class doesn't have a user defined assignment operator.
The default, computer generated, assignment operator performs a shallow copy. The contained text will be lost as soon as one copy is destroyed.
Question
The problem is that i am trying to get user input using insertion operator and initialising the value thechars, to allocate the size to thechars i need the length of input, how do i get it?? And initialise in insertion operator.
Main problem is with insertion operator.
When i run the program it shows the segmentation fault,
plz help
class string1
{
private:
int len;
char *thechars;
//friend ostream& operator<<(ostream&,string1&);##
//friend istream& operator>>(istream&,string1&);##
public:
//string1() :len(0),thechars(NULL){}
string1()
{
thechars = new char[1];
thechars[0] = '\0';
len=0;
// cout << "\tDefault string constructor\n";
// ConstructorCount++;
}
};
// this is the insertion operator i use
istream& operator>>(istream& in, string1& tpr)
{
in >> tpr.thechars;
//tpr.thechars[i+1]='\0';
return in;
}
//this one is the extraction operator
ostream& operator<<(ostream& out,string1& prt)
{
for(int i=0;i<prt.len;i++)
out<<prt.thechars[i];
return out;
}
// main function##
string1 str;
cout << "enter first string" << endl;
cin >> str;
cout << str << endl;
If in is a file input stream, you can do the following:
in.seekg(0, ios::end);
length = in.tellg();
in.seekg(0, ios::beg);
The other option is reading the input stream char by char and double the size of thechars each time it's exhausted. First, introduce one more variable to store the currently allocated size of the buffer --- allocSize. After that update the constructor and operator<< as follows.
Constructor:
string1()
{
allocSize = 1; // initially allocated size
thechars = new char[allocSize];
thechars[0] = '\0';
len=0;
}
Input operator:
istream& operator>>(istream& in, string1& tpr)
{
char inp;
while (in.get(inp)) {
// end-of-input delimiter (change according to your needs)
if (inp == ' ')
break;
// if buffer is exhausted, reallocate it twice as large
if (tpr.len == tpr.allocSize - 1) {
tpr.allocSize *= 2;
char *newchars = new char[tpr.allocSize];
strcpy(newchars, tpr.thechars);
delete[] tpr.thechars;
tpr.thechars = newchars;
}
// store input char
tpr.thechars[tpr.len++] = inp;
tpr.thechars[tpr.len] = '\0';
}
}
But the best option is to use std::string as a type for thechars. Do you really need all this manual memory handling?
Instead of giving the in a char* give it a regular string. Then you can extract the data yourself.
istream& operator>>(istream& in, string1& tpr)
{
string temp;
in >> temp;
tpr.len = temp.length + 1;
tpr.thechars = new char[tpr.len];
tpr.thechars[temp.length] = '\0';
strcpy(tpr.thechars, &temp[0], tpr.len);
return in;
}
you wrote
in>> tpr.thechars; // where thechars="\0";
You allocated only one byte, but i guess you are input string with more bytes.
I think error here.