I try to create objects dynamically. Each object is a pointer in an array of pointers. The compiler gives me
error C4700: uninitialized local variable 'villages' used.
And I can not figure out how to fix it. I would be very grateful to all the helpers.
int villageAmount;
cout << "Defining villages:\n\nEnter how many villages do you want: ";
cin >> villageAmount;
Village **villages;
for (int i = 0; i < villageAmount; i++)
{
cout << "\nDefining village's details #" << i + 1 << ":\n";
villages[i] = new (nothrow) Village;
}
Village **villages;
you declared villages without initializing, so it contains garabage valaue.
for (int i = 0; i < villageAmount; i++)
{
cout << "\nDefining village's details #" << i + 1 << ":\n";
villages[i] = new (nothrow) Village;
}
right below, you access into it and writes. That's no no.
If you want to store pointer of village (i.e. type of Village*) dynamically, you also need to allocate them.
Village **villages = new Village*[villageAmount];
Or if amount is fixed,
Village *villages[10] = { nullptr, }; // 10, 12344, or whatever
villages memory is never allocated, you should use a vector or any sort of container (an array look fine here).
If you really want to allow the memory manually you could do something like :
Village **villages = new Village*[villageAmount];
Don't forget to free EVERY new, (If you only free villages, all the Village* that he contain will remain allocated.
Edit : someone else answered so I guess my answere is usless
Related
I was looking for uses for pointers and this turned out to be one of them. Dynamically allocating memmory. I am a little confused with the keyword new, and when adding [number] in the end. new int[3]. I do understand that this question might be bad. I'm only 13.
#include <iostream>
using namespace std;
int main() {
int* scores;
cout << "Enter top 3 scores: ";
//dynamically allocate memory
scores = new int[3];
for (int i = 0; i < 3; i++) {
"Enter score: ";
cin >> scores[i];
}
cout << endl << "Scores are: ";
for (int i = 0; i < 3; i++) {
cout << scores[i] << " ";
}
delete[] scores;
return 0;
}
A pointer is basically a variable pointing to a specific address in memory. An array is a group of variables allocated consecutively in memory. When you write scores = new int[3] you allocate a memory for three int-type variables and make the scores variable reference the first one's address. Now, when referencing the array fields: scores[i], you take the address of the first field of the array and you add the variable i, giving you the address of the ith element.
When you create an integer pointer, you create a memory that contains the address of another memory. So, when you use the keyword 'new' you are allocating memory and its address is then stored in that pointer. Initially, without any allocation, there is no data stored in that integer pointer.
This is similar to what it means when you do int array[size], however, at times dynamically allocated memory is required e.g. if you need to change the size of an array. If you declared an array without dynamic allocation, you can not change its size but when the help of dynamic memory allocation you can easily delete the previously allocated memory and allocate another memory that is larger. A basic example of where dynamic memory ('new' keyword) is used is when you create an array of the names of students in a class, initially, they might be just 15 students but after a month if they grow over 30 and the array you declared was of size 15 you can just use the 'delete' and 'new' keyword to increase the size.
I know that the common technique of creating a dynamic array using new in C++ is:
int * arr = new int[5];
A book also says:
short tell[10]; // tell is an array of 20 bytes
cout << tell << endl; // displays &tell[0]
cout << &tell << endl; // displays address of the whole array
short (*p)[10] = &tell; // p points to an array of 20 shorts
Now I wonder if there is a way to allocate memory for an array using new, so it can be then assigned to a pointer to the whole array. It might look like this:
int (*p)[5] = new int[5];
The above example doesn't work. The left side looks correct to me. But I don't know what should be on the right.
My intention is to understand if it's possible. And I know that there are std::vector and std::array.
Update:
Here is what I actually wanted to check:
int (*p1)[5] = (int (*)[5]) new int[5];
// size of the whole array
cout << "sizeof(*p1) = " << sizeof(*p1) << endl;
int * p2 = new int[5];
// size of the first element
cout << "sizeof(*p2) = " << sizeof(*p2) << endl;
And here is how to access these arrays:
memset(*p1, 0, sizeof(*p1));
cout << "p1[0] = " << (*p1)[0] << endl;
memset(p2, 0, sizeof(*p2) * 5);
cout << "p2[0] = " << p2[0] << endl;
know that the common technique of creating a dynamic array
In C++ that was written 20 years ago, maybe.
These days you should use std::vector for dynamic arrays and std::array for fixed size array.
If your framework or platform supplies additional array classes (like QT's QVector), they are fine too, as long as you don't mess with C-pointers directly, and you have RAII-based array class.
and as for concrete answer, new T[size] always returns T* , so you cannot catch a pointer returned by new[] with T(*)[size].
The problem is that left and right sights have different types.
The type of:
new int[5]
is
int*.
The type of:
int (*p)[5]
is
int (*)[5].
And compiler cannot assign one to another.
Generally speaking it is impossible to assign T* to T (*)[N]. That is why you need to use the syntax mentioned in the beginning of your question.
Trying to figure out the reasoning behind the mechanics of c strings.
char** text;
text = new char*[5];
for(int i = 0; int < 5; int++) {
cout << endl << "Enter a phrase: ";
cin >> text[i];
cout << text[i];
}
I'm not entirely sure as to why this works for the first 2 iterations, even successfully displaying them, but gets a segfault error on the 3rd iteration.
You are using uninitialized memory. You are experiencing undefined behavior.
The line
text = new char*[5];
allocated memory for five pointers but those pointers haven't been initialized to point to anything valid. Before you can use text[i] to read data, you have to allocate memory for it.
for(int i = 0; int < 5; int++) {
cout << endl << "Enter a phrase: ";
text[i] = new char[SOME_SIZE_LARGE_ENOUGH_FOR_YOUR_NEED];
cin >> text[i];
cout << text[i];
}
Then, it should work.
You've allocated memory for 5 pointers, but you are not allocating anything that those five pointers point to. Assuming that you're using a modern 64-bit CPU with 8 byte-wide pointers, your new operator allocated exactly 40 bytes, five eight-byte pointers. Their initial contents are random, uninitialized memory, and when you write to them, they get interpreted as pointers to random memory addresses, which end up being corrupted with what you've read from std::cin. You got lucky initially, and the first two iterations scribbled over some memory somewhere, but your program continued to limp along, but you won the lottery on the third try; hitting a random address that does not exist, and segfaulting.
Although you can rewrite this to do proper allocation, if you're really trying to write C++, rather than C, here, there's no reason to allocate anything. Why do you want to deal with allocating memory, when C++ will happily do it for you?
std::vector<std::string> text;
for(int i = 0; int < 5; int++)
{
std::cout << std::endl << "Enter a phrase: ";
std::string s;
if (std::getline(std::cin, s).eof())
break;
text.push_back(s);
std::cout << s << std::endl;
}
I have an array of Student objects. I set the array length to 100, but it doesn't have 100 valid Student objects in it. I want to be able to iterate through the array and grab all the valid Student objects, then stop when I get to an array cell that doesn't have a Student object.
I have tried putting NULL into the array cell after the last Student, and then checking if (queriedStudents[i]) as well as if(queriedStudents[i] != NULL), but neither has worked for me.
What is the best way to find the end of the used part of my array?
Student *Welcome::queryStudents(int *queries) {
int query = 0;
Student *matchedStudents[100];
int matchedPos = 0;
while (queries[query] > 0) {
for (int i = 0; i < numStudents; i++) {
if (allStudents[i]->id == queries[query]) {
matchedStudents[matchedPos] = allStudents[i];
matchedPos++;
}
}
query++;
}
matchedStudents[matchedPos] = NULL;
return *matchedStudents;
}
And my code chunk trying to print out each Student's values:
int i = 0;
while (i < 100) {
if (queriedStudents[i]) {
cout << "ID:\t" << queriedStudents[i]->id << endl;
cout << "Name:\t" << queriedStudents[i]->name << endl;
cout << "Addr.:\t" << queriedStudents[i]->address << endl;
cout << "Phone:\t" << queriedStudents[i]->phone << endl;
} else {
i = 100;
}
i++;
}
You've got a bigger problem. You declare the array matchedStudents on the stack in the function queryStudents. When control passes out of that function, the array passes out of scope. If you're trying to use it later (by means of the pointer it returns, which was the first element of the array) then you're messing with deallocated memory, which will almost certainly lead to undefined behavior. It's as if you're visiting a house that has changed owners since you were last there; there's no telling what's changed, and if you wander around with your eyes closed you might get into trouble.
You can declare the array on the heap:
Student **Welcome::queryStudents(int *queries) {
Student **matchedStudents = new *Student[100];
...
return matchedStudents;
}
Or pass it in by reference:
void Welcome::queryStudents(int *queries, Student **&matchedStudents) {
...
}
Either way, you can then tackle the problem of how to indicate the end of valid pointers. Your method looks feasible, but bear in mind that as #JerryCoffin has pointed out, std::vector is available. Arrays are a pain, and the STL containers (such as vector) were made to take care of these grubby details for you. These days working with arrays serves almost no purpose except pedagogy; play with them until you understand the concepts, then use more advanced containers which are base on them.
How can I access elements from myVector like i would do with arrays ( for(i = 0; i < n; i++) cout << v[i] << " "; )
My code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Month
{
public:
char *name;
int nr_days;
Month(char* c, int nr) : name(c), nr_days(nr){};
~Month() { /* free(name); */}
};
int main()
{
Month January("January", 31);
Month February("February", 28);
Month March("March", 31);
Month April("April", 30);
Month May("May", 31);
Month June("June", 30);
Month July("July", 31);
Month August("August", 31);
Month September("September", 30);
Month Octomber("Octomber", 31);
Month November("November", 30);
Month December("December", 31);
vector<Month> *myVect = new vector<Month>;
myVect->push_back(January);
myVect->push_back(February);
myVect->push_back(March);
myVect->push_back(April);
myVect->push_back(May);
myVect->push_back(June);
myVect->push_back(July);
myVect->push_back(August);
myVect->push_back(September);
myVect->push_back(Octomber);
myVect->push_back(November);
myVect->push_back(December);
for(vector<Month>::const_iterator i = myVect->begin(); i != myVect->end(); i++)
{
/*
Month myMonth = i;
cout << myMonth.name << " " << myMonth.nr_days << endl;
*/
}
free(myVect);
return 0;
}
I would want to be something like a foreach algorithm: foreach(Month in myVect) cout << ...
And another question: why it gives me a run-time error at the destructor if I uncomment my line?
Ok, there are a lot of problems here.
You declare myVect as a pointer to a vector. This is unnecessary. One of the major benefits of using a vector is so that you don't have to worry about memory management as the vector does it for you. You stack allocate the vector, but internally it heap allocates the memory used to store the items it contains.
You never initialize the pointer. You are invoking undefined behavior as that pointer is not valid. To initialize a pointer you use new. All you have is an invalid stack allocated pointer that does not point to a vector on the heap. EDIT: I just realized that the new was edited out, so you can disregard this one. Still, it shouldn't be a pointer at all.
You are using free to deallocate a C++ class (that you never allocated to begin with...). Don't. This isn't C, you use new and delete to manage memory (when necessary!) in C++. free does not call destructors, it simply frees up a chunk of memory. delete on the other hand does as it knows how to deal with complex C++ types. Never mix new/delete with malloc/free.
myVect->begin() returns a const_iterator, not a T (i.e., in this case, not a Month object). Dereferencing the iterator via the * operator will yield the current iteration object, so:
Month myMonth = *i // <--- IMPORTANT!
As an aside, if you are going to be looping over the vector often you may want to typedef the iterator to reduce verbosity, i.e.,
typedef vector<Month>::const_iterator cmonth_iter;
Now you can write
for(cmonth_iter i = myVect.Begin(); i != myVect.end(); ++i )
{
Month m = *i;
// do stuff with m
}
You can access elements using iterator using the * operator:
for(vector<Month>::const_iterator i = myVect->begin(); i != myVect->end(); i++)
{
Month myMonth = *i;
cout << myMonth.name << " " << myMonth.nr_days << endl;
}
Also, you never allocate a vector in your code. You shouldn't use free() on a pointer you haven't received from malloc() earlier. It is undefined behavior to do otherwise and a run-time error is likely to occur at the point you call free().
Try this:
vector<Month> *myVect = new vector<Month>;
...
delete myVect;
If you remove the unitialized pointer bug by changing:
vector<Month> *myVect;
to:
vector<Month> myVect;
Then this will work. (Once you define ostream << Month)
for(i = 0; i < myVect.size(); i++)
cout << v[i] << " ";
You have a pointer myVect, but never assign a value to it before using (turn compiler warnings on). you should do something like myVect = new vector<Month>(). (or do not make it pointer and change -> into .). The rest of your "foreach" implementation looks fine. And you can use [] to access elements as well.
You free constant strings, you did not allocate them, so you need not to free them either.
You're declaring myVect as a pointer but never allocating it, that's going to give you lots of trouble. Just drop the * and you should be fine.
If you insist, you can use an index just like you would with an array:
for(int i = 0; i < myVect.size(); i++)
{
Month myMonth = myVect[i];
cout << myMonth.name << " " << myMonth.nr_days << endl;
}
Although I'd rather use iterators as you have done - just one simple fix:
Month myMonth = *i;
You can use the arrow operator with iterators...
for(vector<Month>::const_iterator i = myVect->begin(); i != myVect->end(); i++)
{
cout << i->name << " " << i->nr_days << endl;
}
note also that it's more idiomatic with iterators using ++i instead of i++ (the reason is that i++ will need to create a copy of the iterator that will be thrown away).
Note also that your code is UB (undefined behavior) because you are using a pointer to a vector, but you are not allocating it. By the way the use of a pointer in this case is nonsense, the code would be correct and simpler with:
vector<Month> myVect;
myVect.push_back(January);
myVect.push_back(February);
...
for(vector<Month>::const_iterator i = myVect.begin(); i != myVect->end(); ++i)
...
My suggestion is also to avoid to try learning C++ just by experimenting with a compiler (something that I've the impression you're trying to do).
C++ is powerful but also complex and unfortunately quite illogical and asymmetrical in many parts (due to its evolution history). Add to this that when you make a mistake (e.g. not allocating the vector in your original code) you cannot expect the compiler to help you and even at runtime the program may do ANYTHING, including apparently work as you expected (the worst possible thing). This combo is deadly.
Complexity, asymmetry and lack of runtime checks all make C++ impossible to learn by experimentation... just get a good book and read it. It's much simpler this way.