Two classes: ISBN is 4 strings...... full string, and its segmented parts (area, publisher, title). ISBNPrefix is basically a FILE pointer to a txt file that has a list of acceptable area codes and the publisher ranges for each area code. My problem: I'm getting a segmentation fault on the ISBNPrefix destructor (which basically closes the file). I'm guessing the file pointer goes out of scope but I can't figure out where.
My test main file:
#include <new>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define PREFIX "prefixRanges.txt" // file of ISBN Prefix Ranges
#include "ISBNPrefix.h"
#include "ISBN.h"
int main()
{
ISBNPrefix list(PREFIX);
ISBN sample("0003194876", list);
//sample.testdisplay();
cout << "Signing Off....." << endl;
return 0;
}
what this file does is creates a new ISBNPrefix (basically a file pointer), a new ISBN (with an ISBN input and the ISBNPrefix instance to compare it to to make sure it's valid and separate the string into the three area, publisher, and title strings). The testdisplay() method works fine, ISBN sample constructs A-OK. The empty destructor for ISBNPrefix is automatically called.
Header files:
class ISBNPrefix{
FILE* fp;
public:
ISBNPrefix(const char* filename);
bool isRegistered(int area) const;
int minNoDigits(int area) const;
bool isRegistered(int area, const char* publisher) const;
~ISBNPrefix();
};
Methods are: constructor (open the file for read only);
isRegistered(int area) - is the area registered;
minNoDigits - based on the area, minimum num of digits the publisher can be;
isRegistered(int, const char*) - is the publisher registered based on the given area
~ISBNPrefix() - destructor (closes file)
class ISBNPrefix;
class ISBN
{
char strisbn[11];
char area[6];
char publisher[8];
char title[7];
bool isRegistered(const ISBNPrefix&);
public:
ISBN();
ISBN(const char*, const ISBNPrefix&);
};
int isValid(const char*);
Methods are:
private isRegistered - takes the instance strisbn and separates it into area, publisher, and title if it's registered. This is called by the non-empty constructor and itself calls many of the ISBNPrefix methods.
Empty constructor - set all strings at [0] to '\0'
Constructor - set ISBN, check if it's valid and registered against the list provided as second argument, otherwise does same thing as empty constructor.
isValid - accepts a string and returns if it's in proper ISBN format.
Btw, an Area can be up to 5 characters, a publisher up to 7 characters, and a title up to 6 characters. A full ISBN is always 10 characters..... the segfault is not from too many characters in the array. I think.
ISBNPrefix definition file:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#include "ISBNPrefix.h"
ISBNPrefix::ISBNPrefix(const char* filename)
{
fp = NULL;
fp=fopen(filename, "r");
if (fp == NULL)
cout << "Invalid file!" << endl;
}
// Function checks if the area passed is in the prefix list
bool ISBNPrefix::isRegistered(int area) const
{
bool check=false;
if (fp != NULL)
{
char area2[6]; // read file line into this array
int i, j, k, val; // check is the value returned from the function.
rewind(fp);
fscanf(fp, "%d %*s %*s", &val);
while (check == false && !feof(fp))
{
//cout << "val = " << val << endl;
if (area == val)
check = true;
fscanf(fp, "%d %*s %*s", &val);
} //end while loop
}
return check;
} //end isRegistered()
// Function checks the minimum number of digits in a publisher field
int ISBNPrefix::minNoDigits(int area) const
{
int isreg; //check if area exists in file, returned if false
char line[20], lineinput[20];
int numarray[5], i, j, k, check = 0, val, counter = 0; // numarray is the array that will hold the numeric digits read in from the file. check is the while terminator. counter is returned
if (fp != NULL)
{
rewind(fp);
fgets(lineinput, 20, fp);
isreg = isRegistered(area);
if (isreg == 0)
return isreg;
else
{
rewind(fp);
fgets(lineinput, 20, fp);
while (check != 1 && !feof(fp))
{
val = 0; //val is the number used to turn the char values of area section read from the file into an int
for (i = 0; lineinput[i] != ' '; i++) //loop through until lineinput i == whitespace (ie, only area field of line)
{
lineinput[i] = lineinput[i] - '0'; //turns individual char into its numeric int
numarray[i] = lineinput[i]; // now have an int to work with, made up solely of the area
lineinput[i] = lineinput[i] + '0';
}
i--; //i is now the maximum number of digits that area is minus 1 (count from zero)
for (j = 0; j <= i; j++) //turn the individual numbers into an actual number. Say the number is 972 so i = 2 ((number of digits in 972) - 1)
{
k = pow(10, i - j); //10 to the power of 2 - 0 (on first loop) = 100
numarray[j] = numarray[j] * k; // 9 * 100
val += numarray[j]; // val == 900. On the next pass, the 7 will become 70 and will be added to val, so 970. On the 3rd pass, 2*1 will be added.
}
if (area == val)
check = 1;
strcpy(line, lineinput); //line array holds the values of the publisher fields before lineinput gets updated
fgets(lineinput, 20, fp);
} //end while loop
i += 2; // line[i] now equals the first character of the publisher field
while (line[i] != ' ')
{
counter++;
i++;
}
return counter;
} //end else
}
else
return 0;
} // end minNoDigits()
bool ISBNPrefix::isRegistered(int area, const char* publisher) const
{
bool check = false;
if (fp != NULL)
{
char line[20][20], area2[6], publow[11], pubhigh[11], pubnum[11];
int i = 0, j, check1 = 0, count, mindigits, compare;
check = isRegistered(area);
mindigits = minNoDigits(area);
if (check == 1)
{
rewind(fp);
check = false;
while (check == false && !feof(fp))
{
fscanf(fp, "%s %s %s", area2, publow, pubhigh);
if ((strlen(publisher) == strlen(publow)) && atoi(area2) == area)
{
if ((strcmp(publisher, publow) >= 0) && (strcmp(publisher, pubhigh) <= 0))
{
check = true;
}
}
}
}
}
return check;
}
ISBNPrefix::~ISBNPrefix()
{
rewind(fp);
if (fp != NULL)
{
fclose(fp);
}
}
ISBN definition file:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
#include "ISBNPrefix.h"
#include "ISBN.h"
ISBN::ISBN()
{
strisbn[0]='\0';
area[0]='\0';
publisher[0]='\0';
title[0]='\0';
}
ISBN::ISBN(const char* str, const ISBNPrefix& list)
{
int check = 0;
bool check1 = false;
strcpy(strisbn, str);
check = isValid(strisbn);
if (check)
{
check1 = isRegistered(list);
}
if (!check1)
{
strisbn[0]='\0';
area[0]='\0';
publisher[0]='\0';
title[0]='\0';
}
}
void ISBN::testdisplay()
{
cout << "strisbn = " << strisbn << " and area = " << area << " and publisher = " << publisher << " and title = " << title << endl;
}
bool ISBN::isRegistered(const ISBNPrefix& list)
{
int numarea, i = 0, j, k, check1 = 0;
char temp[11];
int check2 = 0, check3 = 0;
check1 = 0;
if (strisbn[0] == '0')
{
strcpy(area, "0");
numarea = 0;
check1 = 1;
}
//cout << "after testing if first digit is 0, check1 = " << check1 << endl;
if (strisbn[0] != '0')
{
for (i = 5; i >= 1 && check1 == 0; i--) //counts down from max strlen of area
{
strncpy(area, strisbn, i);
area[i] = '\0';
numarea = atoi(area);
check1 = list.isRegistered(numarea);
//cout << "when i = " << i << ", check1 = " << check1 << endl;
if (check1 == 0)
area[0]='\0';
}
}
if (check1 != 0) // area is found in list, extract publisher code if within acceptable range
{
check1 = 0;
i = strlen(area);
int max = 10;
j = (max+1) - i;
strcpy(temp, &strisbn[i]);
int min = list.minNoDigits(numarea), comp = 1, valpub = 0;
// i ends up as the amount of digits in area, j is the amount of digits in publisher, str[k] is where title starts, and l is the length of title
// i has an i--; immediately in the while loop to bring it to 5
//cout << "min = " << min << endl;
while (check1 != 2 && j > 0)
{
j--;
k = j + i; //the last possible space that could be a publisher digit
//strncpy(temp, &str[i], j);
temp[j] = '\0';
valpub = list.isRegistered(numarea, temp);
if (valpub != 0)
{
check1 = 2;
strcpy(publisher, temp);
}
//cout << "check1 if valpub = 0" << endl;
}
}
if (check1 == 2)
{
strcpy(title, &strisbn[k]);
title[strlen(title) - 1] = '\0';
}
//cout << "area = " << numarea << " and publisher is " << publisher << " and title is " << title << endl;
if (check1 == 2)
return true;
else
return false;
}
int isValid(const char* str)
{
int check = 0, i, num[10], val = 0, mod = 1, length = 0;
if (str == NULL)
check = 0;
else if (strlen(str) == 10) //10 characters in the string
{
check = 1;
for (i = 0; i < 9; i++) //go through first 9 characters, make sure they're a digit. If they are valid, propagate num array with numerical values
{
if (str[i] < '0' || str[i] > '9')
check = 0;
else
num[i] = str[i] - '0';
}
if (check != 0) //the first 9 characters are digits, make sure 10th char is either a digit or letter X (10). Propagate 10th num array position with numerical value.
{
if (str[9] < '0' || str[9] > '9' && str[9] != 'X') //if last char is not a digit between 0 and 9 and is not X
check = 0;
else if (str[9] == 'X')
num[9] = 10;
else //in other words, last char is a digit between 0 and 9
num[9] = str[9] - '0';
}
if (check != 0) //do the math to make sure it's all modulo 11
{
for (i = 0; i < 10; i++)
{
val += num[i] * (10 - i);
}
mod = val % 11;
if (mod != 0)
check = 0;
}
} // if statement about there being 10 characters
return check;
}
Help please? I'm guessing fp goes out of scope after the ISBN non-empty constructor wraps up but I can't figure out how! The ISBNPrefix destructor works fine if I comment out the ISBN constructor in the main file.
Edited by Moe45673, 26 October 2011 - 07:23 AM.


Sign In
Create Account

Back to top









