Hello :)

I'm creating a license plate recognition system for my coursework at University. We need to use Binary trees, which I've done but the information needs to be stored in a file to read and write to. I've created some text files with XML tags in for Cars, Lorries, Buses and Motorbikes and I've written some of the code below, but the "File to open" bit my tutor helped me with. When I run the program, it says "File to open" and I'm not sure what I need to do? Would anyone be able to help me?

int _tmain(int argc, _TCHAR* argv[])
{
	char tags[MAX_VEHICLES];
	void * vehicles[MAX_VEHICLES];

	ifstream infile;
	if (argc >1)
	{
		//filename passed as command line argument
		//set in Project->Properties->Configuration->Debugging
		infile.open(argv[1]);
	}
	else 
	{
		string fileName;
		cout << "File to open" << endl;
		cin >> fileName;
		infile.open(fileName.c_str());
	}
	int c = 0;
	string inputLine;
	while (!infile.eof() && (c< MAX_VEHICLES))
	{
		getline(infile, inputLine);
		tags[c] = inputLine[0];
		switch (tags[c])
		{
			case 'C': vehicles[c] = buildC(inputLine); break;
			case 'B': vehicles[c] = buildB(inputLine); break;
			case 'L': vehicles[c] = buildL(inputLine); break;
			case 'M': vehicles[c] = buildM(inputLine); break;
			default: cout << "error with tag " << endl;break;
 		}
		++c;
	}

Thanks :)

Recommended Answers

All 8 Replies

while (!infile.eof() && (c< MAX_VEHICLES))
{
    getline(infile, inputLine);

This is a buggy pattern. eof() doesn't evaluate to true until after you've tried and failed to read past end-of-file, which means you'll process the last record of the file twice. The worst part is that the correct pattern is shorter and easier to understand:

while (c < MAX_VEHICLES && getline(infile, inputLine))
{

When I run the program, it says "File to open" and I'm not sure what I need to do?

I'd guess you should type the name of a file. Your question is vague, and I don't see any binary trees in the code, which suggests that they're hiding in the build* functions. Could you be more specific as to exactly what kind of difficulty you're having?

Yes, sorry! All of the code is below. When I run the program it says "File to open", I've tried typing in files I've made e.g "Cars.txt", or just "Cars", I've tried entering existing files, but it always comes up with "error with tag", so what do I need to write?

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <sstream>


#include "Vehicles.h"

using namespace std;
const unsigned MAX_VEHICLES = 10; 

//4 routines to create & populate various aircraft from csv string
CarC* buildC(string dataLine);
BusB* buildB(string dataLine);
LorryL* buildL(string dataLine);
MotorbikeM* buildM(string dataLine);

//4 routines to display various aircraft on std::cout
void displayC(CarC* cPtr);
void displayB(BusB* bPtr);
void displayL(LorryL* lPtr);
void displayM(MotorbikeM* mPtr);


string extractLastString(string & st);
int extractLastInt(string & st);

int _tmain(int argc, _TCHAR* argv[])
{
	char tags[MAX_VEHICLES];
	void * vehicles[MAX_VEHICLES];

	ifstream infile;
	if (argc >1)
	{
		//filename passed as command line argument
		//set in Project->Properties->Configuration->Debugging
		infile.open(argv[1]);
	}
	else 
	{
		string fileName;
		cout << "File to open" << endl;
		cin >> fileName;
		infile.open(fileName.c_str());
	}
	int c = 0;
	string inputLine;
	while (!infile.eof() && (c< MAX_VEHICLES))
	{
		getline(infile, inputLine);
		tags[c] = inputLine[0];
		switch (tags[c])
		{
			case 'C': vehicles[c] = buildC(inputLine); break;
			case 'B': vehicles[c] = buildB(inputLine); break;
			case 'L': vehicles[c] = buildL(inputLine); break;
			case 'M': vehicles[c] = buildM(inputLine); break;
			default: cout << "error with tag " << endl;break;
 		}
		++c;
	}
	unsigned numVehicles = c;
	for (int i=0; i<numVehicles; ++i)
	{
		switch (tags[i])
		{
			case 'C': displayC((CarC*) vehicles[i]); break;
			case 'B': displayB((BusB*) vehicles[i]); break;
			case 'L': displayL((LorryL*) vehicles[i]); break;
			case 'M': displayM((MotorbikeM*) vehicles[i]); break;
			default: cout << "error with tag " << endl;break;
 		}
	}
	return 0;
}

void displayC(CarC* cPtr)
{
	cout << "Car: " <<  cPtr->carRegistration << endl;
	cout << "Owner: " << cPtr->carOwner << endl;
	cout << "Address: " << cPtr->ownerAddress << endl;
	cout << "Manufacturer: " << cPtr->carManufacturer << endl;
	cout << "Model: " << cPtr->carModel << endl;
	cout << "Number of Doors: " << cPtr->numCarDoors << endl;
	cout << "Number of Seats: " << cPtr->numCarSeats << endl;
	cout << "Car Type: " << cPtr->carType << endl;
	cout << "Other Information: " << cPtr->carInformation << endl;
}


void displayB(BusB* bPtr)
{
	cout << "Bus: " <<  bPtr->busRegistration << endl;
	cout << "Owner: " << bPtr->busOwner << endl;
	cout << "Address: " << bPtr->ownerAddress << endl;
	cout << "Manufacturer: " << bPtr->busManufacturer << endl;
	cout << "Model: " << bPtr->busModel << endl;
	cout << "Colour: " << bPtr->busColour << endl;
	cout << "Number of Axles: " << bPtr->numBusAxles << endl;
	cout << "Number of Passengers: " << bPtr->numBusPassengers << endl;
	cout << "Bus Body Type: " << bPtr->busBodyType << endl;
	cout << "Other Information: " << bPtr->busInformation << endl;
}

void displayL(LorryL* lPtr)
{
	cout << "Lorry: " <<  lPtr->lorryRegistration << endl;
	cout << "Owner: " << lPtr->lorryOwner << endl;
	cout << "Address: " << lPtr->ownerAddress << endl;
	cout << "Manufacturer: " << lPtr->lorryManufacturer << endl;
	cout << "Model: " << lPtr->lorryModel << endl;
	cout << "Colour: " << lPtr->lorryColour << endl;
	cout << "Number of Axles: " << lPtr->numLorryAxels << endl;
	cout << "Bus Body Type: " << lPtr->lorryBodyType << endl;
	cout << "Other Information: " << lPtr->lorryInformation << endl;
}

void displayM(MotorbikeM* mPtr)
{
	cout << "Motorbike: " <<  mPtr->motorbikeRegistration << endl;
	cout << "Owner: " << mPtr->motorbikeOwner << endl;
	cout << "Address: " << mPtr->ownerAddress << endl;
	cout << "Manufacturer: " << mPtr->motorbikeManufacturer << endl;
	cout << "Model: " << mPtr->motorbikeModel << endl;
	cout << "Colour: " << mPtr->motorbikeColour << endl;
	cout << "Side Car: " << mPtr->motorbikeSideCar << endl;
	cout << "Other Information: " << mPtr->motorbikeInformation << endl;
}



CarC* buildC(string dataLine)
{
	//extract values from csv line & populate helicopter struct
	//csv line consumed from the right
	CarC* ptr = new CarC;
	ptr->carInformation = extractLastString(dataLine);
	ptr->carType = extractLastString(dataLine);
	ptr->numCarSeats = extractLastInt(dataLine);
	ptr->numCarDoors = extractLastInt(dataLine);
	ptr->carModel = extractLastString(dataLine);
	ptr->carManufacturer = extractLastString(dataLine);
	ptr->ownerAddress = extractLastString(dataLine);
	ptr->carOwner = extractLastString(dataLine);
	ptr->carRegistration = extractLastString(dataLine);

	return ptr;
}

BusB* buildB(string dataLine)
{
	//extract values from csv line & populate helicopter struct
	//csv line consumed from the right
	BusB* ptr = new BusB;
	ptr->busInformation = extractLastString(dataLine);
	ptr->busBodyType = extractLastString(dataLine);
	ptr->numBusPassengers = extractLastInt(dataLine);
	ptr->numBusAxles = extractLastInt(dataLine);
	ptr->busColour = extractLastString(dataLine);
	ptr->busModel = extractLastString(dataLine);
	ptr->busManufacturer = extractLastString(dataLine);
	ptr->ownerAddress = extractLastString(dataLine);
	ptr->busOwner = extractLastString(dataLine);
	ptr->busRegistration = extractLastString(dataLine);

	return ptr;
}

LorryL* buildL(string dataLine)
{
	//extract values from csv line & populate helicopter struct
	//csv line consumed from the right
	LorryL* ptr = new LorryL;
	ptr->lorryInformation = extractLastString(dataLine);
	ptr->lorryBodyType = extractLastString(dataLine);
	ptr->numLorryAxels = extractLastInt(dataLine);
	ptr->lorryColour = extractLastString(dataLine);
	ptr->lorryModel = extractLastString(dataLine);
	ptr->lorryManufacturer = extractLastString(dataLine);
	ptr->ownerAddress = extractLastString(dataLine);
	ptr->lorryOwner = extractLastString(dataLine);
	ptr->lorryRegistration = extractLastString(dataLine);

	return ptr;
}

MotorbikeM* buildM(string dataLine)
{
	//extract values from csv line & populate helicopter struct
	//csv line consumed from the right
	MotorbikeM* ptr = new MotorbikeM;
	ptr->motorbikeInformation = extractLastString(dataLine);
	ptr->motorbikeSideCar = extractLastString(dataLine);
	ptr->motorbikeColour = extractLastString(dataLine);
	ptr->motorbikeModel = extractLastString(dataLine);
	ptr->motorbikeManufacturer = extractLastString(dataLine);
	ptr->ownerAddress = extractLastString(dataLine);
	ptr->motorbikeOwner = extractLastString(dataLine);
	ptr->motorbikeRegistration = extractLastString(dataLine);

	return ptr;
}

string extractLastString(string & st)
{
	unsigned posLastComma = st.find_last_of(",");	//find last ',' in string
	string result = st.substr(posLastComma+1);		//extract && save everything after the last ,
	st = st.substr(0,posLastComma);					//remove chars from last , including ,
	return result;									//return extracted substring
}
int extractLastInt(string & st)
{
	string numAsString = extractLastString(st);		//extract number as string
	istringstream iss(numAsString);					//research input stringstreams
	int result;
	iss >> result;
	return result;
}

Post a sample of your input file, please.

This is the header file;

#include <string>

using std::string;

struct CarC
{
	string carRegistration;
	string carOwner;
	string ownerAddress;
	string carManufacturer;
	string carModel;
	unsigned numCarDoors;
	unsigned numCarSeats;
	string carType;
	string carInformation;
};

struct BusB
{
	string busRegistration;
	string busOwner;
	string ownerAddress;
	string busManufacturer;
	string busModel;
	string busColour;
	unsigned numBusAxles;
	unsigned numBusPassengers;
	string busBodyType;
	string busInformation;
	
};

struct LorryL
{
	string lorryRegistration;
	string lorryOwner;
	string ownerAddress;
	string lorryManufacturer;
	string lorryModel;
	string lorryColour;
	unsigned numLorryAxels;
	string lorryBodyType;
	string lorryInformation;
};

struct MotorbikeM
{
	string motorbikeRegistration;
	string motorbikeOwner;
	string ownerAddress;
	string motorbikeManufacturer;
	string motorbikeModel;
	string motorbikeColour;
	string motorbikeSideCar;
	string motorbikeInformation;
};

and I created this to put the information in;

<?xml version="1.0" encoding="utf-8"?>
<Car>
  <carRegistration></carRegistration>
  <carOwner></carOwner>
  <ownerAddress></ownerAddress>
  <carManufacturer></carManufacturer>
  <carModel></carModel>
  <carColour></carColour>
  <numCarDoors></numCarDoors>
  <numCarSeats></numCarSeats>
  <carType></carType>
  <carInformation></carInformation>
</Car>

Is that what you mean?

Let me see if I understand. You're opening an XML file and reading it as if it were a flat file, but the XML doesn't magically reformat itself to suit your naive parsing algorithm? What a shock. :icon_rolleyes:

See I'm confused! What do I need to do?

What do I need to do?

Well, you could try to parse the XML either manually or with a library, but I suspect that both of those options are going to be somewhat overwhelming for you at this stage. A better option would be to use a different file format, if you have control over it. For example:

C|<registration>|<owner>|<address>|<manufacturer>|<model>|<color>|<doors>|<seats>|<type>|info
B|<registration>|<owner>|<address>|<manufacturer>|<model>|<color>|<axles>|<passengers>|<body>|<info>
L|<registration>|<owner>|<address>|<manufacturer>|<model>|<color>|<axles>|<body>|<info>
M|<registration>|<owner>|<address>|<manufacturer>|<model>|<color>|<sidecar>|<info>

The stuff in angle brackets would be replaced with actual data. I like to use pipes for delimiters because they're rarely in the data, which makes parsing simpler. This is compared to formats like CSV where embedded commas introduce troublesome quoting rules.

This is really helpful! Thanks :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.