first program evaluation

K

Karl Heinz Buchegger

Pieter said:
Thanks! It's about 140 kb now instead of 500.

Changing the project properties to use a shared
runtime library brings it down to 16 kByte. But then
you need to provide the required DLL's with your exe.
 
P

Pieter Provoost

Daniel T. said:
OK then, lets turn that into a function:

void insertFile( ostream& os, const string& fileName )
{
ifstream includefile( fileName );
string includebuffer;
while ( getline( includefile, includebuffer ) )
os << includebuffer << endl;
}

In main we have:

string bestand = buffer.substr(9, (buffer.find_first_of("}") - 9));
bestand += ".tex";
insertFile( outfile, bestand );

and we can remove the line:

string bestand;

From the top of the file.

What do you think of this minor change? Does it make main easer to
understand or harder? Is the function created easy to understand? Do you
think you could use the insertFile function in other contexts?

Yes I definately think it's a good change. There's one thing that I don't
understand: why is there a "&" after ostream and string?

Thank you!
 
K

Karl Heinz Buchegger

Pieter said:
Yes I definately think it's a good change. There's one thing that I don't
understand: why is there a "&" after ostream and string?

In this case '&' means: reference.
Instead of creating a copy of the original object during the call, a reference
to these objects is passed to the function and thus avoiding to
duplicate the objects (which BTW would be impossible with a stream object)

Look up references in your C++ book. You will use them often in
the future if continue programmin in C++.
 
D

Daniel T.

What do you think of this minor change? Does it make main easer to
understand or harder? Is the function created easy to understand? Do you
think you could use the insertFile function in other contexts?

Yes I definately think it's a good change.[/QUOTE]

You may be wondering at this point, why I picked that particular block
of code to extract into a seperate function. First, I noticed that there
were two variables that were only being used in that particular block of
code and not being used anywhere else in the program (includefile, and
includebuffer.) Second, when I asked you what that block of code did,
you were able to explain it with a simple phrase, one that translated
well into a function name.

Do you see any blocks of code where one or two variables are only being
used in that block and nowhere else? What would you say each block of
code is doing? Care to try turning one of them into a function?


In the mean time, let me introduce you to the 'else if' statement. It
will help make the main body of your code easier to read. Like this:

if (buffer == "")
{
outfile << " " << endl;
}
else if (buffer.substr(1,7) == "include")
{
string bestand = buffer.substr(9, (buffer.find_first_of("}") - 9));
bestand += ".tex";
insertFile( outfile, bestand );
}
else
{
outfile << buffer << endl;
}

See how this removes some of the odd nesting you had, without changing
the meaning of the code?
 
P

Pieter Provoost

Daniel T. said:
Yes I definately think it's a good change.

You may be wondering at this point, why I picked that particular block
of code to extract into a seperate function. First, I noticed that there
were two variables that were only being used in that particular block of
code and not being used anywhere else in the program (includefile, and
includebuffer.) Second, when I asked you what that block of code did,
you were able to explain it with a simple phrase, one that translated
well into a function name.

Do you see any blocks of code where one or two variables are only being
used in that block and nowhere else? What would you say each block of
code is doing? Care to try turning one of them into a function?


In the mean time, let me introduce you to the 'else if' statement. It
will help make the main body of your code easier to read. Like this:

if (buffer == "")
{
outfile << " " << endl;
}
else if (buffer.substr(1,7) == "include")
{
string bestand = buffer.substr(9, (buffer.find_first_of("}") - 9));
bestand += ".tex";
insertFile( outfile, bestand );
}
else
{
outfile << buffer << endl;
}

See how this removes some of the odd nesting you had, without changing
the meaning of the code?[/QUOTE]


Ok, I made a new function (called bestand) that constructs the filename from
the line that contains "include". Maybe I should make a function that reads
all the lines of the configfile to an array? If I choose to add more
configuration parameters to the program later, I won't have to change that
part... Another question: do I really need the "const" before "string&"?

Thank you very much!




#include <string>
#include <fstream>
using namespace std;

void insertfile(ostream& os, const string& filename)
{
ifstream includefile(filename.c_str());
string includebuffer;
while (getline(includefile, includebuffer))
os << includebuffer << endl;
}

string bestand(const string& bufferline)
{
string firstpart = bufferline.substr(9, (bufferline.find_first_of("}") -
9));
firstpart += ".tex";
return firstpart;
}

int main()
{
string buffer;
string configin;
string configout;

ifstream config("config.txt");
getline(config, configin);
getline(config, configout);
config.close();

ifstream infile(configin.c_str());
ofstream outfile(configout.c_str());

while (getline(infile, buffer))
{
if (buffer == "")
{
outfile << " " << endl;
}
else if (buffer.substr(1,7) == "include")
{
insertfile(outfile, bestand(buffer));
}
else
{
outfile << buffer << endl;
}
}


infile.close();
outfile.close();
return 0;
}
 
P

Pieter Provoost

Maybe I should make a function that reads
all the lines of the configfile to an array? If I choose to add more
configuration parameters to the program later, I won't have to change that
part...

This probably is a stupid question, but can I something like this?

string filetoarray[]("textfile.txt")
{
string arraywithlines[];
// some code
return arraywithlines[];
}
 
D

Daniel T.

Pieter Provoost said:
Ok, I made a new function (called bestand) that constructs the filename from
the line that contains "include". Maybe I should make a function that reads
all the lines of the configfile to an array? If I choose to add more
configuration parameters to the program later, I won't have to change that
part... Another question: do I really need the "const" before "string&"?

I suggest either "const string&" or "string". Just putting "string&"
should only be used if you want the function to modify the argument
passed in instead of (or as well as) returning information.

string bestand(const string& bufferline)
{
string firstpart = bufferline.substr(9, (bufferline.find_first_of("}") -
9));
firstpart += ".tex";
return firstpart;
}

What does "bestand" mean? Maybe we can come up with a better name here?
Can you think of other contexts where this function would be useful?
ifstream config("config.txt");
getline(config, configin);
getline(config, configout);
config.close();

What does the above block of code do?

ifstream infile(configin.c_str());
ofstream outfile(configout.c_str());

while (getline(infile, buffer))
{
if (buffer == "")
{
outfile << " " << endl;
}
else if (buffer.substr(1,7) == "include")
{
insertfile(outfile, bestand(buffer));
}
else
{
outfile << buffer << endl;
}
}

Tell me if this statement describes the above block of code. "copy
infile to outfile until a "include" line is reached, insert the named
file at that point in the outfile, then continue copying as above." If
it does, can you think of another algorithm to do it?
 
P

Pieter Provoost

Daniel T. said:
I suggest either "const string&" or "string". Just putting "string&"
should only be used if you want the function to modify the argument
passed in instead of (or as well as) returning information.



What does "bestand" mean? Maybe we can come up with a better name here?
Can you think of other contexts where this function would be useful?

"bestand" means file (in dutch). Well, to be honest, I can't think of other
context where I can use this function. So I guess its better to leave it in
main() after all. Do you agree on that?

What does the above block of code do?

It reads the two first lines of config.txt to variables. They could have
been command line arguments but I prefer not to use the command line here.
Do you think it's useful to make a function that reads all the lines of the
configfile to an array? That's something I can definately use in other
contexts. Something like this maybe?

string filetoarray[]("textfile.txt")
{
string arraywithlines[];
// some code
return arraywithlines[];
}

Tell me if this statement describes the above block of code. "copy
infile to outfile until a "include" line is reached, insert the named
file at that point in the outfile, then continue copying as above." If
it does, can you think of another algorithm to do it?

Your description is correct, and I think this algorithm is the most
efficient way to do it.

Thank you!
 
D

Daniel T.

string bestand(const string& bufferline)
"bestand" means file (in dutch). Well, to be honest, I can't think of other
context where I can use this function. So I guess its better to leave it in
main() after all. Do you agree on that?

Personally, I would leave it in. Pulling it out doesn't make main any
simpler, and as you say it doesn't seem very reusable. However, I
wouldn't have a problem with it being a seperate function as long as we
can come up with a better name for it than simply "file" (in any
language.)

What does the above block of code do?

It reads the two first lines of config.txt to variables. They could have
been command line arguments but I prefer not to use the command line here.
Do you think it's useful to make a function that reads all the lines of the
configfile to an array? That's something I can definately use in other
contexts. Something like this maybe?

string filetoarray[]("textfile.txt")
{
string arraywithlines[];
// some code
return arraywithlines[];
}

To do that, I would write something more like:

void getConfigInfo( vector<string>& data, const string& fileName ) {
// fill data with info from the file
}

and call it like this:

vector<string> configData;
getConfigInfo( configData, "config.txt" );

Your description is correct, and I think this algorithm is the most
efficient way to do it.

What if we could translate the text description direclty into code?

while ( infile ) {
copyFileUntil( infile, outfile, "\\include{" );
string fileName = extractFileName( infile );
if ( fileName != "" )
insertFile( outfile, fileName );
}

What do you think of this as a main?
 
P

Pieter Provoost

Daniel T. said:
What if we could translate the text description direclty into code?

while ( infile ) {
copyFileUntil( infile, outfile, "\\include{" );
string fileName = extractFileName( infile );
if ( fileName != "" )
insertFile( outfile, fileName );
}

What do you think of this as a main?

For me as a starter it is very complicated. It's not really clear to me what
"while(infile)" does. How does "extractfilename" know where "copyfileuntil"
stopped processing the file? What exactly is passed to "extractfilename" and
what would that function look like? It's quite confusing...

Does this algorithm have any advantages over the old version?

Thank you very much!
Pieter
 
D

Daniel T.

Pieter Provoost said:
For me as a starter it is very complicated. It's not really clear to me what
"while(infile)" does.

Sorry, it is shorthand for "while( !infile.fail() )" IE as long as the
next operation will succeed, keep working on the stream.

How does "extractfilename" know where "copyfileuntil"
stopped processing the file?

'extractFileName' doesn't know where copyFileUntil stopped processing,
it doesn't know anything about copyFileUntil at all. All extractFileName
knows is that it should pull the file name out of the stream. To do
this, it must know that '}' represents the end of the file name.

What exactly is passed to "extractfilename" and
what would that function look like? It's quite confusing...

Let's set up a test to demonstrate:

string extractFileName( istream& st );

void testExtractFileName() {
// first, create a stream with some data in it
// we do this because we don't want to have to make a special
// file to test with
stringstream ss;
ss << "myFile}\nrest";
// the above code also shows us what extractFileName expects
// ie what assumptions it makes about the stream. Namely that
// the name of the file is next in the stream and ends with "}\n"
string result = extractFileName( ss );
assert( result == "myFile.tex" );
// in the above, we run the function and then check the result
// we know what we want, and the assert automatically checks it.
string rest;
ss >> rest;
assert( rest == "rest" );
// the above code shows that the "}\n" was removed properly
// leaving the 'rest' of the stream intact.
}

Note, I did *not* implement extractFileName, I leave that for you to do,
but the goal is for you to be able to execute the test function and have
it return without either of the asserts firing... (You might notice that
extractFileName does much the same thing that your 'bestand' function
does.

Does this algorithm have any advantages over the old version?

Not if you find it harder to understand. However I chose the algorithm
because I felt it more directly did what it was we want to do: namely
"copy infile to outfile until a "include" line is reached, insert the
named file at that point in the outfile, then continue copying as above."

The code I wrote literally copies the infile to the outfile until an
include line is reached (that's the job of copyFileUntil,) then extracts
the named file (thats what extractFileName does,) and inserts that file
into the outfile (the job of insertFile.) Then it loops back around and
continues.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,161
Latest member
GertrudeMa
Top