I'm at my wits end! Help!

School assignment to do with ISBN codes. An ISBN number is basically 4 parts: An Area code, publisher code, title code, and check digit. My code checks if the ISBN is valid and if it's registered. To make it less confusing, think of a phone number. It's valid if it's in this format "555-555-5555" but noone in the world might have that number, meaning it's not registered. Same thing with ISBN


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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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 (which I have since removed from my source code), ISBN sample constructs A-OK. The empty destructor for ISBNPrefix is automatically called.


Header files:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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. Called by non-empty constructor and it in turn calls many of the methods in ISBNPrefix.
Empty constructor - set all strings at [0] to '\0'
Constructor - set ISBN, check if it's valid (using isValid) and registered (using isRegistered) against the list provided as second argument, otherwise does same thing as empty constructor.
isValid - accepts an ISBN and says if it's in proper format.

ISBNPrefix definition file:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#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);
    }
}
Last edited on

ISBN definition file:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#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--)
        {
                   
            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 valid, extract publisher code
    {
        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')


                check = 0;


            else if (str[9] == 'X')
                num[9] = 10;






            else
                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. The "Signing off...." text always displays and the segfault occurs after it. Using the gdb debugger, I found that it occurs on the "rewind(fp)" in the destructor if I have it, or on the "fclose(fp)" if I remove the rewind statement.
Last edited on
Topic archived. No new replies allowed.