First time trying out the Code Guru forums, so here it goes. I just completed a first quarter course in Java, and now I’m jumping into a second quarter course in C++. (this is a big jump, first time using pointers & dynamic arrays) I’ve been working on this project for 8 hours now, and I’m stuck at this part in which I need to convert a static array to a dynamic array of pointers, not sure what I’m doing wrong here, hoping someone could point out exactly what it is I’m doing wrong & point me in the right direction as far as fixing it. I got the following problem:
void main()
{
...
Cin >> MaxDBsize;
arr index = new arr[MaxDBsize] //line73
...
}
1) I get the following error codes:
error C2057 ‘<unknown>:’ missing subscript
and
error C2440 ‘initializing’: cannot convert from ‘struct InvRec *(*)[1]’ to ‘struct InvRec *[]’
2) among the many things I tried to fix it was changing line 23 to:
arr InvRecptr[];
but I get the following errors:
: missing ';' before identifier 'InvRecptr'
: missing storage-class or type specifiers
: fatal error C1004: unexpected end of file found
In the first case my reasoning was: declare arr as an array type of inventory record pointers, on line 23, and initialize index (line 73) as an instance of dynamic arr type with a size (MaxDBsize) entered by the user input (cin). I don’t know exactly why this approach fails.
In case 2 I tried declaring a variable, arr, as an array of inventory records, and initializing it in line 73, otherwise same reasoning as above.
So, what am I doing wrong, and how do I fix it? before I rip the rest of my hair out’ve my head.
Darth Hacker
September 2nd, 2005, 07:50 PM
Please don't pull your hair out! ;)
Change MaxDBsize from int to const int. That will eliminate error C2057. Next, get rid of the typedef statements and replace this line:
arr index = new arr[MaxDBsize];
with this line:
InvRec* index = new InvRec[MaxDBsize];
That should get rid of error C2440. You will also get a compiler error with Cin. It needs to be cin (all lowercase).
Andreas Masur
September 3rd, 2005, 10:31 AM
Is there any special reason why you dyanmically need to allocate? This isn't usually necessary in C++, take a look at the following introduction (http://www.codeguru.com/Cpp/Cpp/cpp_mfc/stl/article.php/c4027/) to the 'vector' class...which is the common way of dealing with arrays...
Paul McKenzie
September 3rd, 2005, 11:50 AM
Hello
First time trying out the Code Guru forums, so here it goes. I just completed a first quarter course in Java, and now I’m jumping into a second quarter course in C++.Oh, oh. The advice I can give you is this -- Java isn't C++. Keep that in mind, and you'll do OK. Too many try to code C++ using Java techniques, making a mess of their C++ programs in doing so.
I’ve been working on this project for 8 hours now, and I’m stuck at this part in which I need to convert a static array to a dynamic array of pointers,You are trying to create a "dynamic" array of struct's, not pointers.not not sure what I’m doing wrong here, hoping someone could point out exactly what it is I’m doing wrong & point me in the right direction as far as fixing it.C++ has the standard vector class. There is no need to do this using pointers.
Also, I thnk you should retake the class with better teacher and/or course material. Why? This:
void main()
This is incorrect C++. The main function returns an int. It is not "void main()", it is "int main()". See the many threads on this, including the recent one in the non-Visual C++ section. Once a teacher writes "void main()" instead of "int main()", it's time to get another teacher.
Also, don't type your code into the message window. Copy and paste it in the CodeGuru message window from your code editor. The reason is that there is no way for someone to know whether that typo error is the reason for compiler errors or not. For example:
Cin
Don't you mean:
cin
?
As to your code:
#include <iostream>
int MaxDBsize;
struct InvRec
{
int PartID;
float Price;
};
typedef InvRec *InvRecptr;
int main()
{
InvRecptr arr;
std::cin >> MaxDBsize;
arr = new InvRec[MaxDBsize];
delete [] arr;
}
Now, the same thing using vector:
#include <iostream>
#include <vector>
int MaxDBsize;
struct InvRec
{
int PartID;
float Price;
};
Note that there is no dynamic allocation on your part. This is all handled by the vector class. Also, note the lack of pointers.
On a side note, teaching pointers and dynamic allocation before teaching vector is IMO the wrong approach to teaching C++. Even the author of the language, Stroustrup, plus many books ("Accelerated C++" for example), also recommend that teaching the student standard classes should be emphasized first instead of hard to use pointers:
http://www.research.att.com/~bs/new_learning.pdf
The idea is to get the programmer into writing useful, bug-free programs as quicky as possible. To do this, you introduce them to things such as string classes instead of char arrays and pointers, vectors instead of new[]/delete[], etc. Pointers and dynamic allocation are necessary, but they are unnecessary for purposes of creating dynamic arrays.
Regards,
Paul McKenzie
cilu
September 3rd, 2005, 12:24 PM
[ moved thread ]
Corporal Kindel
September 3rd, 2005, 02:07 PM
Hello:
Thanks for all the help guys. Well the reason I didn't use vectors is that we haven't got to that point yet in the book. I'm sure we'll probably get to that point sometime in the future, in this class or some other class. The textbook we're using is Data Structures and other objects using C++ (Main, Savitch), and chapter 4 is dynamic arrays and pointers. The first project is to convert a static array problem to a dynamic array of pointers & manipulate the functions that way (move pointers instead of Data items). The instuctor provided the base program and we have to "change" it. You're right, should've copied and pasted instead of writing out the appropriate section (it was cin instead of Cin).
I now got the declaration and the initialization of the Array to work using the first posters suggestion, thanks btw. But, I guess you're right, it's a dynamic array of structures and not pointers, it needs to be a dynamic array of pointers though. I got another typedef definition under the header, which is:
typedef InvRecptr * indexarr // pointer to a dynamic array of inventory record pointers.
I tried to change my line 73 index initialization to:
InvRec* index = new InvRecptr[MaxDBsize];
(In order to create a dynamic array of pointers) but I get the following error code:
: error C2440: 'initializing' : cannot convert from 'struct InvRec ** ' to 'struct InvRec *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
I’m just starting out with C++ now, so I’m not up with these error codes at all yet. From what I interpret, somehow, using the above initialization, the index (which is an inventory record pointer type) is pointing to a double pointer array (**) of inventory records? I don’t understand how the double pointer ** error is cropping up and/or creeping into the initialization?
There is a second problem I am trying to fix .... I altered all the remaining function parameters, after using the new index array initialization (which may not be the right definition, since it’s an array of structures) of:
InvRec* index = new InvRecptr[MaxDBsize];
.... which is this structure type error. It involves the following two functions (which I copied and pasted):
void readrec (InvRec*& rec) //line89
/*Pre: Input available as expected.
Post: Record rec filled with input data.*/
{
int x;
float y;
//InvRec z;
cout << "1 test de-ref xptr: " << *xptr << endl; //test to see what is stored
cout << "2 test de-ref yptr: " << *yptr << endl; //test to see what is stored
};
void readdata (arr DB, int & size)
/*Pre: DB is an array of MAXDBSIZE inventory records.
Post: 0<=size<=MAXDBSIZE and the first "size" elements of the DB array are
filled with input data.*/
{
void readrec (InvRec*&);
char YN;
int *sizeptr = &size;
size = 0;
do
{
cout << "More data (Y/y/N/n)? " << endl;
cin >> YN;
if ((YN == 'Y') || (YN == 'y'))
if (size < MaxDBsize) (readrec (DB[size++]); //line 136
<< DB[size] << endl;
else cout << "Database size may not exceed "<< MaxDBsize << endl;
else if ((YN != 'N') && (YN != 'n')) cout << "Please answer Y/y/N/n. ";
}
while ((YN != 'N') && (YN != 'n'));
//DB = new arr[size];
};
All the commented-out stuff are things that I’ve tried & failed with. In the do-while loop of the readdata function, line 136, I’m passing arr DB as an actual parameter to the readrec function, line 89, it’s one element of an array of pointers (at least that’s what I want), but the problem is, I think, that I’m trying to simultaneously do two things in one function, namely: 1) read a structure record composed of a PardID and Price (read record), and 2) while reading in the structure element using user input, simultaneously make it a pointer, so that it doesn’t mismatch with the Formal function parameter, line 89. I may not be approaching it correctly. But anyway, I get the following error codes:
: error C2227: left of '->rec' must point to class/struct/union //line 109
: error C2228 left of '.PartID' must have class/struct/union type //line 109
: error C2227: left of '->rec' must point to class/struct/union //line 110
: error C2228: left of '.Price' must have class/struct/union type //line 110
Is it that the class/struct/union type is an array element, a referance pointer Parameter (InvRec*& rec), instead of (InvRec& rec)? But I want it to be an array of pointers so how would I both do: 1) user-input the rec data structure element and 2) maintain an array of pointers (without having to completely change the array type)? Or is it that I just have a simple syntax error in lines 109 & 110, and if so what is the syntax?
Thanks again for all the help,
rk
But the way, what area did they move this thread to? I assumed it was visual C++ programming because that is the C++ program type that we're using in the class.
Paul McKenzie
September 3rd, 2005, 03:57 PM
The first project is to convert a static array problem to a dynamic array of pointers & manipulate the functions that way (move pointers instead of Data items).There is something wrong with the assignment. There is no such thing as turning a static array of T to an dynamic array of T*. You can't do this. That's like turning a truck into a pancake. They are not the same thing, and this is why you are having problems.
You may have misunderstood the assignment. The only thing that can be converted is an array of T to a dynamic array of T. To do this, yes, you need pointers, where T* is the pointer to the first T, *(T+1) is the second T, *(T+2) is the third T, etc..
The major reasons for T** is if you are
1) Creating a two-dimensional array of type T dynamically
2) You are passing a T* to a function that will initialize the T* to some value
Are you doing any of these? If not, then your assignment, sorry to say, doesn't make sense.
The instuctor provided the base program and we have to "change" itThat's the problem, change it to what? You can't go from array of T to array of T* -- again, it doesn't make sense. This is the reason why you are getting the errors saying that you cannot go from T to T*. The instructor must have given this assignment as a joke or to waste your time (if that is actually what you're supposed to do). I hate these crap C++ courses that not only teach you the wrong things to do, it teaches you things that are not done whatsoever. Then it takes one of us to unteach all of this.
it's a dynamic array of structures and not pointers, it needs to be a dynamic array of pointers though.Let's see what a dynamic array of pointers are:
T** p;
p = new T*[10];
for ( int i = 0; i < 10; ++i )
p[i] = new T;
You now have a dynamic array of pointers to T. Each T then needs to be allocated in a loop, since just creating an array of T* does not initialize each T* to anything.
Is this what you're looking for? But it still doesn't match the original problem of array of T to a dynamic array of T. This is where it not only confuses you, it's confusing me. See the reasons for a T** earlier in my post.
From what I interpret, somehow, using the above initialization, the index (which is an inventory record pointer type) is pointing to a double pointer array (**) of inventory records? I don’t understand how the double pointer ** error is cropping up and/or creeping into the initialization?The way C++ (and C) interprets pointers is as follows:
Note how an array is analogous to using only one "*" when using equivalent pointer syntax. Now to do the T a[5] dynamically, you do not allocate 5 pointers to T -- you allocate one pointer to T, where that pointer points to 5 items.
T *a;
a = new T[5]; // for example
If you create an array of T*, which you claim the assignment is supposed to do, then each element of the array is a T*, not a T.
The easiest way to look at it is that the word "array" means to tack on a "*". So when you have an array of T*, you are dealing with "**" -- one "*" for the array, and the other for the T* element of each item in the array.
There is a second problem I am trying to fix .... I altered all the remaining function parameters, after using the new index array initialization (which may not be the right definition, since it’s an array of structures) of:
Fix or clarify the assignment first, before anyone can understand it. Right now, I doubt that others can get a grasp of what you're really trying to accomplish.
But the way, what area did they move this thread to? I assumed it was visual C++ programming because that is the C++ program type that we're using in the class.There is no C++ program type. There is only one C++. Regardless of the brand of compiler you use, there is only one C++ language. If you posted your program, I could probably compile it using Borland C++ Builder, gcc, CodeWarrior, Digital Mars, etc. compilers with little to no change.
Your code is generic C++, which is why it was moved to the non-Visual C++ section -- there is nothing in it that is specific to Visual C++, i.e. MFC, ATL or some other class library used by Visual C++. It is all plain C++.
Regards,
Paul McKenzie
HighCommander4
September 3rd, 2005, 04:29 PM
I now got the declaration and the initialization of the Array to work using the first posters suggestion, thanks btw. But, I guess you're right, it's a dynamic array of structures and not pointers, it needs to be a dynamic array of pointers though. I got another typedef definition under the header, which is:
typedef InvRecptr * indexarr // pointer to a dynamic array of inventory record pointers.
I tried to change my line 73 index initialization to:
InvRec* index = new InvRecptr[MaxDBsize];
(In order to create a dynamic array of pointers) but I get the following error code:
: error C2440: 'initializing' : cannot convert from 'struct InvRec ** ' to 'struct InvRec *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
I’m just starting out with C++ now, so I’m not up with these error codes at all yet. From what I interpret, somehow, using the above initialization, the index (which is an inventory record pointer type) is pointing to a double pointer array (**) of inventory records? I don’t understand how the double pointer ** error is cropping up and/or creeping into the initialization?
Is InvRecptr a typedef for InvRec*? All these typedefs make your code really confusing. Anyways, assuming that InvRecptr is a typedef for InvRec*, the problem is that creating a dynamic array using new[] returns a pointer to the first element of the array that was created. Here is the syntax for using the new[] operator:
type* identifier = new type[array_size];
So if you are creating an array of InvRec objects ("type" is InvRec), then new[] will return a pointer-to-InvRec (InvRec*). This is the correct way to create a dynamic array of InvRec objects:
// option A - creating an array of InvRec objects
InvRec* index = new InvRec[MaxDBSize];
If, on the other hand, you are creating an array of pointers to InvRec objects ("type" is InvRec*), then new[] will return a pointer-to-pointer-to-InvRec (InvRec**). This is the correct way to create a dynamic array of pointers-to-InvRec
// option B - creating an array of pointers-to-InvRec
InvRec** index = new InvRec*[MaxDBSize];
So read the assignment specifiecations again and see whether it says you need to create an array of InvRec objects (option A) or an array of pointers-to-InvRec (option B). Mixing the two together like you were trying won't work:
InvRec* index = new InvRec*[MaxDBSize];
// doesn't work - new[] returns an InvRec**
// and you can't assign an InvRec** to an InvRec*
Darth Hacker
September 3rd, 2005, 05:08 PM
Take a look at these code snippets.
Statically allocated array of objects:
struct T
{
int Data1;
double Data2;
};
T Arr[10];
int main(int argc, char* argv[])
{
//initialization
for (int i=0; i<10; i++)
{
Arr[i].Data1 = 1;
Arr[i].Data2 = 1.2345;
}
return 0;
}
Statically allocated array of pointers:
struct T
{
int Data1;
double Data2;
};
T* Arr[10];
int main(int argc, char* argv[])
{
int i;
//initialization
for (i=0; i<10; i++)
{
Arr[i] = new T;
Arr[i]->Data1 = 1;
Arr[i]->Data2 = 1.2345;
}
//initialization
for (int i=0; i<10; i++)
Arr.push_back(T(1, 1.2345));
return 0;
}
I agree that vectors et al should be taught first. But my experience with instructors is that they want to teach you the hard way first as motivation for the need of the easy way. If you are learning programming from a theoretical standpoint, that's probably the right approach. But if you are in the real world writing software for a customer, then learn the easy way first.
HighCommander4
September 3rd, 2005, 05:52 PM
: error C2227: left of '->rec' must point to class/struct/union //line 109
: error C2228 left of '.PartID' must have class/struct/union type //line 109
: error C2227: left of '->rec' must point to class/struct/union //line 110
: error C2228: left of '.Price' must have class/struct/union type //line 110
These errors are from the readrec() function. I'm not exactly sure what you are trying to do in the readrec() function, but if your objective is simply to input data into an InvRec structure, it's way overcompikcated. These simple 2 lines of code would suffice:
void readrec (InvRec*& rec) //line89
/*Pre: Input available as expected.
Post: Record rec filled with input data.*/
{
cin >> rec->PartID;
cin >> rec->Price;
}
Also, is there a reason why this function needs to take a reference to a pointer-to-Invrec? Wouldn't it be simpler to pass a reference to an InvRec object?
void readrec (InvRec& rec) //line89
/*Pre: Input available as expected.
Post: Record rec filled with input data.*/
{
cin >> rec.PartID;
cin >> rec.Price;
}
If you correct this and you are still experiencing problems with the readdata() function, please post a piece of complete code (including all the typedefs you are using so I can understand your code) and I'll take a look at it.
Corporal Kindel
September 3rd, 2005, 06:33 PM
Thanks for all your help guys. I'm going to go through my whole program from top to bottom again, and take in what everyone has said. You guys helped me understand quite a bit what was going on behind-the-scenes that I didn't fully understand before. If I still have problems, I'll post the whole enchilada tomorrow night .. been at this for about 16 hours now for 3/4 days. Thank god it's not due until the 12th, so I still got plenty of time to work on it. My instructor has been in China for a week now, so the class hasn't been able to contact him for office hours, email help ... that's mainly why I posted my questions on this forum, and I'm glad I did so.
Corporal Kindel
September 3rd, 2005, 10:18 PM
Well I finally got the program to pass the compiler, unfortunately it failed in the link phase during build. Unfortunately the link error doesn't point me out an exact line number for my to narrow down the problem. The error code & still-in-work program (getting close) is as follows:
but the compiler worked!
my code as far as now is:
#include <iostream.h>
int MaxDBsize;
/*Type delcarations - NO MEMORY ALLOCATED (EVEN STATICALLY)*/
struct InvRec /*Inventory record with its fields*/
{
int PartID;
float Price;
};
typedef InvRec *InvRecptr; /*Inventory record pointer type*/
typedef InvRec* arr[];
arr index;
typedef InvRecptr *indexarr; /* Pointer to a dynamic array of inventory record pointers*/
cout << "Enter a size amount for the index array: " << endl;
cin >> MaxDBsize;
InvRec** index = new InvRec*[MaxDBsize];
int dbsize;
char temp;
readdata (index, dbsize);
cout << "Original data:" << endl;
printdata (index, dbsize);
sortbyPartID (index, dbsize);
cout << "Data sorted by PartID:" << endl;
printdata (index, dbsize);
cout << "Please input a non-white space key to end the session." <<endl;
cin >> temp;
};
void readrec (InvRec*& rec)
/*Pre: Input available as expected.
Post: Record rec filled with input data.*/
{
cin >> rec->PartID;
cin >> rec->Price;
};
void readdata (arr DB, int & size)
/*Pre: DB is an array of MAXDBSIZE inventory records.
Post: 0<=size<=MAXDBSIZE and the first "size" elements of the DB array are
filled with input data.*/
{
void readrec (InvRec*&);
char YN;
size = 0;
do
{
cout << "More data (Y/y/N/n)? " << endl;
cin >> YN;
if ((YN == 'Y') || (YN == 'y'))
if (size < MaxDBsize)
readrec (DB[size++]);
else cout << "Database size may not exceed " << MaxDBsize << endl;
else if ((YN != 'N') && (YN != 'n')) cout << "Please answer Y/y/N/n. ";
}
while ((YN != 'N') && (YN != 'n'));
};
void printrec (InvRec* rec)
/*Pre: rec has data.
Post: The data in rec printed out.*/
{
int x;
float y;
int *xptr;
float *yptr;
xptr = &x;
yptr = &y;
cout << *xptr << ' ' << *yptr << endl;
};
void printdata (arr DB, int size)
/*Pre: 0<=size<=MAXDBSIZE and the first "size" elements of the DB array are
inventory records containing data.
Post: They are all printed out in the order pointed at.*/
{
void printrec (InvRec*);
int i;
for (i=0; i<size; i++) printrec(DB[i]);
};
void swap (InvRec *& x, InvRec *& y)
/*Pre: None.
Post: The values of x and y are swapped.*/
{
InvRec *temp;
temp = x;
x = y;
y = temp;
};
int selectsmallestPartID (arr DB, int first, int last)
/*Pre: "first" through "last" elements of the DB array are inventory
records containing data.
Post: A value k is returned such that, for i ranging from first to last,
the relation DB[k].PartID <= DB[i].PartID holds.*/
{
int j, result;
result = first;
int *jptr=&j, *resultptr=&result, *firstptr=&first;
for (j=first+1; j<=last; j++)
if (DB[*jptr] < DB[*resultptr]) resultptr = jptr;
//if (DB[j].PartID < DB[result].PartID) result = j;
return *resultptr;
};
void sortbyPartID (arr DB, int size)
/*Pre: 0<=size<=MAXDBSIZE and the first "size" elements of the DB array are
inventory records containing data.
Post: for i ranging from 1 to size-2, the relation DB[i].PartID <=
DB[i+1].PartID holds.*/
{
int selectsmallestPartID (arr, int, int);
int i, smallindex;
int *iptr=&i, *smallindexptr=&smallindex;
for (i=0; i<=size-2; i++)
{
smallindex = selectsmallestPartID (DB, i, size-1);
swap (DB[i], DB[smallindex]);
//swap (DB[iptr], DB[smallindexptr]);
};
};
BTW the main array in the program is no longer an array of inventory records, but is now an array of pointers to inventory records, which is what I was supposed to do for the project. I haven't as yet implemented the deollocate function, that will be my next priority as soon as I can get the basic program working correctly.
The link error says unresolved external symbol void, what does that mean? .. the functions that it references are supposed to have a void return type, so I don't understand what is going on there? Gotta hit the sack here this program is draining & it's hard to concentrate late at night.
SuperKoko
September 4th, 2005, 02:46 AM
The errors are not : unresolved external symbol void, but:
unresolved external symbol "void __cdecl sortbyPartID(struct InvRec * *,int)" (?sortbyPartID@@YAXPAPAUInvRec@@H@Z), etc...
It means that the function : void sortbyPartID (InvRec**, int) is imported from the module, but is not defined in any module.
I suppose that it may be due to the difference between the declaration and the definition of the functions.
Firstly you should change this line:
typedef InvRec* arr[];
(My compiler generate an error at the next line, saying that the size of the array is unknown)
Replace it with:
typedef InvRec** arr;
You should also remove the next line:
arr index; // this variable is never used!
With these corrections, my compiler compiles correctly.
But, i suggest that you change the declarations:
It is better if you need to modify the typedef of arr.
If it does not work, try to put the function declarations outside the main function (i remember that once, i had a bug with a compiler which don't mangled function name in local declarations).
Finally, use int main(), not void main()
And, please, use code tags.
To, do so, enclose your code, with tags like that:
[ C O D E]
the code here
[ / C O D E ]
But, don't put the space characters in the tags : i just put them to avoid that the forum interpret them as real code tags.
Note also that there is a '/' character in the closing markup.
Corporal Kindel
September 4th, 2005, 05:31 PM
Ok, finally got my program to compile & build, unfortunately, I get the following error at runtime (the program stops during runtime with an exception, and clicking on debug points me to the following program snipit which I copied and pasted below). The error code pointer points to the else n = (int) value; line near the bottom. My program is going to kill me before I'm done with it. Note: the error code program snipit that fails is not even part of my original program.
I need to figure out what this error is (or where it's referring to in my program, which is not clearly defined). I take it that the cin >> (istream operator) is failing in my program somewhere? Is it possible to determine exactly where the istream operator is failing in my program & why? Also, why is the istream operator failing when I have the library #include <iostream.h> correctly included in the header of my program?
/***
* istrint.cpp - definitions for istream class operaotor>>(int) member functions
*
* Copyright (c) 1991-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* Definitions of operator>>(int) member function(s) for istream class.
* [AT&T C++]
*
*******************************************************************************/
/***
*istream& istream::operator>>(int& n) - extract int
*
*Purpose:
* Extract int value from stream
*
*Entry:
* n = value to update
*
*Exit:
* n updated, or ios::failbit & n=INT_MAX/INT_MIN on overflow/underflow
*
*Exceptions:
* Stream error on entry or value out of range
*
*******************************************************************************/
istream& istream::operator>>(int& n)
{
_WINSTATIC char ibuffer[MAXLONGSIZ];
long value;
char ** endptr = (char**)NULL;
if (ipfx(0))
{
value = strtol(ibuffer, endptr, getint(ibuffer));
if (value>INT_MAX)
{
n = INT_MAX;
state |= ios::failbit;
}
else if (value<INT_MIN)
{
n = INT_MIN;
state |= ios::failbit;
}
else
n = (int) value;
isfx();
}
return *this;
}
Paul McKenzie
September 4th, 2005, 06:06 PM
This is incorrect:
#include <iostream.h>
The standard ANSI C++ header is <iostream>, not <iostream.h>. That's the first thing you should fix. Then your code will (or should) exhibit the same behavior on another compiler if anyone else compiles and runs your code.
Also, please use code tags.
Regards,
Paul McKenzie
Paul McKenzie
September 4th, 2005, 06:20 PM
There are also some other things that are unknown.
First, I know you may not be familiar with all of what is considered standard, but you should strive to make your C++ programs as standard's conforming as possible. For example:
#include <cruntime.h>
#include <internal.h>
What are these headers? I know you don't need these for your program to work. The only headers that you have that are part of standard C++ are as follows:
The first two are holdovers from 'C', the last is the standard ANSI C++ header for std::cin, std::cout, and other definitions associated with console input and output.
Once you include <iostrream>, then cin and cout are included in the "std" namespace.
#include <iostream>
//...
using namespace std;
This is only one form of specfiying that you are using the "std" namespace.
If your C++ book does not explain this in chapter 1 or chapter 2 (namespaces, or at the very least, inform you that you must use them for iostream), then get another book. If this is the case that your book doesn't explain this, you are learning outdated C++. The joke will be on you when you actually branch out and try to either get a job in C++, or at the very least, when you attempt to use a modern C++ compiler.
For example, the Visual C++ 7.1 compiler removed <iostream.h> from the list of files that come with the compiler. The header that is used now is always <iostream>, so your program would not compile on VC 7.1.
Second, what is getint()? isfx()? _WINSTATIC? Those are not standard function and/or identifiers.
Get rid of the non-standard stuff, since that complicates the matter when others are trying to look at your code.
Regards,
Paul McKenzie
Corporal Kindel
September 4th, 2005, 06:24 PM
O.k, sorry, I edited my past couple of posts and put in code tags for the code. You're right, the <iostream.h> was part of the old C code that needed to be modified, but wasn't yet. I changed it to <iostream> and got 16 errrors, but at least I can narrow those down, as they have definite line pointers, breaks (whatever it's called for errors).
Thanks, I'm back in the game again ... looks like it's gonna be another long night though..
Paul McKenzie
September 4th, 2005, 06:25 PM
OK, I see. You copied code from the compiler's runtime. No, that is where the error finally conked out the program. That code is *not* where the error started.
You need to post your code, not the compiler's code.
Regards,
Paul McKenzie
Paul McKenzie
September 4th, 2005, 06:29 PM
To clarify,
The code that you see when your program crashed is valid code, and always works correctly *if* nothing illegal has occurred to corrupt the behavior of that piece of code.
Therefore, you are doing something in your program that corrupts the memory/heap/ or you are accessing invalid memory somewhere, and these illegal operations cause other parts of the program to become corrupted and faulty.
Unlike Java, when you make a mistake in mishandling memory in C++, you do not get an instant exception error. Your program can chug along as if nothing happened, or it can crash right away, or it could crash a year from now or on your 45th customer's PC who is running your program.
Regards,
Paul McKenzie
Corporal Kindel
September 4th, 2005, 06:40 PM
OK, I see. You copied code from the compiler's runtime. No, that is where the error finally conked out the program. That code is *not* where the error started.
You need to post your code, not the compiler's code.
Regards,
Paul McKenzie
Right, I understand what you mean by that. The actual code for my entire program that I'm working on at this point is in in post #12. It's in code tags now. I made the two changes that the poster in post #13 suggested, and just now changed library to <iostream> as you pointed out. I got 14 errors and 4 warnigs after clicking 'build' but at least I can focus on exactly where the errors are taking place, unlike the runtime failure I described in post #14 (which is almost impossible to track down exactly) while using the unmodified <iostream.h>.
It's interesting that the old C library header is not compatible with <iostream> .. I'd noticed that before, but I didn't think it would cause any problems. I guess I was mistaken.
Anyway, appreciate it. It's back to the program-grind to me for tonight. I'll probably be back tomorrow, but I hope I won't need to be. ... hmm, I'll have to keep in mind what you said in #19. It's definitely much different from Java, and it will take me some time to get used to. I'm hoping at some point that things will 'click' a little more for me, but I'm probably not near that point with only 3 weeks of C++ under my belt at this point.
Corporal Kindel
September 5th, 2005, 01:51 PM
I figured out what was causing my program to fail during runtime; I had a pointer in the readrec function as a cin. I changed it to a Local int variable x, and a local float variable y. The program works now but I get garbageas answers (because they were passed into Local variables which cease to exist when the function is exited).
The problem is, I need to pass an inventory record (which is a struct InvRec which is composed of an int and a float item) into a dynamic array of pointers (rather, pointers to these items would be a better wording, a pointer element within an array of pointers pointing to a struct composed of two items). How can I do that? It seems to me I should be able to do two things in one function (namely read in a float & int invRec and at the same time make a pointer to this record as an element of an array of pointers). Would I have to declare a couple of Global pointer variables (instead of Local variables which cease to exist outside the function) and initialize them in the readrec function as an element of the dynamic array of pointers? Or is there something else that I'm overlooking. I changed all the C references to C++ in my program, as far as I know them right now.
/*
*/
#include <iostream>
//#include <cstdlib>
using namespace std;
//const int MAXDBSIZE = 100;
int MaxDBsize;
/*Type delcarations - NO MEMORY ALLOCATED (EVEN STATICALLY)*/
struct InvRec /*Inventory record with its fields*/
{
int PartID;
float Price;
};
typedef InvRec *InvRecptr; /*Inventory record pointer type*/
typedef InvRecptr arr[];
arr index;
typedef InvRecptr *indexarr; /* Pointer to a dynamic array of inventory record
pointers*/
void readdata (arr DB, int & size)
/*Pre: DB is an array of MAXDBSIZE inventory records.
Post: 0<=size<=MAXDBSIZE and the first "size" elements of the DB array are
filled with input data.*/
{
void readrec (InvRec*&);
char YN;
size = 0;
do
{
cout << "More data (Y/y/N/n)? " << endl;
cin >> YN;
if ((YN == 'Y') || (YN == 'y'))
if (size < MaxDBsize)
readrec (DB[size++]);
else cout << "Database size may not exceed " << MaxDBsize << endl;
else if ((YN != 'N') && (YN != 'n')) cout << "Please answer Y/y/N/n. ";
}
while ((YN != 'N') && (YN != 'n'));
};
void printrec (InvRec* rec)
/*Pre: rec has data.
Post: The data in rec printed out.*/
{
int x;
float y;
void printdata (arr DB, int size)
/*Pre: 0<=size<=MAXDBSIZE and the first "size" elements of the DB array are
inventory records containing data.
Post: They are all printed out in the order pointed at.*/
{
void printrec (InvRec*);
int i;
for (i=0; i<size; i++) printrec(DB[i]);
};
void swap (InvRec *& x, InvRec *& y)
/*Pre: None.
Post: The values of x and y are swapped.*/
{
InvRec *temp;
temp = x;
x = y;
y = temp;
};
int selectsmallestPartID (arr DB, int first, int last)
/*Pre: "first" through "last" elements of the DB array are inventory
records containing data.
Post: A value k is returned such that, for i ranging from first to last,
the relation DB[k].PartID <= DB[i].PartID holds.*/
{
int j, result;
result = first;
int *jptr=&j, *resultptr=&result, *firstptr=&first;
for (j=first+1; j<=last; j++)
if (DB[*jptr] < DB[*resultptr]) resultptr = jptr;
//if (DB[j].PartID < DB[result].PartID) result = j;
return *resultptr;
};
void sortbyPartID (arr DB, int size)
/*Pre: 0<=size<=MAXDBSIZE and the first "size" elements of the DB array are
inventory records containing data.
Post: for i ranging from 1 to size-2, the relation DB[i].PartID <=
DB[i+1].PartID holds.*/
{
int selectsmallestPartID (arr, int, int);
int i, smallindex;
int *iptr=&i, *smallindexptr=&smallindex;
for (i=0; i<=size-2; i++)
{
smallindex = selectsmallestPartID (DB, i, size-1);
swap (DB[i], DB[smallindex]);
//swap (DB[iptr], DB[smallindexptr]);
};
};
By the way, when I try to use the:
cin >> rec.PartID;
cin >> rec.Price;
I get the following error code for lines 116 & 117:
: error C2228: left of '.PartID' must have class/struct/union type
: error C2228: left of '.Price' must have class/struct/union type
Error executing cl.exe.
How is this error failing for class/struct/union type when I passed in a pointer to the structure? How can I read these two items in as the struct rec and at the same time create a pointer to them (an element in an array of pointers)?
Paul McKenzie
September 5th, 2005, 02:55 PM
Your typedef's are confusing. I think it is much easier if you not typedef basic things such as pointers.
Also, please change this:
typedef InvRecptr arr[];
1) In C++, arrays must have constant values. A programmer looking at this won't understand what you're trying to do here.
2) Use more descriptive names. The arr could easily be mistaken for a normal variable name, not a typedef.
3) This is incorrect. You didn't read carefully one of my earlier posts:
InvRec** index = new InvRec*[MaxDBsize];
OK, so you now have MaxDBSize uninitialized pointers. Where do you initialize all of these pointers? I don't see anywhere in your code where you do this. A pointer must point somewhere before you use it. Currently, you are doing the equivalent of this:
int *pInt;
*pInt = 10; // accessing uninitialized pointer. Error.
Hopefully you see the problem here. Magnify this by MaxDBsize, and that is exactly what you're doing with your code.
My previous shows a loop that initialized each of the pointers. You didn't do this.
4) Use new[], deallocate with delete[]. Note the brackets.
In all though, I looked at the code. It is (unfortunate for you) not the way that a C++ programmer would write this (using pointers all over the place). I still can't fathom why a teacher would force their students to create programs like this, unless it is to compare later on the correct way to write such programs.
Regards,
Paul McKenzie
Paul McKenzie
September 5th, 2005, 03:05 PM
More problems:
if (DB[*jptr] < DB[*resultptr]) resultptr = jptr;
You are sorting pointers here. You are not sorting data items categorized by part ID. In other words, you are sorting addresses.
Also, you do no checking to see if first and last are in range in the selectsmallestPartID function. It also assumes that things are 1-based when in C++, indexing is 0-based. This is also important that you check your indices here, since you can easily cause an off-by-one error.
But in general, I don't understand what selectsmallestPartID is supposed to do. What is the purpose of the return value? Are you supposed to get the smallest item, and then return the index of this item? If so, you are way overcomplicating this function, even if you must use pointers.
Regards,
Paul McKenzie
Paul McKenzie
September 5th, 2005, 03:12 PM
You also must get out of the habit of declaring functions locally. Yes, it is legal C++, but it is not used to any extent in the real world except as an exercise.
void printdata (InvRec* DB, int size)
{
int i;
for (i=0; i<size; i++)
printrec(DB[i]);
}
Also, remove the extraneous semicolon at the end of your function bodies.
Note that I am using no pointers to pointers here. Again, I don't see how pointers-to-pointers is part of the assignment -- I've tried to understand but can't. This is what you should start with, a single level of indirection. If the teacher wants you to do something weird with all of this, then you can wrap this code and just call it using whatever weird directions the teacher states.
Regards,
Paul McKenzie
codeguru.com
Copyright WebMediaBrands Inc., All Rights Reserved.