-
Help!!!!!!!!
My program compiles perfectly, but I can't get it to work. I'm kind of new at C++ so it's very possible that I'm overlooking something.
Here's my program and a segment from the input file is after the program:
// necessary library header files:
#include<iostream.h>
#include<fstream.h>
#include<iomanip.h>
#include<string.h>
// global user-defined types:
struct Storm {
int beginDate;
int duration;
char name[15];
int category;
int wind;
int pressure;
};
// function prototypes:
int GetRecord( ifstream &input, int &y,int &m, int &d, int &h,
int &s, char name[], int &wind, int &pres);
Storm* GetStorm( ifstream& input );
int SaffirSimpson( int w );
void Sort( Storm* List[], int NStorms );
void DisplayStorms( const char* title, Storm* List[], int NStorms );
void PrintStorm( Storm* StormPointer );
// Constants
const int MAX_STORMS = 200;
const float KnotsToMPH = 1.15;
int main( void ) {
Storm* List[MAX_STORMS];
Storm* CurrentStorm; // storm returned by GetStorm
int NStorms = 0; // number in aray List
int Total = 0; // total number of storms in the input file
// replace with interactive version
ifstream input("HurricaneTestFile.Data");
// while we have storms to process
while( (CurrentStorm = GetStorm( input ) ) != NULL ) {
++Total;
if( CurrentStorm->category < 3 )
delete CurrentStorm;
else
List[NStorms++] = CurrentStorm;
}
input.close();
cout << "Number of storms: " << Total << endl;
cout << "Hurricanes with category 3 and above: " << NStorms << endl;
DisplayStorms("First Ten Storms", List, 10 );
Sort( List, NStorms);
DisplayStorms("Top Ten Storms", List, 10 );
}
int GetRecord( ifstream &in, int &year, int &month, int &day, int &hour,
int &seq, char name[], int &wind, int &pres ) {
// reads one "record" from the input, and stores in reference arguments
// returns 0 if end-of-file, 1 if record read
float junk;
if (!(in.eof())) {
in >> year >> month >> day >> hour >> seq >> name
>> junk >> junk >> wind >> pres;
return 1;
}
return 0;
}
Storm* GetStorm( ifstream& in ) {
// Build a Storm structure, and return the poointer
// static is necesary to save the last record read for
// the next storm.
static int year = 0, month, day, hour, seq, wind, pressure;
static char name[15];
static status = 1;
int current, cat;
Storm* NewStorm; // we'll return this pointer to the new storm object
double mph;
// If the last storm caused end-of-file, we're done.(return NULL)
if( status == 0 )
return NULL;
// If this is the first time this function is called,
// then read first record.
if( year == 0 )
GetRecord(in, year, month, day, hour, seq, name, wind, pressure);
// Make a storm object and initialize it with info from the current record
NewStorm = new Storm;
NewStorm->beginDate = (year * 1000) + (month * 100) + day;
NewStorm->duration = hour;
strcpy(NewStorm->name, name);
NewStorm->wind = wind;
NewStorm->pressure = pressure;
current = seq;
// Now, keep reading records as long as they go with this storm.
// Watch out for end-of-file!
status = GetRecord(in, year, month, day, hour, seq, name, wind, pressure);
while((strcmp(NewStorm->name, name) == 0) && (status == 1)) {
//update storm info:
NewStorm->duration += 6;
if(NewStorm->wind < wind)
NewStorm->wind = wind;
if(((pressure < NewStorm->pressure) && pressure != 0) || NewStorm->pressure == 0 )
NewStorm->pressure = pressure;
cat = SaffirSimpson(NewStorm->wind);
if(cat > NewStorm->category)
NewStorm->category = cat;
//get next record
GetRecord(in, year, month, day, hour, seq, name, wind, pressure);
}
// convert from knots to mph
NewStorm->wind *= KnotsToMPH;
// and return the pointer to the new storm object:
return NewStorm;
}
void PrintStorm( Storm* ptr ) {
// display one storm
cout << ptr->beginDate << ptr->duration << ptr->name << ptr->category
<< ptr->wind << ptr->pressure << endl;
return;
}
void DisplayStorms( const char* title, Storm* List[], int NStorms ) {
// display NStorms storms
// print some title and column headings; make a loop
// and invoke function "PrintStorm" for each storm.
cout << "Begin Date" << setw(10) << "Duration (hours)" << "Name" << setw(10)
<< "Category" << "Maximum Winds (mph)"
<< "Minimum Pressure (mb)" << endl;
cout << "----------------------------------------------------------------" << endl;
for(int i = 0; i < NStorms; i++)
PrintStorm(*List);
return;
}
int SaffirSimpson( int wind ) {
// Compute storm category, using the Saffir-Simpson scale
int category;
if(wind > 134)
category = 5;
else if ((wind < 134) && (wind > 113))
category = 4;
else if ((wind < 113) && (wind > 96))
category = 3;
else if ((wind < 96) && (wind > 83))
category = 2;
else if ((wind < 83) && (wind > 64))
category = 1;
else if ((wind < 64) && (wind > 34))
category = 'TS';
else
category = 'TD';
return category;
}
void Sort( Storm* x[], int N ) {
// bubble sort the list of Storm pointers
int pass = 0, k, switches;
Storm* temp;
switches = 1;
while( switches ) {
switches = 0;
pass++;
for( k = 0; k < N - pass; k++ ) {
if(x[k]->category < x[k + 1]->category) {
temp = x[k];
x[k] = x[k + 1];
x[k + 1] = temp;
switches = 1;
}
}
}
return;
}
A segment of the input file:
1964 9 20 18 9 GLADYS 29.4 69.7 90 964
1964 9 21 0 9 GLADYS 29.8 69.6 90 964
1964 9 21 6 9 GLADYS 30.4 69.6 85 0
1964 9 21 12 9 GLADYS 31.1 69.8 85 980
1964 9 21 18 9 GLADYS 32.2 70.4 80 977
1964 9 22 0 9 GLADYS 33.1 71.0 80 984
-
hmmmmm
Code:
My program compiles perfectly, but I can't get it to work. I'm kind of new at C++ so it's very possible that I'm overlooking something.
Here's my program and a segment from the input file is after the program:
// necessary library header files:
#include<iostream.h>
#include<fstream.h>
#include<iomanip.h>
#include<string.h>
// global user-defined types:
struct Storm {
int beginDate;
int duration;
char name[15];
int category;
int wind;
int pressure;
};
// function prototypes:
int GetRecord( ifstream &input, int &y,int &m, int &d, int &h,
int &s, char name[], int &wind, int &pres);
Storm* GetStorm( ifstream& input );
int SaffirSimpson( int w );
void Sort( Storm* List[], int NStorms );
void DisplayStorms( const char* title, Storm* List[], int NStorms );
void PrintStorm( Storm* StormPointer );
// Constants
const int MAX_STORMS = 200;
const float KnotsToMPH = 1.15;
int main( void ) {
Storm* List[MAX_STORMS];
Storm* CurrentStorm; // storm returned by GetStorm
int NStorms = 0; // number in aray List
int Total = 0; // total number of storms in the input file
// replace with interactive version
ifstream input("HurricaneTestFile.Data");
// while we have storms to process
while( (CurrentStorm = GetStorm( input ) ) != NULL ) {
++Total;
if( CurrentStorm->category < 3 )
delete CurrentStorm;
else
List[NStorms++] = CurrentStorm;
}
input.close();
cout << "Number of storms: " << Total << endl;
cout << "Hurricanes with category 3 and above: " << NStorms << endl;
DisplayStorms("First Ten Storms", List, 10 );
Sort( List, NStorms);
DisplayStorms("Top Ten Storms", List, 10 );
}
int GetRecord( ifstream &in, int &year, int &month, int &day, int &hour,
int &seq, char name[], int &wind, int &pres ) {
// reads one "record" from the input, and stores in reference arguments
// returns 0 if end-of-file, 1 if record read
float junk;
if (!(in.eof())) {
in >> year >> month >> day >> hour >> seq >> name
>> junk >> junk >> wind >> pres;
return 1;
}
return 0;
}
Storm* GetStorm( ifstream& in ) {
// Build a Storm structure, and return the poointer
// static is necesary to save the last record read for
// the next storm.
static int year = 0, month, day, hour, seq, wind, pressure;
static char name[15];
static status = 1;
int current, cat;
Storm* NewStorm; // we'll return this pointer to the new storm object
double mph;
// If the last storm caused end-of-file, we're done.(return NULL)
if( status == 0 )
return NULL;
// If this is the first time this function is called,
// then read first record.
if( year == 0 )
GetRecord(in, year, month, day, hour, seq, name, wind, pressure);
// Make a storm object and initialize it with info from the current record
NewStorm = new Storm;
NewStorm->beginDate = (year * 1000) + (month * 100) + day;
NewStorm->duration = hour;
strcpy(NewStorm->name, name);
NewStorm->wind = wind;
NewStorm->pressure = pressure;
current = seq;
// Now, keep reading records as long as they go with this storm.
// Watch out for end-of-file!
status = GetRecord(in, year, month, day, hour, seq, name, wind, pressure);
while((strcmp(NewStorm->name, name) == 0) && (status == 1)) {
//update storm info:
NewStorm->duration += 6;
if(NewStorm->wind < wind)
NewStorm->wind = wind;
if(((pressure < NewStorm->pressure) && pressure != 0) || NewStorm->pressure == 0 )
NewStorm->pressure = pressure;
cat = SaffirSimpson(NewStorm->wind);
if(cat > NewStorm->category)
NewStorm->category = cat;
//get next record
GetRecord(in, year, month, day, hour, seq, name, wind, pressure);
}
// convert from knots to mph
NewStorm->wind *= KnotsToMPH;
// and return the pointer to the new storm object:
return NewStorm;
}
void PrintStorm( Storm* ptr ) {
// display one storm
cout << ptr->beginDate << ptr->duration << ptr->name << ptr->category
<< ptr->wind << ptr->pressure << endl;
return;
}
void DisplayStorms( const char* title, Storm* List[], int NStorms ) {
// display NStorms storms
// print some title and column headings; make a loop
// and invoke function "PrintStorm" for each storm.
cout << "Begin Date" << setw(10) << "Duration (hours)" << "Name" << setw(10)
<< "Category" << "Maximum Winds (mph)"
<< "Minimum Pressure (mb)" << endl;
cout << "----------------------------------------------------------------" << endl;
for(int i = 0; i < NStorms; i++)
PrintStorm(*List);
return;
}
int SaffirSimpson( int wind ) {
// Compute storm category, using the Saffir-Simpson scale
int category;
if(wind > 134)
category = 5;
else if ((wind < 134) && (wind > 113))
category = 4;
else if ((wind < 113) && (wind > 96))
category = 3;
else if ((wind < 96) && (wind > 83))
category = 2;
else if ((wind < 83) && (wind > 64))
category = 1;
else if ((wind < 64) && (wind > 34))
category = 'TS';
else
category = 'TD';
return category;
}
void Sort( Storm* x[], int N ) {
// bubble sort the list of Storm pointers
int pass = 0, k, switches;
Storm* temp;
switches = 1;
while( switches ) {
switches = 0;
pass++;
for( k = 0; k < N - pass; k++ ) {
if(x[k]->category < x[k + 1]->category) {
temp = x[k];
x[k] = x[k + 1];
x[k + 1] = temp;
switches = 1;
}
}
}
return;
}
A segment of the input file:
1964 9 20 18 9 GLADYS 29.4 69.7 90 964
1964 9 21 0 9 GLADYS 29.8 69.6 90 964
1964 9 21 6 9 GLADYS 30.4 69.6 85 0
1964 9 21 12 9 GLADYS 31.1 69.8 85 980
1964 9 21 18 9 GLADYS 32.2 70.4 80 977
1964 9 22 0 9 GLADYS 33.1 71.0 80 984
Beginner hu? Not really. If you are, your definately catching on fast. That is FAR from doing math, or Hello World. If no one answers such a long question, try CodeGuru.com, they'll help you out.
-
I took look at your code, you need to do better error checking. When opening
files you should check they are opened properly.
[code[
while( (CurrentStorm = GetStorm( input ) ) != NULL
[/code]
You keep looping with out checking if NStorms is over MAX_STORMS
your *current* bug is due to this line
Code:
DisplayStorms("First Ten Storms", List, 10 );
NStorms is 0 but your passing 10 in. This causes a segfault.
and there's a second one following that one.
Sorry but it's hard to tell what the program is supposed to do so I can't help you
too much. Try to avoid the static variables in GetStorm. If you are using static
variables I think it will be more clear if you keep a static counter such as
num_calls, instead of using year for two different purposes.
-
Having code that compiles but doesn't run or produces unexpected results is par for the course in learning how to write programs. The resultant debugging process is a good learning experience. A common saying is that writing the code is 10% of the work but debugging is 90% of the code. You can minimize the chances of having unrunnable code by trying to break down you code into smaller fragments and make sure each additional fragment does what you think before moving on. If you are not familiar with the debugger that (probably) came with your compiler I recommend you learn how to use it, too.
Overwriting arrays or initiating an endless loop is a common cause for code that compiles but doesn't "run". If there is no obvious evidence for that, then there is nothing like taking it line by line to work out the quirks.
OFten I find that restating the goal of the project is important to understand where things went wrong. Looking at your code it appears that you want to create a summary of data contained in a file. The file data contains all the baseline information, some of which is used straight up, some of which needs to be manipulated, and some of which needs to be ignored. The information is about storms. The information is stored as a given assessment of a given storm all on one line, which you call a record. There may be more than one record per storm, in which case it is a follow up evaluation 6 hours after the previous evaluation. The data fields in the file are not of fixed length, but are in fixed order and a space delimited.
The summary is to contain information about how many unique storms are evaluated in the file. You will store only those storms whose severity is greater than 2 (category 3 or above) in a array of up to 200 storms which will then serve as a source for printout of the most severe storms (up to the top ten) and (up to) the first 10 severe storms found in the file in sequence of being found. The summary will indicate how many of the storms found are saved in the array. The array will actually be an array of pointers to the storms, and the storms will be stored on the free store using the new operator.
You intend to use streams to handle the file and the >> to extract the data and place it (eventually) into appropriate data members of a struct called Storm. The names of the storms in the file will be unique. You intend to pull the data for a given record out of the file, and compare the name of the record to the name of a unique storm. If they are the same, update data in the unique form such that after all data for a given storm is reviewed the maximum category, maximum wind, minimal pressure values, and totla duration will be saved for the summary. If the names are different, then assume all data regarding the unique storm have been reviewed and pass it on for further processing. passing the current record into the uniques storm location. If there is no unique storm available it is because there are no records in the file or this is the first record read in. If there is not further record in the file then the unique storm remaining in the data gathering module should be forwarded for further processing.
Processing done outside the primary data gathering module includes evaluating the maximal category for each unique storm to decide whether to save it or not.
Once all unique storms have be reviewed and saved or discarded, the first ten (or fewer if such is the case) will be printed out in sequence. Then the array will be sorted based on severity category, and printed out in sequence of worst severity to least severe with 10 maximal, fewer if appropriate, storms being printed out. The print outs will include date of onset, duration, name, category, wind, and pressure in that order.
It looks like you try to change the file data regarding date into a single variable called beginDate of type int. If you try to use year *10000 + month * 100 + day so you get something like this: 19640551 it is difficult to read, and will be way out of bounds for a routine int (which is actually type short), although it should be ok as type long. A alternate way to handle dates is to use a struct to hold the information regarding year, month, date, and then manipulate the entire struct or one of the data member(s) of the struct as needed if you want/need, for example, to sort by date or whatever.
For functions with return type void do not use a return; statement. Leave return out of it completely.
Try to keep your conditionals as straightforward as possible:
while( (CurrentStorm = GetStorm( input ) ) != NULL )
is not in that category.
In your print fucntion remember to put appropriate spacing to match your column title spacing.
If you rearrange the flow of your program you can get by without use of static variables. Try declaring two variables of type Storm to hold data as it is read in. One could be currentStorm which holds the data as it is read out. The other could be uniqueStorm, which is assigned values only when a new storm name is encountered. Loop through the file comparing currentStorm to uniqueStorm, updating maneuvering etc. Only if values in uiniqueStorm are going to be stored in the array do you need to put values in a variable of type Storm declared on the free store.
It's probably a typo, but the fucntion definition for GetRecord() is located in main(), which is a no-no.
struct Date
{
int year;
int month;
int day;
};
struct Storm
{
Date beginDate;
//etc;
};
void AnalyzeStorm(Storm, Storm *[], int &);
//other functions to manipulate data read in
intmain()
{
int numberOfRecords = 0;
int numberOfUniqueStorms = 0;
int NStorms = 0;
float junk;
char blank[] = " ";
Storm currentStorm;
Storm uniqueStorm;
Storm * savedStorm[200];
uniqueStorm.duration = 0;
strcpy(uniqueStorm.name, blank);
uniqueStorm.wind = 0;
uniqueStorm.pressure = 30000;
ifstream input(//whatever);
input >> currentStorm.beginDate.year;
while(!fin.eof())
{
input >> currentStorm.beginDate.month;
//etc. to read in other data
input >> currentStorm.pressure;
numberOfRecords++;
if uniqueStorm.name is blank
then store values of currentStorm in uniqueStorm
else if uniqueStorm.name is not blank
if uniqueStorm.name is same as currentStorm.name
then update uniqueStorm data as appropriate.
else if uniqueStorm.name not same as currentStorm.name
uniqueStorm++ and
AnalyzeStorm(uniqueStorm, savedStorms, NStorms) and
assign values of currentStorm to uniqueStorm
input >> currentStorm.beginDate.year;
}
//Now run reports
cout << numberOfRecords << ' ' << numberOfUniqueStorms << ' ' << NStorms << endl;
if NStorms < 10
then display NStorms number of storms in savedStorms using loop
else display just first 10 storms.
Sort Storms based on appropriate criteria
Repeat display process.
use loop to delete NStorm number of pointers in savedStorms;
return 0;
}
//////////////////////////////////////////////////////////////
void AnalyzeStorms(Storm UniqueStorm, Storm * savedStorms[], int & NStorms)
{
if UniqueStorm.category > 2
then declare a Storm pointer, newStorm, on free store with new operator and
transfer data from uniqueStorm to the Storm pointed to by
newStorm and
store newStorm at savedStorms[NStorms++]
}
/////////////////////////////////////////////////
//function definitions for funcitons to manipulate data
int SaffirSimpson( int wind ) {
// Compute storm category, using the Saffir-Simpson scale
int category;
if(wind > 134)
category = 5;
else if ((wind < 134) && (wind > 113))
category = 4;
else if ((wind < 113) && (wind > 96))
category = 3;
/*
//the rest of this isn't necessary. anything less than category 3
//will not be saved for display or further use anyway so just
//return a category 2 and don't worry about how to return a
//category 4 (which is an int) vs a category 'TS' (whcih is a string,
//and not ever a char as typed
else if ((wind < 96) && (wind > 83))
category = 2;
else if ((wind < 83) && (wind > 64))
category = 1;
else if ((wind < 64) && (wind > 34))
category = 'TS';
else
category = 'TD';
*/
else category = 2;
return category;
}
Enough rambling for now.
Hi oh Silver! Away!