Why is my variable not declared in the scope? - c++

I'm working on an assignment right now and when run my code returns this error:
main.cpp:60:20: error: ‘dataArr’ was not declared in this scope
if(tolower(dataArr[i].last) == tolower(lastName))
I'm not quite sure what I'm missing here. If I could at least get it to run I'd appreciate it. Thanks.
I thought arrays were declared globally so i thought it wouldn't be an issue in my functions
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Database
{
string first;
string last;
string ID;
string phoneNum;
};
void lastSearch(string);
void idSearch(string);
int main()
{
Database dataArr[100];
ifstream myFile("library_database.txt");
int count = 0;
while(!myFile.eof() && count < 100)
{
myFile >> dataArr[count].first >> dataArr[count].last >> dataArr[count].ID >> dataArr[count].phoneNum;
cout << dataArr[count].first << " " << dataArr[count].last << " " << dataArr[count].ID << " " << dataArr[count].phoneNum << endl;
count++;
}
int input;
string search;
cout << "Would you like to search by last name or member ID?\n1. Last Name\n2. ID\n> ";
cin >> input;
while(input != 1 || input != 2)
{
cout << "Enter a valid answer.\n> ";
cin >> input;
}
if(input == 1)
{
cout << "Enter last name: ";
cin >> search;
lastSearch(search);
}
if(input == 2)
{
cout << "Enter ID: ";
cin >> search;
idSearch(search);
}
return 0;
}
void lastSearch(string lastName)
{
int num = 0;
for(int i = 0; i < 100; i++)
{
if(tolower(dataArr[i].last) == tolower(lastName))
{
cout << dataArr[i].first << " " << dataArr[i].last << " " << dataArr[i].ID << " " << dataArr[i].phoneNum << endl
num++;
}
}
if(num == 0)
{
cout << "No match was found in the file.";
}
}
voidSearch was removed to allow this to be posted

To answer the title of your post: because it isn't.
You declare dataArr in main, but you are trying to use it in lastSearch, so lastSearch can't see it. But you can pass it in as a parameter, that's probably the easiest fix:
void lastSearch(const string lastName, const Database *dataArr) { ... }
and call it like this:
lastSearch (search, dataArr);
Note the use of const (get into the habit of doing that whenever you can) and that your array 'decays' to a pointer when you pass it as a parameter like this, so don't be tempted to use sizeof in lastSearch. If you need to know the number of elements in the array, pass that as a parameter too.
Or, better, use std::array instead of a C-style array and then the size of the array is available in lastSearch without the need to pass it in separately. If you do that, you probably want to pass it by const reference to avoid copying it every time you call the function.
Finally, it might be time to learn about std::vector. At the expense of a little more complexity (but not much), this would avoid the need to allocate a fixed size array. Again, for the same reason, pass it around by reference.
Some bedtime reading: The Definitive C++ Book Guide and List

Arrays are not declared globally, they are declared where you declare them :-)
In your case, you declare it at the top of main() so that is its scope, from point of declaration to end of main(). Trying to use it in lastSearch() is therefore invalid.
The easiest fix is probably just to move the declaration immediately before main() so that it is global. But the easiest things is often not the right thing.
You would be better off embracing C++ fully(1) and using something like std::vector, whose size isn't arbitrarily limited to 100 (for example) and which you could pass around quite easily, something like:
#include <iostream>
#include <vector>
void function(const std::vector<int> &vec) {
std::cout << vec.size() << ' ' << vec[0] << '\n'; // Output: 2 42
}
int main() {
std::vector<int> x;
x.push_back(42);
x.push_back(99);
function(x);
}
The main advantages with vectors are that:
you're not limited to a maximum of 100 items;
you don't have to pass around the actual count of items read separately as with a raw array or even a std::array (you don't do that in your code but I assure you, that's a problem).
the size of the vector is an integral property of the vector, available anywhere the vector is in scope.
(1) There's a variety of developers I like to call C+ developers. These are the people that, though they claim to be C++ developers, have never really embraced the C++ way of doing things, sticking to C style programming practices like non-smart pointers or normal arrays :-)
Some of those things may still have a place in modern C++ code but you should be circumspect in their use.

Related

My homework assignment requires me to use booleans in functions. Do I need to pass them to the functions?

For my homework assignment I'm supposed to make a create-your-own-adventure story. There are certain words in the text that are in all caps to represent boolean values that I need to display at the end if the player got them, like a status effect or something. I'm having trouble figuring out how to pass the booleans to the functions so that it makes it to the end of the program where I can display it. My program has functions within functions.
I've tried making the function that sets the boolean to true a boolean itself, then returning the boolean but that just ends the program it seems. I've also tried passing it through the first function call to see if it reaches the second but it doesn't seem like it wants to.
void A1();
bool A100(bool INTIM);
void A167();
void A232();
void A290();
void A13();
void A212();
void A173();
void A159();
void A161();
int main() {
bool INTIM;
A1();
cout << INTIM << endl;
return 0;
}
void A1()
{
int choice;
cout << "Well, Mr Artanon, ...\n 1. ’It’s you who’ll get a rare cut
across that corpulent neck of yours if you don’t speed things along, you
feckless blob of festering lard.’\n 2. ’Surely in such an industrious
kitchen, there must be a starter or two ready to send along and sate His
Abhorentness’s appetite?’\n (enter a menu option): ";
cin >> choice;
while (choice != 1 && choice != 2)
{
cout << "Enter in a valid choice (1 or 2)";
cin >> choice;
}
if (choice == 1)
{
A100();
}
if (choice == 2)
{
A167();
}
}
bool A100(bool INTIM)
{
int choice;
INTIM = true;
cout << " Repugnis turns a paler...\n 1. Onwards, Mr Artanon.\n (enter
in a menu option): ";
cin >> choice;
while (choice != 1)
{
cout << "Enter in a valid option (1)";
}
return INTIM;
A232();
}
What I'm wanting to happen is, the bool INTIM to be passed along so i can display it back in main with the cout statement. I know it will just be a 1 or 0 at the end but I'm just trying to get it to show up at least in the end when I display it. Again there are functions within functions in this program and that might be my problem but I wouldn't think so. There is also functions that come after this, this is not the end of the program and if I need to post the whole thing I will
Calling A100 as written, you need to pass in INTIM and accept the return value
INTIM = A100(INTIM);
But... The initiqal state of INTIM is never used, so you could
INTIM = A100();
and change A100 to look more like
bool A100()
{
int choice;
cout << " Repugnis turns a paler...\n 1. Onwards, Mr Artanon.\n (enter in a menu option): ";
cin >> choice;
while (choice != 1)
{
cout << "Enter in a valid option (1)";
cin >> choice; // added here because otherwise choice never changes
// and this loop will go on for a long, long time.
}
A232(); // moved ahead of return. Code after a return is not run
return true;
}
But since A232 is called and may set additional flags you cannot return, you have a design flaw: What if A232 also modifies a boolean? You can only return one thing from a function. You could pass A232's boolean in by reference, but what it A232 then calls B484 and it also has a boolean?
You don't want to have to pass around every possible boolean, that would be a confusing mess, so consider making a data structure that stores all of your booleans to pass around.
And that leads to an even better idea: encapsulating the booleans and the functions in the same data structure so that you don't have to pass anything around; it's all in the same place.
Do I need to pass them [the boolean results] to the functions?
Often, but not always, it is my preference to pass them by reference, and yes, it can get to be a big chain thru many functions. sigh.
But your question is "Do you need to pass them ...".
The answer is No.
Because
a) you have tagged this post as C++, and
b) the key feature of C++ is the user-defined-class.
Consider declaring every 'adventurous function' of your story within a class scope.
Each 'adventurous function', as an attribute of the class, is implemented with one 'hidden' parameter, the 'this' pointer to the class instance.
So .. if you place all your 'result' booleans as data attributes of the class, invoking any 'adventurous function' will also 'pass' all the class instance data attributes (all your bools!) as part of the invocation. No data is actually moving, just a pointer, the 'this' pointer.
It might look something like this:
#include <iostream>
using std::cout, std::cerr, std::flush, std::endl;
// using std::cin;
#include <iomanip>
using std::setw, std::setfill;
#include <sstream>
using std::stringstream;
#include <string>
using std::string;
namespace AS // Adventure Story
{
class CreateYourOwnAdventureStory_t
{
private:
// diagnostic purposes
stringstream ssUI;
// command line arguments concatenated into one string
// contents: strings convertable to ints to mimic cin
bool INTIM;
// other results go here
public:
int operator()(int argc, char* argv[]) {return exec(argc, argv);}
private:
int exec(int argc, char* argv[])
{
int retVal = 0;
// capture all command line arguments into a string
for (int i=1; i<argc; ++i)
ssUI << argv[i] << " ";
cout << "\n ssUI: " << ssUI.str() << "\n\n\n";
A1();
cout << "\n INTIM : " << INTIM << endl;
// ?more here?
return retVal;
}
void A1()
{
int choice = 0;
cout << "Well, Mr Artanon, ...\n "
"\n 1. ’It’s you who’ll get a rare cut across that corpulent neck of yours "
"if you don’t speed things along, you feckless blob of festering lard. "
"\n 2. ’Surely in such an industrious kitchen, there must be a starter or two "
"ready to send along and sate His Abhorentness’s appetite?’"
"\n (enter a menu option): ";
ssUI >> choice; // cin >> choice;
if (choice == 1) { A100(); }
if (choice == 2) { A167(); }
}
void A100()
{
int choice = 0;
INTIM = true;
ssUI >> choice; // cin >> choice;
cout << "\n\n A100() choice:" << choice
<< " INTIM: " << INTIM << endl;
}
void A167()
{
int choice = 0;
INTIM = false;
ssUI >> choice; // cin >> choice;
cout << "\n\n A167() choice:" << choice
<< " INTIM: " << INTIM << endl;
}
// other action-functions go here
}; // class CreateYourOwnAdventureStory_t
typedef CreateYourOwnAdventureStory_t CreateYOAS_t;
} // namespace AS
int main(int argc, char* argv[]){return AS::CreateYOAS_t()(argc,argv);}
Notes:
This example grabs the command line parameters and appends them to a string stream. The result is use-able in a fashion much like your cin statements.
Did you notice you (probably) will not need forward declarations for your functions? The compiler has to scan a lot of the class declaration to decide various issues, and thus can figure out that A100 (and A167) are actually with-in the scope of AS::CreateYOAS_t::. The functions can still be moved into a cpp file, so you can still take advantage of separate compilation. (and maybe save some effort compiling smaller files, and only the changed files.)
Did you notice that the functions accessing INTIM simply use the bool, without needing any 'this->' to de-reference?
Main invokes a simple Functor. Nothing else. Main invokes operator(). Simple, minimal. The ctor and dtor are currently default. If you need to use the ctor to initialize results or other intermediate info, I would simply add it near the operator() implementation.
PS: You mentioned using bools to return results. You might as, an alternative, consider using a stringstream ... a single stream with text ... use like a log for capturing the ongoing game, or for a single simple overall report to the user.
Good luck.

Storing dynamic array in vector

I have to display a histogram of a student's grades. I've stored the grades in a dyn. array, but my goal is to store them in a vector. What's the right way of going about this? Hope this makes sense.
Edit:
My attempt at using a vector
void displayHistogram(int minGrade, vector<int> ptrV) {
cout << endl;
for (int i = 0; i <= minGrade; i++) {
if (ptrV[i] != 0) {
cout << "Number of " << i << "'s: " << ptrV[i] << endl;
}
}
}
void histogram() {
int minGrade = 0, grade;
const int grade_max = 100;
vector<int> ptrV(grade_max, 0);
cout << "Enter the student's grades (-1 to stop entering): \n";
do {
cin >> grade;
if (grade > minGrade) {
minGrade = grade;
}
if (grade >= 0) {
ptrV.push_back(grade);
}
} while (grade != -1);
displayHistogram(minGrade, ptrV);
}
Your basic mistake is that you try to force the vector as if it was a raw array. It does stuff for you, let it. It knows it's size, for instance. You don't need
void displayHistogram(int minGrade, vector<int> ptrV) {
cout << endl;
for (int i = 0; i <= minGrade; i++) {
Instead, you can use vector::size:
void displayHistogram(vector<int> ptrV) {
cout << endl;
for (size_t i=0; i<ptrV.size(); i++) {
(Even better: void displayHistogram(const vector<int>& ptrV) to signify that ptrV is not changed here and to avoid copying it every time you call the function by using a reference.)
(If you wouldn't use the i as it is the grade and if you have a newer compiler, I'd recommend a for each loop instead. Those are usually the way to go, just happens that you have one of the rarer cases in which it isn't.)
Likewise, you first set the size of your vector and then increase it, which to me means that you do not trust it:
vector<int> ptrV(grade_max, 0);
At this point, you have a vector with a hundred entries that are all zero. You don't need to resize it later if a hundred entries is all you need. vector::push_back resizes it. But note that setting it to a size of 100 means that [100] is not a valid position, the last one is [99], as we start to count at zero. You'd need to set it to a size of 101 to have both zero and hundred as valid addresses.
I'd change your code to:
const int grade_max = 100;
vector<int> ptrV(grade_max+1, 0); //changed it to +1 here as prtV[100] should be legal
cout << "Enter the student's grades (-1 to stop entering): \n";
while (true)
{
int grade; // put stuff in the smallest scope possible
cin >> grade;
if(grade == -1) break; // doing that here means we don't have to think about it anymore - the do while does it at last, I do it at first, handling all the special cases at the start and then assume I have the regular case.
if(grade < 0 or grade > grade_max) continue; // continue jumps to the top of the most inner loop. Note that I make sure to catch illegal but possible input.
ptrV[grade] += 1; // personal preference, I use ++ only to iterate
}
displayHistogram(ptrV);
I rewrote the structure, using a while(true), I think the way I did it is more intuitive, but there will be people who disagree with that and who would also write things like
if(grade == -1)
{
break;
}
and there are some good arguments for that, mostly a good practice routine, always doing the braces to avoid errors. However, I prefer a one liner to reduce verbosity.
One improvement would also be to tell the user about bad input:
if(grade < 0 or grade > grade_max)
{
cout << "Input not in valid range. Please choose number within 0 to " << grade_max << endl;
continue;
}
Now, another big thing to do here would be to leave the procedural part, by the way.
Go for a class GradeHistogram which has all those functions as a part of it, being called like
GradeHistogram histogram;
histogram.take_input();
histogram.display();
but that is for when you get your code working.
(My answer became more of a review as found on CodeReview, but I think that this is what you need rather than small fixes. This is something I can only recommend you, by the way, putting your code on CodeReview once it works.)
but my goal is to store them in a vector.
The issue seems to be that you've already sized the vector to hold grade_max entries. However when filling the vector, you are using push_back. By using push_back, you are adding more entries to the end of the vector, which is not what you want to do.
The solution is either
Change this vector<int> ptrV(grade_max, 0); to this vector<int> ptrV; and leave the calls to push_back alone, or
Keep vector<int> ptrV(grade_max, 0); but instead merely use ptrV[i] = grade;
If what you want to show is a histogram, then the easiest thing to do would be to use a std::map from grade to count of grade.
Something like this:
#include <iostream>
#include <map>
int main() {
std::cout << "Enter the student's grades (-1 to stop entering): \n";
std::map<int, int> grades_map;
int input_grade = -1;
do {
cin >> input_grade;
if (input_grade > -1) {
grades_map[input_grade]++;
}
} while (input_grade != -1);
// Print histogram
for (const auto& [grade, count] : grades_map) {
std::cout << "Students with grade << grade << ": ";
for (int i = 0; i < count; ++i) {
std::cout << '*';
}
std::cout << '\n';
}
}

Retrieve all data via void function

Been trying to find a way through this. I am new to C++ and creating a simple program to get the user data, validate and cout to the screen. What i'm trying to do is to have the one function use pointers to get the users input and display back to them. This may have been answered before but I haven't had much luck finding it.
So far i have the below code
#include <iostream>
using namespace std;
void userData(int&);
int main(){
int a = 0;
int * kmpointer;
int * dayspointer;
userData();
cout << "You ran " << userData(kmpointer) << endl;
cout << "in " << userData(dayspointer) << "days!!" <<endl;
}
void userData(int& i){
cout << "Enter how Many Km's you ran:";
while (true)
{
cin >> kmpointer;
if ((cin) && (kmpointer >= 0) && (inputYear <= 100))
break;
cin.clear();
cin.ignore( 100, '\n' );
cout << "That can't be right!\n";
cout << "Enter how Many Km's you ran:";
}
cout << "How many days in a row did you run?";
while (true)
{
cin >> dayspointer;
if ((cin) && (dayspointer >= 1) && (dayspointer <= 100))
break;
cin.clear();
cin.ignore( 1000, '\n' );
cout << "Thats way to much!";
cout << "How many days in a row did you run? ";
}
}
IMO, you should start with some reading about C++. You are missing some basic concepts and trying too complex exercises for your level.
1
function is not declared/defined.
2
userData is declared accepting a parameter, but used without.
3
The problem you face is related probably with what we call scope: A variable is only existing and visible within its scope (usually enclosed by { and }.
In your case, kmpointer and dayspointerare only visible within the main function and thus, you cannot use them in userData.
To solve that, I suggest you to pass those variables as parameters for userData.
4
Pointers, references, values: They are different. You are saving the user input as a pointer address, which is indeed problematic.
General
In general, your code is full of mistakes. Try a Hello world! and continue from there steps by steps.
Focussing on the specific question you asked (though as observed you have other problems in your code), don't use pointers, use references.
Before we get to that this
cout << "You ran " << userData(kmpointer) << endl;
won't compile, since as you know userData is a void function, so applying << to it makes no sense. It's void so there's nothing to stream.
You said you wanted to pass parameters into the function and let them be changed so do that. Then display the variables afterwards. (Not the "result" of a void function call).
Correctly getting the user input is a separate question which has been answered before.
#include <iostream>
using namespace std;
void userData(int& i, int& j, int& k);
int main() {
int a = 0;
int kmpointer;
int dayspointer;
//Here we call our function, ONCE
userData(a, kmpointer, dayspointer);
//Here we display what values we now have
//after calling the function, ONCE
cout << "You ran " << kmpointer << endl;
cout << "in " << dayspointer << " days!!" << endl;
}
//simplified to demonstrate changes to the reference parameters
void userData(int& i, int& j, int& k) {
//Here we have three parameters which we refer to as i, j and k
// They may have different names ousdie in the calling code
// but this function (scope) neither knows nor cares
j = 42;
k = 101;
}

Does my source code shows my own understanding of structures in c++? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'd like to know if I am in fact in the right direction, I am currently learning the C++ language and reading this book called Jumping into C++ by Alex Allain and there's a practice problem at the end of the chapter regarding structures, to create a contact book program the user should be able to not just fill out a single structure, but should be able to add new entries, each with a separate name and phone number. Let the user add as many entries as he or she wants—is this easy to do? Add the ability to display all, or some of the entries, letting the user browse the list of entries.
so far below is what I've done, I'd like to know if my source code is in fact right and does it show my understanding about structures and overall c++?
#include "stdafx.h"
#include "iostream"
#include "string"
using namespace std;
struct user{
string name;
int phone_num;
};
int _tmain(int argc, _TCHAR* argv[])
{
int input, number; // will hold the users input at the beginning of the program
int counter = 0; // keep track of the array position
int const arraySize = 10; // size of the array
user new_username[arraySize]; // will hold the users details
string name; // will hold the users input for the name
cout << "CONTACTS\n";
do{
cout << "+ADD [1] -EXIT[0]";
cin >> input;
if(input == 1){
//cout << counter;
cout << "\nName: ";
cin >> name;
new_username[counter].name += name;
cout << endl << "\nPhone: ";
cin >> number;
new_username[counter].phone_num = number;
counter++;
//set_user(counter);
}
cout << "Name Number\n";
cout << "--------------\n";
for(int j=0; j < arraySize; j++){
cout << new_username[j].name;
cout << " -- ";
cout << new_username[j].phone_num;
cout << "\n";
}
cout << "\n";
}while(input != 0);
cout << "\n";
system("PAUSE");
return 0;
}
Stackoverflow isn't meant to be used for code reviews, but there's a different site for this (although still in beta): https://codereview.stackexchange.com/
Just some quick things I noticed:
Your program ignores invalid input (enter 2, 3 or any other number instead of 1 or 0).
You don't check whether your user array is full.
This is not really object oriented.
As for basic understanding... I guess yes, but that's not actually hard to start with.
To fulfill "allow the user to add as many entries as they want" you'll have to use a dynamic array (ask the user how many entries he'd like to add) or use some dynamic storage (e.g. a linked list).
If you want the user to be able to add as many contacts as he/she wants, you can use powerful standard template mechanisms.
For this application, I would recommend looking at either
std::vector
or
std::map
This is how you would use them: (keep in mind this is pseudo code and won't compile)
#include <vector>
typedef struct {
std::string name;
double phoneNumber;
} YourStruct;
int main( int argc, char **argv ) {
std::vector<YourStruct> structVector;
do {
int input;
std::cin >> input;
if (input) {
//(read user input for name and number)
YourStruct yourStruct;
yourStruct.name = (user input)
yourStruct.phoneNumber = (user input)
// insert into the vector
structVector.push_back(yourStruct)
}
} while (input != 0)
// now to print what you have:
for (int i = 0; i < structVector.size(); i++) {
std::cout << structVector[i].name << ", " << structVector[i].number << std::endl;
}
}
The benefit to using vectors is that it automatically resizes and keeps track of how large it is without you having to use a counter item.
Now, for something a bit trickier. We're going to use a map to use the "key" value to get the name. The following code won't compile but it is functionally how you would perform the task:
#include <map>
int main(int argc, char** argv) {
std::map<std::string,double> myMap;
// the string is the "key" value, which can be the name of the person
// while the "independent" is the phone number
do {
// determine if the user wants to put another entry in the map
if (insert) {
std::string name = (user input name)
double number = (user input number)
myMap[name] = number;
}
} while (input != 0)
// now we can iterate through the map
std::map<std::string,double>::iterator it;
for (it = myMap.begin(); it != myMap.end(); ++it) {
std::cout << it.first << ", " << it.second << std::endl;
}
// also, you can look up by name
it = myMap.find("Tony Stark");
if (it != myMap.end()) { // if this condition is met, it means you found one
std::cout << it.first << ", " << it.second << std::endl;
}
}
Overall, your code looks good. However, it is not C++. You're programming like a C programmer. The beauty of C++ (besides polymophisim, of course) is the powerful template libraries.
I've just given you a small taste of what you can do with templates. Please comment if you have any questions of concerns. We've all been where you are, kudos for teaching yourself out of a book.
From your question and the code it seems like you are a new programmer, therefore I'll explain you the answer and I'll give you some notes on your code.
In order to solve the problem of "as many items" there are few approaches. The most easy one, and probably a pretty good solution is to use map, in any language it have different names. But usually the name is dictionary, associative arrays...
Using the map will help you with dealing with:
As many items
Sorted order by name
It will be easier for you to filter, it depends what you would like to do, and how sophisticated is your filter.
The other approaches I talked about i though of, are much more basic, and consist much more code, but they give you the feeling of how you can implement the map object by yourself, but this is a different question.
In the link I mention above, the example is for phone entry. But if you still want to use struct, you can have the key as the name and the value to be the struct itself. One justification for that can be that later on you plan to add address and company name.
Some notes regarding your code.
#include "stdafx.h"
#include "iostream"
#include "string"
using namespace std;
//use meanigful name, instead of user it can be phoneEntry
struct user{
string name;
//Starting using the following conventions using the capital letter in variable names for example phoneNumber
//int won't be god for phone number since some times you will need star or hash, or a leading zero, maybe a plus sign. It is better touse string for tat as well. And of course every time that you get a user input you should validate it
int phone_num;
};
//Why the name of the function is not main, why its _tmain
int _tmain(int argc, _TCHAR* argv[])
{
//Keep going with your comments, with time you would imbrase your own style based on things that you will see. But in general commenting is very important
//Give meanigful name, instead input userCommand for example
int input, number; // will hold the users input at the beginning of the program
int counter = 0; // keep track of the array position
int const arraySize = 10; // size of the array
//Again meangful names
user new_username[arraySize]; // will hold the users details
string name; // will hold the users input for the name
cout << "CONTACTS\n";
do{
cout << "+ADD [1] -EXIT[0]";
cin >> input;
if(input == 1){
//cout << counter;
cout << "\nName: ";
cin >> name;
new_username[counter].name += name;
cout << endl << "\nPhone: ";
cin >> number;
new_username[counter].phone_num = number;
counter++;
//set_user(counter);
}
cout << "Name Number\n";
cout << "--------------\n";
for(int j=0; j < arraySize; j++){
cout << new_username[j].name;
cout << " -- ";
cout << new_username[j].phone_num;
cout << "\n";
}
cout << "\n";
}while(input != 0);
cout << "\n";
system("PAUSE");
return 0;
}
I hope it helped

Creating Structures via fstream

One of the exercises in C++ Primer Plus is having me use fstream to open a txt file and input data into a structure then output it. First line of the txt file is the number of "donors". The problem I seem to be having is that (I think) when I use "inFile >> value;" to retrieve the number and then allocate the structure via new, its expecting an int and its getting a string? Is this correct? What should I be doing differently?
//ch6 p278 exercise #9
#include <iostream>
#include <cstring>
#include <fstream>
#include <cstdlib>
using namespace std;
const int SIZE = 60;
struct contributions
{
char name[20];
double dollars;
};
char filename[20];
string donors;
bool donated;
int main()
{
char filename[SIZE];
cout << "Enter name of file to scan: ";
cin >> filename;
fstream inFile;
inFile.open(filename);
if(!inFile.is_open())
{
cout << "Could not open the file " << filename << endl;
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
inFile >> donors;
contributions * ptr = new contributions[donors];
for(int h = 0; h < donors; h++)
{
inFile >> ptr[h].name);
inFile >> ptr[h].dollars);
}
//BEGIN OUTPUT OF STRUCTURES
cout << "GRAND PATRONS:\n";
for(int i = 0; i < donors; i++)
{
if(ptr[i].dollars >= 10000)
{
cout << ptr[i].name << " donated " << ptr[i].dollars << endl;
donated = true;
}
}
if (!donated) {cout << "none.\n";}
donated = false;
cout << "PATRONS:\n";
for(int i=0; i < donors; i++)
{
if(ptr[i].dollars < 10000)
{
cout << ptr[i].name << " donated " << ptr[i].dollars << endl;
donated = true;
}
}
if (!donated) {cout << "none.\n";}
delete ptr;
return 0;
}
What should I be doing differently?
Well, if the code is based on what C++ Primer Plus has taught you - use a different text book. I don't want to insult you, but the code is really poor. For example, has the book covered the std::string class?
I would recommend junking it, and getting Accelerated C++ by Koenig & Moo (two of the original C++ team) which will teach you modern, good, idiomatic C++.
You are most certainly correct, I assume the code does not compile? You can just change the donors variable to an integer. The input streams are overloaded to work with all built in types, ie. bool, double, int etc.
The following will work, assuming the next value is an integer:
int numDonors;
inFile >> numDonors;
Note that the change to an integer is also necessary for the 'for' loops to work correctly, you are currently comparing a string to an integer, there is no built-in/default behavior for this.
Edit: I also noticed that when you delete your array of contributors you do:
delete ptr;
However, this will only clear out the first dynamically allocated block. The correct way to delete an array of dynamically allocated objects is:
delete [] ptr;
Edit 2: Thanks for the sample, so the reason it is not working correctly is the fact that the names are first and last, and the stream operator '>>' breaks on whitespace. So what is essentially happening is you first attempt to read the name, the stream reads the first name only and stops. Then you try to read the donated value, this attempts to read the last name as the value and cannot convert to an double so it returns 0.
donors is a string, and you are trying to use it as an array size:
string donors;
//...
inFile >> donors;
contributions * ptr = new contributions[donors];
You should make donors an int. Also it's usually better to use std::vector<> instead of manually messing with pointers to raw arrays. That would look something like this:
std::vector<contributions> contribs;
for (...) {
contributions contrib;
// .. Some way read contrib from inFile
contribs.push_back(contrib);
}