Abnormal program termination - Please help!

M

Mahmood Ahmad

Hello,

I have written a program that reads three types of records, validates
them acording to certain requirements and writes the valid records
into a binary file. The invalid records are supposed to be reported on
the printer but I have commented those pieces of code and have got
those records printed on the screen. I am using Microsoft Visual C++
6.0 on Microsoft XP (Home) platform.

I am facing some problems in getting desire results:

1. My program runs with some abnormal termination at the very end
(which is the return 0; line at the end of mymain.cpp).

2.The output saved in the validated file mydataVF.dat is also consists
of characters beyond my expectation.

3. In the function validate_writeC(...), you will find the strings as
local variables spread among various lines in function header. I have
done so, because my program overwrites or "loses" certain strings in
this function if I define all those strings in one line like:

char s1[6], s2[21], s3[61], s4[10], s5[8];

Does this happen because the memory locations for these strings are
contiguous and my program tends to overwrite some of the important
data? Does this have something to do with the size of local variables
for a function? How can I remedy these problems?

Grateful for help,
Mahmood Ahmad



[FILE: myheaderfileP1.h]

#include <iostream>

using std::cout;
using std::endl;
using std::ios;

#include <string>

using std::string;

#include <fstream>

using std::ifstream;
using std::eek:fstream;

#include <iomanip>

using std::setprecision;
using std::setiosflags;
using std::resetiosflags;
using std::setw;

#include <cstdlib>
#include <ctype.h>
//
#define DEBUG
//
typedef struct {
char rec_type;
char cust_code[6];
char part_num[7];
char quantity[5];
} IREC;
//
typedef struct {
char rec_type;
char cust_code[6];
} DREC;
//
typedef struct {
char rec_type;
char cust_code[6];
char cust_name[21];
char cust_add[61];
char cust_balance[10];
char credit_lim[8];
} CREC;
//
#define MAXCHARS 150
#define MINRECORDS 100
#define IREC_SIZE sizeof(IREC)
#define CREC_SIZE sizeof(CREC)
#define DREC_SIZE sizeof(DREC)
//
ifstream trans_file;
ofstream valid_file, prn_file;
//
int nirec = 0;
int ncrec = 0;
int ndrec = 0;
//
int temp, valid_count = 0;
int prn_count = 0;
int total_count = 0;
char valid_char1, valid_char2;
//
bool validate_writeI(char* txtrec);
bool validate_writeC(char* txtrec);
bool validate_writeD(char* txtrec);
//
bool validate_writeI(char* txtrec)
{
bool validation_flag = true;
int rem, sum = 0;
int num_wt[4] = {5, 4, 3, 2};
int part_wt[5] = {6, 5, 4, 3, 2};
IREC irec;
char mych;
char s1[6], s2[7], s3[5];
//
for(int i=1; i<sizeof(IREC); i++)
{
mych = txtrec;
if(i <= 5)
s1[i-1] = mych;
else if((i > 5) && (i <= 11))
s2[i-6] = mych;
else
s3[i-12] = mych;
}
s1[5] = '\0';
s2[6] = '\0';
s3[4] = '\0';
for(i=1; i<5; i++)
{
mych = txtrec;
if(!isdigit(mych))
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid characters."
<< endl << "\t\t"
<< "Part Number = " << s2 << endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid characters."
<< endl << "\t\t"
<< "Part Number = " << s2 << endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;
#endif
prn_count++;
return validation_flag;
}
else
sum = sum + (mych-48)*num_wt[i-1];
}
rem = sum%11;
if(rem == 0)
valid_char1 = 'X';
else if(rem == 1)
valid_char1 = '0';
else
valid_char1 = (char) (11-rem+48);

if(valid_char1 != txtrec[5])
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid code."
<< endl << "\t\t"
<< "Part Number = " << s2 << endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;*/
//
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid code."
<< endl << "\t\t"
<< "Part Number = " << s2 << endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;
#endif
//
prn_count++;
return validation_flag;
}
else
{
sum = 0;
for(i=0; i<=4; i++)
{
mych = s2;
if(!isdigit(mych))
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Part Number = " << s2 << " - Invalid characters."
<< endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Part Number = " << s2 << " - Invalid characters."
<< endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;
#endif
prn_count++;
return validation_flag;
}
else
sum = sum + (mych-48)*part_wt;
}
rem = sum%11;
if(rem == 0)
valid_char2 = 'X';
else if(rem == 1)
valid_char2 = '0';
else
valid_char2 = (char) (11-rem+48);
if(valid_char2 != txtrec[11])
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Part Number = " << s2 << " - Invalid part number."
<< endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;*/
//
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Part Number = " << s2 << " - Invalid part number."
<< endl << "\t\t"
<< "Quantity = " << s3 << endl << endl;
#endif
//
prn_count++;
return validation_flag;
}
else
{
for(i=0; i<=3; i++)
{
mych = s3;
if(!isdigit(mych))
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Part Number = " << s2 << endl << "\t\t"
<< "Quantity = " << s3 << " - Invalid characters."
<< endl << endl; */
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Part Number = " << s2 << endl << "\t\t"
<< "Quantity = " << s3 << " - Invalid characters."
<< endl << endl;
#endif
prn_count++;
return validation_flag;
}
}
irec.rec_type = txtrec[0];
strncpy(irec.cust_code,s1,6);
strncpy(irec.part_num,s2,7);
strncpy(irec.quantity,s3,5);
valid_count++;
validation_flag = true;
nirec++;
#ifdef DEBUG
cout << "s1 = " << s1 << endl
<< "s2 = " << s2 << endl
<< "s3 = " << s3 << endl;
cout << "irec.cust_code = " << irec.cust_code << endl;
cout << "irec.part_num = " << irec.part_num << endl;
cout << "irec.quantity = " << irec.quantity << endl;
#endif
//
IREC *irec_ptr;
irec_ptr = &irec;
valid_file.write((char *) irec_ptr, IREC_SIZE);
return validation_flag;
}
}
}
//
bool validate_writeD(char* txtrec)
{
bool validation_flag = true;
int rem, sum = 0;
int num_wt[4] = {5, 4, 3, 2};
char mych, s1[6];
DREC drec;
//
for (int i=0; i<=4; i++)
{
mych = txtrec[i+1];
s1 = mych;
}
s1[5] = '\0';
for(i=0; i<4; i++)
{
mych = s1;
if(!isdigit(mych))
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid characters."
<< endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid characters."
<< endl << endl;
#endif
prn_count++;
return validation_flag;
}
else
sum = sum + (mych-48)*num_wt;
}
rem = sum%11;
if(rem == 0)
valid_char1 = 'X';
else if(rem == 1)
valid_char1 = '0';
else
valid_char1 = (char) (11-rem+48);
if(valid_char1 != txtrec[5])
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid code."
<< endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid code."
<< endl << endl;
#endif
//
prn_count++;
return validation_flag;
}
else
{
drec.rec_type = txtrec[0];
strncpy(drec.cust_code,s1,6);
valid_count++;
validation_flag = true;
#ifdef DEBUG
cout << "s1 = " << s1 << endl;
cout << "drec.cust_code = " << drec.cust_code << endl;
#endif
ndrec++;

//
DREC *drec_ptr;
drec_ptr = &drec;
valid_file.write((char *) drec_ptr, DREC_SIZE);
return validation_flag;
}
}
//
bool validate_writeC(char* txtrec)
{
char s5[8];
bool validation_flag = true;
int rem, sum = 0;
char s4[10];
int semicolon_cnt = 0;
char s1[6], s2[21];
int num_wt[4] = {5, 4, 3, 2};
char mych, mych_prev;
char s3[61];
CREC crec;
//
for(int i=1; i < 102; i++)
{
mych = txtrec;
if(i <= 5)
s1[i-1] = mych;
else if((i > 5) && (i <= 25))
s2[i-6] = mych;
else if((i > 25) && (i <= 85))
s3[i-26] = mych;
else if((i > 85) && (i <= 94))
s4[i-86] = mych;
else
s5[i-95] = mych;
}
s1[5] = '\0';
s2[20] = '\0';
s3[60] = '\0';
s4[10] = '\0';
s5[8] = '\0';
//
for(i=0; i<=3; i++)
{
mych = s1;
if(!isdigit(mych))
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid characters."
<< endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid characters."
<< endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
prn_count++;
return validation_flag;
}
else
sum = sum + (mych-48)*num_wt;
}
rem = sum%11;
if(rem == 0)
valid_char1 = 'X';
else if(rem == 1)
valid_char1 = '0';
else
valid_char1 = (char) (11-rem+48);
if(valid_char1 != txtrec[5])
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid code."
<< endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << " - Invalid code."
<< endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
prn_count++;
return validation_flag;
}
else
{
for(i=6; i<=25; i++)
{
mych = txtrec;
if(!(isalpha(mych)) && (mych != ' '))
{
validation_flag = false; // print with reason to printer
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << " - Invalid characters."
<< endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << " - Invalid characters"
<< endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
//
prn_count++;
return validation_flag;
}
}
for(i=26; i<=85; i++)
{
mych = txtrec;
if(mych != ';')
{
if((mych != '.') && (mych != ' ') &&
!(isalpha(mych)))
{
if(!isdigit(mych))
{
validation_flag = false; // Address field contains foul
characters
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - WRONG CHARACTERS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - WRONG CHARACTERS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
prn_count++;
return validation_flag;
}
else
{
if((i>26) && (semicolon_cnt == 0))
{
mych_prev = txtrec[i-1];
if(!isdigit(mych))
{
validation_flag = false; // Address field contains foul
characters
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - WRONG CHARACTERS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - WRONG CHARACTERS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
//
prn_count++;
return validation_flag;
}
}
}
}
}
else
{
semicolon_cnt++;
if(semicolon_cnt > 4)
{
validation_flag = false; // too many semicolons in address field
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - TOO MANY SEMI-COLONS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - TOO MANY SEMI-COLONS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
prn_count++;
return validation_flag;
}
else
continue;
}
}
if(semicolon_cnt < 4)
{
validation_flag = false; // too few semicolons in address field
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - TOO FEW SEMI-COLONS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "ERROR - TOO FEW SEMI-COLONS IN ADDRESS."
<< endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
//
prn_count++;
return validation_flag;
}
// CUSTOMER BALANCE CHECK
for(i=86; i<=94; i++)
{
mych = txtrec;
if(!isdigit(mych))
{
validation_flag = false;
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << " - Non-numeric characters."
<< endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;*/
#ifdef DEBUG
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << " - Non-numeric characters."
<< endl << "\t\t"
<< "Credit Limit = " << s5 << endl << endl;
#endif
//
prn_count++;
return validation_flag;
}
}
// CRIDIT LIMIT CHECK
for(i=95; i<=101; i++)
{
mych = txtrec;
if(!isdigit(mych))
{
validation_flag = false;
/* prn_file << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << " - Non-numeric characters."
<< endl << endl;*/
cout << (total_count+1) << "\t\t"
<< "Record Type = " << txtrec[0] << endl << "\t\t"
<< "Customer code = " << s1 << endl << "\t\t"
<< "Customer Name = " << s2 << endl << "\t\t"
<< "Address = " << s3 << endl << "\t\t"
<< "Customer Balance = " << s4 << endl << "\t\t"
<< "Credit Limit = " << s5 << " - Non-numeric characters."
<< endl << endl;
prn_count++;
return validation_flag;
}
}
#ifdef DEBUG
cout << "s1 = " << s1 << endl
<< "s2 = " << s2 << endl
<< "s3 = " << s3 << endl
<< "s4 = " << s4 << endl
<< "s5 = " << s5 << endl;
#endif
crec.rec_type = txtrec[0];
strncpy(crec.cust_code, s1, 6);
strncpy(crec.cust_name, s2, 21);
strncpy(crec.cust_add, s3, 61);
strncpy(crec.cust_balance, s4, 10);
strncpy(crec.credit_lim, s5, 8);
//
valid_count++;
validation_flag = true;
ncrec++;
//
CREC *crec_ptr;
crec_ptr = &crec;
valid_file.write((char *) crec_ptr, CREC_SIZE);
return validation_flag;
}
}

//[END OF FILE: myheaderfileP1.h]

//[FILE: mymain.cpp]
#include "myheaderfileP1.h"
//
char txtrec[MAXCHARS];
//
int main()
{
bool vflag;
char mych1;
//
trans_file.open("mydata.DAT", ios::in);
if(!trans_file.is_open())
{
cout << "Transaction file is not opened" << endl;
exit(1);
}
//
/* prn_file.open("lpt1", ios::eek:ut);
prn_file << "INVALID RECORDS FROM 534216TD.DAT" << endl
<< "---------------------------------" << endl << endl;
prn_file << "Record #\tReason for Invalidation" << endl
<< "--------\t-----------------------" << endl << endl;*/
//
valid_file.open("mydataVF.DAT", ios::eek:ut|ios::binary);
if(!valid_file.is_open())
{
cout << "Validation file is not opened" << endl;
exit(1);
}
while(trans_file && !trans_file.eof())
{
trans_file.getline(txtrec, 103, '\n');
mych1 = toupper(txtrec[0]);
switch(mych1)
{
case 'I':
case 'R':
{
vflag = validate_writeI(txtrec);
total_count++;
break;
}
case 'C':
{
vflag = validate_writeC(txtrec);
total_count++;
break;
}
case 'D':
{
vflag = validate_writeD(txtrec);
total_count++;
break;
}
default:
break;
}
if((mych1 != 'I') && (mych1 != 'R') &&
(mych1 != 'C') && (mych1 != 'D'))
{
if(isalpha(mych1))
{
/* prn_file << (total_count+1) << "\t\t"
<< "Invalid record type."
<< endl;*/
cout << (total_count+1) << "\t\t"
<< "Invalid record type."
<< endl;
prn_count++;
total_count++;
}
}
}
/* prn_file << endl << endl << "Invalid records:\t"
<< setiosflags(ios::right) << setw(3)
<< prn_count << endl;
prn_file << "Valid records:\t\t"
<< setiosflags(ios::right) << setw(3)
<< valid_count << endl;
prn_file << "Total records checked:\t"
<< setiosflags(ios::right) << setw(3)
<< total_count << endl << endl;
prn_file << "End of file reached. Exitting normally." << endl;*/
//
cout << endl << endl << "Invalid records:\t"
<< prn_count << endl;
cout << "Valid records:\t\t"
<< valid_count << endl;
cout << "Total records checked:\t"
<< total_count << endl << endl;
cout << "End of file reached. Exitting normally." << endl;
//
return 0;
}
// [END OF FILE: mymain.cpp]

// [FILE mydata.dat]
I246862456820056
R246802456864089
R357854569002037
D25402
D45900
D4590X
C45675Mahmood Ahmad 16 Greywethers Avenue;Old Town;Swindon
Wiltshire SN3 1QF; 604509.501000000
C45675Mahmood Ahmad Greywethers 16 Avenue;Old Town;Swindon
Wiltshire SN3 QFF; 604509.501000000
C45675Mahmood A9mad 16 Greywethers Avenue;Old Town;Swindon
Wiltshire SN3 1QF; 604509.501000000
C90875Mrs Gwen Metcalfe 10 Bydemill Gardens;Highworth
Swindon;Wiltshire;SN6 7BT 455609.752500000
C90875Mrs Gwen Metcalfe 10 Bydemill Gardens;Highworth
Swindon;Wiltshire;SN6 7BT 455609.752500M00
C90875Mrs Gwen Metcalfe 10 Bydemill
Gardens;Highworth;Swindon;Wiltshire;SN6 7BT 455609.752500000
D29904
C99996Mr D Gupta Ridgeway Hospital;Moremead Road;Wroughton
Swindon;SN4 4DD 009000.000400000
R00121450500987
M34002
D34002
[END OF FILE]
 
A

Artie Gold

Mahmood said:
Hello,

I have written a program that reads three types of records, validates
them acording to certain requirements and writes the valid records
into a binary file. The invalid records are supposed to be reported on
the printer but I have commented those pieces of code and have got
those records printed on the screen. I am using Microsoft Visual C++
6.0 on Microsoft XP (Home) platform.

I am facing some problems in getting desire results:

1. My program runs with some abnormal termination at the very end
(which is the return 0; line at the end of mymain.cpp).

2.The output saved in the validated file mydataVF.dat is also consists
of characters beyond my expectation.

3. In the function validate_writeC(...), you will find the strings as
local variables spread among various lines in function header. I have
done so, because my program overwrites or "loses" certain strings in
this function if I define all those strings in one line like:

char s1[6], s2[21], s3[61], s4[10], s5[8];

Does this happen because the memory locations for these strings are
contiguous and my program tends to overwrite some of the important
data? Does this have something to do with the size of local variables
for a function? How can I remedy these problems?

Grateful for help,

[rather excessive code snipped]

An error like this *very* much suggests that your're overwriting an
automatic (i.e.local) array (perhaps by failing to allow sufficient
space for a trailing nul in a C-style string).

There's no way I'm going to look at hundreds of lines of code with a
fine-toothed comb; indeed, it is quite inappropriate to post so much code.

In the future, please include, as part of the message, the smallest,
compilable/runnable snippet of code that exhibits the problem. This has
two great advantages: 1) Those who *can* help are much more likely to
read your code carefully, and 2) You are likely to find your problem
(i.e. the bug) in the process.

HTH,
--ag
 
D

David Harmon

Does this happen because the memory locations for these strings are
contiguous and my program tends to overwrite some of the important
data? Does this have something to do with the size of local variables
for a function? How can I remedy these problems?

It happens because some of your array indexes exceeds the array
boundary, and so the char you store there clobbers some other memory.

For example:
typedef struct {
char rec_type;
char cust_code[6];
char part_num[7];
char quantity[5];
} IREC;

Here IREC is a minimum of 19 bytes.
char s1[6], s2[7], s3[5];
//
for(int i=1; i<sizeof(IREC); i++)
{
mych = txtrec;
if(i <= 5)
s1[i-1] = mych;
else if((i > 5) && (i <= 11))
s2[i-6] = mych;
else
s3[i-12] = mych;


When i is 17, (i-12) is 5 and s3[5] writes past the end of s3.
And you still have i=18 to go.

You have dozens of little bitty magic numbers like 17, 12, 5, etc.
scattered all over your code. Every one of them is a potential
disaster. Nobody can write code like that for long and remain sane.
Fix things so you don't have to count chars more than once each.
At least, declare consts for the number of chars in each field, and
define everything else in terms of them.
 
M

Mahmood Ahmad

Hello again,

Here is a simplified version of the code which I have tried to modify
too, in the light of your responses. After changing plenty of numbers
to appropriately defined constants, and reviewing the logic of my
program, my program has a normal termination now. However, it still
saves strange characters in the valid_file, strange becuse the
characters are unexpected.

This program reads a line from a text file. Each line read contains
record of one of three types IREC, CREC and DREC. All this program
does is read the line, separate the fields into strings, copy those
strings into fields of appropriate record type and write the record
into a binary file.

I have checked and debugged to see if all the strings get the expected
characters (in number and in content). Everything seems to work fine.
However, in the process of closing the file, some thing has gone wrong
which I do not know.

I hope the present code is of appropriate size. I would appreciate for
your help.

Thanks,

Mahmood.

Here is the code and the example data:

#include <iostream>

using std::cout;
using std::endl;
using std::ios;

#include <string>

using std::string;

#include <fstream>

using std::ifstream;
using std::eek:fstream;

#include <iomanip>

using std::setprecision;
using std::setiosflags;
using std::resetiosflags;
using std::setw;
//
#include <cstdlib>
#include <ctype.h>
//
#define FOUR 4
#define CUSTCODE 6
#define PARTNUMB 7
#define QUANTITI 5
#define CREDITLIM 8
#define CUSTNAME 21
#define CUSTADDR 61
#define BALANCE 10
//
#define MAXCHARS 103
//
typedef struct {
char rec_type;
char cust_code[CUSTCODE];
char part_num[PARTNUMB];
char quantity[QUANTITI];
} IREC;
//
typedef struct {
char rec_type;
char cust_code[CUSTCODE];
} DREC;
//
typedef struct {
char rec_type;
char cust_code[CUSTCODE];
char cust_name[CUSTNAME];
char cust_add[CUSTADDR];
char cust_balance[BALANCE];
char credit_lim[CREDITLIM];
} CREC;
//
#define IREC_SIZE sizeof(IREC)
#define CREC_SIZE sizeof(CREC)
#define DREC_SIZE sizeof(DREC)
//
ifstream trans_file;
ofstream valid_file;
//
int total_count = 0;
int prn_count = 0;
char valid_char1, valid_char2;
char txtrec[MAXCHARS];
//
bool validate_writeI(char* txtrec);
bool validate_writeC(char* txtrec);
bool validate_writeD(char* txtrec);
//
int main()
{
bool vflag;
char mych1;
//
trans_file.open("mydata.DAT", ios::in);
if(!trans_file.is_open())
{
cout << "Transaction file is not opened" << endl;
exit(1);
}
valid_file.open("mydataVF.DAT", ios::eek:ut|ios::binary);
if(!valid_file.is_open())
{
cout << "Validation file is not opened" << endl;
exit(1);
}
while(trans_file && !trans_file.eof())
{
trans_file.getline(txtrec, MAXCHARS, '\n');
mych1 = toupper(txtrec[0]);
switch(mych1)
{
case 'I':
case 'R':
{
vflag = validate_writeI(txtrec);
total_count++;
break;
}
case 'C':
{
vflag = validate_writeC(txtrec);
total_count++;
break;
}
case 'D':
{
vflag = validate_writeD(txtrec);
total_count++;
break;
}
default:
break;
}
if((mych1 != 'I') && (mych1 != 'R') &&
(mych1 != 'C') && (mych1 != 'D'))
{
if(isalpha(mych1))
{
cout << (total_count+1) << "\t"
<< "Invalid record type."
<< endl;
prn_count++;
total_count++;
}
}
}
cout << "Total records checked:\t"
<< total_count << endl << endl;
cout << "End of file reached. Exitting normally." << endl;
//
return 0;
}
//
bool validate_writeI(char* txtrec)
{
bool validation_flag = true;
IREC irec;
char mych;
char s1[CUSTCODE], s2[PARTNUMB], s3[QUANTITI];
//
// First, separating each field into strings
for(int i=1; i<(IREC_SIZE-3); i++)
{
mych = txtrec;
if(i <= (CUSTCODE-1))
s1[i-1] = mych;
else if((i > (CUSTCODE-1)) && (i <= (CUSTCODE+PARTNUMB-2)))
s2[i-CUSTCODE] = mych;
else
s3[i-(CUSTCODE+PARTNUMB-1)] = mych;
}
// Appending null character to the end of each string.
s1[CUSTCODE-1] = '\0';
s2[PARTNUMB-1] = '\0';
s3[QUANTITI-1] = '\0';
// Saving strings into record fields
irec.rec_type = txtrec[0];
strncpy(irec.cust_code,s1,CUSTCODE);
strncpy(irec.part_num,s2,PARTNUMB);
strncpy(irec.quantity,s3,QUANTITI);
validation_flag = true;
//
// Saving the record into te binary file.
IREC *irec_ptr;
irec_ptr = &irec;
valid_file.write((char *) irec_ptr, IREC_SIZE);
return validation_flag;
}
//
bool validate_writeD(char* txtrec)
{
bool validation_flag = true;
char mych, s1[CUSTCODE];
DREC drec;
//
// saving in string
for (int i=1; i<DREC_SIZE; i++)
{
mych = txtrec;
s1[i-1] = mych;
}
s1[CUSTCODE-1] = '\0'; // Append null character at the end.
// Save the string in the record
drec.rec_type = txtrec[0];
strncpy(drec.cust_code,s1,CUSTCODE);
cout << "cust_code = " << s1 << endl;
valid_count++;
validation_flag = true;
//
// Write record in the file
DREC *drec_ptr;
drec_ptr = &drec;
valid_file.write((char *) drec_ptr, DREC_SIZE);
return validation_flag;
}
//
bool validate_writeC(char* txtrec)
{
char s1[CUSTCODE], s2[CUSTNAME], s3[CUSTADDR];
char s4[BALANCE], s5[CREDITLIM];
bool validation_flag = true;
char mych;
//
// separate record fields into strings
for(int i=1; i < 102; i++)
{
mych = txtrec;
if(i <= (CUSTCODE-1))
s1[i-1] = mych;
else if((i > (CUSTCODE-1)) && (i <= (CUSTCODE+CUSTNAME-2)))
s2[i-CUSTCODE] = mych;
else if((i > (CUSTCODE+CUSTNAME-2)) &&
(i <= (CUSTCODE+CUSTNAME+CUSTADDR-3)))
s3[i-(CUSTCODE+CUSTNAME-1)] = mych;
else if((i > (CUSTCODE+CUSTNAME+CUSTADDR-3))
&& (i <= (CUSTCODE+CUSTNAME+CUSTADDR+BALANCE-4)))
s4[i-(CUSTCODE+CUSTNAME+CUSTADDR-2)] = mych;
else
s5[i-(CUSTCODE+CUSTNAME+CUSTADDR+BALANCE-3)] = mych;
}
// Append null character at the end
s1[CUSTCODE-1] = '\0';
s2[CUSTNAME-1] = '\0';
s3[CUSTADDR-1] = '\0';
s4[BALANCE-1] = '\0';
s5[CREDITLIM-1] = '\0';
// save these strings into the record field
CREC crec;
crec.rec_type = txtrec[0];
strcpy(crec.cust_code, s1);
strcpy(crec.cust_name, s2);
strcpy(crec.cust_add, s3);
strcpy(crec.cust_balance, s4);
strcpy(crec.credit_lim, s5);
//
validation_flag = true;
//
// writing record into the file.
CREC *crec_ptr;
crec_ptr = &crec;
valid_file.write((char *)crec_ptr, CREC_SIZE);
return validation_flag;
}
END OF PROGRAM
File: mydata.dat
I246862456820056
R246802456864089
R357854569002037
D25402
D45900
D4590X
C45675Mahmood Ahmad 16 Greywethers Avenue;Old Town;Swindon
Wiltshire SN3 1QF; 604509.501000000
C45675Mahmood Ahmad Greywethers 16 Avenue;Old Town;Swindon
Wiltshire SN3 QFF; 604509.501000000
C45675Mahmood A9mad 16 Greywethers Avenue;Old Town;Swindon
Wiltshire SN3 1QF; 604509.501000000
C90875Mrs Gwen Metcalfe 10 Bydemill Gardens;Highworth
Swindon;Wiltshire;SN6 7BT 455609.752500000
C90875Mrs Gwen Metcalfe 10 Bydemill Gardens;Highworth
Swindon;Wiltshire;SN6 7BT 455609.752500M00
C90875Mrs Gwen Metcalfe 10 Bydemill
Gardens;Highworth;Swindon;Wiltshire;SN6 7BT 455609.752500000
D29904
C99996Mr D Gupta Ridgeway Hospital;Moremead Road;Wroughton
Swindon;SN4 4DD 009000.000400000
R00121450500987
M34002
D34002


David Harmon said:
Does this happen because the memory locations for these strings are
contiguous and my program tends to overwrite some of the important
data? Does this have something to do with the size of local variables
for a function? How can I remedy these problems?

It happens because some of your array indexes exceeds the array
boundary, and so the char you store there clobbers some other memory.

For example:
typedef struct {
char rec_type;
char cust_code[6];
char part_num[7];
char quantity[5];
} IREC;

Here IREC is a minimum of 19 bytes.
char s1[6], s2[7], s3[5];
//
for(int i=1; i<sizeof(IREC); i++)
{
mych = txtrec;
if(i <= 5)
s1[i-1] = mych;
else if((i > 5) && (i <= 11))
s2[i-6] = mych;
else
s3[i-12] = mych;


When i is 17, (i-12) is 5 and s3[5] writes past the end of s3.
And you still have i=18 to go.

You have dozens of little bitty magic numbers like 17, 12, 5, etc.
scattered all over your code. Every one of them is a potential
disaster. Nobody can write code like that for long and remain sane.
Fix things so you don't have to count chars more than once each.
At least, declare consts for the number of chars in each field, and
define everything else in terms of them.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top