C++ skipping functions [duplicate] - c++

This question already has answers here:
Calling a function in main
(4 answers)
Closed 4 years ago.
Okay, I think I fixed most of this, but it doesn't like me passing the constants I think. Any help would be greatly appreciated, thank you.
also, with the !inputFile part, I'm not sure how to pull off a return (EXIT_FAILURE) like my teacher suggested..
Also, as to your suggestion with only using one part of the array, would that still allow me to use the whole thing in the function?
The program is supposed to take a file like this:
ex:
NOT 11010001
and it's supposed to read the command as a string, read the binary in as an array, then perform the command on the binary.
The code here is only main function, just don't want to send a wall of it all at once, if this looks okay, then I will happily add the rest. Also, the void Operate () function pretty much calls all of the other functions in one way or another... I'm not sure if that's what's causing it or what. The print table only cout's a table to put all of the info on.
and they headers are wonky for me on here, so just assume those are right.
/* ========================================================================== */
/* Prototypes */
int Power (int, int);
int ReadFile (ifstream inputFile);
void Operate (const int, ifstream&, string, int, int, int);
void CommandNot (const int, int, int);
void CommandAnd (const int, int, int, int);
void CommandOr (const int, int, int, int);
int CommandConvert (const int, int, int);
void CommandLshift (const int, int, int, int);
void PrintTable ();
void PrintOperand (const int &, int);
int main ()
{
//Constants
const int BIT_SIZE = 8;
//Variables
string fileName = "binaryData.txt";
int operandOne [BIT_SIZE];
int operandTwo [BIT_SIZE];
int operandResult [BIT_SIZE];
ifstream inputFile;
PrintTable ();
Operate (BIT_SIZE, inputFile, fileName, operandOne[BIT_SIZE], operandTwo[BIT_SIZE], operandResult[BIT_SIZE]);
return 0;
}
void PrintTable ()
{
cout << "=================================================" << endl;
cout << "= Eight Bit Binary Number Manipulator =" << endl;
cout << "=================================================" << endl << endl;
cout << setw(14) << "COMMAND" << "Operand #1" << "Operand #2" << "Shift" << "Result" << endl;
cout << "----------------------------------------------------------------------" << endl;
}
void Operate (const int BIT_SIZE, ifstream& inputFile, string fileName, int operandOne[], int operandTwo[], int operandResult[])
{
//Variables
int count, shift;
char myChar;
string command;
const int SIZE = BIT_SIZE; //rename constant
inputFile.open (fileName);
if ( !inputFile ) //Check if file opened sucessfully
{
cout << "Error: Data file could not be opened" << endl;
}
while (inputFile) //Read file, and apply commands
{
inputFile >> command;
cout << command << endl;
for ( count = 0; count < SIZE; count++ )
{
inputFile >> myChar;
operandOne[count] = myChar - '0';
}
if (command == "NOT")
{
CommandNot (BIT_SIZE, operandOne[BIT_SIZE], operandResult[BIT_SIZE]);
PrintOperand (BIT_SIZE, operandResult[BIT_SIZE]);
}
else if (command == "AND")
{
count = 0;
for ( count = 0; count < SIZE; count++ )
{
inputFile >> myChar;
operandTwo[count] = myChar - '0';
}
CommandAnd (BIT_SIZE, operandOne[BIT_SIZE], operandTwo[BIT_SIZE], operandResult[BIT_SIZE]);
PrintOperand (BIT_SIZE, operandResult[BIT_SIZE]);
}
else if (command == "OR")
{
count = 0;
for ( count = 0; count < SIZE; count++ )
{
inputFile >> myChar;
operandTwo[count] = myChar - '0';
}
CommandOr (BIT_SIZE, operandOne[BIT_SIZE], operandTwo[BIT_SIZE], operandResult[BIT_SIZE]);
PrintOperand (BIT_SIZE, operandResult[BIT_SIZE]);
}
else if (command == "CONVERT")
{
CommandConvert (BIT_SIZE, operandOne[BIT_SIZE], operandResult[BIT_SIZE]);
PrintOperand (BIT_SIZE, operandResult[BIT_SIZE]);
}
else if (command == "LSHIFT")
{
inputFile >> shift;
CommandLshift (BIT_SIZE, operandOne[BIT_SIZE], operandResult[BIT_SIZE], shift);
PrintOperand (BIT_SIZE, operandResult[BIT_SIZE]);
}
else
{
command = "INVALID";
PrintOperand (BIT_SIZE, operandOne[BIT_SIZE]);
cout << "--- ERROR! Invalid Command ---";
}
}
inputFile.clear();
inputFile.close();
return ;
}
void CommandNot (const int BIT_SIZE, int operandOne[], int operandResult[])
{
int count;
const int SIZE = BIT_SIZE;
for ( count = 0; count < SIZE; count++ )
{
if (operandOne[count] == 0)
{
operandResult[count] = 1;
}
else
{
operandResult[count] = 0;
}
}
}
void CommandAnd (const int BIT_SIZE, int operandOne[], int operandTwo[], int operandResult[])
{
int count;
const int SIZE = BIT_SIZE;
for ( count = 0; count < SIZE; count++ )
{
if ((operandOne[count] == 1) && (operandTwo[count] == 1))
{
operandResult[count] = 1;
}
else
{
operandResult[count] = 0;
}
}
}
void CommandOr (const int BIT_SIZE, int operandOne[], int operandTwo[], int operandResult[])
{
int count;
const int SIZE = BIT_SIZE;
for ( count = 0; count < SIZE; count++ )
{
if ((operandOne[count] == 0) && (operandTwo[count] == 0))
{
operandResult[count] = 0;
}
else
{
operandResult[count] = 1;
}
}
}
int CommandConvert (const int BIT_SIZE, int operandOne[])
{
int count;
const int SIZE = BIT_SIZE;
int baseTenResult = 0;
int place;
for ( count = 0; count < SIZE; count++ )
{
place = SIZE - (count + 1);
if (operandOne[count] == 1)
{
baseTenResult = baseTenResult + Power (2, place);
}
else
{
continue;
}
}
return baseTenResult;
}
void CommandLshift (const int BIT_SIZE, int operandOne[], int operandResult[], int shift)
{
int count;
const int SIZE = BIT_SIZE;
int shiftStart = SIZE - shift;
for ( count = 0; count < SIZE-shift; count++ )
{
operandResult[count] = operandOne[count + shift];
}
for ( count = SIZE - shift; count < SIZE; count++ )
{
operandResult[count] = 0;
}
}
int Power (int base, int power)
{
int count;
int result = 1;
for ( count = 0; count < power; count++ )
{
result = result * base;
}
return result;
}
void PrintOperand (const int BIT_SIZE, int operandResult[])
{
int count;
const int SIZE = BIT_SIZE;
for ( count = 0; count < SIZE; count++ )
{
cout << operandResult[count];
}
}

You need to call the functions from main. You can't do this by sort-of redeclaring them:
void PrintTable();
void Operate (const int BIT_SIZE, ifstream& inputFile, string fileName, int operandOne[], int operandTwo[], int operandResult[]);
Instead, you need to call them:
PrintTable();
Operate(BITSIZE,inputFile,fileName,operandOne,operandTwo,operandResult);
Note, however that there is another problem: Operate requires three integer arguments at the end, but you seem to try to use integer arrays as arguments. You'll need to select one element of each array and submit only that as argument.
(EDIT) A few things have changed in your question, and I don't understand enough to tell what the best overall structure for your data and functions should be, but if you are dealing with integer arrays and you'd like to pass an entire array to a function, you can do it in this way (I've simplified it to a function that takes only one array of integers. Of course you can have more than one function argument):
#include <iostream>
const int SIZE = 3;
/* This is a simpified version of 'operate'. It
takes one argument, which is an array of integers. */
void operate(int a[])
{
/* The only thing I do is to iterate through
all elements of the array and print them. */
int i = 0;
while (i < SIZE) {
std::cout << a[i] << std::endl;
++i;
}
/* IMPORTANT: The length of the array is defined by a
global constant SIZE. Alternatively, you can pass
along the size of the array as a separate argument
to the function. */
}
int main()
{
/* Main program. Here is our array: */
int my_array[SIZE] = { 1,2,3 };
/* And here we call our function: */
operate(my_array);
return 0;
}
However, all of this is a bit complicated and not really as conventient as you could have it in C++ (as opposed to C). In all likelihood, you'll be much better of not using arrays at all, and replacing them with std::vector. Best check on cppreference for examples of how to use it (also click on some of the member functions, such as the constructor and push_back to get specific code examples.)

Related

Part of the char array?

I got a task in which I receive babies' firstname and weight in kilogram in a character array (for example: Johnny, 2 kg). I must store them in an array that can hold maximum 1000 elements and must be a struct type, storing the baby's firstname and weight.
Every actions must be done in functions - however, when I tried to get the name until the comma, str.copy() didn't work for me. Its specific problem was something with the last parameter, the position. Could someone help me out with that? Also, I'm kinda new to C++ and imagining how to separately, in two functions ask in the char arrays until empty line and do the copying in the other... if someone could help me out, I'd be grateful for that ^^'
Thanks for the help in advance!
#include<iostream>
#include<string>
#define M 1000
struct baby{
std::string baby_name;
float weight;
};
int readIn(baby* baby_datapair, int max);
// int maxWeight(baby* baby_datapair);
// int minWeight(baby* baby_datapair);
// void descendingOrder(baby* baby_datapair, int num);
int main(){
baby baby_array[M];
int n = readIn(baby_array, M);
return 0;
}
int readIn(baby* baby_datapair, int max){
int n = 0;
char name[12];
while (n < max){
std::cout << "Baby" << n+1 << "'s datas (Nickname, weight in kg): ";
std::getline(std::cin, name);
//~ std::cin.ignore(1);
if (neve == ""){
std::cout << "Wrong input!\n";
break;
}else{
std::size_t pos = name.find(',');
std::size_t until = name.copy(baby_datapair[n].baby_name, 0, pos);
}
n++;
}
return n;
}
// int maxWeight(baby* baby_datapair){
// }
// int minWeight(baby* baby_datapair){
// }
// void descendingOrder(baby* baby_datapair, int num){
// }
You must use std::string name; instead of char name[12]; as std::getline 's parameter. BTW, It make better for memory management. After input data, check pos value for valid value.
#include<iostream>
#include<string>
#define M 1000
struct baby {
std::string baby_name;
float weight;
};
int readIn(baby* baby_datapair, int max);
// int maxWeight(baby* baby_datapair);
// int minWeight(baby* baby_datapair);
// void descendingOrder(baby* baby_datapair, int num);
int main() {
baby baby_array[M];
int n = readIn(baby_array, M);
return 0;
}
int readIn(baby* baby_datapair, int max) {
int n = 0;
//char name[12];
std::string name;
while (n < max) {
std::cout << "Baby" << n + 1 << "'s datas (Nickname, weight in kg): ";
std::getline(std::cin, name);
//~ std::cin.ignore(1);
if (name == "") {
std::cout << "Wrong input!\n";
break;
}
else {
std::size_t pos = name.find(',');
if (pos <= 0) {
std::cout << "Invalid input structure!\n";
continue;
}
//std::size_t until = name.copy(baby_datapair[n].baby_name, 0, pos);
baby_datapair[n].baby_name = name.substr(0, pos);
baby_datapair[n].weight =(float)atof(name.substr(pos+1).c_str());
//std::cout << std::endl;
//std::cout << baby_datapair[n].baby_name;
//std::cout << ", " << baby_datapair[n].weight;
}
n++;
}
return n;
}
// int maxWeight(baby* baby_datapair){
// }
// int minWeight(baby* baby_datapair){
// }
// void descendingOrder(baby* baby_datapair, int num){
// }
You are taking it the wrong size. You should not try to copy to, but just copy from. BTW, name must be a std::string for you program to compile, and you should check for possible end of file. So a minally fixed version could be:
std::string name;
while (n < max) {
std::cout << "Baby" << n + 1 << "'s datas (Nickname, weight in kg): ";
std::getline(std::cin, name);
//~ std::cin.ignore(1);
if ((! std::cin) || name == "") {
std::cout << "Wrong input!\n";
break;
}
else {
std::size_t pos = name.find(',');
baby_datapair[n].baby_name = std::string(name.c_str(), pos);
baby_datapair[n].weight = strtof(name.c_str() + pos + 1, nullptr);
}
But using a std::stringstream would be more idiomatic in C++. Above code is rather C-ish...

Huffman Encoding priority queue

I'm working on an assignment where I should write an encoding and decoding application for the Huffman algorithm, based on a priority queue. We have to read a file, count the frequencies of the letters and then start the algorithm. I have the following problem:
My counting function works fine but it stores the frequency of every letter in an array - even if it's zero. But if I want to use that array to build my min heap I get major problems because of the zeros. Therefore I need to find a way to 'eliminate' them. I can't just skip them because then the min heap algorithm doesn't work anymore (wrong neighbours). So I wanted to transfer all non-zero entries in a vector and use the vector instead of the array. But there I always get an error that tells me that there's a problem with the vector size. I don't really know how to deal with that problem. (My min heap still uses the array because I can't even transfer the entries in a vector).
(Please ignore the main I was just trying stuff there!)
using namespace std;
struct huffman_node
{ char data;
int frequency;
bool vector;
huffman_node *left;
huffman_node *right;
};
void swap_huffman_nodes(huffman_node &a, huffman_node &b)
{ char store_data = a.data;
int store_frequency = a.frequency;
a.data = b.data;
a.frequency=b.frequency;
b.data = store_data;
b.frequency = store_frequency;
huffman_node *store_left = a.left;
huffman_node *store_right= a.right;
a.left = b.left;
a.right = b.right;
b.left = store_left;
b.right = store_right;
}
void print_node (huffman_node a)
{ cout << a.data << a.frequency << endl;
}
string line;
huffman_node Table[52];
vector <huffman_node> non_zero;
void build_table()
{ for (int i=1; i<27; i++)
{ Table[i].data = (char) (i+64);
Table[i].left = NULL;
Table[i].right = NULL;
}
for (int i=27; i<53; i++)
{ Table[i].data = (char) (i+70);
Table[i].left = NULL;
Table[i].right = NULL;
}
}
int counter =0;
void count(){
ifstream yourfile ("example.txt");
if (yourfile.is_open())
{
while ( getline (yourfile,line) )
{
/*cout << line << '\n'; */
unsigned long z=line.length();
int i=0;
while ( i < z)
{ /* cout << line[i] << endl; */
for (int j=65; j<91; j++)
{ if ((int) line[i] == j)
{ int k=-64+j;
Table[k].frequency++;
}
}
for (int j=97; j<123; j++)
{ if ((int) line[i] == j)
{ int k=-70+j;
Table[k].frequency++;
}
}
i++;
}
}
for (int i=1; i<53; i++)
{ if (Table[i].frequency!=0)
{ non_zero.push_back(Table[i]);
counter ++;
}
}
yourfile.close();
}
else cout << "Unable to open file";
}
class heap{
public:
void buildheap()
{
for (int i=1; i<53; i++)
{reheap(i);
};
}
void reheap(int new_index)
{ int parent_index = new_index/2;
while (parent_index > 0 && Table[parent_index].frequency > Table[new_index].frequency)
{ swap_huffman_nodes(Table[parent_index], Table[new_index]);
parent_index=parent_index/2;
new_index=new_index/2;
}
};
void delete_root()
{ int non_null_entries=0;
for (int i=1; i<53; i++)
{ if (Table[i].frequency!=-1) {non_null_entries++;};
}
swap_huffman_nodes(Table[1],Table[non_null_entries]);
Table[non_null_entries].frequency=-1;
non_null_entries--;
rebuild_heap_root_deletion(1, non_null_entries);
}
void rebuild_heap_root_deletion(int new_root,int non_null_entries){
int n;
if (2 * new_root > non_null_entries){
return;
}
if (2 * new_root + 1 <= non_null_entries
&& Table[2*new_root+1].frequency < Table[2*new_root].frequency){
n = 2 * new_root + 1;
} else {
n = 2 * new_root;
}
if (Table[new_root].frequency > Table[n].frequency){
swap_huffman_nodes(Table[new_root], Table[n]);
rebuild_heap_root_deletion(n, non_null_entries);
}
}
void add_element(huffman_node new_heap_element)
{ for (int i=52; i>0;i-- )
{ if (Table[i].frequency==-1 && Table[i-1].frequency!=-1)
{ Table[i]=new_heap_element;
reheap(i);
break;
}
}
}
void print_Table()
{
for (int i=1; i<53; i++)
{ /*if (Table[i].frequency != -1) */
cout << Table[i].frequency << " , " << Table[i].data << endl;
}
}
bool empty_heap() // a heap is empty here if there are only "invalid huffman nodes" in it except the first one that contains all information.
{ for (int i=2; i < 53; i++)
{ if (Table[i].frequency!=-1)
{ return false;}
}
return true;
}
};
int main(){
ofstream myfile ("example.txt");
if (myfile.is_open())
{
myfile << "Flori ist ein Koala.";
myfile << "";
myfile.close();
}
else cout << "Unable to open file";
build_table();
count();
heap allan;
cout << "\n";
allan.buildheap();
allan.print_Table();
int i=0;
/*while(i<500)
{
huffman_node base_1 = Table[1];
allan.delete_root();
huffman_node base_2 = Table[1];
allan.delete_root();
huffman_node parent;
parent.data = '/';
parent.frequency = base_1.frequency + base_2.frequency;
parent.left = &base_1;
parent.right = &base_2;
allan.add_element(parent);
i++;
}
return 0;
}

(C++) terminate called after throwing an instance of 'std::bad_alloc'

I keep getting an error of bad memory allocation. I've spent the whole night trying to find where I went wrong but I can't figure out what.
I've combed through every line but still nothing. Could it be that my program/laptop just isn't strong enough?
Any help would be extremely helpful. My head is ringing and I need some rest.
Here's my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
// struct to store word + count combinations
struct wordItem{
string word;
int count;
};
void getStopWords(char *ignoreWordFileName, vector<string>& _vecIgnoreWords);
bool isCommonWord(string word, vector<string>& _vecIgnoreWords);
void printTopN(wordItem wordItemList[], int topN);
void doubleArray(wordItem wordItemList[], int size);
int getTotalNumberNonCommonWords(wordItem wordItemList[], int size, int wordCount);
const int STOPWORD_LIST_SIZE = 50;
// ./a.out 10 HW1-HungerGames_edit.txt HW1-ignoreWords.txt
int main(int argc, char* argv[]){
vector<string> vecIgnoreWords(STOPWORD_LIST_SIZE);
// verify we have the correct # of parameters, else throw error msg & return
if (argc != 4){
cout << "Usage: ";
cout << argv[0] << " <number of words> <filename.txt> <ignorefilename.txt>"<< endl;
return 0;
}
//Set vector with stop words
getStopWords(argv[3], vecIgnoreWords);
//initialize struct array
int aSize = 100;
wordItem *theStructArray = new wordItem[aSize];
int counter = 0;
int doubleCount = 0;
//read main txt file
ifstream inFile(argv[1]);
if(inFile.is_open()){
string line;
string theWord;
//extract words from file
while(getline(inFile, line)){
istringstream iss(line);
//extract and analyze word
while(iss >> theWord){
if(!(isCommonWord(theWord, vecIgnoreWords))){
bool inStructArray = false;
int inStructPosition;
//search for word in Struct array
while (inStructArray == false){
for(int i=0; i<aSize; i++){
if (theWord == theStructArray[i].word){
inStructArray = true;
inStructPosition = i;
}
}
break;
}
//if word is in struct array
if (inStructArray == true){
theStructArray[inStructPosition].count++;
}
//else if it isn't
else{
//create new wordItem and add into struct
wordItem newWord;
newWord.word = theWord;
newWord.count = 1;
theStructArray[counter+(100*doubleCount)] = newWord;
counter++;
}
//if struct array hits maximum amount of elements,
if (counter == (aSize-1)){
doubleArray(theStructArray, aSize);
counter = 0;
doubleCount++;
aSize +=100;
}
}
}
}
inFile.close();
}
//Bubble sort masterArray
int bI, bJ, flag = 1;
wordItem bTemp;
for(bI=1; (bI <= aSize && flag); bI++){
flag = 0;
for(bJ=0; bJ<aSize; bJ++){
if(theStructArray[bJ+1].count > theStructArray[bJ].count){
bTemp = theStructArray[bJ];
theStructArray[bJ] = theStructArray[bJ+1];
theStructArray[bJ+1] = bTemp;
flag = 1;
}
}
}
//Print topN words
printTopN(theStructArray, atoi(argv[1]));
//print others
cout << "#" << endl;
cout << "Array doubled: " << doubleCount << endl;
cout <<"#" << endl;
cout << "Unique non-common words: "<< (aSize-100+counter)<<endl;
cout << "#"<<endl;
cout <<"Total non-common words: "<< getTotalNumberNonCommonWords(theStructArray, aSize, counter)<<endl;
return 0;
}
void getStopWords(char *ignoreWordFileName, vector<string>& _vecIgnoreWords){
ifstream inFile(ignoreWordFileName);
if(inFile.is_open()){
int a = 0;
string line;
while(getline(inFile, line)){
_vecIgnoreWords.insert(_vecIgnoreWords.begin() + a, line);
}
inFile.close();
}
return;
}
bool isCommonWord(string word, vector<string>& _vecIgnoreWords){
for(int i=0; i<STOPWORD_LIST_SIZE; i++){
if(word == _vecIgnoreWords.at(i)){
return true;
}
}
return false;
}
void printTopN(wordItem wordItemList[], int topN){
cout << endl;
for(int i=0; i<topN; i++){
cout<< wordItemList[i].count << '-' << wordItemList[i].word << endl;
}
return;
}
void doubleArray(wordItem wordItemList[], int size){
wordItem *tempArray = new wordItem[size+100];
for(int i=0; i<size; i++){
tempArray[i] = wordItemList[i];
}
delete [] wordItemList;
wordItemList = tempArray;
}
int getTotalNumberNonCommonWords(wordItem wordItemList[], int size, int wordCount){
int total = 0;
for(int i=0; i<(size-100+wordCount); i++){
total+=wordItemList[i].count;
}
return total;
}
You are doing very bad things in void doubleArray(wordItem wordItemList[], int size)
you can call delete [] on the array if you pass an array, but you cannot change its value, so doubleArray(theStructArray, aSize); will cause theStructArray to be deleted but not assigned to the memory you allocated. You are just assigning the local variable in the function doubleArray
It is similar to:
void doubleit(int x)
{
x *= 2;
}
int y=3;
doubleit(y);
here x was momentarily doubled to 6, but y never changed.
you need to use references, or better make theStructArray a std::vector and be done with it.

Moving For Loop to Function

in the following code I have a for loop in my main function. Since a function can't return 2 values, what are some ways I could create a function, or functions, to remove it from my main function. Thanks!
#include <iostream>
#include <cmath>
using namespace std;
int getNumberExercises();
int getScores(int numberOfExercises);
int getPoints(int numberOfExercises);
double roundToTenth(double number);
double calcPercentage(int totalScore, int totalPoints);
void getTotal(int totalScore, int totalPoints, double scorePercentage);
int main() {
int numberOfExercises = 0;
int totalScore = 0;
int totalPoints = 0;
double scorePercentage = 0.0;
numberOfExercises = getNumberExercises();
for (int i = 1; i <= numberOfExercises; i++) {
totalScore += getScores(i);
totalPoints += getPoints(i);
}
scorePercentage = calcPercentage(totalScore, totalPoints);
getTotal(totalScore, totalPoints, scorePercentage);
return 0;
}
int getNumberExercises() {
int numberOfExercises;
cout << "How many exercises to input? ";
cin >> numberOfExercises;
cout << endl;
return numberOfExercises;
}
int getScores(int i) {
int score = 0;
cout << "Score received for exercise " << i << ": ";
cin >> score;
return score;
}
int getPoints(int i) {
int points = 0;
cout << "Total points possible for exercise " << i << ": ";
cin >> points;
cout << endl;
return points;
}
double roundToTenth(double number) {
return floor(number * 100 + 0.5) / 100;
}
double calcPercentage(int totalScore, int totalPoints) {
double scorePercentage = (double) totalScore / totalPoints * 100;
return scorePercentage;
}
void getTotal(int totalScore, int totalPoints, double scorePercentage) {
cout << "Your total is " << totalScore << " out of " << totalPoints << ", or " << roundToTenth(scorePercentage) << "%";
}
Either typedef a std::pair to a descriptive name, or create your own type to hold the things you want to return:
using ScorePointPair = std::pair<int, int>; // C++11
typedef std::pair<int, int> ScorePointPair; // pre C++11
Or
struct ScorePointPair
{
int score;
int points;
};
Then simply return this from your function (by value):
ScorePointPair fun()
{
// Loop etc...
return {score, points};
};
I would recommend the custom type (struct/class) approach, as this tends to be more maintainable.
To return multiple values use pass by pointer:
void modify(int *val1, int *val2)
{
*val1 = 46;
*val2 = 100;
}
In caller:
int a, b;
modify(&a, &b);
Now a will be 46, and b will be 100. This is because the address is copied, rather than the actual variable, which is what happens in pass by value.
So if you want to find the number of occurences of tabs and commas in a file:
void findtabcomma(const char *fn, int *ncomma, int *ntab)
{
FILE *fp;
int c;
if (fp = fopen(fn, "r")) {
while ((c = getc(fp)) != EOF) {
if (c == '\t')
++(*ntab);
if (c == ',')
++(*ncomma);
}
fclose(fp);
}
}
You can use the function like this:
int c, t;
findtabcomma(filenam, &c, &t);
printf("Commas: %d\nTabs: %d", c, t);
And in C++, you can use reference variables. So the findtabcomma function could be rewritten as:
void findtabcomma(const char *fn, int &ncomma, int &ntab)
{
FILE *fp;
int c;
if (fp = fopen(fn, "r")) {
while ((c = getc(fp)) != EOF) {
if (c == '\t')
++ntab;
if (c == ',')
++ncomma;
}
fclose(fp);
}
}
And used like this:
int c, t;
findtabcomma(filenam, c, t);
printf("Commas: %d\nTabs: %d", c, t);
Notice how there are no more *s and &s with C++ references.
You can create a function that either returns an array of type int of size 2 such as
int* functionName(arg1, arg2)
array[0] = totalScore;
array[1] = totalPoints;
return array;
or you could pass in the values by reference by doing something like
void functionName(&arg1, &arg2)
What passing by reference does is it passes the ADDRESS of the variable and then modifies the variable directly instead of creating a copy and passing it into the function.
You can use reference in the argument list to return data
int fun(); can be coded as void fun(int& )

Why is my data member empty even after construction?

I have included both my definition of the Question class and its implementation, the first is a header file and the second a cpp file.
I put comments in to show where the problem is. For some reason under the constructor I can cout the questionText just fine but when I try to do this under the getQuestionText function it just outputs an empty string? Any help would be most appreciated!! Thanks!
#include <string>
#include <vector>
#include <iostream>
using namespace std;
#ifndef QUESTION_H
#define QUESTION_H
class Question{
public:
Question(int thePointValue, int theChapterNumber, \
string theQuestionText);
int getPointValue() const;
int getChapterNumber() const;
string getQuestionText() const;
virtual void writeQuestion(ostream& outfile) const;
virtual void writeKey(ostream& outfile) const;
private:
int pointValue;
int chapterNumber;
string questionText;
void writePointValue(ostream& outfile) const;
};
#endif
#include "Question.h"
Question::Question(int thePointValue, int theChapterNumber, \
string theQuestionText)
{
pointValue = thePointValue;
chapterNumber = theChapterNumber;
questionText = theQuestionText;
//HERE THIS WORKS PERFECTLY
cout << questionText << endl;
}
int Question::getPointValue() const
{
return pointValue;
}
int Question::getChapterNumber() const
{
return chapterNumber;
}
string Question::getQuestionText() const
{
//THIS IS THE PROBLEM. HERE IT OUPUTS AN EMPTY STRING NO MATTER WHAT!
cout << questionText << endl;
return questionText;
}
void Question::writeQuestion(ostream& outfile) const
{
writePointValue(outfile);
outfile << questionText << endl;
}
void Question::writeKey(ostream& outfile) const
{
writePointValue(outfile);
outfile << endl;
}
void Question::writePointValue(ostream& outfile) const
{
string pt_noun;
if (pointValue == 1)
pt_noun = "point";
else
pt_noun = "points";
outfile << "(" << pointValue << " " << pt_noun << ") ";
}
vector<Question *> QuestionsList(string filename, int min, int max)
{
vector<Question *> QuestionList;
string line;
vector<string> text;
ifstream in_file;
in_file.open(filename.c_str());
while (getline(in_file, line))
{
text.push_back(line);
}
string type;
for(int i = 0; i < text.size(); i ++)
{
int num = text[i].find('#');
type = text[i].substr(0, num);
if (type == "multiple")
{
MultipleChoiceQuestion myq = matchup(text[i]);
MultipleChoiceQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
if (type == "short")
{
ShortAnswerQuestion myq = SAmatchup(text[i]);
ShortAnswerQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
if (type == "long")
{
LongAnswerQuestion myq = LAmatchup(text[i]);
LongAnswerQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
if (type == "code")
{
CodeQuestion myq = CODEmatchup(text[i]);
CodeQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
cout << QuestionList[QuestionList.size()-1]->getQuestionText() << endl;
}
for (int i = 0; i < QuestionList.size(); i ++)
{
int numm = QuestionList.size();
cout << QuestionList[numm-1]->getQuestionText() << endl;
}
return QuestionList;
}
then when i call this in main the code breaks
vector<Question *> list = QuestionsList(pool_filename, min_chapter, max_chapter);
cout << list[0]->getQuestionText() << endl;
You are declaring, multiple times in your code, local objects and storing their pointer into the QuestionList vector (returned by the function) which, at the end of the function block, will contains dangling pointers.
MultipleChoiceQuestion myq = matchup(text[i]); // < local object
MultipleChoiceQuestion* myptr = &myq; // < pointer to local object
QuestionList.push_back(myptr); // < push back into vector
At this point you can either use dynamic memory allocation (I suggest you not to do that unless you are absolutely forced, and even in that case use one of the smart pointers provided by the standard library) or store the objects directly inside the vector.