need help with function calls

I am getting a Debug Error that I can't seem to figure out. I'm guessing its how my functions are calling other functions (and not the code).

The message in the error said "the value of ESP was not properly saved across a function call. This is a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."

The program runs and once functionCall4( ) is called and the code is executed, it crashes.

void main( )
{
stuff...;
functionCall1( );
functionCall2(int param1, int param2);
}

void functionCall1( )
{
stuff... ;
}

void functionCall2(int param1, int param2)
{
stuff... ;
if (whatever)
{
functionCall3( );
}
else
{
functionCall4( );
}
}

void functionCall3( )
{
stuff... ;
functionCall2(int paramA[0], int paramA[1]);
}

void functionCall4( )
{
stuff...;
}

P.S.. Where is the "Code" button?? It says to use this option when including code.
[1175 byte] By [mdumont] at [2007-11-20 11:57:14]
# 1 Re: need help with function calls
P.S.. Where is the "Code" button?? It says to use this option when including code.
Surround the code with [ CODE] and [ /CODE] (without the spaces after the '['.

Now post your actual code, preferable a compilable small example that reproduces the error you are getting. We can not help if you keep writing "whatever" and "stuff" in your code. That might be important.

Laitinen
laitinen at 2007-11-11 4:01:58 >
# 2 Re: need help with function calls
I didnt include the code b/c I thought it was how my functions move from one to the other, and because there is lot. However, I guess it would help. Here it is.

Thanks!

#include <iostream>
#include <fstream>
#include <string>

#include <ctime> // For time()
#include <time.h>
#include <cstdlib> // For srand() and rand()

using namespace std;

//*** Functions ***
void RollDice(int d1, int d2, int d3, int d4, int d5);
void DisplayScorePad();
void TakeScore();
void KeepDice();

//*** Global Variables ***
int TurnsLeft; //# of turns left. TurnsLeft=0 means game over
int RollsLeft; //# of rolls left in turn. RollsLeft = 0 means player must score before next turn.
int Dice[4]; //represents dice 1 through dice 5. Possible values are between 1 and 6
int Points; // represents points obtained for certain functions. Initial value set (or re-set) to
//zero at the start of each function that uses it

struct Score //all variables used to set values on score pad
{
int
Ones,
Twos,
Threes,
Fours,
Fives,
Sixes,
UpperSubTotal,
BonusPoints,
UpperSectionTotal,

ThreeKind,
FourKind,
FullHouse,
SmStraight,
LrgStraight,
Yahtzee,
Chance,
BonusYahtzee,

LowerSectionTotal,
GrandTotalScore,
RollsLeft,
TurnsLeft;
};

Score ScorePad;

//*** Start ***
void main()
{
char rules, ready; //answer variables
// variables for displaying text file of written rules of the game, if player chooses to
string line;
ifstream rulesFile;

// Ask Player if they want to see game rules, Display contents of rules.txt file if requested
cout << "Welcome to YAHTZEE!" << endl;
cout << "This is a Single Player game.\n";
cout << "The best possible score you can achieve is 375 points." << endl << endl;
cout << "Would you like to review the Rules of YAHTZEE? Y/N: ";
cin >> rules;
cout << endl << endl;

if ((rules == 'Y')|| (rules == 'y'))
{
rulesFile.open("rules.txt");

if (rulesFile.is_open())
{
while (! rulesFile.eof())
{
getline (rulesFile,line);
cout << line << endl;
}
rulesFile.close();
}
else
{
cout << "\nUnable to open file."<< endl << endl;
}
}


cout << "\n\nAre you ready to begin play? Y/N: ";
cin >> ready;

if ((ready == 'Y') || (ready == 'y'))
{
//Set initial values for # or turns, rolls, and score sums
TurnsLeft = 13;
RollsLeft =3;
ScorePad.UpperSubTotal = 0;
ScorePad.BonusPoints = 0;
ScorePad.UpperSectionTotal =0;
ScorePad.LowerSectionTotal =0,
ScorePad.GrandTotalScore =0;

system("cls");
cout << "This is your score pad."<< endl << endl;

DisplayScorePad( );

cout << "Let's Begin!!" << endl << endl;
RollDice(0,0,0,0,0); // First roll, all 5 dice are rolled

}
else
{
cout << "Goodbye" << endl;
}

} //end of main()

/**************************************************************************************
Each time the score pad is displayed, the Upper & Lower section totals will be recalculated
with the score box variables that are initialized.
**************************************************************************************/
void DisplayScorePad()
{
if (ScorePad.Ones !=NULL)
{
ScorePad.UpperSubTotal = ScorePad.UpperSubTotal + ScorePad.Ones;
}
if (ScorePad.Twos !=NULL)
{
ScorePad.UpperSubTotal = ScorePad.UpperSubTotal + ScorePad.Twos;
}
if (ScorePad.Threes !=NULL)
{
ScorePad.UpperSubTotal = ScorePad.UpperSubTotal + ScorePad.Threes;
}
if (ScorePad.Fours !=NULL)
{
ScorePad.UpperSubTotal = ScorePad.UpperSubTotal + ScorePad.Fours;
}
if (ScorePad.Fives !=NULL)
{
ScorePad.UpperSubTotal = ScorePad.UpperSubTotal + ScorePad.Fives;
}
if (ScorePad.Sixes !=NULL)
{
ScorePad.UpperSubTotal = ScorePad.UpperSubTotal + ScorePad.Sixes;
}
if (ScorePad.UpperSubTotal > 62)
{
ScorePad.BonusPoints = 35;
}

ScorePad.UpperSectionTotal = (ScorePad.UpperSubTotal + ScorePad.BonusPoints);


if (ScorePad.ThreeKind !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.ThreeKind;
}
if (ScorePad.FourKind !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.FourKind;
}
if (ScorePad.FullHouse !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.FullHouse;
}
if (ScorePad.SmStraight !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.SmStraight;
}
if (ScorePad.LrgStraight !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.LrgStraight;
}
if (ScorePad.Yahtzee !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.Yahtzee;
}
if (ScorePad.Chance !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.Chance;
}
if (ScorePad.BonusYahtzee !=NULL)
{
ScorePad.LowerSectionTotal = ScorePad.LowerSectionTotal + ScorePad.BonusYahtzee;
}

ScorePad.GrandTotalScore = (ScorePad.UpperSectionTotal + ScorePad.LowerSectionTotal);
ScorePad.RollsLeft = RollsLeft;
ScorePad.TurnsLeft = TurnsLeft;

//Display score pad
cout << "***********************************************************************************************************"<< endl;
cout << "* YAHTZEE Score Pad *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* Upper Section ** Lower Section *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* 1 | ONES - sum of all Ones : " << ScorePad.Ones;
cout << " ** 7 | THREE OF A KIND - sum of all dice : " << ScorePad.ThreeKind;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* 2 | TWOS - sum of all Twos : " << ScorePad.Twos;
cout << " ** 8 | FOUR OF KIND - sum of all dice : " << ScorePad.FourKind;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* 3 | THREES - sum of all Threes : " << ScorePad.Threes;
cout << " ** 9 | FULL HOUSE - 25 points : " << ScorePad.FullHouse;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* 4 | FOURS - sum of all Fours : " << ScorePad.Fours;
cout << " ** 10 | SM STRAIGHT - 30 points : " << ScorePad.SmStraight;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* 5 | FIVES - sum of all Fives : " << ScorePad.Fives;
cout << " ** 11 | LRG STRAIGHT - 40 points : " << ScorePad.LrgStraight;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* 6 | SIXES - sum all all Sixes : " << ScorePad.Sixes;
cout << " ** 12 | YAHTZEE - 50 points : " << ScorePad.Yahtzee;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* ** 13 | CHANCE - sum of all dice : " << ScorePad.Chance;
cout << " *" << endl;
cout << "* ******************************************************" << endl;
cout << "* ** 14 | BONUS YAHTZEE - 100 points each : " << ScorePad.BonusYahtzee;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* ** *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* Sub Total : " << ScorePad.UpperSubTotal;
cout << " ** *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* Bonus Points of 35 if Sub Total is over 62 : " << ScorePad.BonusPoints;
cout << " ** *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* Upper Section Total : " << ScorePad.UpperSectionTotal;
cout << " ** Lower Section Total : " << ScorePad.LowerSectionTotal;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* GRAND TOTAL : " << ScorePad.GrandTotalScore;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << "* Rolls Left: " << ScorePad.RollsLeft << " * Turns Left: " << ScorePad.TurnsLeft;
cout << " *" << endl;
cout << "***********************************************************************************************************" << endl;
cout << endl << endl << endl;

} //end DisplayScore()

/**************************************************************************************
This function uses parameters to determine which dice[x] to roll. A zero value indicates
the die is to be rolled. A non-zero value indicates that die is to be 'kept'
***************************************************************************************/
void RollDice(int d1, int d2, int d3, int d4, int d5)
{
Dice[0] = d1;
Dice[1] = d2;
Dice[2] = d3;
Dice[3] = d4;
Dice[4] = d5;

char role_score; //answer variable

const int low = 1;
const int high =6;
time_t seconds;
time(&seconds);

srand((unsigned int)seconds);

cout << "**************************************************************************" << endl;
cout << "Rolling the dice." << endl;

if (Dice[0] ==0)
{
Dice[0] = rand() % (high - low + 1) + low;
}
if (Dice[1] ==0)
{
Dice[1] = rand() % (high - low + 1) + low;
}
if (Dice[2] ==0)
{
Dice[2] = rand() % (high - low + 1) + low;
}
if (Dice[3] ==0)
{
Dice[3] = rand() % (high - low + 1) + low;
}
if (Dice[4] ==0)
{
Dice[4] = rand() % (high - low + 1) + low;
}

RollsLeft = RollsLeft--;

cout << "\n\nDice 1 = " << Dice[0] << endl;
cout << "Dice 2 = " << Dice[1] << endl;
cout << "Dice 3 = " << Dice[2] << endl;
cout << "Dice 4 = " << Dice[3] << endl;
cout << "Dice 5 = " << Dice[4] << endl << endl;

if (RollsLeft == 0)
{
TakeScore();
}
else
{
cout << "RollsLeft = " << RollsLeft << endl;
cout << "Do you want to roll again or score now? R/S: ";
cin >> role_score;

if ((role_score == 'S') || (role_score == 's'))
{
TakeScore();
}
else if ((role_score == 'R') || (role_score == 'r'))
{
KeepDice();
}
else
{
cout << "\nInvalid Answer." << endl;
}
}

} // end of RollDice

/**************************************************************************************
This function passes five parameters back to RollDice( ), which represents each of the
five dice. Playe's input flags which die to keep (if any) before they roll again
**************************************************************************************/
void KeepDice()
{
char diekeep[4]; //char var that = input and transfer the info to each die[x]
int die[4]; //int variable used to pass parameters back to RollDice( )

cout << "\nWhich dice do you want to keep?" << endl;
cout << "Your entry must follow the format xxxxx which represents each dice." << endl;
cout << "Enter a non-zero value to keep and a zero value to roll." << endl;
cout << "Example 1: 10045 - means you want to keep dice 1, 4, 5, and re-roll dice 2 and 3" << endl;
cout << "Example 2: 00000 - means you want to roll all 5 dice." << endl << endl;
cout << "Enter your choices: ";
cin >> diekeep;

for (int i=0; i<=4; i++)
{
if (diekeep[i] == '0')
{
die[i] = 0;
}
else
{
die[i] = 1;
}
}

RollDice(die[0], die[1], die[2], die[3], die[4]);

} //end of KeepDice

/**************************************************************************************
Player is ready to score points in available option box. Ask player what score box they
want to score in. If the chosen score box is available, then run function of chosen option
else, tell player it's an invalid selection and offer choices again. Once score has been
taken, decrease TurnsLeft.

If TurnsLeft !=0 then reset RollsLeft and decrease TurnsLeft by 1, or
Else Game Over, Ask if player wants to play again.

If Y, rerun, else end program
**************************************************************************************/

void TakeScore()
{
cout << "yes" << endl;
} //end of TakeScore()
mdumont at 2007-11-11 4:03:04 >
# 3 Re: need help with function calls
...preferable a compilable small example that reproduces the error...It is impossible to find your errors without actually running your code and doing some debugging. I dont want to do that. But you should learn to debug your program yourself. You will never succeed as a programmer without being familiar with the debugger.

When your program crash, break into the code and have a look at your variables and your call stack. Also put some breakpoints at critical sections in your code to check that everything is as it is supposed to be.

You might also want to try to single step through your app line by line. This is very good way of learning, to watch how your variables and objects changes.

What IDE are you using?

Laitinen
laitinen at 2007-11-11 4:04:05 >
# 4 Re: need help with function calls
int Dice[4];
This only allocates an array with 4 elements, indexed 0 thru 3. Yet, you are assigning to index 4:
void RollDice(int d1, int d2, int d3, int d4, int d5)
{
Dice[0] = d1;
Dice[1] = d2;
Dice[2] = d3;
Dice[3] = d4;
Dice[4] = d5;
This is a bug, and undefined behavior.

Viggy
MrViggy at 2007-11-11 4:05:11 >
# 5 Re: need help with function calls
I didnt include the code b/c I thought it was how my functions move from one to the other, and because there is lot. However, I guess it would help. Here it is.

int Dice[4];
//...
Dice[0] = d1;
Dice[1] = d2;
Dice[2] = d3;
Dice[3] = d4;
Dice[4] = d5;

Do you see a problem with this? You've declared Dice as an array of 4 ints, and you're sticking 5 ints into this array. This is a memory overwrite, and one of the errors that can trigger the message about "ESP" that you're seeing.

Regards,

Paul McKenzie
Paul McKenzie at 2007-11-11 4:06:04 >
# 6 Re: need help with function calls
I am using MS Visual C++.

I already stepped through the code, put in breakpoints, followed through the code step by step through my calls and through the library files -- all that you suggested. The FULL program runs, it crashes after the very last line executes [which is a simple cout << "yes";] and the debugger brings me to a file_chkesp.c. I don't know what I'm looking at and thus my reason for my post. My guess is the way in which my functions are calling each other. I tried alternative solutions to pinpoint the problem but I keep getting the same message so obviously I am trying the wrong thing.

I appreciate you looking at my code but your comment assumes I haven't attempted to figure this out on my own. I tried to slim down my example in my original post, and my first question was whether the order in which the functions are called was incorrect. I'm at a point where I don't know where/what/how to debug next and asking this was my starting point.
mdumont at 2007-11-11 4:07:03 >
# 7 Re: need help with function calls
MrViggy & Paul,

I see the error (thanks)! and it turns out I removed that code before I saw your response. Instead of using Dice[0]... in my if statements, I am just using the paramaters.. For example:

if (d1 ==0)
{
Dice[0] = rand() % (high - low + 1) + low;
}

But, I'm still getting the same debug message.
mdumont at 2007-11-11 4:08:07 >
# 8 Re: need help with function calls
I'm not clear. Did you fix the length of the array or not?
Lindley at 2007-11-11 4:09:13 >
# 9 Re: need help with function calls
MrViggy & Paul,

I see the error (thanks)! and it turns out I removed that code before I saw your response. Instead of using Dice[0]... in my if statements, I am just using the paramaters.. For example:

if (d1 ==0)
{
Dice[0] = rand() % (high - low + 1) + low;
}

This is no indication that you fixed the error.

The Dice array is too small. All you needed to do was to declare it properly:

int Dice[5];

Then leave the rest of the code alone. Then report back if you get the error. If you still get the error, please post your current code.

Some other comments:

1) The main() function returns int, not void.

int main()

2) Even though ScorePad is global, you should still initialize the members to 0 just in case it no longer becomes global.

If the members will all be ints, then you can initialize it this way:

memset(&ScorePad, 0, sizeof(ScorePad));

However I recommend a constructor if in the future you add members to the struct that are non-integral.

3) There are some patterns in your display code. Proper usage of arrays would cut down the coding. Also, I would consider that you pass things as reference parameters, and not rely on global variables.

4) Another thing -- why are you checking for NULL on an int in the display code? First, you should be checking for 0. However, if the int is 0, there is no harm in adding 0 to the total, so why the check? Get rid of the NULL checks altogether.

Here is a version of the Score struct that has the difference of using an array, and how the display function is invoked:

struct Score //all variables used to set values on score pad
{
int Singles[6]; // replaces Ones, Twos, ... Sixes

UpperSubTotal,
BonusPoints,
UpperSectionTotal,

ThreeKind,
FourKind,
FullHouse,
SmStraight,
LrgStraight,
Yahtzee,
Chance,
BonusYahtzee,

LowerSectionTotal,
GrandTotalScore,
RollsLeft,
TurnsLeft;
};
'
//...
DisplayScorePad( ScorePad );
//...
void DisplayScorePad(Score& theScores)
{
for (int i = 0; i < 6; ++i )
theScores.UpperSubTotal += theScores.Singles[i];

if (theScores.UpperSubTotal > 62)
theScores.BonusPoints = 35;
// etc...
}

You would need to change your code to use Singles[0] for Ones, Singles[1] for Twos, etc.

Note that it is a simple loop, and regardless, get rid of the NULL checks.

Regards,

Paul McKenzie
Paul McKenzie at 2007-11-11 4:10:10 >
# 10 Re: need help with function calls
Lindley.. yes, I did correct my error Dice[5] in the global variables;

Paul, I do have responses to your questions but I will try the things you suggested first. One thing I can say now, however, is I NEED to check for NULL (instead of 0). A zero value is a valid score and indicates an intentional score of zero. Once a score option has been used (zero or any number of points) it is no longer available. A null value indicates the score option has not been used yet.

Just to let you know, (if you don't know already) I am writing a Yahtzee program for a school project. I can see already how I can improve certain things. However, some of the methods I used to accomplish tasks may not be changeable, technically, because they have already been approved in my pseudo code in my software spec (in the last school term).

I appreciate the input. I will work on it and get back on my progress.
mdumont at 2007-11-11 4:11:16 >
# 11 Re: need help with function calls
Paul, I do have responses to your questions but I will try the things you suggested first. One thing I can say now, however, is I NEED to check for NULL (instead of 0). A zero value is a valid score and indicates an intentional score of zero. Once a score option has been used (zero or any number of points) it is no longer available. A null value indicates the score option has not been used yet.


If you look in windef.h, you'll find this line of code.

#define NULL 0
GCDEF at 2007-11-11 4:12:15 >
# 12 Re: need help with function calls
In response to Paul's last post...

First 2 comments) "This is no indication that you fixed the error... The Dice array is too small. All you needed to do was to declare it properly:"
I'm sorry I wasn't clear in my post. I actually edited the code if (d1 ==0) because using if (Dice[0] == 0) was just the wrong formula. However, I did change the declaration of Dice[ ] variable to Dice[5].

1) "The main() function returns int, not void."
You're saying my main() SHOULD be int and not void? I don't see this so I'll have to take another look.

2) "Even though ScorePad is global, you should still initialize the members to 0 just in case it no longer becomes global."
I'm not sure I understand "in case it no longer becomes global". I didn't initialize them because I need a way to determine if they have been "used" yet. Using a zero value won't work. I thought about initializing them to some ridiculous value (setting a flag) in which I can test against (instead of testing against NULL) but thought that would be useless code.

I just did wrote a mini program and tested for NULL and I didn't get the result I thought I would. CDGEF posted about looking into windef.h, so I will do that.

3) Thanks. I will look into this

4) "Another thing -- why are you checking for NULL on an int in the display code? First, you should be checking for 0. However, if the int is 0, there is no harm in adding 0 to the total, so why the check? Get rid of the NULL checks altogether"
Same NULL issue.
mdumont at 2007-11-11 4:13:13 >
# 13 Re: need help with function calls
1) "The main() function returns int, not void."
You're saying my main() SHOULD be int and not void? I don't see this so I'll have to take another look.

Newer compilers don't really care either way, but for maximum compatibility, you should declare:
int main(int argc, char *argv[])

Older compilers may require this, and it's the only way to get a command-line argument.
Lindley at 2007-11-11 4:14:14 >
# 14 Re: need help with function calls
Newer compilers don't really care either way, but for maximum compatibility, you should declare:
int main(int argc, char *argv[])

Older compilers may require this, and it's the only way to get a command-line argument.
Actually, the C++ standard allows for the following three declarations of main:
int main() {}
int main(int argc, char *argv[]) {}
int main(int argc, char *argv[], char *envp[]) {}
If you're compiler complains about the first case (no args), then I'd upgrade.

Viggy
MrViggy at 2007-11-11 4:15:20 >
# 15 Re: need help with function calls
2) "Even though ScorePad is global, you should still initialize the members to 0 just in case it no longer becomes global."
I'm not sure I understand "in case it no longer becomes global". I didn't initialize them because I need a way to determine if they have been "used" yet.If a Score variable is not global, it will contain uninitialized, garbage values. You can't determine or use uninitialized variables as some sort of marker to indicate a variable hasn't been used. Uninitialized could mean those values could be anything. Please read up on this, as this is basic C++ knowledge.
Using a zero value won't work.But that is exactly what you used when you made ScorePad global. By default, global variables are initialized to 0. So you're saying it doesn't work, but it must have worked since that is what is going on.

Again, read up on the differences between global and local variables, and what is and not initialized to 0 by default. In brief, global variables are initialized to 0, and local variables are not initialized (garbage, unknown values).
I just did wrote a mini program and tested for NULL and I didn't get the result I thought I would. CDGEF posted about looking into windef.h, so I will do that.NULL is defined as 0. So when you're adding 0, you aren't doing anything. That's why those checks were meaningless. In theory, you were supposed to do something special if the value is 0 (I don't know Yahtzee), but in actual coding and logic, your code did nothing special, as it just would have added 0 to a total, thereby not changing the total at all.

Regards,

Paul McKenzie
Paul McKenzie at 2007-11-11 4:16:15 >