How to include global functions in a separate file - c++

I am trying to organize my code by grouping functions in seperate header/source files. I've #included the header file in my main .cpp, but the compiler does not see the functions in convertTypes.cpp. What gives? And how do I use my 'key' typedef globally (so also in the seperated function sources)? Lots of code, sorry.
/*
* NoteMaker.cpp
*
* Created on: Sep 4, 2013
* Author: edwinrietmeijer
*/
typedef struct {
int keyNum;
int keyType;
} key;
#include <iostream>
#include <string>
#include <iomanip>
#include "convertTypes.h"
using namespace std;
const int KEYSET[ ] = { 0, 2, 4, 5, 7, 8, 9 };
int* generateNotes( int, key );
void echoNoteList( const int* , const int, const key );
string getKeyStringFromUser();
int main() {
key keyStruct;
int octave;
int nrOfNotes;
string firstNoteName;
// Get inputs
cout << "What key would you like to generate notes in? ( f, cis, es, etc.)" << endl;
firstNoteName = getKeyStringFromUser();
cout << "In what octave would you like to generate notes? (-1 / 9)" << endl;
cin >> octave;
octave += 1;
cout << "How many notes do you wish to generate?" << endl;
cin >> nrOfNotes;
// create a key data struct from input string
keyStruct = convertKeyStringToKeyStruct( firstNoteName );
// add the starting octave nr to the keyStruct
keyStruct.keyNum += octave * 12;
// generate note list
int* noteList = new int[ nrOfNotes ];
noteList = generateNotes( nrOfNotes, keyStruct );
// echo note list to terminal
echoNoteList( noteList , nrOfNotes, keyStruct);
cin.get();
}
int* generateNotes( int notes, key keyStruct) {
int* newList = new int [notes];
int currNote = keyStruct.keyNum + keyStruct.keyType;
int currDist = 0;
newList[0] = currNote;
for (int i=1; i < notes; i ++) {
currDist = i % 7;
if ( currDist == 0 || currDist == 3 ) // half step or whole step?
{ currNote = currNote + 1; }
else
{ currNote = currNote + 2; }
newList[ i ] = currNote;
}
cout << "Generated list." << endl;
return newList;
}
void echoNoteList( const int* noteList, const int nrOfNotes, const key thisKeyStruct )
{
int currNote;
for (int i = 0; i < nrOfNotes ; i ++) {
currNote = noteList[ i ] % 12;
if ( currNote < 0 )
currNote += 12;
cout << left;
cout << setw(5) << noteList[ i ] << setw( 5 ) << convertToNoteName( currNote, thisKeyStruct.keyType ) << endl;
}
}
string getKeyStringFromUser() {
bool correctInput = false;
string getKeyName;
int keyNum;
while ( ! correctInput ) {
cin >> getKeyName;
cout << endl;
keyNum = getKeyName[ 0 ];
if ( keyNum > 96 && keyNum < 104 ) {
correctInput = true;
}
else
{
cout << "Wrong input. Try again." << endl;
}
}
return getKeyName;
}
convertTypes.h
#ifdef CONVERTTYPES_H
#define CONVERTTYPES_H
std::string convertToNoteName( int, int );
key convertKeyStringToKeyStruct( std::string );
#endif
convertTypes.cpp
/*
* convertTypes.cpp
*
* Created on: Sep 5, 2013
* Author: edwinrietmeijer
*/
#include <string>
#include "convertTypes.h"
using namespace std;
typedef struct {
int keyNum;
int keyType;
} key;
key convertKeyStringToKeyStruct( string firstNote ) {
int stringSize;
int keyType = 0;
char keyChar;
key thisKey;
keyChar = firstNote[ 0 ];
// get key type (flat, sharp, normal)
stringSize = firstNote.size( );
if (stringSize > 1 ) {
switch( firstNote[ 1 ] ) {
case 'e':
keyType = -1; break;
case 's':
keyType = -1; break;
case 'i':
keyType = 1; break;
default:
keyType = 0; break;
}
}
// convert key char to ascii code
int ASkey = keyChar;
thisKey.keyNum = KEYSET[ ASkey - 99 ];
thisKey.keyType = keyType;
return thisKey;
}
string convertToNoteName( int thisNote, int thisKeyType = 0) {
string noteName;
char addKeyType;
switch( thisKeyType ) {
case -1:
addKeyType = 'b'; break;
case 0:
addKeyType =' '; break;
case 1:
addKeyType = '#'; break;
}
switch( thisNote ) {
case 0:
noteName = "C"; break;
case 1:
if( thisKeyType == 1)
noteName = string ("C") + addKeyType;
else
noteName = string("D") + addKeyType; break;
case 2:
noteName = "D"; break;
case 3:
if( thisKeyType == 1)
noteName = string ("D") + addKeyType;
else
noteName = string("E") + addKeyType; break;
case 4:
noteName = "E"; break;
case 5:
noteName = "F"; break;
case 6:
if( thisKeyType == 1)
noteName = string ("F") + addKeyType;
else
noteName = string("G") + addKeyType; break;
case 7:
noteName = "G"; break;
case 8:
if( thisKeyType == 1)
noteName = string ("G") + addKeyType;
else
noteName = string("A") + addKeyType; break;
case 9:
noteName = "A"; break;
case 10:
if( thisKeyType == 1)
noteName = string ("A") + addKeyType;
else
noteName = string("B") + addKeyType; break;
case 11:
noteName = "B"; break;
default:
noteName = "!"; break;
}
return noteName;
}

Change:
#ifdef CONVERTTYPES_H
to:
#ifndef CONVERTTYPES_H
You are effectively compiling-out your definitions.
As to your second point, move this:
typedef struct {
int keyNum;
int keyType;
} key;
into the header file (before its first use there).
However I would warn against using a name like key as it's commonly used as a variable name. I would go for key_t or MySpecialKeyForStuffImDoing (or somesuch).

In addition to #trojanfor's anwer: also create a new NoteMaker.h containing the key structure definition or move the stuct definition to convertTypes.hso that you don't duplicate it in multiple places

Related

c++ terminate std::logic error ......where did my code go wrong?

I'm encountering this really weird error and I dont know where I'm constructing a string with a null parameter, could someone please help me out? Thanks!
Here's the error:
terminate_called_after_throwing_an_instance_of_'std::logic_error'
__what():__basic_string::_M_construct_null_not_valid
Here's my code:
/*
ID: 2005amr1
TASK: friday
LANG: C++
*/
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
using namespace std;
vector <string> days = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
bool leap (int y){
if (y%100 == 0){
if (y%400 == 0){
return true;
}
else{
return false;
}
}
else if (y%4 == 0){
return true;
}
else{
return false;
}
}
int targetedSearch (vector<string> array, string key){
int index = 0;
while( (index < array.size( )) && (key != array[index])){
if (array[index] != key){
index++;
}
}
return (index);
}
string findLastDay(string FDAY, int daysInMonth){ // all good here
int indexOfString = targetedSearch(days, FDAY);
if (FDAY == "Mon" && daysInMonth == 28){
return ("Sun");
}
return (days[(daysInMonth - (7*(daysInMonth/7))-1) + indexOfString]);
}
string find13Day (string firstDay){ // all good here
int indexOfString = targetedSearch(days, firstDay);
return (days[indexOfString+5]);
}
string findFirstDayNextMonth (string LDAY){
int indexOfString = targetedSearch(days, LDAY);
if (indexOfString+1 > 6){
return (days[(indexOfString+1)-7]);
}
else{
return (days[indexOfString+1]);
}
}
int numDays (int month, int year){
switch(month) {
case 0:
return 31;
break;
case 1:
if (leap(year) == true){
return 29;
}
else{
return 28;
}
break;
case 2:
return 31;
break;
case 3:
return 30;
break;
case 4:
return 31;
break;
case 5:
return 30;
break;
case 6:
return 31;
break;
case 7:
return 31;
break;
case 8:
return 30;
break;
case 9:
return 31;
break;
case 10:
return 30;
break;
case 11:
return 31;
break;
}
return 31;
}
int main() {
ofstream fout ("friday.out");
ifstream fin ("friday.in");
string startDay = "Mon";
int dayValues[7] = {0,0,0,0,0,0,0};
int n;
fin >> n;
map <string,int> dayValue;
for (int i = 1900; i< 1900+n; i++){
for (int m =0; m<12; m++){
int PAN = numDays (m,i);
string tday = find13Day(startDay);
dayValues[targetedSearch(days,tday)]++;
string LDAY = findLastDay(startDay, PAN);
startDay = findFirstDayNextMonth(LDAY);
}
}
fout << " " << dayValues[5] << " " << dayValues[6]<< " " << dayValues[0]<< " " << dayValues[1]<< " " << dayValues[2]<< " " << dayValues[3]<< " " << dayValues[4];
}

Parsing a file to assign variables to strucuture. C++

Here is my code, I'm genuinely interested how far off I am.
bool characterGetCFG(char typeOverLoad, string var_name, string full_text)
{
int pos = full_text.find(var_name) + 1;
if (full_text.at(pos) == *"t") {
cout << "returned " << full_text.at(pos) << "\n";
return true;
}
else
{
return false;
}
}
int characterGetCFG(int typeOverLoad, string var_name, string full_text)
{
int pos = full_text.find(var_name) + var_name.length() + 1;
cout << "returned " << full_text.at(pos) << "\n";
return full_text.at(pos);
}
features setconfig(features featstruct)
{
features config; //BOOL/BOOL/BOOL/BOOL/INT[2]/BOOL/INT
ifstream file;
file.open("config.cfg");
if (!file.is_open()) {
exit(-1);
}
string raw;
while (file.good()) {
file >> raw;
}
for (int x = 0; x < 11; x++) {
switch (x) {
case 1:
config.var1 = characterGetCFG('t', "var1", raw);
case 2:
config.var2 = characterGetCFG('t', "var2", raw);
case 3:
config.var3 = characterGetCFG('t', "var3", raw);
case 4:
config.var4 = characterGetCFG('t', "var4", raw);
case 5:
config.var5[1] = characterGetCFG(136, "var51", raw); //min
case 6:
config.var6[2] = characterGetCFG(542, "var62", raw); //max
case 7:
config.var7 = characterGetCFG('t', "var7", raw);
case 8:
config.var8 = characterGetCFG('t', "var8", raw);
case 9:
config.var9 = characterGetCFG('t', "var9", raw);
case 10:
config.var10 = characterGetCFG('t', "var10", raw);
case 11:
config.var11 = characterGetCFG('t', "var11", raw);
}
}
file.close();
return config;
}
And here is my text/cfg file I am using
var1=false
var2=false
var3=true
var4=false
var51=2
var62=7
var7=true
var8=t
var9=true
var10=true
var11=true
Here is what I am getting returned when I print what I am returning to console
As you can see it does not reflect how many times I iterate through the loop, so at the end of the day I'm stumped.

Parsing a string : my code apparentely works after testing, but is inelegant

This is a c++ question. I want the code of the desired c++ function (see below) to be (as much as possible) in c-style and using c string library functions because I think that this will lead the quickest code in terms of execution time. (Am I wrong ? If so, how much ?) Yes, I value performance more than readability for this question because the desired function will be called a lot (millions) of times.
I am receiving const char *'s of the form "25Dec2016" that represent dates and I am parsing them to back out from them three int's (one for the day, the second for the month and the last for the year (that I assumed to be a number between 0 and 9999)) thanks to a function
Parse(const char * cDate, int & day, int & month, int & year)
I coded such a function and tested it : it works on correct const char*s (those that indeed represent date in my format), but I feel that my use of c functions (atoi for instance) is incorrect, even if I don't see why. There are also other problems :
the code is inelegant (the big if ... else if ... if) : one cannot do a switch statement on a string, but is there an elegant way to do this without resorting the std::map and c++11 ?
surely problematic from a c string point of view (I am not an expert) : for instance, I am really not happy with the way I extract the three substring into "buffers" ... Plus it appears I have problems with not null terminated char arrays that I'd like to correct. I could force a \0 at the end of _day and _year as I did for _month but I find that doing so is awful, so that I suspect a bad "design" of my parsing function
quite bad from an error handling point of view : the function is not a constructor for now, but could finally be, this is the reason why I throw.
I am open to any comments !
Here is the initial code :
Parse(const char * cDate, int & day, int & month, int & year)
{
if (0 == cDate)
{
throw "Error : null string pointer";
}
else
{
if (strlen(cDate) < 8)
{
throw "Error : invalid string format";
}
else
{
char _day[2];
char _month[4];
char _year[5]; // implictely the biggest year we authorize is 99999 ; it should suffice
for (int i = 0; i < 2; ++i)
{
_day[i] = cDate[i];
}
day = atoi(_day); // if fail, Undefined behaviour, see strtol for a more robust cross-platform alternative
char c;
for (int i = 2; i < 5; ++i)
{
c = cDate[i];
_month[i-2] = toupper(c);
}
_month[3] = '\0';
if (0 == strcmp("JAN", _month))
{
month = 1;
}
else if (0 == strcmp("FEB", _month))
{
month = 2;
}
else if (0 == strcmp("MAR", _month))
{
month = 3;
}
else if (0 == strcmp("APR",_month))
{
month = 4;
}
else if (0 == strcmp("MAY", _month))
{
month = 5;
}
else if (0 == strcmp("JUN", _month))
{
month = 6;
}
else if (0 == strcmp("JUL", _month))
{
month = 7;
}
else if (0 == strcmp("AUG", _month))
{
month = 8;
}
else if (0 == strcmp("SEP", _month))
{
month = 9;
}
else if (0 == strcmp("OCT",_month))
{
month = 10;
}
else if (0 == strcmp("NOV", _month))
{
month = 11;
}
else if (0 == strcmp("DEC", _month))
{
month = 12;
}
else
{
throw "Error : invalid month string";
}
for (int i = 5; i < 10; ++i)
{
_year[i-5] = cDate[i];
}
year = atoi(_year);
}
}
}
I finally opted for the function to be a constructor of a Date class, and inspired myself from rici's answer also using strtol as I intended initially (see comment in my initial code) instead of atoi:
#include <cstring> // for strlen
#include <ctype.h> // for toppuer
#include <stdlib.h>
int up(char c)
{
return toupper((unsigned char)(c));
}
Date::Date(const char * cDate)
{
if (0 == cDate)
{
throw "Error : null string pointer";
}
else
{
if (strlen(cDate) < 8)
{
throw "Error : invalid string format. String format is DDMMMYYYY with M's in upper or lower case"; // for now, valid format is 24Oct1979
}
else
{
char * ppEnd;
int day = strtol(cDate, &ppEnd, 10);
if (0 == day)
throw "Error : invalid string format. String format is DDMMMYYYY with M's in upper or lower case";
m_Day = day;
char cMonth[4];
int month;
memcpy(cMonth, &ppEnd[0], 3);
switch (up(cMonth[0]))
{
case 'A':
{
switch (up(cMonth[1]))
{
case 'P': if (up(cMonth[2]) == 'R') month = 4;
break;
case 'U': if (up(cMonth[2]) == 'G') month = 8;
break;
}
break;
}
case 'D':
{
if (up(cMonth[1]) == 'E' && up(cMonth[2]) == 'C')
month = 12;
break;
}
case 'F':
{
if (up(cMonth[1]) == 'E' && up(cMonth[2]) == 'B')
month = 2;
break;
}
case 'J':
{
switch (up(cMonth[1]))
{
case 'A': if (up(cMonth[2]) == 'N')
month = 1;
break;
case 'U': switch (up(cMonth[2]))
{
case 'N': month = 6;
case 'L': month = 7;
}
break;
}
break;
}
case 'M':
{
if (up(cMonth[1]) == 'A')
{
switch (up(cMonth[2]))
{
case 'R': month = 3;
case 'Y': month = 5;
}
}
break;
}
case 'N':
{
if (up(cMonth[1]) == 'O' && up(cMonth[2]) == 'V') month = 11;
break;
}
case 'O':
{
if (up(cMonth[1]) == 'C' && up(cMonth[2]) == 'T') month = 10;
break;
}
case 'S':
{
if (up(cMonth[1]) == 'E' && up(cMonth[2]) == 'P') month = 9;
break;
}
}
m_Month = (Month)month;
int year = strtol(ppEnd + 3, &ppEnd, 10);
if (0 == year)
throw "Error : invalid string format. String format is DDMMMYYYY with M's in upper or lower case";
m_Year = year;
updateSerial();
}
}
}
Remark. Being lazy, I did not throw everywhere I should in the "month" part of the code.
If your system is Posix-compatible, then you could just use strptime with the format %d%b%Y:
bool Parse(const char* date, int& day, int& month, int& year) {
struct tm components;
const char* rest = strptime(date, "%d%b%Y", &components);
if (rest == NULL || *rest != '\0') return false;
day = components.tm_mday;
month = components.tm_mon;
year = components.tm_year + 1900;
return true;
}
That is likely to be as fast as a naive parser, and it is certainly a lot easier to write :)
Otherwise, you should use strtol rather than atoi, since it will let you know both whether the parse was successful and where the next character is. And if you want to parse the month names quickly, you'll want to build a trie, either as a table or directly in code (the table is probably faster, fwiw):
static int up(char c) { return toupper((unsigned char)(c)); }
int parseMonth(const char* p) {
switch (up(p[0])) {
case 'A': {
switch (up(p[1])) {
case 'P': if (up(p[2]) == 'R') return 4;
break;
case 'U': if (up(p[2]) == 'G') return 8;
break;
}
break;
}
case 'D': {
if (up(p[1]) == 'E' && up(p[2]) == 'C') return 12;
break;
}
case 'F': {
if (up(p[1]) == 'E' && up(p[2]) == 'B') return 2;
break;
}
case 'J': {
switch (up(p[1])) {
case 'A': if (up(p[2]) == 'N') return 1;
break;
case 'U': switch (up(p[2])) {
case 'N': return 6;
case 'L': return 7;
}
break;
}
break;
}
case 'M': {
if (up(p[1]) == 'A') {
switch (up(p[2])) {
case 'R': return 3;
case 'Y': return 5;
}
}
break;
}
case 'N': {
if (up(p[1]) == 'O' && up(p[2]) == 'V') return 11;
break;
}
case 'O': {
if (up(p[1]) == 'C' && up(p[2]) == 'T') return 10;
break;
}
case 'S': {
if (up(p[1]) == 'E' && up(p[2]) == 'P') return 9;
break;
}
}
return -1;
}
Solution based on boost Spirit X3
#include <iostream>
#include <memory>
#include <string.h>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
namespace x3 = boost::spirit::x3;
struct Month_ : x3::symbols<std::uint8_t>
{
Month_()
{
add
("Jan", 1)
("Feb", 2)
("Mar", 3)
("Apr", 4)
("May", 5)
("Jun", 6)
("Jul", 7)
("Aug", 8)
("Sep", 9)
("Oct", 10)
("Nov", 11)
("Dec", 12);
}
}month_;
using ResultType = std::tuple<int, int, int>;
namespace grammar
{
using namespace x3;
auto const start_ = rule<struct start_, ResultType>{"start"}
= int_ >> month_ >> int_;
};
int main(int athc, char* argv[])
{
std::string str{"25Dec2016"};
auto beg = std::begin(str);
auto end = std::end(str);
ResultType res;
auto ret = x3::parse(beg,end, grammar::start_, res);
if(ret && (beg==end) )
{
std::cout << "parse done :" << std::get<0>(res) << " " << std::get<1>(res) << " " << std::get<2>(res) << "\n";
}
else
{
std::cout << "parse failed '" << std::string(beg, std::next(beg, 10)) << "'\n";
}
return 0;
}
Note, this works also with char*
Live On Coliru
Here are remarks on your code and some possible simplifications:
You can remove the else branches from the error handling if tests that throw an exception. As a matter of fact, you could just return a completion status instead of throwing exceptions.
Structured exceptions would be more precise than just throwing strings, but I'm not a C++ expert.
If the input string is null-terminated after the year part, there is no need to extract the number fields, but you might want to verify correct formatting.
Using an array to match the month part would greatly simplify that part.
Here is a simpler version:
typedef enum ParseStatus {
Parse_OK = 0,
Parse_NullStringPointer,
Parse_InvalidStringFormat,
Parse_InvalidDayNumber,
Parse_InvalidMonthName,
Parse_InvalidYearNumber
} ParseStatus;
ParseStatus Parse(const char *cDate, int &day, int &month, int &year) {
static const char months[4][12] = {
"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
};
static const int maxday[12] = {
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
char mon[4];
unsigned int dd, mm, yyyy;
char c;
if (!cDate) {
return Parse_NullStringPointer;
}
/* Using sscanf for a simple solution.
* If the string has the correct form, `sscanf` will convert 3 fields.
* extra spaces will be accepted and ignored.
*/
if (sscanf(cDate, "%u%3s%u%c", &dd, mon, &yyyy, &c) != 3) {
return Parse_InvalidStringFormat;
}
/* If you have `strupr(char *);`, you could use it here */
mon[0] = toupper((unsigned char)mon[0];
mon[1] = toupper((unsigned char)mon[1];
mon[2] = toupper((unsigned char)mon[2];
for (mm = 0; mm < 12; mm++) {
if (!strcmp(mon, months[mm]))
break;
}
if (mm >= 12) {
return Parse_InvalidMonthName;
}
/* Further validation on the day number */
if (dd < 1 || dd > 31 || dd > maxday[mm]) {
return Parse_InvalidDayNumber;
}
/* check for leap year, assuming gregorian calendar */
if (dd == 29 && mm == 1 &&
(yyyy % 4 != 0 || (yyyy % 100 == 0 && yyyy % 400 != 0)) {
return Parse_InvalidDayNumber;
}
/* check some limits for the year */
if (yyyy < 1 || yyyy > 9999) {
return Parse_InvalidYearNumber;
}
day = dd;
month = mm + 1;
year = yyyy;
return Parse_OK;
}
If you do not want to use sscanf(), you can use strtol() this way, but it is more cumbersome:
char *p;
int i;
dd = strtol(cDate, &p, 10);
for (i = 0; i < 3 && isalpha((unsigned char)p[i]); i++) {
mon[i] = toupper((unsigned char)p[i]);
}
mon[i] = '\0';
yyyy = strtol(p, &p, 10);
if (*p != '\0') {
return Parse_InvalidStringFormat;
}
When it comes to low level parsing I think std::strtol is your friend because it keeps track of the current pointer position in the string you are parsing. Not that that is critical in this type of string with fixed length components. Also std::strtol has easy error checking.
Also using iterators and algorithms helps to keep things neat and tidy.
This is about as "elegant" as I can make this using low level constructs:
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
void parse(const char* cDate, int& day, int& month, int& year)
{
static const char* months[] =
{
"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
};
char* pos;
day = std::strtol(cDate, &pos, 10);
if(std::distance(cDate, static_cast<const char*>(pos)) != 2)
throw std::runtime_error("bad date format");
char mon[4] = {};
for(auto m = std::begin(mon); m != std::end(mon) - 1; ++m)
*m = std::toupper(*pos++);
auto found = std::find_if(std::begin(months), std::end(months),
[&](const char* m){ return !std::strcmp(mon, m); });
if(found == std::end(months))
throw std::runtime_error("bad month format");
month = std::distance(months, found) + 1;
char* end;
year = std::strtol(pos, &end, 10);
if(std::distance(pos, end) != 4)
throw std::runtime_error("bad year format");
}
int main()
{
try
{
auto s = "25Dec2016";
int d, m, y;
parse(s, d, m, y);
std::cout << d << "/" << m << "/" << y << '\n';
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
N.B. Not heavily tested may contain bugs.

"Program received signal SIGSEGV, Segmentation fault. In ?? () ()" when debugging my C++ project in Code::Blocks

first post here.
I'm doing a university assignment where I'm required to finish implementing a program that simulates the opening bid of a game of contract bridge. I was provided with the following file that contains the main function:
/// File: bridge.cpp
/// Creates a deck of cards, shuffles them and displays them.
#include <iostream>
#include <iomanip>
#include <fstream>
#include "game.h"
const int NUM_DEALS = 4;
using namespace std;
int main(int argc, char *argv[]) {
Game game;
ifstream infile;
bool fromFile = false;
if (argc == 2) {
// open the file and check it exists
infile.open(argv[1]);
if (infile.fail()) {
cerr << "Error: Could not find file" << endl;
return 1;
}
fromFile = true;
}
for (int deal = 0; deal < NUM_DEALS; deal++) {
game.setup(fromFile);
if (fromFile) {
infile >> game;
}
game.deal();
game.auction();
cout << game << endl;
cout << endl << "==============================================================" << endl << endl;
game.nextDealer();
}
// close the file
if (argc == 2) {
infile.close();
}
return 0;
}
I've completed the other classes that simulate the card objects, the deck object, the hand objects and the game object but my program crashed when I clicked "Build and Run". The next logical step was to debug, but when I did so I got the following output in the debugger window:
Building to ensure sources are up-to-date
Selecting target:
Release
Adding source dir: C:\Users\Jack\Documents\CodeBlocks\BridgeAssignment\
Adding source dir: C:\Users\Jack\Documents\CodeBlocks\BridgeAssignment\
Adding file: C:\Users\Jack\Documents\CodeBlocks\BridgeAssignment\bin\Release\BridgeAssignment.exe
Changing directory to: C:/Users/Jack/Documents/CodeBlocks/BridgeAssignment/.
Set variable: PATH=.;C:\Program Files (x86)\CodeBlocks\MinGW\bin;C:\Program Files (x86)\CodeBlocks\MinGW;C:\Program Files (x86)\PHP;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Intel\iCLS Client;C:\Program Files\Intel\iCLS Client;C:\Program Files (x86)\AMD APP\bin\x86_64;C:\Program Files (x86)\AMD APP\bin\x86;C:\Windows\System32;C:\Windows;C:\Windows\System32\wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Sony\VAIO Improvement;C:\Program Files (x86)\Sony\VAIO Startup Setting Tool;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files (x86)\Jahshaka\..\gtk2\bin;C:\Program Files (x86)\Jahshaka\..\mlt\bin;C:\Program Files (x86)\OpenLibraries\bin;C:\Users\Jack\AppData\Local\Smartbar\Application;C:\Program Files\Microsoft\Web Platform Installer;C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0;C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit;C:\Program Files\Microsoft SQL Server\110\Tools\Binn;C:\Program Files (x86)\QuickTime\QTSystem;C:\Program Files (x86)\Autodesk\Backburner
Starting debugger: C:\Program Files (x86)\CodeBlocks\MINGW\bin\gdb.exe -nx -fullname -quiet -args C:/Users/Jack/Documents/CodeBlocks/BridgeAssignment/bin/Release/BridgeAssignment.exe
done
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
Reading symbols from C:\Users\Jack\Documents\CodeBlocks\BridgeAssignment\bin\Release\BridgeAssignment.exe...(no debugging symbols found)...done.
Debugger name and version: GNU gdb (GDB) 7.5
Child process PID: 13628
Program received signal SIGSEGV, Segmentation fault.
In ?? () ()
If it would help in solving the problem, here are my other classes.
Card.h:
#include <string>
#include <iostream>
#ifndef CARD_H
#define CARD_H
using namespace std;
enum Suit {CLUBS, DIAMONDS, HEARTS, SPADES};
enum Rank {TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE};
class Card
{
public:
Card();
Card(Rank rank, Suit suit);
Card(string);
~Card();
Rank getRank();
Suit getSuit();
bool operator() (Card*, Card*);
friend ostream& operator<<(ostream&, Card&);
private:
Suit suit;
Rank rank;
};
#endif // CARD_H
Card.cpp:
#include "card.h"
#include <iostream>
Card::Card()
{
this->suit = CLUBS;
this->rank = TWO;
}
Card::Card(Rank rank, Suit suit)
{
this->suit = suit;
this->rank = rank;
}
Card::Card(string str)
{
char rank = str.at(0);
char suit = str.at(1);
Rank cardRank = TWO;
Suit cardSuit = CLUBS;
switch(rank)
{
case '2': cardRank = TWO;
break;
case '3': cardRank = THREE;
break;
case '4': cardRank = FOUR;
break;
case '5': cardRank = FIVE;
break;
case '6': cardRank = SIX;
break;
case '7': cardRank = SEVEN;
break;
case '8': cardRank = EIGHT;
break;
case '9': cardRank = NINE;
break;
case 'T': cardRank = TEN;
break;
case 'J': cardRank = JACK;
break;
case 'Q': cardRank = QUEEN;
break;
case 'K': cardRank = KING;
break;
case 'A': cardRank = ACE;
break;
}
switch(suit)
{
case 'C': cardSuit = CLUBS;
break;
case 'D': cardSuit = DIAMONDS;
break;
case 'H': cardSuit = HEARTS;
break;
case 'S': cardSuit = SPADES;
break;
}
this->suit = cardSuit;
this->rank = cardRank;
}
Card::~Card()
{
}
Rank Card::getRank()
{
return this->rank;
}
Suit Card::getSuit()
{
return this->suit;
}
bool Card::operator() (Card* cardOne, Card* cardTwo)
{
if (cardOne->getSuit() > cardTwo->getSuit())
{
return cardOne->getRank() >= cardTwo->getRank();
}
else if (cardOne->getSuit() < cardTwo->getSuit())
{
return cardOne->getRank() > cardTwo->getRank();
}
else
{
return cardOne->getRank() > cardTwo->getRank();
}
}
ostream& operator <<(ostream& out, Card& card)
{
string cardID = "";
switch(card.getRank())
{
case TWO: cardID += "2";
break;
case THREE: cardID += "3";
break;
case FOUR: cardID += "4";
break;
case FIVE: cardID += "5";
break;
case SIX: cardID += "6";
break;
case SEVEN: cardID += "7";
break;
case EIGHT: cardID += "8";
break;
case NINE: cardID += "9";
break;
case TEN: cardID += "T";
break;
case JACK: cardID += "J";
break;
case QUEEN: cardID += "Q";
break;
case KING: cardID += "K";
break;
case ACE: cardID += "A";
}
switch(card.getSuit())
{
case CLUBS: cardID += "C";
break;
case DIAMONDS: cardID += "D";
break;
case HEARTS: cardID += "H";
break;
case SPADES: cardID += "S";
break;
}
out << cardID;
return out;
}
Deck.h:
#ifndef DECK_H
#define DECK_H
#include "card.h"
#include <iostream>
using namespace std;
class Deck
{
public:
Deck();
virtual ~Deck();
void reset();
Card* dealNextCard();
void shuffle();
friend ostream& operator<<(ostream&, Deck&);
friend istream& operator>>(istream&, Deck&);
private:
int cardsDealt;
Card** deckArray;
};
#endif // DECK_H
Deck.cpp:
#include "Deck.h"
#include "Card.h"
#include "random.h"
#include <iostream>
Deck::Deck()
{
deckArray = new Card*[52];
int counter = 0;
cardsDealt = 0;
for (int i = 0; i < 13; i++)
{
for (int j = 0; j < 4; j++)
{
*deckArray[counter] = Card((Rank)i, (Suit)j);
counter++;
}
}
}
Deck::~Deck()
{
//dtor
}
void Deck::reset()
{
cardsDealt = 0;
}
Card* Deck::dealNextCard()
{
cardsDealt++;
return deckArray[cardsDealt-1];
}
void Deck::shuffle()
{
Random rand;
int index1 = rand.randomInteger(0,53);
int index2 = rand.randomInteger(0,53);
Card temp = *deckArray[index1];
deckArray[index1] = deckArray[index2];
*deckArray[index2] = temp;
}
ostream& operator<<(ostream& out, Deck& deck)
{
string cards = "";
for (int i = 0; i < 52; i++)
{
out << " " << deck.deckArray[i];
}
return out;
}
istream& operator>>(istream& in, Deck& deck)
{
string text[52];
for (int i = 0; i < 52; i++)
{
in >> text[i];
}
for (int i = 0; i < 52; i++)
{
char rank = text[i].at(0);
char suit = text[i].at(1);
Rank cardRank = TWO;
Suit cardSuit = CLUBS;
switch(rank)
{
case '2': cardRank = TWO;
break;
case '3': cardRank = THREE;
break;
case '4': cardRank = FOUR;
break;
case '5': cardRank = FIVE;
break;
case '6': cardRank = SIX;
break;
case '7': cardRank = SEVEN;
break;
case '8': cardRank = EIGHT;
break;
case '9': cardRank = NINE;
break;
case 'T': cardRank = TEN;
break;
case 'J': cardRank = JACK;
break;
case 'Q': cardRank = QUEEN;
break;
case 'K': cardRank = KING;
break;
case 'A': cardRank = ACE;
break;
}
switch(suit)
{
case 'C': cardSuit = CLUBS;
break;
case 'D': cardSuit = DIAMONDS;
break;
case 'H': cardSuit = HEARTS;
break;
case 'S': cardSuit = SPADES;
break;
}
*deck.deckArray[i] = Card(cardRank, cardSuit);
}
return in;
}
Hand.h:
#ifndef HAND_H
#define HAND_H
#include "card.h"
#include <iostream>
#include <vector>
#include <set>
class Hand
{
public:
Hand();
virtual ~Hand();
void clear();
void addCard(Card*);
string makeBid();
friend ostream& operator<< (ostream&, Hand&);
private:
unsigned int strength;
unsigned int highCardPoints;
unsigned int lengthPoints;
int addHighCards(vector<Card*>);
int findLengthPoints(vector<Card*>);
void getStrength();
bool balanced;
void getBalance();
void getWinningSuit();
set<int> suitLen;
vector<Card*> clubs;
vector<Card*> diamonds;
vector<Card*> hearts;
vector<Card*> spades;
vector< vector<Card*> > winningSuit;
vector<string> winningSuitStr;
};
#endif // HAND_H
Hand.cpp:
#include "Hand.h"
#include "card.h"
#include <vector>
#include <set>
#include <iterator>
#include <iostream>
Hand::Hand()
{
strength = 0;
balanced = false;
}
Hand::~Hand()
{
//dtor
}
void Hand::clear()
{
clubs.clear();
diamonds.clear();
hearts.clear();
spades.clear();
strength = 0;
balanced = false;
}
void Hand::addCard(Card* card)
{
switch(card->getSuit())
{
case CLUBS: clubs.push_back(card);
break;
case DIAMONDS: diamonds.push_back(card);
break;
case HEARTS: hearts.push_back(card);
break;
case SPADES: spades.push_back(card);
break;
}
}
void Hand::getBalance()
{
if ((suitLen.count(4)==2 && suitLen.count(3)==1 && suitLen.count(2)==1)
|| (suitLen.count(4)==1 && suitLen.count(3)==3))
{
balanced = true;
}
else
{
balanced = false;
}
}
void Hand::getWinningSuit()
{
if (clubs.size() >= diamonds.size() && clubs.size() >= hearts.size() && clubs.size() >= spades.size())
{
winningSuit.push_back(clubs);
winningSuitStr.push_back("C");
}
if (diamonds.size() >= clubs.size() && diamonds.size() >= hearts.size() && diamonds.size() >= spades.size())
{
winningSuit.push_back(diamonds);
winningSuitStr.push_back("D");
}
if (hearts.size() >= clubs.size() && hearts.size() >= diamonds.size() && hearts.size() >= spades.size())
{
winningSuit.push_back(hearts);
winningSuitStr.push_back("H");
}
if (spades.size() >= clubs.size() && spades.size() >= diamonds.size() && spades.size() >= hearts.size())
{
winningSuit.push_back(spades);
winningSuitStr.push_back("S");
}
}
int Hand::addHighCards(vector<Card*> suit)
{
int highCardPoints = 0;
for (unsigned int i = 0; i < suit.size(); i++)
{
switch(suit[i]->getRank())
{
case ACE: highCardPoints += 4;
break;
case KING: highCardPoints += 3;
break;
case QUEEN: highCardPoints += 2;
break;
case JACK: highCardPoints += 1;
break;
default:
break;
}
}
return highCardPoints;
}
int Hand::findLengthPoints(vector<Card*> suit)
{
if (suit.size() > 4)
{
return suit.size() - 4;
}
return 0;
}
void Hand::getStrength()
{
highCardPoints = 0;
lengthPoints = 0;
highCardPoints += addHighCards(clubs);
highCardPoints += addHighCards(diamonds);
highCardPoints += addHighCards(hearts);
highCardPoints += addHighCards(spades);
lengthPoints += findLengthPoints(clubs);
lengthPoints += findLengthPoints(diamonds);
lengthPoints += findLengthPoints(hearts);
lengthPoints += findLengthPoints(spades);
strength = highCardPoints + lengthPoints;
}
string Hand::makeBid()
{
suitLen.insert(clubs.size());
suitLen.insert(diamonds.size());
suitLen.insert(hearts.size());
suitLen.insert(spades.size());
getStrength();
getBalance();
getWinningSuit();
if (balanced)
{
if (strength >= 0 && strength <= 12)
{
if (suitLen.count(6)==1)
{
if (winningSuit[0]==clubs)
{
return "PASS";
}
else
{
return "2" + winningSuitStr[0];
}
}
else if (suitLen.count(6)==2)
{
return "2" + winningSuitStr[0];
}
else if (suitLen.count(7)==1)
{
return "3" + winningSuitStr[0];
}
else if (suitLen.count(8)==1)
{
return "4" + winningSuitStr[0];
}
else
{
return "PASS";
}
}
else if (strength >= 13 && strength <= 21)
{
if (winningSuit.size()==2 && winningSuit[0].size()>=5)
{
return "1" + winningSuitStr[0];
}
else if (winningSuit.size()>=2 && winningSuit[0].size()==4)
{
return "1" + winningSuitStr[winningSuitStr.size()-1];
}
else
{
return "1" + winningSuitStr[0];
}
}
else /**< if (strength >= 22)*/
{
return "2C";
}
}
else
{
if (strength >= 0 && strength <= 12)
{
return "PASS";
}
else if (strength == 13 || strength == 14 || strength == 18 || strength == 19)
{
if (clubs.size() == diamonds.size())
{
if (clubs.size() == 4)
{
return "1D";
}
return "1C";
}
else
{
if (clubs.size() > diamonds.size())
{
return "1C";
}
return "1D";
}
}
else if (strength >= 15 && strength <= 17)
{
return "1 NT";
}
else if (strength == 20 || strength == 21)
{
return "2 NT";
}
else
{
return "2C";
}
}
}
ostream& operator<<(ostream& out, Hand& hand)
{
out << "SPADES : ";
for (unsigned int i = 0; i < hand.spades.size(); i++)
{
out << hand.spades[i] << " ";
}
out << endl;
out << "HEARTS : ";
for (unsigned int i = 0; i < hand.hearts.size(); i++)
{
out << hand.hearts[i] << " ";
}
out << endl;
out << "DIAMONDS : ";
for (unsigned int i = 0; i < hand.diamonds.size(); i++)
{
out << hand.diamonds[i] << " ";
}
out << endl;
out << "CLUBS : ";
for (unsigned int i = 0; i < hand.clubs.size(); i++)
{
out << hand.clubs[i] << " ";
}
out << endl;
out << hand.highCardPoints << " HCP, " << hand.lengthPoints << " LP, Total = " << hand.strength << endl;
return out;
}
Game.h:
#ifndef GAME_H
#define GAME_H
#include <iostream>
#include "Deck.h"
#include "Hand.h"
enum Position {NORTH, EAST, SOUTH, WEST};
class Game
{
public:
Game();
virtual ~Game();
void setup(bool);
void deal();
void auction();
void nextDealer();
friend ostream& operator<< (ostream&, Game&);
friend istream& operator>> (istream&, Game&);
private:
Deck gameDeck;
Hand** gameHands;
Position dealer;
string* openingBid;
};
#endif // GAME_H
Game.cpp:
#include "Game.h"
#include "Deck.h"
#include "Hand.h"
#include <iostream>
Game::Game()
{
gameDeck = Deck();
gameHands = new Hand*[4];
gameHands[0] = new Hand();
gameHands[1] = new Hand();
gameHands[2] = new Hand();
gameHands[3] = new Hand();
dealer = NORTH;
}
Game::~Game()
{
//dtor
}
void Game::setup(bool fromFile)
{
if (!fromFile)
{
gameDeck.shuffle();
gameDeck.reset();
for (unsigned int i = 0; i < 4; i++)
{
gameHands[i]->clear();
}
}
}
void Game::deal()
{
for (unsigned int i = 0; i < 52; i++)
{
gameHands[(i%4)+1]->addCard(gameDeck.dealNextCard());
}
}
void Game::auction()
{
openingBid = new string[2];
openingBid[0] = "PASS";
openingBid[1] = "PASS";
for (unsigned int i = 0; i < 4; i++)
{
if (gameHands[i]->makeBid() != "PASS")
{
switch(i)
{
case 0: openingBid[0] = "NORTH";
break;
case 1: openingBid[0] = "EAST";
break;
case 2: openingBid[0] = "SOUTH";
break;
case 3: openingBid[0] = "WEST";
break;
}
openingBid[1] = gameHands[i]->makeBid();
break;
}
}
}
void Game::nextDealer()
{
int temp = (int)dealer;
temp++;
temp = temp % 4;
dealer = (Position)temp;
}
ostream& operator<< (ostream& out, Game& game)
{
out << "NORTH";
out << game.gameHands[0];
out << endl;
out << "EAST";
out << game.gameHands[1];
out << endl;
out << "SOUTH";
out << game.gameHands[2];
out << endl;
out << "WEST";
out << game.gameHands[3];
out << endl;
return out;
}
istream& operator>> (istream& in, Game& game)
{
in >> game.gameDeck;
return in;
}
Also here is the premade random class I'm using.
Random.h:
#ifndef _random_h
#define _random_h
/// This class provides several functions for generating pseud-random numbers.
///
class Random {
public:
/// \brief
///
/// Initialize the randomizer.
///
Random();
/// \brief
///
/// Generates a random integer number greater than or equal to low and less than high.
/// \param low int - lower bound for range (inclusive).
/// \param high int - upper bound for range (exclusive).
/// \return int - A random integer number greater than or equal to low and less than high.
///
int randomInteger(int low, int high);
/// \brief
/// Generates a random real number greater than or equal to low and less than high.
///
/// \param low double - lower bound for range (inclusive).
/// \param high double - upper bound for range (exclusive).
/// \return double - A random real number greater than or equal to low and less than high.
///
double randomReal(double low, double high);
/// \brief
/// Generates a true false outcome based on the probability p.
/// Calling randomChance(0.30) returns true 30% of the time.
///
/// \param p double - Value between 0 (never) and 1 (always).
/// \return bool - true or false based on p.
///
bool randomChance(double p);
private:
/// \brief
///
/// Initializes teh random-number generator so that its results are unpredictable. If this function is
/// not called the other functions will return the same values on each run.
///
void randomize();
};
#endif // _random_h
Random.cpp:
#include <cstdlib>
#include <ctime>
#include "random.h"
/// This class provides several functions for generating pseud-random numbers.
///
Random::Random() {
randomize();
}
/// \brief
/// Generates a random integer number greater than or equal to low and less than or equal to high.
///
/// \param low int - lower bound for range (inclusive).
/// \param high int - upper bound for range (inclusive).
/// \return int - A random integer number greater than or equal to low and less than or equal to high.
///
int Random::randomInteger(int low, int high) {
double d = double(rand()) / (double(RAND_MAX) + 1);
int k = int(d * (high - low + 1));
return low + k;
}
/// \brief
/// Generates a random real number greater than or equal to low and less than high.
///
/// \param low double - lower bound for range (inclusive).
/// \param high double - upper bound for range (exclusive).
/// \return double - A random real number greater than or equal to low and less than high.
///
double Random::randomReal(double low, double high) {
double d = double(rand()) / (double(RAND_MAX) + 1);
return low + d * (high - low);
}
/// \brief
/// Generates a true false outcome based on the probability p.
/// Calling randomChance(0.30) returns true 30% of the time.
///
/// \param p double - Value between 0 (never) and 1 (always).
/// \return bool - true or false based on p.
///
bool Random::randomChance(double p) {
return randomReal(0, 1) < p;
}
/// \brief
///
/// Initializes the random-number generator so that its results are unpredictable. If this function is
/// not called the other functions will return the same values on each run.
///
void Random::randomize() {
srand(int(time(NULL)));
}
I've been hunting around the internet for solutions to this problem, but nothing seemed to fit my scenario, with the crash on run and the SIGSEGV on debug. Hoping someone here can help me, I'm getting desperate lol.
Thanks.
Your code is way too much to be sure but the problem resides very likely in yout deck constructor.
Deck::Deck()
{
// Here you allocate space for 52 pointers, not Cards
deckArray = new Card*[52];
...
// at this location there's no space for a card but for a pointer
//*deckArray[counter] = Card((Rank)i, (Suit)j);
// so you should do this instead:
deckArray[counter] = new Card((Rank)i, (Suit)j);
// to allocate needed space for the card
...
}
To sum it up, you never allocate the space needed to store the cards.
The deckArray in Deck is an array of pointers, but you never allocate its elements.
This means that all your assignments through these pointers are invalid dereferences whose behaviour is undefined.
You need to either allocate those elements with new, or avoid pointers, which is usually the best way.
Replacing Hand** gameHands; with Hand gameHands[4]; and Card** deckArray; with Card deckArray[52]; would be a good start.
(Unlike in java, where "new" is the only way to instantiate classes, C++ programmers usually only use that word when necessary.)
SIGSEGV usually raises when you dereference a nullpointer or uninitialized pointer.
If you don't know how to use breakpoints, I suggest using logging macro to figure out, where the problem is. For example:
//#define NOLOGGING // uncomment this line to disable logging
#include <iostream>
#ifndef NOLOGGING
#define LOG(msg)
#else
#define LOG(msg) std::cout << "[LOG] (" __FILE__ ":" << __LINE__ << ") from " << __func__ << "()\n " << msg << "\n";
#endif
You are targeting the Release version of the project, and you don't get any debug information. Change the build target to Debug and you would get:
Building to ensure sources are up-to-date
Selecting target:
Debug
done
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
Debugger name and version: GNU gdb (GDB) 7.6.1-ubuntu
Program received signal SIGSEGV, Segmentation fault.
At /home/user/src/card/bridge/Deck.cpp:15
Which would lead you to the answer dogiordano provided.
Make sure you are giving argument at load time with a run command (parallelly) in your gdb as example:
fix.c
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char** argv)
{
int sum;
sum=(atoi(argv[1])+ atoi( argv[2]));
printf("sum=%d",sum);
}
I compile with option -g
gcc -g fix.c
gdb a.out
you will be enter to gdb here you need to run your code in gdb with argument note if command line argument are missed
run enter (missing argument)
"Program received signal SIGSEGV, Segmentation fault."
so give here make sure to give argument
run 1 2
Now its good !!

What does my destructor need to be in this function?

My program executes fine, except at the end, when I debug it, it's getting a segmentation error after calling my destructor. I'm not sure what the cause of the issue is. I've posted 2 of the relevant files.
Breakpoint 1, main () at Prog3.cc:12
12 cout << "Program executed" << endl;
(gdb) s
Program executed
~Lex (this=0x80375c4) at lex.cc:36
36 delete [] str;
(gdb) s
37 }
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0xfef49418 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string () from /usr/sfw/lib/libstdc++.so.6
(gdb) Quit
lex.h is below:
#ifndef LEX_H
#define LEX_H
#include "token.h"
#include <iostream>
#include <stdlib.h>
class Lex {
public:
Lex(istream& in, string fileName);
//Lex();
//Lex(const Lex& l);
~Lex();
static const int INTLIT = 1;
static const int FLOATLIT = 2;
static const int STRLIT = 3;
static const int IDENT = 4;
static const int PLUS = 5;
static const int MINUS = 6;
static const int TIMES = 7;
static const int DIVIDE = 8;
static const int REM = 9;
static const int ASSIGN = 10;
static const int LPAREN = 11;
static const int RPAREN = 12;
static const int COMMA = 13;
static const int EQ = 14;
static const int LT = 15;
static const int LE = 16;
static const int GT = 17;
static const int GE = 18;
static const int NE = 19;
static const int SET = 20;
static const int PRINT = 21;
static const int WHILE = 22;
static const int DO = 23;
static const int END = 24;
static const int AND = 25;
static const int OR = 26;
static const int IF = 27;
static const int THEN = 28;
static const int ELSE = 29;
static const int ENDIF = 30;
static const int PROGRAM = 31;
static const int ENDOFFILE = 32;
static const int ERROR = 33;
int charIndex;
int lineIndex;
int spaceIndex;
int lineNum;
int lineLength[100];
char ch;
bool hashCheck;
bool stopLoop;
Token nextToken();
char nextChar();
char str[256][256];
bool checkSet;
void printLex();
string idents[256];
int identCount;
friend ostream& operator<<(ostream& out, const Token& t);
};
#endif
#include "lex.h"
#include "token.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
lex.cc is here.
Lex::Lex(istream& in, string fileName) {
stopLoop = false;
charIndex = 0;
lineIndex = 0;
identCount = 0;
lineNum = 0;
hashCheck = false;
checkSet = false;
int tempSize;
ifstream file;
string temp;
for (int i = 0; i < 100; ++i)
lineLength[i] = 0;
if (!file.is_open()) { file.open(fileName.c_str()); }
while(!file.eof()) {
std::getline(file,temp);
tempSize = temp.size();
for (int i = 0; i < tempSize; ++i) {
str[lineNum][i] = temp[i];
lineLength[lineNum] += 1;
}
lineNum++;
}
file.close();
}
Lex::~Lex() {
delete [] str;
}
void Lex::printLex() {
charIndex = 0;
lineIndex = 0;
while (stopLoop == false) {
cout << nextToken();
// cout << "Line index: " << lineIndex << endl;
}
}
ostream& operator <<(ostream& out, const Token& t) {
out << t.type() << " \t " << t.lexeme() << " \t \t " << (t.line() + 1) << " \t \t " << t.pos() << endl;
return out;
}
bool isReal(char ch) {
string alphabet = "abcdefghijklmnopqrstuvwxyz1234567890(){}<>+-/=!*,%&|.";
if (alphabet.find(ch) != alphabet.npos) return true;
else return false;
}
bool isNum(char ch) {
string specialChars = "1234567890.";
if (specialChars.find(ch) != specialChars.npos) return true;
else return false;
}
bool isNumFinal(string b) {
int length = b.length();
const char* temp = b.c_str();
bool henry = true;
for (int i = 0; i < length; ++i) {
if (henry == false) { break; }
henry = isNum(temp[i]);
}
return henry;
}
bool isSpecialChar(char ch) {
string specialChars = "(){}<>+-/=!*,%&|";
if (specialChars.find(ch) != specialChars.npos) return true;
else return false;
}
char Lex::nextChar() {
if (lineIndex >= lineNum) {
// cout << "End of file reached\n";
stopLoop = true;
return '#';
}
else if (charIndex >= lineLength[lineIndex]) {
lineIndex++;
charIndex = 0;
return nextChar();
}
else if (str[lineIndex][charIndex] == '#') {
hashCheck = true;
while (hashCheck = true) {
if (str[lineIndex][charIndex] == '#') { hashCheck = false; }
charIndex++;
if (charIndex > lineLength[lineIndex]) {
charIndex = 0;
lineIndex++;
}
}
}
else {
ch = str[lineIndex][charIndex];
charIndex++;
return ch;
}
cout << "you shouldn't be here\n";
return str[lineIndex][charIndex];
}
Token Lex::nextToken() {
if (charIndex == lineIndex && charIndex == 0) { ch = nextChar(); }
while (ch == ' ') { ch = nextChar(); }
// cout << "CI: " << charIndex << endl;
string build;
int tempCharIndex = charIndex;
int tempLineIndex = lineIndex;
build += ch;
if (charIndex == lineIndex && charIndex == 0) { build = ""; }
if (checkSet == true) {
checkSet = false;
while (ch != ' ' && tempLineIndex == lineIndex) {
ch = nextChar();
if (ch != ' ' && tempLineIndex == lineIndex)
build += ch;
}
idents[identCount] = build;
identCount++;
return Token(IDENT, build, tempLineIndex, tempCharIndex);
}
else if (isSpecialChar(ch)) {
switch(ch) {
case '(':
ch = nextChar();
return Token(LPAREN, build, tempLineIndex, tempCharIndex);
case ')':
ch = nextChar();
return Token(RPAREN, build, tempLineIndex, tempCharIndex);
case '{':
ch = nextChar();
return Token(THEN, build, tempLineIndex, tempCharIndex);
case '}':
ch = nextChar();
return Token(ENDIF, build, tempLineIndex, tempCharIndex);
case '+':
ch = nextChar();
return Token(PLUS, build, tempLineIndex, tempCharIndex);
case '-':
ch = nextChar();
return Token(MINUS, build, tempLineIndex, tempCharIndex);
case '/':
ch = nextChar();
return Token(DIVIDE, build, tempLineIndex, tempCharIndex);
case '*':
ch = nextChar();
return Token(TIMES, build, tempLineIndex, tempCharIndex);
case '=':
ch = nextChar();
if (ch == '=') {
build += ch;
ch = nextChar();
return Token(EQ, build, tempLineIndex, tempCharIndex);
}
else {
return Token(ASSIGN, build, tempLineIndex, tempCharIndex);
}
case '>':
ch = nextChar();
if (ch == '=') {
build += ch;
ch = nextChar();
return Token(GE, build, tempLineIndex, tempCharIndex);
}
else return Token(GT, build, tempLineIndex, tempCharIndex);
case '<':
ch = nextChar();
if (ch == '=') {
build += ch;
ch = nextChar();
return Token(LE, build, tempLineIndex, tempCharIndex);
}
else return Token(LT, build, tempLineIndex, tempCharIndex);
case '!':
ch = nextChar();
if (ch == '=') {
build += ch;
ch = nextChar();
return Token(NE, build, tempLineIndex, tempCharIndex);
}
else return Token(ERROR, build, tempLineIndex, tempCharIndex);
case '%':
ch = nextChar();
return Token(REM, build, tempLineIndex, tempCharIndex);
case '&':
ch = nextChar();
return Token(AND, build, tempLineIndex, tempCharIndex);
case '|':
ch = nextChar();
return Token(OR, build, tempLineIndex, tempCharIndex);
default:
return Token(ERROR, build, tempLineIndex, tempCharIndex);
}
}
else if (isNum(ch)) {
tempCharIndex = charIndex;
while (ch != ' ' && tempLineIndex == lineIndex) {
ch = nextChar();
if (isSpecialChar(ch)) {
break;
}
if (ch != ' ' && tempLineIndex == lineIndex)
build += ch;
}
if (isNumFinal(build)) {
if (build.find('.') != build.npos)
return Token(FLOATLIT, build, tempLineIndex, tempCharIndex);
else return Token(INTLIT, build, tempLineIndex, tempCharIndex);
}
else return Token(ERROR, build, tempLineIndex, tempCharIndex);
}
else {
tempCharIndex = charIndex;
while (ch != ' ' && tempLineIndex == lineIndex) {
ch = nextChar();
// cout << "ch: " << ch << endl;
if (ch != ' ' && tempLineIndex == lineIndex)
//cout << "inserted: " << ch << endl;
build += ch;
}
if (build.compare("while") == 0)
return Token(WHILE, build, tempLineIndex, tempCharIndex);
else if (build.compare("if") == 0)
return Token(IF, build, tempLineIndex, tempCharIndex);
else if (build.compare("print") == 0)
return Token(PRINT, build, tempLineIndex, tempCharIndex);
else if (build.compare("end") == 0)
return Token(ENDOFFILE, build, tempLineIndex, tempCharIndex);
else if (build.compare("else") == 0)
return Token(ELSE, build, tempLineIndex, tempCharIndex);
else if (build.compare("do") == 0) { return Token(DO, build, tempLineIndex, tempCharIndex); }
else if (build.compare("set") == 0) {
checkSet = true;
// cout << "CI: " << str[lineIndex] << endl;
return Token(SET, build, tempLineIndex, tempCharIndex);
}
else {
for (int i = 0; i < identCount; ++i) {
if (build.compare(idents[i]) == 0) { return Token(IDENT, build, tempLineIndex, tempCharIndex); }
}
cout << "build:" << build << ".\n";
return Token(STRLIT, build, tempLineIndex, tempCharIndex);
}
}
}
Don't call delete[] unless you called new[]. str is a statically sized array in your class, you need neither new[] nor delete[] for it.
Your class consists entirely of objects which will either handle their own cleanup, or need no cleanup, so your destructor can simply be empty. Don't even declare it, and the compiler will provide the correct destructor for you in this case.
str does not have dynamic storage duration but you are trying to delete it in the destructor. Remove delete[] str from your destructor.
You also are not doing any bounds checking when you fill str. This may cause you to overwrite other member variables causing additional problems and is likely the cause of the fault you are experiencing.
// tempSize and/or lineNum may be greater than 256
for (int i = 0; i < tempSize; ++i) {
str[lineNum][i] = temp[i];
lineLength[lineNum] += 1;
}
You have
Lex::~Lex() {
delete [] str;
}
in your code, but str is not heap allocated. It is a data member of your Lex class
I believe a recent GCC invoked as g++ -Wall -g would probably have warned you about that mistake.
Well, cause you don't need to delete the str array at all, it's not created by you using new so you don't need to call delete.
VS gives me :
warning C4154: deletion of an array expression; conversion to pointer supplied