C++ can't call same function twice with different parameters - c++

I have a C++ program that calls the same function tempGauge() twice. It hits the first call then skips the second call and goes to userData() and gives me the error "finished with exit code 6". when I comment out the first call the second call works as expected and ends with the exit code 0.
int tempGuage(int &array, int &actDay);
void userData();
int main() {
const int totalTemp(10);
int firstDay[totalTemp];
int secondDay[totalTemp];
int dayOne = 1;
int dayTwo = 2;
tempGauge(firstDay[totalTemp], dayOne);
tempGauge(secondDay[totalTemp], dayTwo);
userData();
return 0;
}
int tempGauge(int &array,int &actDay)
{
int i;
int maxTemps;
for(i=1;i < maxTemps;++i)
{
cout << "Enter # of temps on DAY " << actDay <<":";
cin >> maxTemps;
if(maxTemps <=0||maxTemps>=11)
{
cout << "Enter at least 1 but no more than 10. Try again.";
}
else
{
cout << "Enter the " << maxTemps << " temps(s):";
cin >>array;
i++;
}
}
return array;
}

Your code has undefined behavior.
Both of your calls to tempGuage() are passing in invalid int& references in the 1st parameter, as the [totalTemp] index is accessing an int that is beyond the bounds of each array. So, even if tempGauge() worked properly (which it doesn't), it would be filling in invalid memory. Since you clearly want to fill the arrays, you need to change [totalTemp] to [0] instead so you start filling at the beginning of each array rather than at the end.
Inside of tempGauge(), maxTemps is uninitialized when entering the loop, so the number of iteration is indeterminate. But, even if it weren't, the statement cin >>array; does not read in an entire array, like you are expecting. Even if it could, it would not know how many ints to read, since array is declared as a reference to a single int and you can't pass maxTemps to operator>>. You would need a loop to read each int individually, which you are trying to do, but you are not looping correctly. And also, cin >> array would need to be changed to cin >> array[i];, which won't work unless int &array is changed to either int (&array)[10] or int *array. In which case, main() would then have to be updated accordingly, by dropping the [0] when passing in each array.
With that said, try this instead:
#include <limits>
const int totalTemp = 10;
int tempGuage(int (&array)[totalTemp], int actDay);
void userData();
int main()
{
int firstDay[totalTemp] = {};
int secondDay[totalTemp] = {};
tempGuage(firstDay, 1);
tempGuage(secondDay, 2);
userData();
return 0;
}
int tempGuage(int (&array)[totalTemp], int actDay)
{
int maxTemps;
cout << "Enter # of temps on DAY " << actDay << ":";
do
{
if (!(cin >> maxTemps))
{
cout << "Invalid input. Try again.";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
else if ((maxTemps <= 0) || (maxTemps > totalTemp))
{
cout << "Enter at least 1 but no more than " << totalTemp << ". Try again.";
}
else
{
cout << "Enter the " << maxTemps << " temps(s):";
for(int i = 0; i < maxTemps; ++i)
{
while (!(cin >> array[i]))
{
cout << "Invalid input for temp " << i+1 << ". Try again.";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
break;
}
}
while (true);
return maxTemps;
}
void userData()
{
//...
}
Live Demo

Related

Passing dynamic arrays to recieve inputs in separate functions

I would like to pass dynamic arrays to functions and receive user input. Currently I'm using the following code:
#include <iostream>
using namespace std;
struct make
{
int part;
int graph;
int like;
};
int z;
int *p = new int [z];
void inpart( make x[],int *fig)
{
cout << "Input part\n";
cin >> x[*fig].part;
}
void ingraph(make x[],int *tig)
{
cout << "Input graph\n";
cin >> x[*tig].graph;
}
void inlike(make x[],int *gig)
{
cout << "Input like\n";
cin >> x[*gig].like;
}
int main()
{
cout << "Input array count\n";
cin >> z;
make p[z];
for (int i=0; i < z; i++)
{
inpart(p,&z);
ingraph(p,&z);
inlike(p,&z);
}
for (int i=0; i < z; i++)
{
cout << "the result is\n";
cout << p[z].part << ", ";
cout << p[z].graph << ", ";
cout << p[z].like << "\n";
}
}
My input 1,1,1 for all the structure objects should output 1,1,1. However, the answer I receive is 1,0,2. Why?
Firstly, you shouldn't trying to initialize a static buildin array in run-time:
Your implementation is wrong here:
cout<< "Input array count\n";
cin>>z;//initialized in run-time
make p[z]; // wrong, need to be allocated with new
make* example = new make[z]; // Ok!
Secondly, you're trying to read and write out of bounds of the created array. It's Undefined behaviour. When you're creating an array with size N, chunk of the memory will be allocated to which you can have access by index. In your case from 0 to z or [0,z), excluding z. To sum up, your cycle should look like this:
for (int i = 0; i < z; i++) {
inpart(p,&i);
ingraph(p,&i);
inlike(p,&i);
}
Actually u've made a lot of mistakes in your code, but I feel like you will understand this later when continue learning.

cin a char into an int variable to stop a loop

I would like to read numbers into a static array of fixed size 10, but the user can break the loop by entering character E.
Here's my code:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int myArray[10];
int count = 0;
cout << "Enter upto 10 integers. Enter E to end" << endl;
for (int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
cin >> myArray[i];
if (myArray[i] != 'E')
{
cout << myArray[i] << endl;
count++;
}
else
{
break;
}
}
cout << count << endl;
system("PAUSE");
return 0;
}
However, I get the following results while entering E:
Enter upto 10 integers. Enter E to end
Enter num 1:5
5
Enter num 2:45
45
Enter num 3:25
25
Enter num 4:2
2
Enter num 5:E
-858993460
Enter num 6:-858993460
Enter num 7:-858993460
Enter num 8:-858993460
Enter num 9:-858993460
Enter num 10:-858993460
10
Press any key to continue . . .
How can I fix this code in the simplest way?
cin fails for parsing character 'E' to int. The solution would be to read string from user check if it is not "E" (it is a string not a single char so you need to use double quotes) and then try to convert string to int. However, this conversion can throw exception (see below).
Easiest solution:
#include <iostream>
#include <cmath>
#include <string> //for std::stoi function
using namespace std;
int main()
{
int myArray[10];
int count = 0;
cout << "Enter upto 10 integers. Enter E to end" << endl;
for (int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
std::string input;
cin >> input;
if (input != "E")
{
try
{
// convert string to int this can throw see link below
myArray[i] = std::stoi(input);
}
catch (const std::exception& e)
{
std::cout << "This is not int" << std::endl;
}
cout << myArray[i] << endl;
count++;
}
else
{
break;
}
}
cout << count << endl;
system("PAUSE");
return 0;
}
See documentation for std::stoi. It can throw exception so your program will end suddenly (by termination) that is why there is try and catch blocks around it. You will need to handle the case when user puts some garbage values in your string.
Just use:
char myArray[10];
because at the time of taking input console when get character then try to convert char to int which is not possible and store default value in std::cin i.e. 'E' to 0 (default value of int).
Use below code:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
char myArray[10];
int count = 0;
cout << "Enter upto 10 integers. Enter E to end" << endl;
for (int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
cin >> myArray[i];
if (myArray[i] == 'E')
{
break;
}
else
{
cout << myArray[i] << endl;
count++;
}
}
exitloop:
cout << count << endl;
system("PAUSE");
return 0;
}
Output:
Enter upto 10 integers. Enter E to end
Enter num 1:1
1
Enter num 2:E
1
sh: 1: PAUSE: not found
If you debug this, you will find all your myArray[i] are -858993460 (=0x CCCC CCCC), which is a value for the uninitialized variables in the stack.
When you put a E to an int variable myArray[i]. std::cin will set the state flag badbit to 1.
Then when you run cin >> myArray[i], it will skip it. In other words, do nothing.
Finally, you will get the result as above.
The problem is that attempting to read E as an int fails, and puts the stream in an error state where it stops reading (which you don't notice because it just doesn't do anything after that) and leaves your array elements uninitialized.
The simplest possible way is to break on any failure to read an integer:
for(int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
if (cin >> myArray[i])
{
cout << myArray[i] << endl;
count++;
}
else
{
break;
}
}
If you want to check for E specifically, you need to read a string first, and then convert that to an int if it's not E.
As a bonus, you need to handle everything that's neither int nor E, which complicates the code a bit.
Something like this:
int count = 0;
string input;
while (cin >> input && count < 10)
{
if (input == "E")
{
break;
}
istringstream is(input);
if (is >> myArray[count])
{
cout << myArray[count] << endl;
count++;
}
else
{
cout << "Please input an integer, or E to exit." << endl;
}
}

Comparing two arrays of strings c++

Ok thank you everyone for your comments. I have fixed much of it. Now when I compile it, it gives me an error on line in main where I call getPercent() saying this :
error: cannot convert ‘std::string’ to ‘std::string*’ for argument ‘3’
to ‘void getPercent(int, std::string*, std::string*, std::string*)’
What can fix this?
#include <iostream>
#include <string>
using namespace std;
string getYours()
{
cout << "Enter your DNA sequence: " ;
string sequence;
cin >> sequence;
return sequence;
}
int getNumber()
{
cout << "Enter the number of potential relatives: ";
int number;
cin >> number;
cout << endl;
return number;
}
void getNames(int number, string name[])
{
for (int i = 0; i < number; i++)
{
cout << "Please enter the name of relative #" << i + 1 << ": ";
cin >> name[i];
}
}
void getSequences(int number, string name[], string newsequence[])
{
cout << endl;
for (int i = 0; i < number; i++)
{
cout << "Please enter the DNA sequence for " << name[i] << ": ";
cin >> newsequence[i];
}
}
void getPercent(int number, string name[], string sequence[],
string newsequence[])
{
cout << endl;
int count = 0;
for (int i = 0; i < number; i++)
{
if (sequence[i] == newsequence[i])
count = count + 10;
cout << "Percent match for " << name[i] << ": " << count << "%";
}
}
int main()
{
string sequence = getYours();
int number = getNumber();
string name[50];
string newsequence[50];
getNames(number, name);
getSequences(number, name, newsequence);
getPercent(number, name, sequence, newsequence);
return 0;
}
A few problems:
getYours() has no side effects. You probably meant to assign to the string sequence in main(), but instead are assigning to a local variable that will be destroyed as it goes out of scope.
No error checking for too many elements in your arrays (try using a std::vector).
You stop at 10 in getPercent() instead of number elements (if that's what you wanted).
In getPercent(), count is not initialized to 0. Something seems strange about the logic in getPercent(), so I am not exactly sure what you are trying to do.
The arguments sequence and newsequence in getPercent() are actually the same type, and would compile fine.
And probably a few other things I've overlooked.

Segmentation fault using string pointer

I'm a C++ newbie, I'm trying to put in practice pointers with strings. The program I have made is just to store strings the user types in the command line. But I'm getting segfault, not sure why.
This is the code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
//This code is meant to learn how to use pointers and strings
//Ask the user for who are they in the family and save it in string array!
void print_string (string* Value, int const nSize);
int get_names(string* Family_input);
int main ( int nNumberofArgs, char* pszArgs[])
{
cout << "Tis program stores your family members\n";
cout<< "Type the names and write 0 to exit\n";
string familia_string;
string* familia = &familia_string;
int family_number;
family_number=get_names(familia);
cout << "The family members are: ";
print_string(familia, family_number);
cout << endl;
return 0;
}
int get_names(string* Family_input)
{
int i=0;
string input="";
string old_input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
//cin >> *(Family_input+i);
//input=*(Family_input+i);
cin >> input;
*(Family_input + old_input.length()) = input;
old_input=input;
i++;
}
return i;
}
void print_string (string* Value, int const nSize)
{// I don't want to &psValue to be changed!
for (int i=0; i<nSize; i++)
{
cout << *(Value+i) << " ";
//&psValue++;
}
}
I'm not sure if it's because I'm not taking correctly the size of the string, or I'm not using correctly the pointer or is that I have to allocate memory before using the offset.
As #kleszcz pointed out already, the line
*(Family_input + old_input.length()) = input;
is wrong. You are accessing memory that you are not supposed to.
The easiest fix is to change get_names slightly:
int get_names(string* Family_input)
{
int i=0;
string input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
cin >> input;
*Family_input += input; // Just keep on appending to the input argument.
*Family_input += "\n"; // Add a newline to separate the inputs.
i++;
}
return i;
}
Also change print_string to:
void print_string (string* Value)
{
cout << *Value;
}
Of course, print_string has become so simple, you don't need to have it at all.
You could change get_names to use a reference argument instead of a pointer argument. This is a better practice.
int get_names(string& Family_input)
{
int i=0;
string input="";
while (input!="0")
{
cout << "type " << i <<" member\n";
cin >> input;
Family_input += input; // Just keep on appending to the input argument.
Family_input += "\n"; // Add a newline to separate the inputs.
i++;
}
return i;
}
Then, change the call to get_names. Instead of using
family_number=get_names(familia);
use
family_number=get_names(familia_string);
You get seg fault because you haven't allocate memory for an array of strings.
*(Family_input + old_input.length()) = input;
This is total nonsense. If you'd have an array you increment index only by one not by length of string.
If you want to save different names in different string objects I would suggest:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
void print_string(string** Value, int const nSize);
void get_names(string** Family_input, int count);
int main(int nNumberofArgs, char* pszArgs[]) {
cout << "This program stores your family members\n";
int family_number;
cout << "Types the number of family members";
cin >> family_number;
/*allocate the number of string pointers that you need*/
string** familia = new string*[family_number];
cout << "Type the names\n";
get_names(familia, family_number);
cout << "The family members are: ";
print_string(familia, family_number);
cout << endl;
return 0;
}
void get_names(string** Family_input, int count) {
for(int i = 0 ; i < count; i++){
cout << "type " << i << " member\n";
/*create a string obj in the heap memory*/
string *input = new string ("");
// using that way you get only a single word
cin >> *input;
/*create a string object on the stack and put its pointer in the family_array*/
Family_input[i] = input;
}
}
void print_string(string** Value, int const nSize) {
for (int i = 0; i < nSize; i++) {
cout << *(Value[i]) << " ";
}
}

Using variables declared inside an if else construct later in the program results in an undeclared identifier error

This program is pretty self explanatory, so I won't really get into the purpose of what its for.
My main problem right now is on lines 82, 89, 95, and 101, I'm getting "Undeclared Identifier" errors for "arr" and "input" when i compile.
Is this because I declared them inside of an if else if construct, and if so, is there any way to get around this. Thanks for any help in advance!!!!
Here is the code
#include <iostream>
#include <string>
using namespace std;
template<class T> void selectionSort(T arr[], T num)
{
int pos_min;
T temp;
for (int i = 0; i < num - 1; i++)
{
pos_min = i;
for (int j = i + 1; j < num; j++)
{
for (arr[j] < arr[pos_min])
{
pos_min = j;
}
}
if (pos_min != i)
{
temp = arr[i];
arr[i] = arr[pos_min];
arr[pos_min] = temp;
}
}
}
int main()
{
char check = 'C';
while (toupper(check) != 'Q')
{
char dataType;
int num = 0;
cout << "What kind of data do you want to sort?" << endl;
cout << " For integer enter i, for string enter s, for character enter c. ";
cin >> dataType;
//User input dataType
if (toupper(dataType) == 'I')
{
int arr[100];
int input;
cout << " You've chosen Integer dataType" << endl;
}
else if (toupper(dataType) == 'S')
{
string arr[100];
string input;
cout << " You've chosen String dataType" << endl;
}
else if(toupper(dataType) == 'C')
{
char arr[100];
char input;
cout << " You've chosen Character dataType" << endl;
}
else
{
cout << "Not a recognizable dataType. Shuting down..." << endl;
return -1;
}
//User input # of num
cout << "How many num will be sorted? ";
cin >> num;
for (int i = 0; i < num; i++)
{
cout << "Enter an input of the dataType you selected: ";
cin >> input;
arr[i] = input;
}
//Display user input
cout << "The data as you entered it: ";
for (int i = 0; i < num; i++)
{
cout << arr[i];
cout << " ";
}
cout << endl;
//Sort user input by calling template functon selectionSort
selectionSort(arr, num);
//Display sorted user input
cout << "After sorting your data by calling selectionSort: ";
for (int i = 0; i < num; i++)
{
cout << arr[i];
cout << " ";
}
cout << endl;
//Query user to quit or continue
cout << " Would you like to continue? Enter 'Q'. Enter anything else to continue.";
cin >> check;
}
return 0;
}
It is because you declared them inside an if/else block. Once the block completes, these variable go out of scope and are no longer accessible.
One way around this would be to always read in the input as character data, then convert it into the specified type after the fact. See atoi for how to convert from char to int.
A variable can never have unknown type. Even inside a template, the type of every variable is fixed for any particular instantiation.
Which suggests a solution. All the code that works on a variable with multiple types can be placed into a template function.
You may find the template syntax for passing an arbitrary length array of arbitrary element type useful:
template<typename T, size_t N>
void func1( T (&arr)[N] )
{
//...
}
But you really don't even need to pass the array. Just pass a type, and use that type when creating the array inside the function.
template<typename T>
void process_it()
{
T arr[100];
T input;
// now work on them
}
Either way, you'll need to call this function from inside all the if/else branches, where the exact type is known.