So I have a file that has contents that need to be stored into a growing object. By growing I mean that it'll explicitly concatenate the new line it reads into the growing object, pBuff, each time every line is read from the file. I only get the last line to be outputted when I try to output the growing object after the file has been read (for my example below, only "Line 5.\n" is what gets output). Can someone steer me into the right direction?

Here is my code.

bool DynString::readLine(std::istream& in)
{
	if(in.eof())
	{
		*this = DynString();	// Default string value.
		pBuff = "";
		return(false);
	}

	char s[1001];
	in.getline(s, 1001);

	// Delete old string-value and create new pBuff string with copy of s
	delete [] pBuff;
	pBuff = new char[1001];
	strncpy(pBuff, s, 1001);

	return(true);
}

// Read entire input file into string
bool DynString::readFile(const char filename[])
{
	std::ifstream in(filename);
	if(! in.is_open() )
	{
		*this = DynString();	// Default string value.
		pBuff = "";
		return(false);
	}

	// Delete old string-value and
	// Read the file-contents into a new pBuff string
	delete [] pBuff;
	pBuff = new char[1001];
	
	while(!in.eof())
	{
		readLine(in);
	}

	return(true);
}

Text file has contents like so:

Line 1.\n
Line 2.\n
Line 3.\n
Line 4.\n
Line 5.\n

The comments are what my professor put in as instructions so I DO have to follow them. I've been at this for hours and I'm still stuck! Any suggestions would be great! Also, I tried using the strcat function like so: strcat(pBuff, s); but that resulted in my program to crash :(

Edited 4 Years Ago by yongj: n/a

Let me make sure that I understand what you want to do.

  1. Read in a file line by line.

  2. Save that line into a DynString object.
  3. As you read the next line, keep what is in the current pBuff and append the new line to the end of the pBuff.
    1. In doing that de-allocate pBuff memory and re-allocate more memory to store

    2. data.
  4. When all lines are read out of file, DynString has the full contents of the input file.

Let me make sure that I understand what you want to do.

  1. Read in a file line by line.

  2. Save that line into a DynString object.
  3. As you read the next line, keep what is in the current pBuff and append the new line to the end of the pBuff.
    1. In doing that de-allocate pBuff memory and re-allocate more memory to store

    2. data.
  4. When all lines are read out of file, DynString has the full contents of the input file.

PERFECT!

Can you post your whole DynString.h and DynString.cpp? I want to get the full picture before I start here and there and there.

Can you post your whole DynString.h and DynString.cpp? I want to get the full picture before I start here and there and there.

Sure thing.

Header

#include <iostream>

class DynString 
{
public:
	// Construct a new DynString, initialized to substring of s 
	//   starting at position 0, of length len
	// If len < 0, utilize entire string s
	// If len > length of s, then utilize entire string s
	// Both s and len have default parameter values
	DynString(const char s[]="", const int len=-1);
	
	// Copy Constructor.  Construct new (deep) copy of s
	DynString(const DynString &s);
	// Assignment operator= override.  Make new (deep) copy of s.
	DynString& operator=(const DynString &s);
	// Destructor.  Delete allocated string-value
	~DynString();

	// Return current string-value length
	const int length() const;

	// Return ASCIIZ char* string pointer
	const char* toString() const;

	// Read next input line into string
	// Assumes that incoming input line has at most 256 characters
	// Returns true if a line is successfully input.
 	// Returns false and sets the string value to "" if the end-of-file is reached.
	bool readLine(std::istream& in = std::cin);

	// Read entire input file into string as single, long string-value
	//   with embedded \n newline characters marking the ends-of-lines.
	// Returns true if the filename is successfully opened and read.
 	// Returns false and sets the string value to "" if a file error occurs.
	bool readFile(const char filename[]);

	// Concatenate s to end of string-value
	void concat(const DynString &s);

	// Compare string-value to s.
	// Return (-), 0, or (+) depending on result of comparison
	const int compare(const DynString &s) const;

	// Retrieve string[position].  Return 0 if out of range
	const char getChar(const int position) const;

	// Find position of ch in string.  Return -1 if not found
	// Begin searching with [startoffset] position
	const int findChar(const char ch, const int startoffset=0) const;

	// Return new DynString with value that is substring of original
	DynString substr(const int start, const int len=-1) const;

	// Return substring of original corresponding to linenum (1 .. n)
	// Do not include '\n' at end of line
	DynString findLine(const int linenum) const;

	// Return line number 1 .. n corresponding to position in string
	int findLineNumber(const int position) const;

private:
	char *pBuff;				// The actual string buffer array
	int   curLength;			// current length of string-value

	// Added extra -- not required for lab assignment. Implementation provided.
	// Overload << operator for DynStrings
	// Note: friend function, not a class method
	friend std::ostream &operator<<(std::ostream& out, const DynString &s);
};

.CPP

#include <cstring>
#include <assert.h>
#include <iostream>
#include <fstream>

#include "DynString.h"

// Default and Convert Constructor
// Default parameters are provided for both s and len
DynString::DynString(const char s[], const int len)
{
	curLength = len;							// new string length
	int maxLen = strlen(s);						// limit
	if(curLength < 0 || curLength > maxLen)
		curLength = maxLen;

	pBuff = new char[curLength + 1];
	assert(pBuff);

	for(int i=0; i<curLength; ++i)		// or, strncpy_s(pBuff, curLength+1, s, curLength);
		pBuff[i] = s[i];

	pBuff[curLength] = 0;		// Sentinel
}

// Copy Constructor
DynString::DynString(const DynString &s)
{
	if(s.pBuff != NULL)
	{
		curLength = s.curLength;

		pBuff = new char[curLength + 1];
		for(int i = 0; i < s.curLength; i++)
			pBuff[i] = s.pBuff[i];

		pBuff[curLength] = 0;
	}
	else 
	{
		curLength = 0;
		pBuff = 0;
	}
}

// Assignment operator=
DynString& DynString::operator=(const DynString &rhs)
{
	if(this != &rhs)
	{
		// Delete old string-value and create new pBuff that
		// is copy of rhs string-value
		if(this == &rhs)
			return *this;

		delete [] pBuff;
		
		if(rhs.pBuff != NULL)
		{
			curLength = rhs.curLength;

			pBuff = new char[curLength + 1];
			for(int i = 0; i < curLength; i++)
				pBuff[i] = rhs.pBuff[i];

			pBuff[curLength] = 0;
		}
		else
		{
			curLength = 0;
			pBuff = 0;
		}
	}

	return *this;
}

// Destructor
DynString::~DynString()
{
	if(pBuff != NULL)
		delete [] pBuff;
}

const int DynString::length() const
{
	return(curLength);
}

const char* DynString::toString() const
{
   return pBuff;
}

bool DynString::readLine(std::istream& in)
{
	if(in.eof())
	{
		*this = DynString();	// Default string value.
		pBuff = "";
		return(false);
	}

	char s[1001];
	in.getline(s, 1001);

	// Delete old string-value and create new pBuff string with copy of s
	delete [] pBuff;
	pBuff = new char[1001];
	//strncpy(pBuff, s, 1001);
	concat(s);

	return(true);
}

// Read entire input file into string
bool DynString::readFile(const char filename[])
{
	std::ifstream in(filename);
	if(! in.is_open() )
	{
		*this = DynString();	// Default string value.
		pBuff = "";
		return(false);
	}

	// Delete old string-value and
	// Read the file-contents into a new pBuff string
	delete [] pBuff;
	pBuff = new char[1001];
	
	while(!in.eof())
	{
		readLine(in);
	}

	return(true);
}

void DynString::concat(const DynString &s)
{
	strcat_s(pBuff, 50, s.pBuff);

	return;
}

You won't need the implementation for the other functions as they are not relevant to this issue. Also, I forgot that I had a "concatenate" function. Utilizing that would be most efficient :)

This should get you started. I tried to modify you code as little as possible. Leave the debug in until the end, so you can make sure you are doing what you think you are doing. I just changed the header.
Check, check, and check the size of the array to make sure the '\0' is there and in the correct position. I didn't! This is your task.
When doing this use a file like below, to make it easy to debug.

1
22
333
4444
#include <cstring>
#include <assert.h>
#include <iostream>
#include <fstream>
#include "DynString.h"

using namespace std;

// Default and Convert Constructor
// Default parameters are provided for both s and len
DynString::DynString(const char s[], const int len)
{
//        cout << "---> DynString(s("<<s<<") len("<<len<<"))" <<endl;
	curLength = len;							// new string length
	int maxLen = strlen(s);						// limit
	if(curLength < 0 || curLength > maxLen)
		curLength = maxLen;

	pBuff = new char[curLength + 1];
	assert(pBuff);

	for(int i=0; i<curLength; ++i)		// or, strncpy_s(pBuff, curLength+1, s, curLength);
		pBuff[i] = s[i];

	pBuff[curLength] = 0;		// Sentinel
        //cout << "<--- DynString(pBuff("<<pBuff<<") curLength("<<curLength<<"))" <<endl;
}

// Copy Constructor
DynString::DynString(const DynString &s)
{
	if(s.pBuff != NULL)
	{
		curLength = s.curLength;

		pBuff = new char[curLength + 1];
		for(int i = 0; i < s.curLength; i++)
			pBuff[i] = s.pBuff[i];

		pBuff[curLength] = 0;
	}
	else 
	{
		curLength = 0;
		pBuff = 0;
	}
}

// Assignment operator=
DynString& DynString::operator=(const DynString &rhs)
{
	if(this != &rhs)
	{
		// Delete old string-value and create new pBuff that
		// is copy of rhs string-value
		if(this == &rhs)
			return *this;

		delete [] pBuff;
		
		if(rhs.pBuff != NULL)
		{
			curLength = rhs.curLength;

			pBuff = new char[curLength + 1];
			for(int i = 0; i < curLength; i++)
				pBuff[i] = rhs.pBuff[i];

			pBuff[curLength] = 0;
		}
		else
		{
			curLength = 0;
			pBuff = 0;
		}
	}

	return *this;
}

// Destructor
DynString::~DynString()
{
	if(pBuff != NULL)
		delete [] pBuff;
}

const int DynString::length() const
{
	return(curLength);
}

const char* DynString::toString() const
{
   return pBuff;
}

bool DynString::readLine(std::istream& in)
{
      if(in.eof())
      {
//		*this = DynString();	// Default string value.
//		pBuff = "";
		return(false);
	}

	char s[1002];
	in.getline(s, 1001);
        size_t justRead(in.gcount());
        if ( justRead == 1000 ) {
           // Hit the max chars before '\n'
        }
        else {
           if ( !in.eof() )
              s[justRead-1] = '\n';
        }
	// Delete old string-value and create new pBuff string with copy of s
	//delete [] pBuff;
	//pBuff = new char[1001];
	//strncpy(pBuff, s, 1001);
	concat(s);

	return(true);
}

// Read entire input file into string
bool DynString::readFile(const char filename[])
{
	std::ifstream in(filename);
	if(! in.is_open() )
	{
	  //*this = DynString();	// Default string value.
	  //pBuff = "";
          cout << "Error on file open" << endl;
  	  return(false);
	}

	// Delete old string-value and
	// Read the file-contents into a new pBuff string
	//delete [] pBuff;
	//pBuff = new char[1001];
	
	while(readLine(in));
//	{
//		readLine(in);
//	}

	return(true);
}

void DynString::concat(const DynString &s)
{
    //strcat_s(pBuff, 50, s.pBuff);
    char *ptr(0);
    size_t bytesNeeded(curLength+s.length()+1);
    ptr = new char[bytesNeeded];
    memcpy(ptr,pBuff,curLength);
    memcpy(&ptr[curLength],s.toString(),s.length());
    delete [] pBuff;
    pBuff = ptr;
    curLength = bytesNeeded-1;
    pBuff[curLength] = 0;
    cout << "---> DynString(curLength("<<curLength<<") concat: " << pBuff; 
    return;
}
This article has been dead for over six months. Start a new discussion instead.