Initialise a dynamically allocated array [duplicate] - c++

In C++, I can statically initialize an array, e.g.:
int a[] = { 1, 2, 3 };
Is there an easy way to initialize a dynamically-allocated array to a set of immediate values?
int *p = new int[3];
p = { 1, 2, 3 }; // syntax error
...or do I absolutely have to copy these values manually?

You can in C++0x:
int* p = new int[3] { 1, 2, 3 };
...
delete[] p;
But I like vectors better:
std::vector<int> v { 1, 2, 3 };
If you don't have a C++0x compiler, boost can help you:
#include <boost/assign/list_of.hpp>
using boost::assign::list_of;
vector<int> v = list_of(1)(2)(3);

You have to assign each element of the dynamic array explicitly (e.g. in a for or while loop)
However the syntax int *p = new int [3](); does initialize all elements to 0 (value initialization $8.5/5)

To avoid endless push_backs, I usually initialize a tr1::array and create a std::vector (or any other container std container) out of the result;
const std::tr1::array<T, 6> values = {T(1), T(2), T(3), T(4), T(5), T(6)};
std::vector <T> vec(values.begin(), values.end());
The only annoyance here is that you have to provide the number of values explicitly.
This can of course be done without using a tr1::array aswell;
const T values[] = {T(1), T(2), T(3), T(4), T(5), T(6)};
std::vector <T> vec(&values[0], &values[sizeof(values)/sizeof(values[0])]);
Althrough you dont have to provide the number of elements explicitly, I prefer the first version.

No, you cannot initialize a dynamically created array in the same way.
Most of the time you'll find yourself using dynamic allocation in situations where static initialization doesn't really make sense anyway. Such as when you have arrays containing thousands of items. So this isn't usually a big deal.

Using helper variable:
const int p_data[] = {1, 2, 3};
int* p = (int*)memcpy(new int[3], p_data, sizeof(p_data));
or, one line
int p_data[] = {1, 2, 3}, *p = (int*)memcpy(new int[3], p_data, sizeof(p_data));

Never heard of such thing possible, that would be nice to have.
Keep in mind that by initializing the array in the code that way
int a[] = { 1, 2, 3 };
..... only gains you easier code writing and NOT performance.
After all, the CPU will do the work of assigning values to the array, either way you do it.

Related

C++ Array Reinitialization using Braces [duplicate]

So I am playing around with some arrays, and I cannot figure out why this won't work.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
values = numbers;
The following error appear:
Error 1 error C2106: '=' : left operand must be l-value c:\users\abc\documents\visual studio 2012\projects\consoleapplication7\consoleapplication7\main.cpp 9 1 ConsoleApplication7
Why can't I do like that? What does the error mean?
Arrays have a variety of ugly behavior owing to C++'s backward compatibility with C. One of those behaviors is that arrays are not assignable. Use std::array or std::vector instead.
#include <array>
...
std::array<int,5> numbers = {1,2,3};
std::array<int,5> values = {};
values = numbers;
If, for some reason, you must use arrays, then you will have to copy the elements via a loop, or a function which uses a loop, such as std::copy
#include <algorithm>
...
int numbers[5] = {1, 2, 3};
int values[5] = {};
std::copy(numbers, numbers + 5, values);
As a side note, you may have noticed a difference in the way I initialized the values array, simply providing an empty initializer list. I am relying on a rule from the standard that says that if you provide an initializer list for an aggregate, no matter how partial, all unspecified elements are value initialized. For integer types, value initialization means initialization to zero. So these two are exactly equivalent:
int values[5] = {0, 0, 0, 0, 0};
int values[5] = {};
You can't assign arrays in C++, it's stupid but it's true. You have to copy the array elements one by one. Or you could use a built in function like memcpy or std::copy.
Or you could give up on arrays, and use std::vector instead. They can be assigned.
Array names are constant not modifiable l-value, you can't modify it.
values = numbers;
// ^
// is array name
Read compiler error message: "error C2106: '=' : left operand must be l-value" an l-value is modifiable can be appear at lhs of =.
You can assign array name to a pointer, like:
int* ptr = numbers;
Note: array name is constant but you can modify its content e.g. value[i] = number[i] is an valid expression for 0 <= i < 5.
Why can't I do like that?
Basically this constrain is imposed by language, internally array name uses as base address and by indexing with base address you can access content continue memory allocated for array. So in C/C++ array names with be appear at lhs not a l-value.
values = numbers;
Because numbers and values are pointers.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
for(int i = 0;i < 5; i ++){
values[i] = numbers[i];
}
std::array is a good idea, but this is also possible:
struct arr { int values[5]; };
struct arr a{{1, 2, 3}};
struct arr b{{}};
a = b;
Otherwise, use std::memcpy or std::copy.
I think the reason for non-assignability is that C wants to make sure that any pointers to any element in the array would pretty much always remain valid.
Think about vectors that allow dynamic resizing: the older pointers become invalid (horribly) after resizing happens automatically.
PS. With the design philosophy for vectors, the following block works well.
vector<int> v = {1, 5, 16, 8};
vector<int> v_2 = {7, 5, 16, 8};
v_2 = v;

Declaring array of pointers to char arrays

How come I can do this:
char a[] = {1, 2};
char b[] = {3, 4, 5};
const char *r[] = {
a, b
};
But I can't do it this way:
const char *r[] = {
{1,2}, {3,4,5}
};
Is there any shortcut for initializing an array of pointers to arrays of different length?
There is no easy solution to achieve the syntax you're looking for: these pointers have to point at some arrays, and these arrays must have an adequate lifetime.
You probably want them to be automatic, which implies declaring them as local variables the way you did.
You could achieve sort of what you want with dynamic allocation, i.e:
const char *r[] = {
new char[]{1,2}, new char[]{3,4,5}
};
... in which case the arrays will have sufficient lifetime, but then you have the burden of delete[]ing them at the right time. Not really a solution.
The first form works because, when used like this, the name of each array is converted to a pointer (to its first element). Since the result of the conversion is a char * it can be stored in an array of char *.
The second form doesn't work since {1,2} and {3,4,5} are (initialisers for) arrays, and arrays are not pointers. An unnamed array (which these are) cannot be implicitly be converted to a pointer.
The first form IS the only shortcut to initialise an array of pointers, so each pointer points to the first element of an array.
You would be normally better off using standard containers (e.g. a std::vector<std::string>) and avoid the complexity of pointers (and conversions of array names to pointers) entirely.
this code doesn't work,
const char r[][] = {{1,2}, {3,4,5}};
fails with :
x86-64 gcc 5.1!!error: declaration of 'r' as multidimensional array
must have bounds for all dimensions except the first
fix it like so:
const char r[][3] = {{1,2}, {3,4,5}};
side note: it's a bad practice to use C-like arrays in c++ use std::array if you know your values at compile time.
EDIT:
you can do this ugly hack(it compiles, but I don't know how many rockets it will launch).
const char *r[] = { (const char[]){1,2}, (const char[]){1,2,3}};
you can't write:
const char *r[] = { {1,2}, {3,4,5} };
because you cannot write:
r[0] = 1, 2, 3; // but you can r[0] = "1, 2, 3";
to initialize your array of pointers to char you can:
const char *r[] = {
{"1,2"}, {"3,4,5"}};
so r is a an array of pointers to char.

How can I give values for a newly initialized array right after declaration

How can I give values of my new initialized array if I am using a pointer? E.g.
int* array = new int[3]; <- I want to give the values {1,2,3} on the same row but not:
array[0] = 5;
array[1] = 3;
array[2] = 4;
You can use a brace enclosed initializer:
int* array = new int[3]{1, 2, 3};
The usual warning is that you would need to ensure that you call delete [] on array. This is harder to guarantee than apears at first sight. For this and other reasons, it may be a better idea to use an std::vector<int>:
std::vector<int> v{1,2,3};
If you are stuck with an older, pre-C++11 implementation, then you cannot use the brace enclosed initializer syntax. You will have to use a loop at some level (whether your own, or by using some standard or 3rd party library function.)
If you absolutely, positively have to use C++98, you could do something like this:
#include <algorithm> //copy
#include <iostream> // cout
#include <iterator> // iostream_iterator
void foo()
{
int init[] = { 1, 2, 3 };
int* array = new int[3];
std::copy(init, init + 3, array);
std::copy(array, array + 3, std::ostream_iterator<int>(std::cout, ", "));
// better hope nothing bad like an exception happens in between
delete[] array;
}
int main()
{
foo();
}
Live Example. So you define a C-array of initializers and copy them into your dynamically allocated array. The C-array init will be automatically deleted when foo() exits, but you have to manually delete array. The recommended way is to use std::vector in C++11 with an initializer-list.

Assign array to array

So I am playing around with some arrays, and I cannot figure out why this won't work.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
values = numbers;
The following error appear:
Error 1 error C2106: '=' : left operand must be l-value c:\users\abc\documents\visual studio 2012\projects\consoleapplication7\consoleapplication7\main.cpp 9 1 ConsoleApplication7
Why can't I do like that? What does the error mean?
Arrays have a variety of ugly behavior owing to C++'s backward compatibility with C. One of those behaviors is that arrays are not assignable. Use std::array or std::vector instead.
#include <array>
...
std::array<int,5> numbers = {1,2,3};
std::array<int,5> values = {};
values = numbers;
If, for some reason, you must use arrays, then you will have to copy the elements via a loop, or a function which uses a loop, such as std::copy
#include <algorithm>
...
int numbers[5] = {1, 2, 3};
int values[5] = {};
std::copy(numbers, numbers + 5, values);
As a side note, you may have noticed a difference in the way I initialized the values array, simply providing an empty initializer list. I am relying on a rule from the standard that says that if you provide an initializer list for an aggregate, no matter how partial, all unspecified elements are value initialized. For integer types, value initialization means initialization to zero. So these two are exactly equivalent:
int values[5] = {0, 0, 0, 0, 0};
int values[5] = {};
You can't assign arrays in C++, it's stupid but it's true. You have to copy the array elements one by one. Or you could use a built in function like memcpy or std::copy.
Or you could give up on arrays, and use std::vector instead. They can be assigned.
Array names are constant not modifiable l-value, you can't modify it.
values = numbers;
// ^
// is array name
Read compiler error message: "error C2106: '=' : left operand must be l-value" an l-value is modifiable can be appear at lhs of =.
You can assign array name to a pointer, like:
int* ptr = numbers;
Note: array name is constant but you can modify its content e.g. value[i] = number[i] is an valid expression for 0 <= i < 5.
Why can't I do like that?
Basically this constrain is imposed by language, internally array name uses as base address and by indexing with base address you can access content continue memory allocated for array. So in C/C++ array names with be appear at lhs not a l-value.
values = numbers;
Because numbers and values are pointers.
int numbers[5] = {1, 2, 3};
int values[5] = {0, 0, 0, 0, 0};
for(int i = 0;i < 5; i ++){
values[i] = numbers[i];
}
std::array is a good idea, but this is also possible:
struct arr { int values[5]; };
struct arr a{{1, 2, 3}};
struct arr b{{}};
a = b;
Otherwise, use std::memcpy or std::copy.
I think the reason for non-assignability is that C wants to make sure that any pointers to any element in the array would pretty much always remain valid.
Think about vectors that allow dynamic resizing: the older pointers become invalid (horribly) after resizing happens automatically.
PS. With the design philosophy for vectors, the following block works well.
vector<int> v = {1, 5, 16, 8};
vector<int> v_2 = {7, 5, 16, 8};
v_2 = v;

Can i push an array of int to a C++ vector?

Is there any problem with my code ?
std::vector<int[2]> weights;
int weight[2] = {1,2};
weights.push_back(weight);
It can't be compiled, please help to explain why:
no matching function for call to ‘std::vector<int [2], std::allocator<int [2]> >::push_back(int*&)’
The reason arrays cannot be used in STL containers is because it requires the type to be copy constructible and assignable (also move constructible in c++11). For example, you cannot do the following with arrays:
int a[10];
int b[10];
a = b; // Will not work!
Because arrays do not satisfy the requirements, they cannot be used. However, if you really need to use an array (which probably is not the case), you can add it as a member of a class like so:
struct A { int weight[2];};
std::vector<A> v;
However, it probably would be better if you used an std::vector or std::array.
You cant do that simply.
It's better you use either of these:
vector <vector<int>> (it's basically a two dimensional vector.It should work in your case)
vector< string > (string is an array of characters ,so you require a type cast later.It can be easily.).
you can declare an structure (say S) having array of int type within it i.e.
struct S{int a[num]} ,then declare vector of
vector< S>
So indirectly, you are pushing array into a vector.
Array can be added to container like this too.
int arr[] = {16,2,77,29};
std::vector<int> myvec (arr, arr + sizeof(arr) / sizeof(int) );
Hope this helps someone.
Arrays aren't copy constructable so you can't store them in containers (vector in this case). You can store a nested vector or in C++11 a std::array.
You should use std::array instead of simple array:
#include <vector>
#include <array>
std::vector<std::array<int, 2>> weights;
std::array<int, 2> weight = {1, 2};
weights.push_back(weight);
or with a constructor:
std::vector<std::array<int, 2>> weights;
weights.push_back(std::array<int, 2> ({1, 2});
One possible solution is:
std::vector<int*> weights;
int* weight = new int[2];
weight[0] =1; weight[1] =2;
weights.push_back(weight);
Just use
vector<int*> .That will definitely work.
A relevant discussion on the same topic : Pushing an array into a vector
Situation like:
int arr[3] = { 1, 2, 3 };
std::vector<int[]> v;
v.push_back(arr);
doesn't work with error "cannot initialize array in vector with .."
This, could be worked well
int * arr = new int[3] { 1, 2, 3 };
std::vector<int*> v;
v.push_back(arr);
To instantiate the vector, you need to supply a type, but int[2] is not a type, it's a declaration.