Passing an array to a function w/ a pointer.

Started by
13 comments, last by Zahlman 17 years, 7 months ago
templewulf:
Yes it gets printed.
I looked at the cin.ignore documentation, and implimented it as such
getline(cin.ignore(2), p[n].employee_name);

which worked perfectly. Thanks for the help!
Advertisement
You used to write in C?

At the least, you have a Cism in your code.

There is no need to declair variables at the start of a function. It is usually considered a better practice to declair variables as close as reasonable to where they are initialized and used.

	int i,n;	int *p;	cout << "How many employees do you wish to enter? ";	cin >> i;	p = new (nothrow) employee;	if (p==0)		cout << "Error: Memory couldn't be allocated.";


Change that to

	cout << "How many employees do you wish to enter? ";	int i;	cin >> i;	employee* p = new (nothrow) employee;	if (p==0)		cout << "Error: Memory couldn't be allocated.";


----

And change this:
		for (n=0; n<i; n++)

to:
		for (int n=0; n<i; n++)


----

The next big issue is that you are newing memory you do not delete. This is a bad habit to get into.

There are better practices than what I will tell you to do -- but to start with, include at the end of the function:
delete[] p;

Other than that, you are looking good!
Thanks,
I wasn't sure if 'new' was anything like malloc... Guess it is.

And yes, I've done some C coding, but it's been YEARS... And I'm as close to a newbie as you can get without the PineFresh car hanger slung around my neck..
Do some googling on "RAII" -- resource allocation is initialization.

It is a pattern that really helps with the entire allocate/delete.
cplusplus.com isn't very good from what I've seen.

Please pay careful attention:

#include <iostream>#include <string>// The stringstream technique you were using is a good way of making the input// more robust; if you just do that when you read 'i' as well, then you will// have no problems, because the newline is "consumed".// However, because we are going to do that several times, we'll make a helper// function for it.#include <sstream>// We're also going to need one more include:#include <vector>// This is a nice toy that we're going to use to avoid having to play with// memory allocation ourselves.// By the way, in normal C++ code you shouldn't use 'nothrow' delete, nor check// for success. The normal form of new cannot return NULL; it will throw an// exception on error. You then have much more freedom over how you handle // memory allocation failures. Most programs don't, because realistically you're// screwed anyway :)// But with std::vector, all memory allocation and deallocation will be handled// for us; the only thing we might have to do is handle an exception, but it's// usual to ignore them (the behaviour of an exception that falls all the way// through is quite well defined).using namespace std;struct employee {  // Don't include "employee" or short forms thereof in the names of "employee"  // data members. It's redundant and does not add extra information.  int id;  string name;  float salary;  string position;};// In C++, we can "make structs printable": just as formatted stream output // handles each primitive type differently according to the type, we can// define how it behaves for our own types:ostream& operator<<(ostream& os, const employee& e) {  // Within the operator overload, we don't want to flush the buffer, because  // that confuses responsibilities - and isn't consistent: other types don't  // do this. So instead, we'll just output the newlines:  return os << "Name:     " << e.name << '\n'            << "ID:       " << e.id << '\n'            << "Salary:   " << e.salary << '\n'            << "Position: " << e.position << '\n';  // Notice (a) we're outputting to a *parameter* 'os', instead of always to  // cout; it's the calling code's responsibility to define where to output to,  // and we can output to any stream now.  // (b) there's nothing about ending a line - of source or output text - which  // requires you to "start over".  // (c) the reason this "chaining" works is because the operator returns the  // stream object from the left hand side (by reference), so that it can be  // reused for the next operator invocation. We take advantage of that  // convention by doing it all in one statement, and respect the convention by  // returning the "os".}// Because we have code now to "print an employee", we can easily print all// employees:void printemployees(const vector<employee>& employees){	for (int n = 0; n < employees.size(); n++)	{		cout << employees << endl;	}}// Notice:// (a) now we can, as promised, just "feed each employee to cout" as if it were// of a built-in type.// (b) we can declare and initialize the counter variable as part of the for// statement.// (c) we can index the vector just as if it were an array.// (d) we pass the vector "by const reference": the '&' indicates// pass-by-reference, which is *like* passing by pointer (to avoid copying// something and "sharing" an object between caller and callee), but without// requiring the caller to address-of, or the function to dereference. For all// intents and purposes, it makes the vector inside the function *be* the// vector in the calling function (main(), for us).// (e) the vector "knows its size", so we don't have to pass that information// along at all.// (f) there are plenty of other ways to do this, some of which don't actually// involve writing a loop, but instead invoking "algorithms" from the standard// library. The C++ standard library is a wonderful thing. :) Anyway, this// function is pretty useless for what it does, but it illustrates a lot ;)// Here's our function for reading a line of input and interpreting it as the// given type. I'll again use a reference parameter; this time it is not// 'const', because we want to change the value locally (the caller will// automatically see the change, as if it had been done by the caller). This// function is templated (like the std::vector class is templated), so we can// use it for any type that can be read in by the >> operator; at compile-time,// the compiler can determine which version of the function to use according to// the compile-time type of the parameter we give it.// We'll return false, and make no change, to indicate that there was an // error in input. We'll make the change and return true to indicate that input// was successful. This allows us to know what happened if the input value// happened to equal the old value of the variable.template <typename T>bool input(istream& is, T& result){	// First, grab a line from the input.	string line;	getline(is, line);	// Now, try to read it out, and see if we're successful.	return stringstream(line) >> result;	// The operator>> returns the stringstream by reference, of course,	// but since we are returning a bool, an implicit cast occurs. The	// result tells us whether reading was successful.	// That property is often exploited like this:	// while (cin >> variable) { /* do something */ } /* reached EOF now */	// Since we read into a temporary stringstream, the input stream is	// will not have been "failed" by an invalid read, so we are OK.}// Of course, that doesn't work right for inputting a string, because it will// just grab the first word. So for that case we'll just use raw getline() :)// To be rigorous about the design, though, it would be a good idea to// "specialize" the template for that case... Oh, heck, I'll show that:template <>bool input(istream& is, string& result){	return getline(is, result); // nice and simple.	// Although now we lost the ability to chain getline calls because	// of the cast to boolean ;\}// By the way, notice how I've been putting the functions *ahead of* main().// This lets us avoid extra typing (and maintenance) for prototypes, and exposes// any circular dependencies (because we're forced to prototype for those).int main(){	// As was mentioned, in C++ there is no need to declare variables at	// the top of a scope, and it's generally agreed that you *should not* -	// instead, put them near first use.	cout << "How many employees do you wish to enter? ";	int i;	input(cin, i);	// Now we have the information we need to create our vector:	vector<employee> employees(i);	// This declares and initializes a single vector, via one of the	// "constructors" of std::vector: this one just takes an int value,	// and uses it as the size of the dynamic memory that is allocated.	// (A vector can be resized during its lifetime, but it will not	// automatically resize just because you ask for an array index beyond	// its current bounds. Also, when the vector resizes, the contents will	// relocate in memory, with the old memory allocation being cleaned up	// automatically. There *is* a member function available, .push_back(),	// which you can use to append to the end (automatically resizing if	// needed).	for (int n = 0; n < employees.size(); n++)	// Again, as noted, we don't need 'i' any more.	{		cout << "Please enter the employee's name: ";		input(cin, employees[n].name);					cout << "Please enter the employee's ID Number: ";		input(cin, employees[n].id);					cout << "Please enter the employee's salary: ";		input(cin, employees[n].salary);		cout << "Please enter the employee's position: ";		input(cin, employees[n].position);	}	printemployees(employees);	// You don't need to 'return 0' at the end explicitly. As a special	// case, reaching the end of main() returns 0.}

This topic is closed to new replies.

Advertisement