Creating a global array of structs - c++

For a project I am working on I need to have a global array of entry structs. I am having trouble though because I can't allocate memory until while running my program I determine the size of a file. The overall goal of this project is to create a word reference. So far how I am doing it is:
struct info{
//stores the specific character
std:: string c;
//stores the amount of times a word has come up in the file
float num;
}
info info_store[];
This project is to learn about arrays so I need to use an array

You can:
- use new/delete[]
info* p_array=new info[100]; // create an array of size 100
p_array[10].num; // member access example
delete[] p_array; // release memory
- use std::unique_ptr
std::unique_ptr<info[]> array(new info[size]);
-> The advantage is that your memory is automatically released when array is destroyed (no more delete[])

First of all, use std::vector or any other STL container.
Second, you can use dynamic arrays.
auto length = count_structs(file);
auto data = new info[length];
Something like this. Then just fill this array.
Ohh, and make sure you have delete [] data to prevent memory leaks.

Related

How can I allocate memory for the std::vector<std::vector<int> > data type?

Suppose the following data structure typedef std::vector<std::vector<int> > MYARRAY is defined. Then for the variable MYARRAY var, how can I allocate memory for this variable before pushing data in it. For example,
std::vector<int> p1;
p1.push_back(1);
p1.push_back(2);
std::vector<int> p2;
p2.push_back(22);
p2.push_back(33);
var.push_back(p1);
var.push_back(p2);
If we do not allocate memory for var, then it will allocate memory automatically. So how can I allocate memory for this var before pushing data insider it? If it is std::vector<int> var2, I can just use var2.reserve(n) to allocate memory before using it.
EDIT:
Two suggestions have been made, but neither can work:
Solution 1: allocate memory for each element
var.reserve(3);
for(int i=0; i<3; i++)
var[i].reserve[20];
I use VC 2010 to compile and run the codes in the debug mode, and the following error message is given:
Solution 2: create the object in the beginning
std::vector<std::vector<int> > var(3, std::vector<int>(5));
After you created this variable, you can see this variable in VC 2010:
Its contents are already there. Therefore, if you push data on this variable, it will allocate memory once again.
EDIT 2:
Someone is interested in why I need allocate memory before using this variableļ¼Œ and the main reason is because of run-time library of windows. The variable var is defined in a executable program as an empty variable, and its contents are given by a function defined in a dynamic library. If both are using dynamic run-time library, it will not be an issue. But in my case both are linked with static run-time library, which means that each module is in charge of its memory allocation. Since var is defined in the executable program, it also should take care of its memory allocation.
The way you reserve memory for a vector is independent of what type the vector contains. If you want to reserve space for n elements in MYARRAY, call MYARRAY.reserve(n);.
Its contents are already there. Therefore, if you push data on this variable, it will allocate memory once again.
Right. Do you want to reserve memory or not? If you want to reserve memory, you'll have to use the memory you reserved. In order for you to "push data on this variable", you'd have to have the data somewhere, somewhere other than the memory you reserved. If you reserve memory and use that memory, you'll never have anything to push, because that would imply that you have something someplace other than in the memory you reserved that you need to add to the vector, which you couldn't possibly have.
You basically have three choices:
1) Don't reserve memory. Assemble the objects wherever you want and then push them into the vector. vec.push_back(myVector);
2) Reserve memory. Assemble the objects in place in the vector. vec[n].push_back(myInt);
3) Reserve memory. Assemble the objects wherever you want and then assign them into the memory you reserved. vec[n]=myIntVector
Notice that in none of these cases do you reserve memory and then push into the vector.
Like you already pointed out, std::vector has the reserve method that will reserve space for more data items. If you were to do p1.reserve(3) the vector would attempt to allocate space for 3 integers. If you run var.reserve(3), var will attempt to allocate space for 3 std::vector<int>'s, which is what it sounds like you want to do.
To allocate for the std::vector's inside of var, you could do:
for(int x=0; x<var.size(); x++) var[x].reserve(n);
EDIT
If you want to allocate space before inserting the vectors, you can declare var as:
std::vector<std::vector<int> > var(VEC_COUNT, std::vector<int>(n));
And then copy the new vectors in.
You cannot reserve space for vector's data before the vector exists. I believe you're looking for this:
void reserve(MYARRAY &arr, size_t dim1, size_t dim2)
{
arr.resize(dim1);
for (size_t idx = 0; idx < dim1; ++idx) {
arr[idx].reserve(dim2);
}
}

pointer to string that can be used to dynamically allocate array of strings

Im writing a project and its for a car lot and im creating classes. I need to fullfill certain requirements. For accessory descriptions I need to use a pointer to a string that can be used to dynamically allocate an array of strings with the exact number of accessories. Each element will hold the name of the accessory.
If the number of accessories is 0, there is no need to allocate space, set the pointer to null.
And also pointer to a double that can eb used to dynamically allocate an array of doubles with the same number of elements as accessories. Each element will hold the cost of the associated accessory, that is, the cost in element 0 is the cost of the accessory in element 0.
If the number of accessories is zero, set the pointer to null since there is no need to allocate space.
Heres what my class is so far without those last two requirements. Im stumped.
#ifndef VEHICLE_H
#define VEHICLE_H
class Vehicle
{
public:
Vehicle();
protected:
int vin_number;
string manufacturer;
string model;
string color;
double basecost;
int accessories;
string accessory_list;
private:
};
#endif // VEHICLE_H
Please help it's an online course and ive been googling and reading for hours.
You should not dynamically allocate an array of string.
If you decide to use C++, you should be using STL and collections. Like this:
std::list<std::string> accessory_list;
If you decide to use C, a dynamically allocated string list could look like this:
//init
int accessory_count = 0;
int accessory_cap = 20;
char** accessory_list = calloc (sizeof(char*), accessorry_cap);
//add:
if (accessory_count==accessory_cap) {
accessory_cap += 20;
accessory_list = realloc (accessory_list, sizeof(char*)* accessorry_cap);
}
accessory_list[accessory_count++] = new_accessory.
If you really need a dynamic array of strings, you can do:
int accessory_arr_cap = 20;
string* accessory_arr = new string[accessory_arr_cap];
But since there is no realloc possible in this case, you will have to copy the entire array into new one if you need to enlarge it.
If the cost and name of the option are related, put them in a struct:
struct Option
{
char* Name;
double price;
}
Than what you are looking for is a collection, perhaps a std::vector<Option>. I'll leave it up to you to google the std::vector, it's a good learning exercise.
On a side note, do you have to use C++? You might find another language like C#, or Java a little easier to learn to program with.
If you can't use vectors, make your own collection. I won't post the code because I sense this is an assignment but here's how they normally work:
instantiate with a default size array of say 10.
keep a variable with this max in it
keep a variable with the current number of items in it (starts at 0, maybe call it count or something)
when you add a pointer, put it in element 'count' and increment the counter
if count = capacity then allocate a new array 2*capacity, copy all elements into it, delete the old one and assign the new array to the variable that was the old array.

Why can't initial length be 1 in a dynamically-allocated array?

Let's say we start out with:
int *newArray = new int[1];
And then later have something like:
ifstream inputFile("File.txt");
Counter=0;
while (inputFile >> newValue)
{
newArray[Counter] = newValue;
Counter++
}
If I try to pull 100 lines from the text file, the program will eventually crash. However, if I had used
int *newArray = new int[100];
originally, it doesn't crash.
If it's dynamically allocating memory, why does it need an initial value more than 1? That makes no sense to me. Having to define any initial length beyond a small number such as 1 or 10 defeats the whole purpose of dynamic memory allocation...
EDIT: This is for school, we aren't allowed to use vectors yet.
The language will not "dynamically allocate memory" for you. It is your responsibility to allocate and reallocate your arrays so that their sizes are sufficient for your purposes.
The concept of "dynamic allocation" in C++ never meant that memory will somehow allocate itself automatically for you. The word "dynamic" in this context simply means that the parameters and lifetime of the new object are determined at run time (as opposed to compile time). The primary purpose of dynamic memory allocation is: 1) to manually control object's lifetime, 2) to specify array sizes at run-time, 3) to specify object types at run-time.
The second point is what allows you to do this
int n = ...; // <- some run-time value
int *array = new int[n];
which is not possible with non-dynamically allocated arrays.
In your example, you can allocate an array if size 1 initially. Ther's nothing wrong with it. But it is still your responsibility to allocate a new, bigger array, copy the data to the new array and free the old one once you need more space in your array.
In order to avoid all that hassle you should simply use a library-provided resizable container, like std::vector.
It's not dynamic in the sense that it can dynamically resize itself. It's dynamic in the sense that its size can be chosen dynamically at runtime, instead of compile time. One of the primary philosophies of C++ is that you don't pay for what you don't use. If dynamic arrays worked the way you are asking, that would require bounds checking, something I don't need, so I don't want to pay for it.
Anyway, the problem is solved with the standard library.
std::vector<int> vec;
...
while (inputFile >> newValue)
{
vec.push_back(newValue);
}
Isn't that much nicer? You don't even have to keep track of the size, because vector keeps track of it for you.
If you can't use vector, then you've got a lot of work ahead of you. The principle is essentially this. You keep 2 additional integer variables. One to indicate the number of values you are using in your array, and one to indicate the current capacity of your array. When you run out of room, you allocate more space. For example, here is a poor man's non-exception safe version of a vector:
int size = 0;
int capacity = 1;
int array = new int[capacity];
while (inputFile >> newValue)
{
if (size == capacity)
{
capacity *= 2;
int * newArray = new int[capacity];
for (int i=0; i<size; ++i)
newArray[i] = array[i];
delete [] array;
array = newArray;
}
array[size++] = newValue;
}
You're only creating space for one int but trying to store several, of course it crashes. Even if you created it with size 100 it'd still crash when you tried to save the 101'th value.
If you need an automatically resizing container check out std::vector.
#include <vector>
std::vector<int> data;
while (inputFile >> newValue)
{
data.push_back(newValue);
}
This will work until your process runs out of memory.

C++ Allocate Memory Without Activating Constructors

I'm reading in values from a file which I will store in memory as I read them in. I've read on here that the correct way to handle memory location in C++ is to always use new/delete, but if I do:
DataType* foo = new DataType[sizeof(DataType) * numDataTypes];
Then that's going to call the default constructor for each instance created, and I don't want that. I was going to do this:
DataType* foo;
char* tempBuffer=new char[sizeof(DataType) * numDataTypes];
foo=(DataType*) tempBuffer;
But I figured that would be something poo-poo'd for some kind of type-unsafeness. So what should I do?
And in researching for this question now I've seen that some people are saying arrays are bad and vectors are good. I was trying to use arrays more because I thought I was being a bad boy by filling my programs with (what I thought were) slower vectors. What should I be using???
Use vectors!!! Since you know the number of elements, make sure that you reserve the memory first (by calling myVector.reserve(numObjects) before you then insert the elements.).
By doing this, you will not call the default constructors of your class.
So use
std::vector<DataType> myVector; // does not reserve anything
...
myVector.reserve(numObjects); // tells vector to reserve memory
You can use ::operator new to allocate an arbitrarily sized hunk of memory.
DataType* foo = static_cast<DataType*>(::operator new(sizeof(DataType) * numDataTypes));
The main advantage of using ::operator new over malloc here is that it throws on failure and will integrate with any new_handlers etc. You'll need to clean up the memory with ::operator delete
::operator delete(foo);
Regular new Something will of course invoke the constructor, that's the point of new after all.
It is one thing to avoid extra constructions (e.g. default constructor) or to defer them for performance reasons, it is another to skip any constructor altogether. I get the impression you have code like
DataType dt;
read(fd, &dt, sizeof(dt));
If you're doing that, you're already throwing type safety out the window anyway.
Why are you trying to accomplish by not invoking the constructor?
You can allocate memory with new char[], call the constructor you want for each element in the array, and then everything will be type-safe. Read What are uses of the C++ construct "placement new"?
That's how std::vector works underneath, since it allocates a little extra memory for efficiency, but doesn't construct any objects in the extra memory until they're actually needed.
You should be using a vector. It will allow you to construct its contents one-by-one (via push_back or the like), which sounds like what you're wanting to do.
I think you shouldn't care about efficiency using vector if you will not insert new elements anywhere but at the end of the vector (since elements of vector are stored in a contiguous memory block).
vector<DataType> dataTypeVec(numDataTypes);
And as you've been told, your first line there contains a bug (no need to multiply by sizeof).
Building on what others have said, if you ran this program while piping in a text file of integers that would fill the data field of the below class, like:
./allocate < ints.txt
Then you can do:
#include <vector>
#include <iostream>
using namespace std;
class MyDataType {
public:
int dataField;
};
int main() {
const int TO_RESERVE = 10;
vector<MyDataType> everything;
everything.reserve( TO_RESERVE );
MyDataType temp;
while( cin >> temp.dataField ) {
everything.push_back( temp );
}
for( unsigned i = 0; i < everything.size(); i++ ) {
cout << everything[i].dataField;
if( i < everything.size() - 1 ) {
cout << ", ";
}
}
}
Which, for me with a list of 4 integers, gives:
5, 6, 2, 6

What is the array form of 'delete'?

When I compiled a code using the array name as a pointer, and I deleted the array name using delete, I got a warning about deleting an array without using the array form (I don't remember the exact wording).
The basic code was:
int data[5];
delete data;
So, what's the array form of delete?
The array form of delete is:
delete [] data;
Edit: But as others have pointed out, you shouldn't be calling delete for data defined like this:
int data[5];
You should only call it when you allocate the memory using new like this:
int *data = new int[5];
You either want:
int *data = new int[5];
... // time passes, stuff happens to data[]
delete[] data;
or
int data[5];
... // time passes, stuff happens to data[]
// note no delete of data
The genera rule is: only apply delete to memory that came from new. If the array form of new was used, then you must use the array form of delete to match. If placement new was used, then you either never call delete at all, or use a matching placement delete.
Since the variable int data[5] is a statically allocated array, it cannot be passed to any form of the delete operator.
As the other have said, you must use the vector form of delete:
void some_func(size_t n)
{
int* data = new int[n];
. . . // do stuff with the array
delete [] data; // Explicitly free memory
}
Be very wary of this, because some compilers will not warn you.
Even better, there is very rarely any need for using vector new/delete. Consider whether your code can be altered to make use of std::vector:
void some_func(size_t n)
{
std::vector<int> data(n);
. . . // do stuff with the array
} // memory held by data will be freed here automatically
And if you are dealing with the memory in a local scope, consider using STLSoft's auto_buffer, which will allocate from an internal buffer (held on the stack, as part of the instance) if possible, only going to the heap if it cannot:
void some_func(size_t n)
{
stlsoft::auto_buffer<int, 10> data(n); // only allocates if n > 10
. . . // do stuff with the array
} // memory held by data will be freed here automatically, if any was allocated
Read more about auto_buffer.
The code as shown has the array either on the stack, or in initialized part of the data segment, i.e. you don't deallocate it (which, as mentioned by others, would be "undefined behavior".) Were it on the "free store", you'd do that with delete [] data.
Just as RichieHindle stated above when you want to free the space dynamically allocated for an array pointed by data you have to put two brackets [] between the reserved word delete and the pointer to the beginning of the allocated space. Since data can point to a single int in memory as well as to the first element in the array this is the only way you let the compiler know that you want to delete the whole chunk of memory. If you don't do it the proper way the behaviour is "undetermined" (Stroustrup, The C++ Programming Language).
Fixes C4154 and C4156 warnings
float AR[5] = { 1.0f, 2.0f, ..., ..., ...};
delete [] & AR;