Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
I'm trying to write a function that reads several numbers from a file (it interprets them as powers of X and coefficients and stores them in an array that represents a polynomial.)

Anyways, I want it to skip over lines that start with a '/' character, to provide a mechanism of including comments in the file. Here's the code:

Oh, and a quick note.

POWER and COEFFICIENT are enum as 0 and 1, respectively. MAX_SIZE is #define as 32767 (fairly arbitrary value.)

Code:
		// Read the file.
		int reading = POWER;
		int Xpower = 0;
		long double Xcoefficients[MAX_SIZE] = { 0.0 };
		long double diffTerm = 0.0;
		long double mostNegDiffTerm = 0.0, mostPosDiffTerm = 0.0;
		
		for (int i = 0; i < (MAX_SIZE*2); i++)
		{
			#ifdef NDEBUG
			[b]cout << "Running..." << endl;[/b]
			#endif
			[b]if (file.peek() == '/')[/b]
			{
				#ifdef NDEBUG
				[b]cout << "Ignoring..." << endl;[/b]
				#endif
				[b]file.ignore(MAX_SIZE, '\n');
				file.clear(); // I've tried both with and without this line - behavior does not change.[/b]
			}
			
			switch (reading)
			{
				case COEFFICIENT:
					file >> Xcoefficients[Xpower];
					diffTerm = Xcoefficients[Xpower]*Xpower;
					mostNegDiffTerm = (diffTerm<mostNegDiffTerm)?diffTerm:mostNegDiffTerm;
					mostPosDiffTerm = (diffTerm>mostPosDiffTerm)?diffTerm:mostPosDiffTerm;
					reading = POWER;
					break;
				case POWER: default:
					file >> Xpower;
					polyDegree = (Xpower>polyDegree)?Xpower:polyDegree;
					reading = COEFFICIENT;
					break;
			}
			
			[b]if (file.peek() == EOF)[/b]
			{
				#ifdef NDEBUG
				[b]cout << "Reached EOF" << endl;[/b]
				#endif
				break;
			}
		}

This works perfectly for files with only one comment line, for example, this file:

Code:
// polynomial f(x) = 2.5x^3 + 3x^2 - 2.13x + 1

1  -2.13
0  1
2  3.0
3  2.5

The output for the above file is this:
Code:
Running...
Ignoring...
Running...
Running...
Running...
Running...
Running...
Running...
Running...
Running...
Reached EOF

However, if a file includes multiple comments in it, like this one:
Code:
// polynomial f(x) = 2.5x^3 + 3x^2 - 2.13x + 1

1  -2.13
0  1
//4	26
2  3.0
3  2.5

My output should look exactly the same, but instead I get this:
Code:
Running...
Ignoring...
Running...
Running...
Running...
Running...
Reached EOF

It doesn't print out that it has ignored the second comment line... it doesn't even attempt to read the rest of the file, instead it just skips straight to the end of the file?

I've tried placing the second comment in multiple places in the file, and no matter where I put it, it always skips straight to the EOF when it reaches it, without even printing that it is ignoring a comment line.

Any suggestions on why it's doing this or how I can fix it to behave the way I want it to?
 

chown33

Moderator
Staff member
Aug 9, 2009
10,740
8,416
A sea of green
Would you mind posting the whole source? And a sample file that fails?

I agree with this. Please include the exact data file that causes it to fail.

When I see this:
Code:
file.ignore(MAX_SIZE, '\n');
my first thought is, "What if the file doesn't contain another \n?". Depending on where the file came from, or how it was last edited, it's possible there are only CRs (\r's) remaining in the file, even though it appears to have multiple remaining lines when edited. Many Mac text editors will accept single CRs, single LFs, or CRLF pairs as line-endings, without regard to what line-endings came before. Programming editors in particular will do this. Many of them have a way to normalize line-endings, or convert all lines to a specific form.

I suggest looking at the failing file in a hex editor. Something like Hex Fiend (google it), or this command-line:
Code:
hexdump -C failing-file.txt
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
Silly questions -

Is this your own file format?
If so why the power first and then the coefficient?
Why not put everything on a single line instead of spreading it out over four lines?

Others to follow at a later time!
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
Silly questions -

Is this your own file format?
If so why the power first and then the coefficient?
Why not put everything on a single line instead of spreading it out over four lines?

Others to follow at a later time!

It's a class assignment. We were told the files would be formatted as having a pair of numbers on each line, the power first and then the coefficient. Some lines would have comments on them, starting with "//", which should be ignored.

I'm on my iPhone right now, I'll post the files in a few hours when I have my laptop in a wifi hotspot.

Quick question... Is it possible to have multiple delaminators for the ignore command? So I could say stop ignoring at the next '/n' or next '/r', for example? I don't have control over the files that my code will be tested with, so I don't know what the line endings the files will actually have.

Edit:

I had a couple seconds between classes to try doing the hex dump, here's the hex dump for a sample file that fails (this is for poly.txt, which is attached to the post.)
Code:
00000000  2f 2f 70 6f 6c 79 20 66  28 78 29 20 3d 20 31 39  |//poly f(x) = 19|
00000010  78 5e 34 2d 33 34 78 5e  33 2b 37 36 78 5e 32 2d  |x^4-34x^3+76x^2-|
00000020  31 30 30 38 [b]0a[/b] 2f 2f 33  [b]0a[/b] 34 09 31 39 [b]0a[/b] 33 09  |1008.//3.4.19.3.|
00000030  2d 33 34 [b]0a[/b] 32 09 37 36  [b]0a[/b] 30 09 2d 31 30 30 38  |-34.2.76.0.-1008|
00000040  [b]0a[/b]                                                |.|
00000041

0a is a '\n', correct?

Here's enough of the source code that it compiles on its own:

(the args are optional. stepSize/argv[2] aren't actually used in this function... they get passed to another function unrelated to reading the file. If argv[1] isn't provided, it'll ask for it. It behaves the same way whether it asks or not.)

Code:
#include <iostream>
#include <fstream>
#include <cmath>

#define MAX_SIZE 32767

using namespace std;

static int polyDegree = 0;

typedef enum {
	POWER = 0,
	COEFFICIENT = 1
	} readingTypes;

int main(int argc, char* argv[])
{
	fstream file;
	char fileName[MAX_SIZE];
	double stepSize = 0.0005;
	
	if (argc > 1)
	{
		for (int i = 0; i < MAX_SIZE; i++)
		{
			if (i < (MAX_SIZE-1))
			{
				fileName[i] = argv[1][i];
				if (fileName[i] == '\0') break;
			}
			
			else
			{
				fileName[MAX_SIZE-1] = '\0';
				cout << "File name is too long! Truncated to: " << fileName << endl;
			}
		}
		
		if (argc == 3)
		{
			stepSize = atof(argv[2]);
		}
	}
	
	else
	{
		cout << "Enter the name of the file." << endl << "> " << endl;
		cin.getline (fileName, MAX_SIZE, '\n');
	}
	
	file.open(fileName);
	
	if (file.is_open())
	{
		// Read the file.
		int reading = POWER;
		int Xpower = 0;
		long double Xcoefficients[MAX_SIZE] = { 0.0 };
		long double diffTerm = 0.0;
		long double mostNegDiffTerm = 0.0, mostPosDiffTerm = 0.0;
		
		for (int i = 0; i < (MAX_SIZE*2); i++)
		{
			#ifdef NDEBUG
			cout << "Running..." << endl;
			#endif
			if (file.peek() == '/')
			{
				#ifdef NDEBUG
				cout << "Ignoring..." << endl;
				#endif
				file.ignore(MAX_SIZE, '\n');
				file.clear();
			}
			
			switch (reading)
			{
				case COEFFICIENT:
					file >> Xcoefficients[Xpower];
					diffTerm = Xcoefficients[Xpower]*Xpower;
					mostNegDiffTerm = (diffTerm<mostNegDiffTerm)?diffTerm:mostNegDiffTerm;
					mostPosDiffTerm = (diffTerm>mostPosDiffTerm)?diffTerm:mostPosDiffTerm;
					reading = POWER;
					break;
				case POWER: default:
					file >> Xpower;
					polyDegree = (Xpower>polyDegree)?Xpower:polyDegree;
					reading = COEFFICIENT;
					break;
			}
			
			if (file.peek() == EOF)
			{
				#ifdef NDEBUG
				cout << "Reached EOF" << endl;
				#endif
				break;
			}
		}
		
		// Print out f(x)
		cout << endl << "f(x)=";
		
		for (int i = polyDegree; i >= 0; i--)
		{
			if (!Xcoefficients[i]) continue;
			cout << showpos << Xcoefficients[i];
			switch(i)
			{
				case 1:
					cout << "x";
				case 0:
					break;
				default:
					cout << "x^" << noshowpos << i;
			}
		}
		
		cout << endl << endl;
		cout << noshowpos;
		file.close();
	}

	else
	{
		cout << "A file named \"" << fileName << "\" could not be opened." << endl;
	}
	
	return 0;
}

I've also attached three sample files.

When I test poly.txt, it doesn't read anything.

When I test polynomial.txt, it reads the first two pairs, then skips everything else.

When I test test.txt, it reads everything properly.

In polynomial.txt, if I remove the second comment, it reads everything properly.

2X Edit: I wonder if this could be remedied by moving a read pointer around or something? (I seem to recall hearing there's something called a read pointer or something like that.)
 

Attachments

  • poly.txt
    65 bytes · Views: 83
  • polynomial.txt
    83 bytes · Views: 80
  • test.txt
    58 bytes · Views: 71
Last edited:

vandersmissenc

macrumors newbie
Sep 22, 2011
25
0
Houston, TX
order of events

Upon looking at the code it seems like when you try to ignore it was only ignoring the first '/' in the row and so then when it began trying to read in it read 47 , the ascii representation of '/' and then just started reading from the wrong point. I went ahead and moved it to first check if file.peek() == EOF and if not then it checks if the character is a '/' or '\n' finally if none of those cases are met it reads in the character, the way you had it before it read a character every time instead of only in certain cases when other tests pass. Anyways, here is the working code.

Code:
#include <iostream>
#include <fstream>
#include <cmath>

#define MAX_SIZE 32767

using namespace std;

static int polyDegree = 0;

typedef enum {
	POWER = 0,
	COEFFICIENT = 1
} readingTypes;

int main(int argc, char* argv[])
{
	fstream file;
	char fileName[MAX_SIZE];
	double stepSize = 0.0005;
	
	if (argc > 1)
	{
		for (int i = 0; i < MAX_SIZE; i++)
		{
			if (i < (MAX_SIZE-1))
			{
				fileName[i] = argv[1][i];
				if (fileName[i] == '\0') break;
			}
			
			else
			{
				fileName[MAX_SIZE-1] = '\0';
				cout << "File name is too long! Truncated to: " << fileName << endl;
			}
		}
		
		if (argc == 3)
		{
			stepSize = atof(argv[2]);
		}
	}
	
	else
	{
		cout << "Enter the name of the file." << endl << "> " << endl;
		cin.getline (fileName, MAX_SIZE, '\n');
	}
	
	file.open(fileName);
	
	if (file.is_open())
	{
		// Read the file.
		int reading = POWER;
		int Xpower = 0;
		long double Xcoefficients[MAX_SIZE] = { 0.0 };
		long double diffTerm = 0.0;
		long double mostNegDiffTerm = 0.0, mostPosDiffTerm = 0.0;
		
		for (int i = 0; i < (MAX_SIZE*2); i++)
		{
#ifdef NDEBUG
			cout << "Running..." << endl;
#endif
            if (file.peek() == EOF)
			{
#ifdef NDEBUG
				cout << "Reached EOF" << endl;
#endif
				break;
			}
            
			else if (file.peek() == '/' || file.peek() == '\n')
			{
#ifdef NDEBUG
				cout << "Ignoring..." << endl;
#endif
				file.ignore(MAX_SIZE, '\n');
				file.clear();
			}
			
			else { switch (reading)
			{
				case COEFFICIENT:
					file >> Xcoefficients[Xpower];
					diffTerm = Xcoefficients[Xpower]*Xpower;
					mostNegDiffTerm = (diffTerm<mostNegDiffTerm)?diffTerm:mostNegDiffTerm;
					mostPosDiffTerm = (diffTerm>mostPosDiffTerm)?diffTerm:mostPosDiffTerm;
					reading = POWER;
					break;
				case POWER: default:
					file >> Xpower;
					polyDegree = (Xpower>polyDegree)?Xpower:polyDegree;
					reading = COEFFICIENT;
					break;
			}
			}

		}
		
		// Print out f(x)
		cout << endl << "f(x)=";
		
		for (int i = polyDegree; i >= 0; i--)
		{
			if (!Xcoefficients[i]) continue;
			cout << showpos << Xcoefficients[i];
			switch(i)
			{
				case 1:
					cout << "x";
				case 0:
					break;
				default:
					cout << "x^" << noshowpos << i;
			}
		}
		
		cout << endl << endl;
		cout << noshowpos;
		file.close();
	}
    
	else
	{
		cout << "A file named \"" << fileName << "\" could not be opened." << endl;
	}
	
	return 0;
}
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
Although I haven't verified at this point I'm assuming vandersmissenc got you up and running.

If you don't mind - what class is this for, what text are you using and how far into the text are you?
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
Upon looking at the code it seems like when you try to ignore it was only ignoring the first '/' in the row and so then when it began trying to read in it read 47 , the ascii representation of '/' and then just started reading from the wrong point. I went ahead and moved it to first check if file.peek() == EOF and if not then it checks if the character is a '/' or '\n' finally if none of those cases are met it reads in the character, the way you had it before it read a character every time instead of only in certain cases when other tests pass. Anyways, here is the working code.

I tried your code but it didn't work? Except I noticed from your code that I was able to use peek() to learn that the next character was a '\n'.

After looking at the hex dump and keeping track of where tellg() - the position of the get cursor was - all the time, I found that after it passes over a '\n', it seems to jump to -1 and report itself as being at the EOF.

Thus, I gave this a shot: seekg(int, pos) moves the cursor an int distance from pos, so I just moved forward 1 character without actually reading the line break. Somehow, that caused it to avoid reading it and mistaking a peek of the next character as being an EOF?
Code:
for (int i = 0; i < (MAX_SIZE*2); i++)
		{
			#ifdef NDEBUG
			cout << "Running... at " << file.tellg() << endl;
			#endif
			
			if (file.peek() == EOF)
			{
				#ifdef NDEBUG
				cout << "Reached EOF at " << file.tellg() << endl;
				#endif
				break;
			}
			
			[b]// Without this bit, it'll report the get cursor as being at -1 and
	 		// cause it to declare itself as at EOF. I couldn't find out why,
	 		// but just moving the get cursor one character forward avoids it.
			else if (file.peek() == '\n')
			{
				file.seekg(1, ios::cur);
			}[/b]
			
			if (file.peek() == '/')
			{
				#ifdef NDEBUG
				cout << "Ignoring... at " << file.tellg() << endl;
				#endif
				file.ignore(MAX_SIZE, '\n');
			}
			
			switch (reading)
			{
				case COEFFICIENT:
					file >> Xcoefficients[Xpower];
					diffTerm = Xcoefficients[Xpower]*Xpower;
					mostNegDiffTerm = (diffTerm<mostNegDiffTerm)?diffTerm:mostNegDiffTerm;
					mostPosDiffTerm = (diffTerm>mostPosDiffTerm)?diffTerm:mostPosDiffTerm;
					reading = POWER;
					break;
				case POWER: default:
					file >> Xpower;
					polyDegree = (Xpower>polyDegree)?Xpower:polyDegree;
					reading = COEFFICIENT;
					break;
			}
		}

And it works!
 
Last edited:

vandersmissenc

macrumors newbie
Sep 22, 2011
25
0
Houston, TX
great

I'm glad you got it working. What IDE are you using ? Perhaps thats why it did not work for you. I tried on Xcode and VS2010 and it was able to output everything properly in both using my code.

Exactly as you stated however, when I was debugging everything was set to -1 and that was what alerted me to an issue with the reading of the file.
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
I'm glad you got it working. What IDE are you using ? Perhaps thats why it did not work for you. I tried on Xcode and VS2010 and it was able to output everything properly in both using my code.

Exactly as you stated however, when I was debugging everything was set to -1 and that was what alerted me to an issue with the reading of the file.

I wrote the code in gedit and compiled it in terminal with

Code:
g++ -Wall -g -DNDEBUG HW#2.cpp -o HW#2exe

In the interest of becoming more comfortable with terminal, I use it instead of Xcode when working on school/"personal learning" assignments. (When I'm working on bigger apps that I intend to submit to the iOS or Mac OS app store, I use Xcode.)

I'm using llvm-g++ 4.2, on a computer running Mac OS X 10.7.4. I use Xcode 4.3.2 and the command line tools are installed. 64 bit intel. I can't think of any other relevant data.
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
'NDEBUG' means NO DEBUG. To me it looks like you've gotten it's usage reversed.

Once you get more familiar with 'iostream''s in their many forms reading the parameters can be much simplified.

An example follows:

Code:
/* =====================================================================================================================
 * File - main.cpp
 * ---------------------------------------------------------------------------------------------------------------------
 * <<https://forums.macrumors.com/threads/1373702/>
 * 
 * Set working directory
 *      cd ~/Desktop/MacRumors\ Forums/SimplerFileIO
 *  
 * Debug build
 *      clang++ -stdlib=libc++ -std=c++11 main.cpp
 * 
 * Release build
 *      clang++ -stdlib=libc++ -std=c++11 -DNDEBUG main.cpp
 * 
 * Run with
 *      ./a.out
 */

/* =====================================================================================================================
 * ---------------------------------------------------------------------------------------------------------------------
 */

//#define NDEBUG

#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

#include <cmath>


/* =====================================================================================================================
 * ---------------------------------------------------------------------------------------------------------------------
 */

#ifdef NDEBUG
    #define DebugString(OS, PSTR)
#else
    inline void DebugString(std::ostream& os, const char* const psz) {
        using std::endl;
        
        os << psz << endl;
    }
#endif


/* =====================================================================================================================
 * ---------------------------------------------------------------------------------------------------------------------
 */

struct param_pair_t
{
    long double     _power;
    long double     _coefficient;
};

typedef std::vector<param_pair_t>           parameters_t;
typedef std::vector<param_pair_t>::iterator parameters_itr;


/* =====================================================================================================================
 * ---------------------------------------------------------------------------------------------------------------------
 */

const std::string   strFilename("poly.txt");
const std::string   strComment("//");


/* =====================================================================================================================
 * ---------------------------------------------------------------------------------------------------------------------
 * Support Routines
 */

// --- string 'trimming'

inline std::string& ltrim(std::string& str) {
    str.erase(str.begin(), find_if(str.begin(), str.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
    return str;
}

inline std::string& rtrim(std::string& str) {
    str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), str.end());
    return str;
}

inline std::string& trim(std::string& str) {
    return ltrim(rtrim(str));
}


// --- 'sort' comparator routines

inline bool sort_ascending(const param_pair_t& lfs, const param_pair_t& rhs) {
    return (lfs._power < rhs._power);
}

inline bool sort_descending(const param_pair_t& lfs, const param_pair_t& rhs) {
    return (lfs._power > rhs._power);
}


/* =====================================================================================================================
 * ---------------------------------------------------------------------------------------------------------------------
 */

std::ostream& parameters_dump(std::ostream& os, parameters_t& parameters)
{
#if 1
    // dump contents of read 'parameters' using 'iterator'
    for ( parameters_itr itr = parameters.begin(); itr != parameters.end(); itr++ )
    {
        os << "power: " << (*itr)._power << " _coefficient: " << (*itr)._coefficient << std::endl;
    }
#else
    // dump contents of read 'parameters' using array syntax
    for ( size_t i = 0; i < parameters.size(); i++ )
    {
        os << "power: " << parameters[i]._power << " _coefficient: " << parameters[i]._coefficient << std::endl;
    }
#endif

    return os;
}


/* =====================================================================================================================
 * ---------------------------------------------------------------------------------------------------------------------
 */

int main(int argc, const char* const argv[])
{
    DebugString(std::cout , "\n\n!!!Warning debug build!!!\n");

    parameters_t    paramsDB;

    std::fstream    ifs(strFilename.c_str());
    if ( ifs.is_open() )
    {
        std::istringstream  iss;
        std::string         str;
        while ( getline(ifs, str) )
        {
            trim(str);

            if ( strComment != str.substr(0, strComment.size()) )
            {
                iss.clear();
                iss.str(str);
                
                param_pair_t   params;
                iss >> params._power;
                iss >> params._coefficient;
                if ( iss )
                {
                    paramsDB.push_back(params);
                }
            }
        }

        sort(paramsDB.begin(), paramsDB.end(), sort_descending);

        parameters_dump(std::cout, paramsDB);

        return EXIT_SUCCESS;
    }
    
    return EXIT_FAILURE;
}
 
Last edited:

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
'NDEBUG' means NO DEBUG. To me it looks like you've gotten it's usage reversed.

Why do you comment out the preprocessor lines? I thought the whole point of including #ifdef NDEBUG was so that you could easily change whether those lines were considered when you make.

So if I'd like to make with the lines, I can include -DNDEBUG, and if I don't want them, I just leave off that flag.

Regarding whether I have it backwards... I really don't know. No one else has commented on it to me yet. I copied the convention a lot of Apple's sample code seems to follow.
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
NDEBUG is used by the C/C++ assert library routines to enable or disable verbose assertion output.

<http://www.cplusplus.com/reference/clibrary/cassert/assert/>
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
So if I'd like to make with the lines, I can include -DNDEBUG, and if I don't want them, I just leave off that flag.

Your wording still makes it unclear if your saying defining NDEBUG enables extra debugging or disables it. Would you mind making your understanding more explicit?

During development the normal state is extra code not in the release build. So in building the release version one defines NDEBUG which removes debugging aides.
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,558
6,058
Your wording still makes it unclear if your saying defining NDEBUG enables extra debugging or disables it. Would you mind making your understanding more explicit?

During development the normal state is extra code not in the release build. So in building the release version one defines NDEBUG which removes debugging aides.

Interesting. I just reviewed your code and it makes some sense to me. I'll have to double check some Apple code to see if they do the same thing and I've just been misunderstanding their code (possibly overlooking "//#define NDEBUG" hidden somewhere in the code?)

Anyways, here's what I've done in the past:
- Lines that should only appear in the debug build of my app are surrounded by #ifdef NDEBUG and #endif.
- If I'd like to have a debug build of my app, I include the flag -DNDEBUG when building with g++.

- Lines that should appear in all builds of my app are not surrounded by any special preprocessor directives.
- I don't include any special flags to do the release build of my app.
 

lloyddean

macrumors 65816
May 10, 2009
1,047
19
Des Moines, WA
It's normally done as '-DNDEBUG' option to the compiler but can be useful in debugging individual modules by placing in a source file here and there.

The ONLY reason I placed it into the example code was to make others aware of it for the conditionally compiled 'DebugString'. After all it's just a bunch of code with nothing to indicate compiler options required for debug vs release.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.