I'm kinda new on C++ and I'm having trouble on an exercise which is necessary to keep a name and the height of 10 people using structs.
The structs are:
typedef struct
{
char nome[50];
float altura;
} pserhumano;
typedef struct
{
float dia;
float mes;
float ano;
} dnasc;
And the functions are:
void CriaData(dnasc *D[], int i)
{
D[i]->mes = 1 + (rand() % 12);
D[i]->ano = 1950 + (rand() % 49);
D[i]->dia = 1 + (rand() % 30);
}
void InserirNome(pserhumano *Z[])
{
dnasc a[10];
for (int contador = 0; contador < 10; contador++) {
cout << "Insira o seu nome." << endl;
gets (Z[contador]->nome);
cout << "Insira a sua idade." << endl;
cin >> Z[contador]->altura;
CriaData(&a, contador);
}
}
This is the output on Ubuntu:
athos#ubuntu:~$ g++ exercicio1.cpp -w -o a
exercicio1.cpp: In function ‘void InserirNome(pserhumano**)’:
exercicio1.cpp:35:33: error: cannot convert ‘dnasc (*)[10]’ to ‘dnasc**’ for argument ‘1’ to ‘void CriaData(dnasc**, int)’
CriaData(&a, contador);
I'm having trouble to understand how to pass these arrays to the function. Any help is appreciated.
a is an array of dnasc
The function CriaData expects an array of pointers to dnasc
Change to :
void CriaData(dnasc D[], int i)
{
D[i].mes = 1 + (rand() % 12);
D[i].ano = 1950 + (rand() % 49);
D[i].dia = 1 + (rand() % 30);
}
And simply call:
CriaData(a, contador);
Notes:
Do not use gets, it is unsafe. Use std::cin
In your code you are using arrays, not vectors.
I'll go differently compared to the other answers. IMHO, What you really want is:
void CriaData(dnasc &D) {
D.mes = 1 + (rand() % 12);
D.ano = 1950 + (rand() % 49);
D.dia = 1 + (rand() % 30);
}
(i.e., Just to pass a dnasc object by reference).
and then in the loop just call:
dnasc a[10];
for(int contador = 0; contador < 10; ++i) {
...
CriaData(a[contador]);
}
No need to pass in the function useless subscripts etc.
Furthermore, if your compiler supports C++11 then you could use the new random number generation facilities. In this very nice talk Stephan T. Lavavej explains why you should not use rand() anymore.
The type of a in InserirNome is an array of 10 dnasc.
The type of &a is a pointer to an array of 10 dnasc. In C++, that is dnasc (*)[10].
This cannot be converted to dnasc**, which is the expected argument type of CriaData.
That's the compiler error message when you use
CriaData(&a, contador);
The following changes to CriaData should make it easier.
void CriaData(dnasc D[], int i)
{
D[i].mes = 1 + (rand() % 12);
D[i].ano = 1950 + (rand() % 49);
D[i].dia = 1 + (rand() % 30);
}
Then, you can call it using:
CriaData(a, contador);
The first parameter of function CriaData has type dnasc *D[] that is adjasted to type dnasc **D
void CriaData(dnasc *D[], int i)
But you call the function passing an expression of type dnasc( * )[10] that is you pass a pointer to local array dnasc a[10];
CriaData(&a, contador);
The correct function declaration would look as
void CriaData(dnasc D[], int i);
and the corresponding its call would look as
CriaData(a, contador);
Though I do not see a sense in calling this function for this local array.
Related
I'm kind of inexperienced with C++, and I'm converting a program that I wrote in C to C++. I have a RollDice function that takes numbers that I read in from a text file and uses them to generate the number. This is the function in C:
void rollDice(Move *move, GameState *game_state) {
int diceNum1 = 0;
int diceNum2 = 0;
int randomNumber1 = 0;
int randomNumber2 = 0;
randomNumber1 = game_state->randomNums[game_state->current_roll]; //gets the random number from the array randomNum (which holds the numbers from the text file), at index "current_roll"
game_state->current_roll++; //increments so the next random number will be the next number in the array
diceNum1 = 1 + (randomNumber1 % (1 + 6 - 1));
randomNumber2 = game_state->randomNums[game_state->current_roll];
game_state->current_roll++;
diceNum2 = 1 + (randomNumber2 % (1 + 6 - 1));
move->dice_sum = diceNum1 + diceNum2;
printf("You rolled a %d!\n", move->dice_sum);
}
This works just how I want it to when I run it. Now, when converting my program to C++ I had to change things around. My parameters are now pass by reference and I made a vector to store the list of random numbers from the text file:
void rollDice(Move& move, GameState& game_state) {
std:: vector<int> randomNums = game_state.getRandomNums();
int current_roll = game_state.getCurrentRoll();
int diceNum1 = 0;
int diceNum2 = 0;
int randomNumber1 = 0;
int randomNumber2 = 0;
randomNumber1 = randomNums.at(current_roll);
current_roll++;
diceNum1 = 1 + (randomNumber1 % (1 + 6 - 1));
randomNumber2 = randomNums.at(current_roll);
current_roll++; //this line is grayed out and says "this value is never used"
diceNum2 = 1 + (randomNumber2 % (1 + 6 - 1));
move.dice_sum = diceNum1 + diceNum2;
std:: cout << "You rolled a " << move.dice_sum << "!\n";
}
My code is telling me that the second time I increment current_roll it is unused. This didn't happen for my C code, so why is it happening here and how can I fix it? I'm completely lost.
It's never used because you write to the variable, but never read from it. Having a variable that you never read is effectively meaningless.
Presumably your game_state.getCurrentRoll function returns an integer, when you store this, you store the value (rather than a reference to the value), thus incrementing it doesn't increment the current roll inside the game_state, instead you should add a function to your game_state called makeRoll for example which increments the game_states internal current_roll value.
This is different from your C code which increments the current_roll value directly using game_state->current_roll++ (alternatively you could make game_state.current_roll public and increment it the same way as in your C code).
From your comment I assume you have some class:
class GameState {
private:
int current_roll;
...
public:
int getCurrentRoll() {
return current_roll;
}
...
}
All you'd need to do is add another function to your class to increment the current_roll:
class GameState {
private:
int current_roll;
...
public:
int getCurrentRoll() {
return current_roll;
}
void makeRoll() {
current_roll++;
}
...
}
Then you can call it as normal.
Regarding your new issue in the comments regarding the error:
parameter type mismatch: Using 'unsigned long' for signed values of type 'int'.
This is because the signature of at is std::vector::at( size_type pos ); That is, it expects a value of type size_type which is an unsigned integer type, rather than int as you're using which is signed. This post may be helpful.
Here is my code I have looked up what to do multiple times and still haven't figured out what to do.
It keeps giving me this error: C++ expression must be an lvalue or a function designator with the part of the code :
avg_score = (float)*&get_average_score(score_1, score_2, score_3);`
how can i fix the error?
the original error was cannot convert a void to a float
avg_score = get_average_score(score_1, score_2, score_3);
how can i fix the error?`
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <ctime>
using namespace std;
void print_scores(int score_1, int score_2, int score_3);
void get_average_score(int score_1, int score_2, int score_3);
int main()
{
srand(time(NULL));
int score_1, score_2, score_3;
float avg_score;
score_1 = rand() % 21 + 20;
while (score_1 % 2 == 0)
{
score_1 = rand() % 21 + 20;
}
score_2 = rand() % 21 + 20;
score_3 = rand() % 21 + 20;
print_scores(score_1, score_2, score_3);
avg_score = (float)*&get_average_score(score_1, score_2, score_3);
cout << fixed << setprecision(1);
cout << "Average score = " << avg_score <<
endl;
return 0;
}
void print_scores(int score_1, int score_2, int score_3)
{
cout << "score 1 = " << score_1 << endl << "score 2 = " << score_2 << endl
<< "score 3 = " << score_3 << endl;
}
void get_average_score(int score_1, int score_2, int score_3)
{
(float)(score_1 + score_2 + score_3) / (float)3;
}
Your first mistake lies in the fact that you are trying to get a function that does not return a value to return a value. You've tried to reference a pointer *& which is not how you should be handling this as
1) you've tried to reference a pointer but instead you've done it on a function
2) you want a value, not a pointer so its the wrong approach.
If you need to use pointers (because thats the task at hand) then what you need to do is pass a reference to avg_score into your function.
void get_average_score(float * avg_score, int score_1, int score_2, int score_3)
{
*avg_score = (score_1 + score_2 + score_3) / 3.0;
}
and call it in main with:
get_average_score(&avg_score, score_1, score_2, score_3);
and dont forget to update the header declaration:
void get_average_score(float * avg_score, int score_1, int score_2, int score_3);
If you don't have to use pointers the easiest fix is to actually return a value.
Declare the function as type float :
float get_average_score(int score_1, int score_2, int score_3);
and edit the get_average_score function to be:
float get_average_score(int score_1, int score_2, int score_3)
{
return (score_1 + score_2 + score_3) / 3.0;
}
and get rid of (float)*& from main.
This means your function will return a float value that will be stored in avg_score on return.
Also note, by changing the denominator to 3.0 instead of 3 you don't need to don't need to type cast the result as a float.
Your coding style does come off as a little basic (which is ok, everyone has to start somewhere) but you have room for improvement, so take the time to learn now rather than struggling later (trust me it makes life easy in the long run).
Rather than making a function that will only work when you are averaging 3 numbers why not make a more modular function that would work for as many numbers as you want!
Try learning how to use vectors! If you're coming from C its kinda like an array but can be dynamically allocated i.e. any size you want.
Have a look around the net for some tutorials on what vectors are and how to use them.
I won't write out the code for this because you should learn how to do it your self (trust me you'll understand it better) but basically using a vector of int's std::vector<int> you can iterate through them all and add each element together and then at the end divide by the total number of elements (the number of iterations you do) to get your average!
**obviously theres a limit but thats a limit of your computer... *
Calculate nth power of P (both p and n are positive integer) using a recursive function myPowerFunction(int p, int n, int ¤tCallNumber). currentCallNumber is a reference parameter and stores the number of function calls made so far. myPowerFunction returns the nth power of p.
int myPowerFunction(int p, int n, int &z)
{
z++;
if(n==1)return p;
else if(n==0)return 1;
else if(n%2==0)return myPowerFunction(p,n/2,z)*myPowerFunction(p,n/2,z);
else return myPowerFunction(p,n/2,z)*myPowerFunction(p,n/2,z)*p;
}
int main()
{
cout << myPowerFunction(3,4,1);
}
You need a variable to pass as the third argument in main_program. You can't pass a constant as a non-const reference.
int count = 0;
std::cout << myPowerFunction(3, 4, count) << 'n';
std::cout << count << '\n';
Third parameter expects a lvalue, so you cannot pass numeric constant there, so possible solution can be:
int z = 1;
cout<< myPowerFunction(3,4,z);
or better to create a function that calls recursive one:
int myPowerFunction(int p, int n)
{
int z = 1;
return myPowerFunction(p,n,z);
}
In myPowerFunction(3,4,1) the literal 1 cannot be passed to a non const reference as it is a prvalue [basic.lval]. You need to store the value into a variable and then use that variable when calling the function.
int z = 0;
std::cout << myPowerFunction(3, 4, z);
You don't have to give a reference as parameter as many here state.
But yes, your input for z cannot be modified as it comes from read-only memory. Treat the input for z as const, copy z internally and give the copy as reference. Then your desired usage works:
int myPowerFunction(int p, int n, const int &z) // z is now const !
{
int _z = z + 1; // copy !
if (n == 1) return p;
else if (n == 0) return 1;
else if (n % 2 == 0) return myPowerFunction(p, n /2 , _z) * myPowerFunction(p, n / 2, _z);
else return myPowerFunction(p, n / 2, _z) * myPowerFunction(p, n / 2, _z) * p;
}
int main()
{
std::cout << myPowerFunction(3, 4, 1);
}
I'm having some trouble with this non recursive Fibonacci function. I am using this array of numbers and passing it to FiboNR, however I am getting large negative values and Access Violation errors.
int n[15] = { 1,5,10,15,20,25,30,35,40,45,50,55,60,65,70 };
int FiboNR(int n) // array of size n
{
int const max = 100;
int F[max];
F[0] = 0; F[1] = 1;
for (int i = 2; i <= n; i++) {
F[n] = F[n - 1] + F[n - 2];
}
return (F[n]);
}
The function was one provided by the instructor and I assume its correct if he's giving it out but with these memory errors I don't fully understand what's going on. The only way I'm calling the in a loop to go through the array and outputting the answer like cout << FiboNR(n[i]);
First of all, your trouble is in loop. Replace:
F[n] = F[n - 1] + F[n - 2];
with:
F[i] = F[i - 1] + F[i - 2];
Because i is your iterator and n is only the limit.
Just FYI, the braces ( ) in return statement are not needed, you can ignore them.
I am using this array of numbers and passing it to FiboNR
You are not supposed to do that since FiboNR() excepts its argument to be an integer (one, not an array of integers). So you should pass only one number to your function, like: FiboNR(n[2]).
You get a negative numbers due to int overflow for int array (n > 46).
Change array type from int to long long.
Other solutions: change array type to float/double type with less precision of the results or use long arithmetic.
Type | Typical Bit Width | Typical Range
int | 4bytes| -2147483648 to 2147483647
Link: C++ Data Types
Example of code below.
#include <iostream>
long long FiboNR(int n);
long long FiboNR(int n) {
int const max = 100;
long long F[max];
if (n > max) {
n = max;
}
F[0] = 0;
F[1] = 1;
for (int i = 2; i <= n; i++){
F[i] = F[i - 1] + F[i - 2];
}
return (F[n]);
}
int main() {
for (int i=0; i < 100; i++) {
std::cout << "i = " << i << " : " << FiboNR(i) << std::endl;
}
return 0;
}
Alright so i have two identical string methods...
string CreateCust() {
string nameArray[] ={"Tom","Timo","Sally","Kelly","Bob","Thomas","Samantha","Maria"};
int d = rand() % (8 - 1 + 1) + 1;
string e = nameArray[d];
return e;
}
string CreateFood() {
string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
int d = rand() % (3 - 1 + 1) + 1;
string f = nameArray[d];
return f;
}
however no matter what i do it the guts of CreateFood it will always crash. i created a test chassis for it and it always fails at the cMeal = CreateFood();
Customer Cnow;
cout << "test1" << endl;
cMeal = Cnow.CreateFood();
cout << "test1" << endl;
cCustomer = Cnow.CreateCust();
cout << "test1" << endl;
i even switched CreateCust with CreateFood and it still fails at the CreateFood Function...
NOTE: if i make createFood a int method it does work...
Also guys even if i changed CreateFood to just COUT a message and nothing more it still crashed...
Take out the + 1 on both of them, you access arrays starting from 0:
int d = rand() % (8 - 1 + 1); // 0-7, not 1-8
int d = rand() % (3 - 1 + 1); // 0-2, not 1-3
Otherwise you're accessing a non-existent element, and this is undefined behavior. (That means it could appear to work, like in CreateCust, crash like in CreateFood, do nothing, or do anything.)
I'm not sure what the purpose of subtracting 1 then adding 1 is. In any case, now is the perfect time to learn: Don't Repeat Yourself. Even if you do something just twice, make a function out of it, it'll be less cryptic and more concise:
int random(int min, int max)
{
return rand() % ((b - a) + 1) + a;
}
This is a simple function that returns a random number between a and b, inclusive. (Means it can include both a and b in the results.) Now your code reads:
// I'll leave CreateCust up to you
string CreateFood(void)
{
string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
int d = random(0, 2); // either 0, 1, or 2, randomly
string f = nameArray[d];
return f;
}
And you'll see even just one function makes it much easier to read; your goal is to make your code easy to read by humans. Also, this is much more concise:
string CreateFood(void)
{
string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
return nameArray[random(0, 2)];
}
Another bad thing to do is hardcode magic numbers into your program. For example, why 3 or 8? It can be deduced those are array sizes, but that doesn't stand on its own. What you might want is something like:
string CreateFood(void)
{
const size_t ArraySize = 3; // 3 elements, 0-2
string nameArray[ArraySize] = {"spagetti", "ChickenSoup", "Menudo"};
// ^ Ensure it matches
return nameArray[random(0, ArraySize - 1)];
}
Now the range for the number number makes sense up front.
The rest may be a bit advanced (which you won't understand until you get to templates), but shows how we might go on:
template <typename T, size_t N>
char (&countof_detail(T (&)[N]))[N];
#define countof(pX) sizeof(countof_detail(pX))
This nifty tool will give you the number of elements in an array. The code might turn into this
string CreateFood(void)
{
string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
// ^ no explicit size
return nameArray[random(0, countof(nameArray) - 1)];
}
We got rid of any numbers altogether, you can just manipulate the array as you please. Lastly, we're repeating ourselves again: getting a random element from an array. We should make a function for that:
template <typename T, size_t N>
T& random_element(T (&pArray)[N])
{
return pArray[random(0, N - 1)];
}
This returns a random element from any array. Your function would then simply be:
string CreateFood(void)
{
string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
return random_element(nameArray);
}
Note in this refactoring (refactoring is taking code and factoring it into new, simpler parts) it reads much better: To get a food, we have an array of foods and we pick one at random.
Keep this kind of stuff in mind while you work, and as you learn C++ you can make better code. Anytime you repeat a task that isn't trivial, make it a function. Suddenly that task is trivial, because you don't care about how the function works (that's in the function), just what the function does (that's the function name).
The crash is happening because you are accessing an invalid index. This is because array indexes start from 0 and not 1, so you don't want to add a 1 to the rvalue of the modulus operator.
Here is a neat trick that you can use to make your code a little more maintainable:
template <class T>
T getRandElem( const T[] arr )
{
return arr[ rand() % ( sizeof(arr) / sizeof((arr)[0]) ) ];
}
string CreateCust(){
static string nameArray[] = {"Tom","Timo","Sally","Kelly","Bob","Thomas","Samantha","Maria"};
return getRandElem<string>( nameArray );
}
string CreateFood(){
static string nameArray[] = {"spagetti", "ChickenSoup", "Menudo"};
return getRandElem<string>( nameArray );
}
Look here:
int d = rand() % (8 - 1 + 1) + 1;
This will return a number between 1 and 8 inclusive. What you need is this:
int d = rand() % 8;
You're going outside the bounds of the array. The array object begins at 0.
I don't understand why you have
int d = rand() % (8 - 1 + 1) + 1;
Why not just use
int d = rand() % 8;
I think modern c++ compilers will still let you use an old C trick for static arrays:
string CreateFood()
{
char* nameArray = {"spagetti", "ChickenSoup", "Menudo"};
// note the trick to get the compiler to count the array elements for you:
int d = rand() % (sizeof(nameArray) / sizeof(nameArray[0]));
return std::string( nameArray[d] );
}