Sign in to follow this  

c++ Problem with reading/outputting file -solved

This topic is 4244 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

After several months of developement I finally got bored of recompiling for every spelling mistake and have disengaged the, written, content into text files (it's a simple text based game). I'm having some trouble because it's adding newlines before every line it reads. The problem is that I wish to indent the text if it is a character speaking however this doesn't work because it indents at the end of the last line before the newline when I use:
cout << " " << line;
The code to read the files is:
void ReadIn(PLAYER* player,string file, int anchor, bool speech)
{
	ifstream in(file.data());
	char* newline = new char[MAX_LINE_SIZE]; 
	string name = "<name>";
	string shorttitle = "<shorttitle>";
	string longtitle = "<longtitle>";
	string end = "<endread>";
	string nline = "\n";
	string blank = "";
	string s_anchor = IntToString(anchor);
	string fullanchor = "<a="+s_anchor+">";
	int anchorlocation = FindAnchor(file,anchor);
	in.seekg(anchorlocation);
	int i = 0;
	if (speech)
	{
		// Getname
		in.getline(newline,MAX_LINE_SIZE,'$');
		string line = std::string(newline);   //turn into type std::string

		line.append(":");
		cout << line;
	}
	while(true)
	{
		/* Read in speech
		 * If <end> appears break out of while
		 * and return.
		 * Before displaying to screen parse
		 * to see if any special commands were used.
		 * If they were execute them, then return.

		 * Special commands
		 * <name> - insert players name
		 * <shorttitle> - insert players short title and name
		 * <fulltitle> - insert players full title and name
		 */

		in.getline(newline,MAX_LINE_SIZE,'$');
		string line = std::string(newline);   //turn into type std::string		
		for(i = line.find(name, 0); i != string::npos; i = line.find(name, i))
		{
			string n = player->GetName();
			line.erase(i,name.size());
			line.insert(i,n);
			i++;  // Move past the last discovered instance to avoid finding same
		}			
		i = 0;
		for(i = line.find(longtitle, 0); i != string::npos; i = line.find(longtitle, i))
		{
			string temptitle = GetFullTitle(player);
			line.erase(i,longtitle.size());
			line.insert(i,temptitle);
			i++;  // Move past the last discovered instance to avoid finding same
		}		
		i = 0;
		i = line.find(end, 0);
		if (i != string::npos)
		{
			line.erase(i,end.size());
			line.insert(i,blank);
			// Move past the last discovered instance to avoid finding same
			cout << line;
			break;
		}
		if (speech)
		{
			cout << " " << line;		
		}
		else
		{
			cout << line;
		}
	}
	delete newline;

	in.close();
}


Is the problem to do with using the "getline" function? Is there anything I can do to fix the problem? EDIT: Solved it with "ignore(INT_MAX,'\n');" [Edited by - Iccarus on April 29, 2006 11:40:46 PM]

Share this post


Link to post
Share on other sites
Is your file reading in text mode? That can contribute to interperetations of lines...
(Haven't looked through all of the code yet, though).

Share this post


Link to post
Share on other sites
I think I am (I'm using the default mode, I know it's not binary).

I could understand it putting a line at the end but a line at the beginning seems wrong. Can anyone else help with this?

Share this post


Link to post
Share on other sites
i only have a minute here so i skimmed over the code real quick. i want to point out that you don't need to use a char array for your input. use a string instead. quick example:

std::ifstream input_file( "foo.txt" );
std::string input_string;
char terminating_char = '$';
std::getline( input_file, input_string, terminating_char );

check a reference or google std::getline for details.

Share this post


Link to post
Share on other sites
Another quick notation:
This line:
delete newline;

should be:
delete [] newline;

You use the "delete[]" operator when deleting dynamic arrays allocated by "new[]".

Share this post


Link to post
Share on other sites
First off, congratulations on your good design decision :)

A bunch of style comments.

0) As noted, use a string for reading in. When you do need a character array for something, you should see if you can allocate it on the stack rather than the heap. Here MAX_LINE_SIZE is a compile-time constant (presumably) and is not huge, so there's nothing stopping you from doing 'char newline[MAX_LINE_SIZE]', and not having to worry about deleting the memory yourself. (Remember, not having to worry about it is one of the reasons for using std::string in the first place.) But when you do have to allocate dynamically, you *must* make sure your deletion matches your allocation: delete[] for new[], delete for new. (And free for malloc, but don't use that in C++.)

1) Don't reuse your counter variables, and try to scope things according to where they are used.

2) Mark your constants as constants.

3) Prefer to pass complex arguments by reference - const reference if you don't need to change them.

4) Think about your interfaces. IntToString() can be generalized, assuming you're using stringstream techniques, to handle other types, by the magic of templating. FindAnchor should probably just seek the file to the desired point and return nothing (pass the stream by reference).

5) Mark your constants as const.

6) A function called "ReadIn()" should be actually reading into some container; do the output somewhere else. I've arranged to return the whole text as a string here. There may be better approaches depending on context. Normally, though, you want to separate the functionality of communicating with the user from the rest of the code.

7) Don't declare variables for simple expressions that are only used in one place.

8) Extract helper functions for repetitive sections of code.


// Warning: all off the top of my head, not compiled or tested.

bool ReplaceAll(string& in, const string& what, const string& with) {
// replace all occurrences of 'what' in 'in' with 'with', mutating the
// supplied 'in'. Return whether any replacements occurred.
// Instead of the 'i++' logic that was here, I just adjust the loop 'find'.
// This is only a problem if "with" contains "what", but eh... This is
// actually more robust, since the other version only guards against "with"
// *starting with* "what".
boolean found = false;
for (int i = in.find(what); i != string::npos;
i = in.find(what, i + with.size())) {
found = true;
in.replace(i, what.size(), with);
}
return found; // note the loop doesn't get to execute if the first find() fails
}

string ReadIn(PLAYER& player, const string& filename, int anchor, bool speech) {
const string name = "<name>";
const string shorttitle = "<shorttitle>";
const string longtitle = "<longtitle>";
const string end = "<endread>";
const string nline = "\n";
const string blank = "";

ifstream in(filename.data());
SeekTo(in, "<a=" + boost::lexical_cast<string>(anchor) + ">");

string result;

if (speech) {
// Get name. We will constantly be appending to the result.
// At the start, the result is empty, so we can read in there directly.
getline(in, result, '$');
result.append(":");
}

bool done = false;
while (!done) {
string line; // into which we read.
getline(in, line, '$');
ReplaceAll(line, name, player.GetName());
ReplaceAll(line, longtitle, GetFullTitle(player));
// Why is GetName() a member function but GetFullTitle() a free function?
// Also, you seem to have forgotten about <shorttitle> entirely?
done = ReplaceAll(line, end, blank));
// If there was a line end, we're done at the end of this iteration.
// Note that your version wouldn't emit the space on the last line of a
// speech ;)
if (speech) { result.append(" "); }
result.append(line);
result.append(nline);
}
// You don't have to .close() the stream; that is done automatically by the
// destructor.
return result;
}

Share this post


Link to post
Share on other sites

This topic is 4244 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this