C++ vector accessing elements - c++

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.

Related

Dynamic object creation of an array of pointers

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

C++ Displaying a Vector when using a pointer

#include <iostream>
#include <vector>
int main()
{
unsigned int numVec;
unsigned int input;
std::cout << "Enter Number of Vectors: ";
std::cin >> numVec;
std::vector<int>* Vec;
for (unsigned int i = 0; i < numVec; i++)
{
std::cout << "Enter Vector Value " << i << ": ";
std::cin >> input;
Vec->push_back(input);
}
std::cout << std::endl;
for (unsigned int i = 0; i < Vec->size(); i++)
{
std::cout << "Value at Index (" << i << ") " << Vec->at(i) << std::endl;
}
std::cout << std::endl;
return 0;
}
I am trying to learn how Vectors work as it is a topic that i have withheld learning for a very long time for no apparently reason.
My above code will compile and run however once i put in a number to store in the Vector it will crash.
The program did work before when i was just using a vector without the pointer but just for learning reasons i wanted to try it with a pointer, I am just wondering what am i doing wrong with this code and if someone could possibly flame me for doing something or give me some good advice on what i am doing wrong in this situation so i can learn for future reference.
Replace
std::vector<int>* Vec;
with
std::vector<int> vec;
and replace the pointer to member operator -> with the member selection operator ..
Only on rare occasions do you need to use dynamic storage for a std::vector instance, as that class does an excellent job of managing the memory for you. Currently you are not allocating any memory for your vector, and the behaviour of your code is undefined.
If you must use a pointer then write
std::vector<int>* vec = new std::vector();
and don't forget to call delete vec; when you're done. Consider using std::unique_ptr &c. so the delete is taken care of automatically.
My above code will compile and run however once i put in a number to store in the Vector it will crash.
What vector?
You never created a vector.
You only created a pointer, one which (a) is uninitialised, and (b) does not point to anything, let alone a (c) vector.

Find last used element in object array

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.

C++ program with map is not giving same resutls as it stored last time

I have the following program, which is storing four strings in map and printing first time. Now its running the another time to retrieve the stored values. But the second resutls are not same as first time results.
#include <map>
using namespace std;
void fun_call(void **,char * );
main(){
void *data=NULL;
char value[100];
int i=0,j=0;
char key[][10]={"disk1","disk2","disk3","disk4"};
cout << "printing all mapped values " << endl ;
data = (void *) malloc( 100);
for(j=0;j<2;j++){
for(i=0;i<4;i++){
fun_call(&data,key[i]);
memcpy(value,data,100);
cout << "key ="<<key[i]<<" value is " << value << endl;
}
cout <<"====================="<< endl;
}
}
void fun_call(void **tmp,char name[10])
{
void *tmp_data;
char str[100]="ravindra";
int len =0;
static std::map<std::string,void *> name_data_map;
std::map<std::string,void *>::iterator iter ;
iter=name_data_map.find(name) ;
if ( iter == name_data_map.end())
{
len=strlen(str)+strlen(name)+1;
tmp_data = (void *) malloc ( len );
strcat(str,name);
memcpy(tmp_data,str,len);
name_data_map[name]=tmp_data;
cout << "Inside the if" << endl ;
}
else
cout << "disk pos "<< iter->first << endl;
cout << "Outside the if" << endl ;
iter=name_data_map.find(name) ;
memcpy(*tmp,iter->second,len);
}
Output:
$ ./a.out
printing all mapped values
Inside the if
Outside the if
key =disk1 value is ravindradisk1
Inside the if
Outside the if
key =disk2 value is ravindradisk2
Inside the if
Outside the if
key =disk3 value is ravindradisk3
Inside the if
Outside the if
key =disk4 value is ravindradisk4
=====================
disk pos disk1
Outside the if
key =disk1 value is ravindradisk4
disk pos disk2
Outside the if
key =disk2 value is ravindradisk4
disk pos disk3
Outside the if
key =disk3 value is ravindradisk4
disk pos disk4
Outside the if
key =disk4 value is ravindradisk4
any idea why the second iteration is giving all data as : "ravindradisk4"
len is set to 0 in the beginning of fun_call, so if in the second run it doesn't go into your if, memcpy copies 0 bytes in the end. So the last value in main() from the first iteration remains the same regardless of key.
There are a lot of things wrong with your code, if it is intended to be a valid (or remotely idiomatic) C++ program.
As #starbugs points out, you're not using the right length the second time through to copy your result out. The one-line "fix" would be to change:
memcpy(*tmp,iter->second,len);
...to:
memcpy(*tmp,iter->second,strlen((char*)iter->second)+1);
For some basics on why brittle C string techniques are best replaced with C++ methodology, I like to show people this:
Learning Standard C++ As A New Language (PDF) by Bjarne
Once you've grasped that you might be more able to embrace the spirit in which C++ and the standard library should be used.
Your program is so trivial that it's easy to show how it can be simplified to produce idiomatic code which is far more robust and easy to read:
#include <map>
#include <iostream>
#include <string>
using namespace std;
string fun_call(string name)
{
static map<string,string> name_data_map;
map<string,string>::iterator iter;
iter = name_data_map.find(name);
if (iter == name_data_map.end()) {
string mapvalue = "ravindra";
mapvalue += name;
name_data_map[name] = mapvalue;
cout << "Inside the if" << endl ;
}
else
cout << "disk pos "<< iter->first << endl;
cout << "Outside the if" << endl;
iter = name_data_map.find(name) ;
return iter->second;
}
int main() {
string keys[] = {"disk1","disk2","disk3","disk4"};
cout << "printing all mapped values " << endl ;
for(int j = 0; j < 2; j++) {
for(int i = 0; i < 4; i++){
string value = fun_call(keys[i]);
cout << "key =" << keys[i] <<" value is " << value << endl;
}
cout << "=====================" << endl;
}
}
I'll stop there at providing a basically equivalent program with the same output and control flow.
Notes:
In standard C++, main must have an int as the return type (though it doesn't need arguments or a return statement, oddly enough)
The using namespace std; line frees you from having to type std:: in front of things in front of standard library classes like string, map, and their iterators. But don't put that in header files because it can cause problems with other source files that include them and have their own definitions which might conflict with the standard names when not disambiguated.
If you use the standard library then value types do their memory management under the hood, and the memory they use is allocated inside the class and freed in the destructor. Should you ever need to do explicit memory management then use new and delete.
First off, in general, in C++ consider using new/delete instead of malloc()/free().
I am not sure what you are exactly trying to accomplish (i.e. why you continuously copy values) but you have no length set so memcpy() doesn't copy anything.
Another simple fix to this issue is to use the pointer stored in iter->second (note that you would be able to modify data then and update that map entry - so perhaps this is not what you want).
For instance, do not allocate memory for your data variable in main and simply change this line
memcpy(*tmp, iter->second, len);
to
*tmp = iter->second;
Now the pointer address of data in main is set to the pointer address stored in the map.
First of all, I'm not even sure how your code compiles. Your main function lacks a return type and void/no-return is just bad practice. Restructure it to accomodate a simple return of 0 and make its return type int.
Furthermore, several includes are lacking before it even compiles (namely, iostream and string). Instead of using using namespace std, try to "pull" only the things you need from the std namespace. Bringing it all in is a potential hazard and bad practice in general, because you might encounter naming convention collisions in the future (and that will bring forth lots of headaches).
Back to the issue at hand. You're, if you're not experimenting/punishing your mind, applying some very bad practices here. This much memory-copying and pointer shifting around I don't get to do even while I'm working with moving vertex buffers around. And match your allocations with deallocations, that's some very bad memory management. And in C++, we use new/delete.
Since you're passing in the address of the pointer to the data variable, you can simply modify data's pointer by using *tmp.
Since your name_data_map is static, it survives the loop. Therefore, the second data member of the iter is the actual pointer to the data object at hand. Simply change the last line of code of your second function:
*tmp = iter->second;
Anyways, that's my two cents... I don't even get what you're trying to do. Good luck!

Legality and morality if differeing scopes of 'new' and 'delete'

I am creating a dynamic array inside a function. The code (posted below) runs without any problem. I am wondering if the way I have written is the right way to do it or if it will create problems in more complicated codes in the future. I am aware that the specific task my program (below) is trying to achieve is better effected with strings or vectors. But I created this artificial example to get my question across. however, if you strongly feel that dynamic arrays should be avoided, please feel free to share your opinion and the reasoning for it.
Result of my prior research: I was unable to find a coherent discussion on legality and morality of creating dynamic arrays using new [] and later deleting them in a different scope.
Thanks for your thoughts and insights.
My example code follows:
==========================
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
void getNonPunct(string _str, char* &_npcarr, int &_npsize);
int main()
{
string input_string;
char* npchar_arr;
int npsize;
cout << "Enter any string: ";
getline(cin, input_string);
getNonPunct(input_string, npchar_arr, npsize);
// Now display non-punctuation characters in the string
cout << "string with non-punctuation characters removed:\n";
for (int n = 0; n <= npsize - 1; n++)
cout << npchar_arr[n];
cout << "\n(" << npsize << ") non-punctuation characters\n";
// Now return the memory allocated with 'new' to heap
delete [] npchar_arr;
// Is it okay to 'delete' npchar_arr eve if it was created in the function
// getNonPunct() ?
return(0);
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void getNonPunct(string _str, char* &_npcarr, int &_npsize)
//This void function takes an input array of strings containing arbitrary
//characters and returns a pointer to an array of characters containing only
//the non-punctuation characters in the input string. The number of
//non-punctuation characters are stored in size. Prior to the function call,
//int_arr and size are undefined. After the function call, char_arr points to
//the first location of an array of the non-punctuation character array.
//'size' is equal to the number of non-punctuation characters in the input
//string.
{
// First get the number of non-punctuation characters in the string
int str_len, npcount = 0;
str_len = static_cast<int>( _str.length() );
_npsize = 0;
for (int i = 0; i <= str_len - 1; i++)
{
if ( !ispunct(_str[i]) )
_npsize++;
}
// Now that you know how many non-punctuation characters are in the string,
// create a (dynamic) character array of _npsize.
_npcarr = new char [_npsize];
for (int k = 0; k <= str_len - 1; k++)
{
if ( !ispunct(_str[k]) )
_npcarr[npcount++] = _str[k];
}
return;
}
Is it valid? Yes. The array pointed to by npchar_arr exists until you destroy it and it is okay to destroy it using a delete[] expression in another function.
Is it a good idea? No. You would be much better off using a smart pointer that manages the lifetime of the object automatically, releasing you from the responsibility of delete[]ing the pointer manually yourself.
Consider using a std::unique_ptr<char[]> if your compiler and Standard Library support unique_ptr, or std::auto_ptr or std::shared_ptr if you cannot use unique_ptr (shared_ptr may also be found in Boost and C++ TR1).
Allocating in one scope and deleting in another is one of the major reasons for using dynamic allocation instead of an automatic local variable.
As James says, prefer to use smart pointers to track dynamically allocated objects.
The only constraint I can think of on allocation in one scope and deallocation in another is multi-component applications where different components are built with different compilers (or maybe different versions of the same compiler). On Windows, each compiler provides its own memory management library, and you shouldn't free memory from a different component than the one that allocated it. Or you can use Windows-provided memory management routines which are common to all compilers (e.g. HeapAlloc/HeapFree). On Linux, everyone uses the glibc-supplied malloc, free, new[], and delete[], so it isn't such an issue. For other OSes, you need to investigate.
This example is very trivial, but image the following modification of your code:
int main()
{
string input_string;
char* npchar_arr;
int npsize;
cout << "Enter any string: ";
getline(cin, input_string);
getNonPunct(input_string, npchar_arr, npsize);
// Now display non-punctuation characters in the string
cout << "string with non-punctuation characters removed:\n";
for (int n = 0; n <= npsize - 1; n++)
cout << npchar_arr[n];
cout << "\n(" << npsize << ") non-punctuation characters\n";
return(0); // WHOOPS! I JUST RETURNED AND DIDN'T FREE THE MEMORY
delete [] npchar_arr;
// Is it okay to 'delete' npchar_arr eve if it was created in the function
// getNonPunct() ?
return(0);
}
I just returned before freeing the memory, which results in a memory leak! Of course, you might be thinking that you would never do such a thing, but imagine a much more complex program, it is easy to make such a mistake as the above, and using smart pointers as the other answers suggest, would alleviate you of having to worry about such tasks.