void pre_process(string& pattern, vector<int>& c)
{
c.reserve(pattern.length());
c[0] = -1;
c[1] = 0;
for(int i=2; i<pattern.length(); ++i)
{
if(pattern[c[i-1]] == pattern[i-1])
c[i] = c[i-1]+1;
else
c[i] = 0;
}
cout << c.size() << endl; //why the size is zero here?
}
After reserving the space in vector, I am assigning values to different positions of vector. So shouldn't the size be increased?
What is the right way to use vector as a fixed length container?
Because std::vector::reserve doesn't resize a vector. It simply re-allocates a larger chunk of memory for the vector's data (and copies elements from the original if necessary).
You need std::vector::resize for that:
c.resize(pattern.length());
Currently, you are accessing c out of bounds.
Alternatively, you can keep the call to resize and use push_back instead of operator[]
c.reserve(pattern.length());
c.push_back(-1);
c.push_back(0);
Related
I hope to use vector to process the 2d array data obtained by calling a third-party library.
Although I can simply use the loop to assign values one by one, But I prefer to use methods such as insert and copy to deal with this.
I found that reserve doesn't seem to work here. So I used resize instead.
double **a = new double *[1024];
for (int i = 0; i < 1024; ++i) {
a[i] = new double[512];
}
std::vector<std::vector<double>> a_v;
a_v.resize(1024, std::vector<double>(512));
// Copy a -> a_v
I made these attempts:
// Not Working, just 0 in vector
for (int i = 0; i < 1024; ++i){
a_v[i].insert(a_v[i].end(), a[i], a[i] + 512);
}
Is there any good way to solve this problem.
For a 1D array I write like this:
double *b = new double[1024];
std::vector<double> b_v;
b_v.reserve(1024);
b_v.insert(b_v.end(), b, b + 1024);
If the size of the source array is fixed, it is strongly recommended to use std::array instead of std::vector. std::array has continuous memory layout for multidimensional structures, thus std::memcpy can be used for copy if the source array is also continuous in memory.
Look back to the original question. If you want to construct a std::vector<std::vector<double>> from the source array, use a single loop to construct 1D vectors from the source:
std::vector<std::vector<double>> a_v;
a_v.reserve(1024);
for (int i = 0; i < 1024; ++i) {
a_v.emplace_back(std::vector<double>(&(a[i][0]), &(a[i][512])));
}
If there is already a std::vector<std::vector<double>> with the proper size, and you literally just want to do a copy from the source, use the assign member function:
for (int i = 0; i < 1024; ++i) {
a_v[i].assign(&(a[i][0]), &(a[i][512]));
}
std::vector<std::vector<double>> a_v;
a_v.resize(1024, std::vector<double>(512));
is just
std::vector<std::vector<double>> a_v{1024, std::vector<double>(512)};
Unfortunately there is no vector constructor that takes over ownership of a C-style array. So you have to copy all 1024 * 512 doubles. And with the above definition of the vector you needlessly initialize all the doubles before you overwrite them.
You can do it with reserve so none of the double get initialized before you overwrite them and no vector gets copied or moved:
std::vector<std::vector<double>> a_v;
a_v.reserve(1024);
for (std::size_t i = 0; i < 1024; ++i) {
a_v.emplace_back();
std::vector<double> &b_v = a_v.back();
b_v.reserve(512);
b_v.insert(b_v.end(), a[i], a[i] + 512);
}
I would like to write to internal array of vector. I could write using data() if vector is initialised.
However if the vector is empty (but having enough storage), I am not able to write directly to internal array of vector.
#include <vector>
#include <iostream>
using namespace std;
void write_seq(int *v, size_t len)
{
for (int i = 0; i < len; i++)
v[i] = i;
}
int main(void)
{
vector<int> v;
cout << "reserve and write\n";
v.reserve(10);
write_seq(v.data(), v.capacity());
cout << "seq length " << v.size() << "\n";
return 0;
}
Output:
$ g++ main.cpp && ./a.out
reserve and write
seq length 0
How to avoid this kind of situations, is it possible to validate data() pointer of vector?
Edit:
I assumed two things with this question, on an empty vector v;,
v.reserve(10) allocates memory for 10 elements and
v.data() points to that allocated memory.
You want to use resize, not reserve, and size instead of capacity. reserve simply gives the vector the added capacity, without actually increasing the size. resize increases the size to match the reserved capacity.
There's no need to concern yourself with how much memory you need to reserve beforehand. If performance is not really an issue, you may consider instead using auto-resizable back inserting iterators to push the elements at the step you want to push them.
#include <vector>
#include <iostream>
template<typename Iterator>
void write_seq(Iterator v) {
for (int i = 0; i < 10; i++) {
*v = i; // actually calls std::vector<>::push_back() internally
v++;
}
}
int main(void)
{
std::vector<int> v;
std::cout << "just write them data!\n";
write_seq(std::back_inserter(v));
std::cout << "seq length " << v.size() << "\n";
return 0;
}
You need to understand the concept of size and capacity of a vector. size is the number of elements stored while capacity is internal space allocated. capacity is always great than or equal to size. If you insert elements into the vector and caused the vector to run out of capacity, it will automatically increase its capacity by allocating a new space twice of current capacity, then copy existing elements into the new space, then delete the old space.
If you are planning to insert a large number of elements into a vector, the "auto increasing capacity" feature is not efficient, as it will keep allocating new spaces and copying elements. Instead, you can use reserve() to allocate enough space beforehand, and thus to avoid the process to keep allocating new spaces.
capacity(): Returns the number of elements that the container has currently allocated space for.
reserve(): Increase the capacity of the vector to the given size or more.
size(): Returns the number of elements in the container.
resize(): Changes the number of elements stored.
Back to your question, you can simply replace reserve with resize:
int main(void)
{
vector<int> v;
cout << "reserve and write\n";
v.resize(10); // use resize() instead of reserve()
write_seq(v.data(), v.size());
cout << "seq length " << v.size() << "\n";
return 0;
}
Or, you can insert into the vector directly:
void write_seq(vector<int>& v, size_t len)
{
for (int i = 0; i < len; i++)
v.push_back(i); // add an element to the vector, this changes the size
}
int main(void)
{
vector<int> v;
cout << "reserve and write\n";
v.reserve(10); // this does not change size, the vector is still empty
write_seq(v, v.capacity());
cout << "seq length " << v.size() << "\n";
return 0;
}
You cannot assign to an element that does not exist. Allocating memory is not sufficient, but your code is fine when you resize the vector (or create it with sufficient elements):
int main(void)
{
vector<int> v(10); // vector with 10 element
write_seq(v.data(), v.size()); // write to those 10 element
cout << "seq length " << v.size() << "\n"; // size is (still) 10
return 0;
}
Note that your code is not very idomatic. I assume you have reasons for that, but passing iterators to write_seq would be much more natural.
Here is the code for adding vertex to a graph:
void myGraph::addVertex(const string &newVertex)
{
if (getIndex(newVertex) != -1)
{
std::cout << ("addVertex: ");
std::cout << newVertex;
std::cout << (" failed -- vertex already exists.") << std::endl;
return;
}
// if array of vertices is full, we need to expand it and
// also expand Edges
if (sizeof(Vertices)/sizeof(Vertices[0])==numVertices)
{
Vertices = resize(Vertices, 2*numVertices + 1);
Edges = resize(Edges, 2*numVertices + 1);
}
Vertices[numVertices++] = newVertex;
}
and here is the code for resizing of Vertices array:
string *myGraph::resize(string array1[], int newSize)
{
// make array of size equal to new size
string *temp = new string [newSize];
int smallerSize = newSize;
// if the size of input array is less than the new size then smaller size will be that of input array
if (sizeof(array1)/sizeof(array1[0]) < smallerSize)
{
smallerSize = sizeof(array1) / sizeof(array1[0]);
}
// loop till smaller size and copy the content of input array to newly created array
for (int i = 0; i < smallerSize; i++)
{
temp[i] = array1[i];
}
return temp;
}
When I debug this code, it adds only 1 vertice, i.e. numVertices=1 and on next step it says in Vertices[numVertices++]
sizeof is giving the size of the pointer to the data in your array, not the total size of the array. It depends on your platform, but it is very likely that sizeof(string*)/sizeof(string) (equivalent to your size calculation) is always going to return 1. You should probably be using something like std::vector or std::list for this, the right choice depends on how exactly you will be using it. These standard container classes will handle allocating memory and resizing for you, so you don't have to worry about it.
You can fix it by passing old array size to resize:
string *myGraph::resize(string array1[], int array1Size, int newSize)
then:
if (array1Size < smallerSize) {
smallerSize = array1Size ;
}
as Katie explains, sizeof(array1) in your code is not the size of the actual array, you should rather use string* array1 to make clear that it is pointer to allocated memory on heap
I have allocated an array as follows.
#include <iostream>
int main() {
const int first_dim = 3;
const int second_dim = 2;
// Allocate array and populate with dummy data
int** myArray = new int*[first_dim];
for (int i = 0; i < first_dim; i++) {
myArray[i] = new int[second_dim];
for (int j = 0; j < second_dim; j++) {
myArray[i][j] = i*second_dim + j;
std::cout << "[i = " << i << ", j = " << j << "] Value: " << myArray[i][j] << "\n";
}
}
// De-allocate array
for (int i = 0; i < first_dim; i++)
delete[] myArray[i];
delete[] myArray;
}
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
I've heard that Vectors are so much more efficient for this purpose, but I hardly know what they are and I've never used them before.
Yes, but in a very painful way. What you have to do is allocate new memory which now has your new desired dimensions, in this case 4 and 2, then copy all the contents of your matrix to your new matrix, and then free the memory of the previous matrix... that's painful. Now let's see how the same is done with vectors:
#include <vector>
using std::vector;
int main()
{
vector< vector <int> > matrix;
matrix.resize(3);
for(int i = 0; i < 3; ++i)
matrix[i].resize(2);
matrix[0][1] = 4;
//...
//now you want to make the first dimension 4? Piece of cake
matrix.resize(4);
matrix[3].resize(2);
}
HTH
edit:
some comments on your original code:
In C++ ALL_CAP_NAMES usually refer to macros (something you #define). Avoid using them in other contexts
why do you declare FIRSTDIM and SECONDDIM static? That is absolutely unnecessary. If a local variable is static it means informally that it will be the same variable next time you call the function with kept value. Since you technically can't call main a second sime this is useless. Even if you could do that it would still be useless.
you should wrire delete [] array[i]; and delete [] array; so the compiler knows that the int* and int** you're trying to delete actually point to an array, not just an int or int* respectively.
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
Yes, but it's a pain in the neck. It basically boils down to allocating a new array, just as your existing code does (hint: put it in the function and make the sizes arguments to that function) and copying compatible elements over.
Edit: One of the things that std::vector does for you is properly de-allocating you memory. In the code you have, failure to allocate one of the arrays along the 2nd dimension will result in a memory leak. A more robust solution would initialize pointers to 0 before performing any allocation. An exception block could then catch the exception and free whatever was partially allocated.
Because this code becomes complex quickly, people resort to allocating a single buffer and addressing using a stride or using a 1D array of 1D arrrays (i.e. std::vector of std::vectors).
I read to get the length of array in C++, you do this:
int arr[17];
int arrSize = sizeof(arr) / sizeof(int);
I tried to do the same for a string:
where I have
string * arr;
arr = new (nothrow) string [213561];
And then I do
arr[k] = "stuff";
where I loop through each index and put "stuff" in it.
Now I want the size of the array which should be 213561, what's the correct way to do it and why is it so complex in C++?
What you are trying to do cannot work because sizeof works on types at compile-time (and pointer types never hold the size of the array they may be pointing to).
In your case, computing sizeof(arr) returns the size taken in memory by the pointer, not
size of the array * size of a std::string
I suggest you use one of these two options
either use fixed-size arrays (sizeof works)
or vectors (myVector.size() returns what you need)
... unless you have a good reason not to.
The correct way of doing this in C++ is to use a vector. That way you can either specify a size up-front, or resize it as you go.
Specifying size up-front:
using namespace std;
vector<string> arr(213561);
for (vector<string>::iterator p = arr.begin(); p != arr.end(); ++p)
{
*p = "abc";
}
Expanding the vector as you go:
using namespace std;
vector<string> arr; // <-- note, default constructor
for (int i = 0; i < 213561; ++i)
{
// add elements to the end of the array, automatically reallocating memory if necessary
arr.push_back("abc");
}
Either way, the size of the array is found with:
size_t elements = arr.size(); // = 213561
The sizeof method only works as long as your array is really an array, i.e. an object that has the array type. In your first example object arr has type int[17]. It is an array type, which means that you can use the sizeof method and get 17 as the result.
Once you convert your array type T[N] to a pointer type T *, you basically lose your array type. The sizeof method applied to a pointer will not evaluate to the size of the original array.
When you allocate array of type T[N] with new[], the result is a pointer of type T * right away. It is not an array type from the very beginning. The information about array size is lost right away and trying to use the sizeof method with such a pointer will not work. In order to preserve the size information about a dynamically allocated run-time sized array, you have to store it in a separate variable yourself.
Here is how you find the size of an array:
const size_t ARRAY_SIZE = 17;
int array[ARRAY_SIZE];
//...
std::cout << "My array size is: " << ARRAY_SIZE << "\n";
You can put ARRAY_SIZE into a header so that other translation units can access the array size.
If you want a dynamic array, that will grow as needed, try std::vector.
You need to keep track of the length using a separate variable. There is no way of getting the length of an area that you only have a pointer to, unless you store that length somewhere.
You cannot get the length of the allocated array.
What you can do is save it seperately at the time of allocation..
Also, you could check the length of the string (which isn't what you're asking, but still..) using strlen()
In c++ here arr is simply a reference to the first element of the array. In case of dynamic arrays it is not possible.
There is a subtle nuance in both C and C++ with memory allocation. Neither language supports dynamic arrays. Here is what you are seeing:
int ary[17];
int arrSize = sizeof(ary) / sizeof(ary[0]);
Here ary is a true array of 17 integers. The array size calculation works because sizeof(ary) returns the size of the memory block allocated for the entire array. You divide this by the size of each element and violĂ you have the number of elements in the array.
std::string * arr;
arr = new (std::nothrow) std::string[213561];
In this case arr is a pointer to some memory. The new operator allocates a block of memory large enough to hold 213,561 contiguous std::string objects and constructs each of them into the memory. The arr variable simply points to the beginning of the block of memory. C++ does not track the number of elements that you have allocated. You didn't really create a dynamic array - instead, you have allocated enough memory for a bunch of contiguous objects.
C and C++ both allow you to apply the subscripting operator to a pointer as syntactical sugar. You will see a lot of comments about how arr[0] translates into *(arr + 0). The reality is that allocating memory using the new operator results in a block of memory that is not an array at all. The syntactical sugar makes it look like one. The next thing that you will encounter is that multi-dimensional arrays are similar sugar.
Consider the following snippet. Once you understand what is going on there, you will be a lot closer to understanding how memory works. This is the primary reason why C and C++ cannot tell you how large an array is if it is dynamically allocated - it does not know the size, all that it has is a pointer to the allocated memory.
#include <iostream>
int
main()
{
//
// The compiler translates array subscript notation into
// pointer arithmetic in simple cases so "hello"[3] is
// is translated into *("hello" + 3). Since addition is
// commutative, the order of "hello" and 3 are irrelevant.
//
std::cout
<< "\"hello\"[3] = '" << "hello"[3] << "'\n"
<< "3[\"hello\"] = " << 3["hello"] << "\n"
<< std::endl;
//
// All memory is linear in C or C++. So an 3x3 array of
// integers is a contiguous block of 9 integers in row
// major order. The following snippet prints out the 3x3
// identity matrix using row and column syntax.
//
int ary[3][3] = { { 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 } };
for (int r=0; r<3; ++r) {
for (int c=0; c<3; ++c) {
std::cout << "\t" << ary[r][c];
}
std::cout << "\n";
}
std::cout << "\n";
//
// Since memory is linear, we can also access the same
// 3x3 array linearly through a pointer. The inner loop
// is what the compiler is doing when you access ary[r][c]
// above - "ary[r][c]" becomes "*(ptr + (r * 3) + c)"
// since the compiler knows the dimensions of "ary" at
// compile time.
//
int *ptr = &ary[0][0];
for (int i=0; i<9; ++i) {
ptr[i] = i;
}
for (int r=0; r<3; ++r) {
for (int c=0; c<3; ++c) {
std::cout << "\t" << *(ptr + (r * 3) + c);
}
std::cout << "\n";
}
return 0;
}