C++ Create array with dynamic name - c++

I need a create array in c++ but I need array always with variables name
int Magic(string name_array,int n)
{
string Name = "Something";
Name.append(name_array);
double * Name = new double[n];
}
int main()
{
Magic("a.txt",10);
}
And I have this error:
operator' : 'identifier1' differs in levels of indirection from 'identifier2'
I know it's not a python but maybe a map help me? How I can make this?

If you want to be able to access different arrays by string names, consider using a std::map<std::string, std::vector<double>>. This maps strings to C++'s better, more dynamic answer to arrays. In this case your code would be something like:
#include <iostream>
#include <map>
#include <vector>
void AddVector(std::map<std::string, std::vector<double>> &io_map,
const std::string& i_name,
const std::size_t i_size)
{
io_map[i_name].resize(i_size);
}
int main()
{
std::map<std::string, std::vector<double>> vector_map;
AddVector(vector_map, "Vector1", 3);
AddVector(vector_map, "Vector2", 10);
std::cout << "Vector with string key Vector1 has size: " << vector_map["Vector1"].size() << std::endl;
return 0;
}
In this code I've tried to be as close to the code you've given - resizing the vectors to the size you would have created the array in your "Magic" function. However, vectors can dynamically resize, so you may not even need to create/resize them in your code depending on your use case.

Related

How to retrieve an array from a pointer in c++

I'm having problems with a program that only accepts arrays. I'm having plenty of pointers to different arrays, but using *p seems to only give me the first element of the array. I want to return all the elements of the array. I know the length of the array, if that helps.
#include <typeinfo>
#include <iostream>
int i[10];
int* k=i;
cout<<typeid(i).name()<<'\n';
cout<<typeid(*k).name()<<'\n';
results in 'int [10]' and 'int' respectively. I want some way of returning k as 'int [10]'.
Your k is a pointer to int. It points to the first element of the array. If you want a pointer to the whole array then you need to declare it as such.
#include <typeinfo>
#include <iostream>
int main() {
int i[10];
int* k=i;
int(*p)[10] = &i;
std::cout<<typeid(i).name()<<'\n';
std::cout<<typeid(*k).name()<<'\n';
std::cout<<typeid(*p).name()<<'\n';
}
Output:
A10_i
i
A10_i
However, as others have said, std::array is much less confusing to work with. It can do (almost) anything a c-array can do without its quirks.
Certainly there is a solution to your actual problem that does not require to get the array from a pointer to a single integer.
Example to show you how much more convenient C++ array/vector is then "C" style arrays with pointers :
#include <vector>
#include <iostream>
// with std::vector you can return arrays
// without having to think about pointers and/or new
// and your called cannot forget to call delete
std::vector<int> make_array()
{
std::vector<int> values{ 1,2,3,4,5,6 };
return values;
}
// pass by reference if you want to modify values in a function
void add_value(std::vector<int>& values, int value)
{
values.push_back(value);
}
// pass by const refence if you only need to use the values
// and the array content should not be modified.
void print(const std::vector<int>& values)
{
// use range based for loops if you can they will not go out of bounds.
for (const int value : values)
{
std::cout << value << " ";
}
}
int main()
{
auto values = make_array();
add_value(values, 1);
print(values);
std::cout << "\n";
std::cout << values.size(); // and a vector keeps track of its own size.
return 0;
}

How to make a class with 'dynamic' data types?

In the C++ standard library, there is std::vector, and you can specify the type you want to put into a vector while declaring it.
I want to create a class which would contain a vector of either strings, or ints, or whatever I would ever need. Is it possible to do this in an easy way, or would I have to write thousands of lines in C and assembly?
If you put the data type in the declaration, you can instantiate different kinds of vectors: vector<int> myint_v; vector<string> mystring_v; etc.... but I think your asking about how to make a Generic class and GeeksForGeeks has a really good article on this.
#include <iostream>
using namespace std;
template <typename T>
class Array {
private:
T* ptr;
int size;
public:
Array(T arr[], int s);
void print();
};
template <typename T>
Array<T>::Array(T arr[], int s)
{
ptr = new T[s];
size = s;
for (int i = 0; i < size; i++)
ptr[i] = arr[i];
}
template <typename T>
void Array<T>::print()
{
for (int i = 0; i < size; i++)
cout << " " << *(ptr + i);
cout << endl;
}
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
Array<int> a(arr, 5);
a.print();
return 0;
}
That's just an example of using a template to declare a methods in a class. Hopefully that helps. Let me know.
C++ has variant and any. Variant supports a fixed list of alternative types; any supports any type of object that can be copied.
Now, any is really tricky to use right; in order to get back your data, you have to know what type of data (exactly) is in the any. And often variant is all you need.
If your goal is something akin to a json structure, well there are plenty of implementations of that.
Yes you can do via some sort of manipulation. Easiest method so far i have would be using std::pair<type1,type2> method. I will initiliaze with string and double which would be able to hold most of the things you need. String can hold single character to whole text and double pretty much same thing for the number.
Easiest way is,
vector<pair<type1,type2>> vector_name;
Then push each value via make_pair method
vector_name.push_back(make_pair(type1 Value, type2 Value));
When accessing it .first is for type1 and .second would be for type2. You can see more in the code below
#include <iostream>
#include <vector>
#include <utility>
#include <string>
using namespace std;
int main(){
vector<pair<string, double>> mypair;
mypair.push_back(make_pair("HelloWorld!", 8.2021));
mypair.push_back(make_pair("!", 8));
for(auto &&i:mypair){
cout << i.first << " " << i.second << "\n";
}
return 0;
}
I want to add a major difference. std::variant is a compile time feature where std::any is runtime.
Generally, what you want is std::any. Variant is a type safe union which somehow breaks what the original union was designed for (to overlook types at runtime as well).
The benefit of std::any is that your don't have to change often a type which can contain a std::any instead of constantly changing the data (and, for example, to recompile the entire precompilation headers). The drawback is that you have to ensure that it contains the type you want, or you get an exception when using std::any_cast. There is added overhead as well.
The final advice is to avoid using any of the two, unless there is a good reason. There are safer ways to use multiple types (polymorphism). As said, your can also put your data inside an object like json or XML.

Copy vector of vectors into 1D array

I have following C++ object
std::vector<std::vector<SomeClass>> someClassVectors(sizeOFOuter);
where I know the size of "outer" vector, but sizes of "inner" vectors varies. I need to copy the elements of this structure into 1D array like this:
SomeClass * someClassArray;
I have a solution where I use std::copy like this
int count = 0;
for (int i = 0; i < sizeOfOuter; i++)
{
std::copy(someClassVectors[i].begin(), someClassVectors[i].end(), &someClassArray[count]);
count += someClassVectors[i].size();
}
but the class includes large matrices which means I cannot have the "vectors" structure and 1D array allocated twice at the same time.
Any ideas?
Do you previously preallocate someClassArray to a given size? I'd suggest using 1D vector for getting rid of known problems with the plain array if possible.
what about something like this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<std::vector<int>> someClassVectors {
{1,2,3},
{4,5,6},
{7,8,9}
};
std::vector<int> flat;
while (!someClassVectors.empty())
{
auto& last = someClassVectors.back();
std::move(std::rbegin(last), std::rend(last), std::back_inserter(flat));
someClassVectors.pop_back();
}
std::reverse(std::begin(flat), std::end(flat));
int * someClassArray = flat.data();
std::copy(someClassArray, someClassArray + flat.size(), std::ostream_iterator<int>(std::cout, " "));
}
The extra reverse operation doesn't have an effect on memory metrics - such an approach helps to avoid unneeded memory reallocations resulting from removing vector elements from beginning to end.
EDIT
Inspired by comments I changed copy to move semantics
Embrace Range-v3 (or whatever will be introduced in C++20) and write a solution in (almost) a single line:
auto flattenedRange = ranges::views::join(someClassVectors);
this gives you a range in flattenedRange, which you can loop over or copy somewhere else easily.
This is a possible use case:
#include <iostream>
#include <vector>
#include <range/v3/view/join.hpp>
int main()
{
std::vector<std::vector<int>> Ints2D = {
{1,2,3},
{4},
{5,6}
};
auto Ints1D = ranges::views::join(Ints2D);
// here, going from Ints1D to a C-style array is easy, and shown in the other answer already
for (auto const& Int : Ints1D) {
std::cout << Int << ' ';
}
std::cout << '\n';
// output is: 1 2 3 4 5 6
}
In case you want to get a true std::vector instead of a range, before writing it into a C-style array, you can include this other header
#include <range/v3/range/conversion.hpp>
and pipe join's output into a conversion function:
auto Ints1D = ranges::views::join(Ints2D) | ranges::to_vector;
// auto deduces std::vector<int>
In terms of standard and versions, it doesn't really require much. In this demo you can see that it compiles and runs just fine with
compiler GCC 7.3
library Range-v3 0.9.1
C++14 standard (option -std=c++14 to g++)
As regards the copies
ranges::views::join(Ints2D) is only creating a view on Ints2D, so no copy happens; if view doesn't make sense to you, you might want to give a look at Chapter 7 from Functional Programming in C++, which has a very clear explanation of ranges, with pictures and everything;¹
even assigning that output to a variable, auto Ints1D = ranges::views::join(Ints2D);, does not trigger a copy; Ints1D in this case is not a std::vector<int>, even though it behaves as one when we loop on it (behaves as a vector because it's a view on it);
converting it to a vector, e.g. via | ranges::to_vector, obviously triggers a copy, because you are no more requesting a view on a vector, but a true one;
passing the range to an algorithm which loops on its elements doesn't trigger a copy.
Here's an example code that you can try out:
// STL
#include <iostream>
#include <vector>
// Boost and Range-v3
#include <boost/range/algorithm/for_each.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/range/conversion.hpp>
struct A {
A() = default;
A(A const&) { std::cout << "copy ctor\n"; };
};
int main()
{
std::vector<std::vector<A>> Ints2D = {
{A{},A{}},
{A{},A{}}
};
using boost::range::for_each;
using ranges::to_vector;
using ranges::views::join;
std::cout << "no copy, because you're happy with the range\n";
auto Ints1Dview = join(Ints2D);
std::cout << "copy, because you want a true vector\n";
auto Ints1D = join(Ints2D) | to_vector;
std::cout << "copy, despite the refernce, because you need a true vector\n";
auto const& Ints1Dref = join(Ints2D) | to_vector;
std::cout << "no copy, because we movedd\n";
auto const& Ints1Dref_ = join(std::move(Ints2D)) | to_vector;
std::cout << "no copy\n";
for_each(join(Ints2D), [](auto const&){ std::cout << "hello\n"; });
}
¹ In an attempt to try giving a clue of what a range is, I would say that you can imagine it as a thing wrapping two iterators, one poiting to the end of the range, the other one pointing to the begin of the range, the latter being incrementable via operator++; this opearator will take care of the jumps in the correct way, for instance, after viewing the element 3 in Ints2D (which is in Ints2D[0][2]), operator++ will make the iterator jump to view the elment Ints[1][0].

Unable to initialize size of vector along with contents

The code below is just the isolated problem. I want to not only reserve the size of the vector but also initialize the contents so that if a vector element within the size range is suddenly assigned a value, it won't throw a vector subscript out of range error. I'm basically replacing a fixed-size array that is used throughout a large amount of code and I want the same functionality without having to add "item.push_back(newItem)" to throughout the file. I tried putting a for loop inside the Node constructor that just added but for some reason the .push_back() method was unrecognized.
How would I not only reserve the size, but also initialize the contents within the constructor?
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
int maxSize = 3;
struct Item{
string key;
string value;
};
struct Node{
int count;
vector<Item> items;
Node()
{
items.reserve(maxSize + 1);
}
};
int main(int argc, char *argv[])
{
Item item;
item.key = "Hi";
item.value = "there";
Node *p = new Node();
p->items[1] = item; // Error: vector subscript out of range
cout << p->items[1].key << " " << p->items[1].value << endl;
return 0;
}
Reserving only allocates underlying memory, for purposes of optimisation. If you don't know you need it, you don't. If you don't know you need it, and you wrote it, you shouldn't have done.
What you're trying to do is make the vector actually take on a size, and fill up with elements that you can immediately access via operator[].
To do so, write resize instead of reserve.
In fact, since you're doing so on a member in the constructor of its container, what you really should be doing is initialising the vector by calling its proper constructor:
struct Node
{
int count;
vector<Item> items;
Node()
: items(maxSize + 1)
{}
};
You're looking for resize instead of reserve

My code prints out the address instead of the array value?

What is wrong with my code? I want to print out the array, but when I try to do so it seems to print out an address instead.
#include <iostream>
#include <ctime>
#include <stdlib.h>
using namespace std;
int main ()
{
srand(time(NULL));
int array[9]= {0};
for (int i=0;i<=8;i++)
{
array[i]= (rand()%101);
}
cout<< array;
system ("PAUSE");
return 0;
}
You can't just cout an array. Arrays are not cout-able. Whenever you successfully cout something of type T, it means that there's a dedicated overloaded << operator designed specifically to cout values of type T. And there's no dedicated << operator for cout-ing arrays (aside from strings). For this reason the compiler chooses the closest match for the given argument type: a << operator for pointers. Since arrays are convertible to pointers, that << is applicable here.
If you want to cout the values of all elements of your array, you'll have to either cout them manually, one by one, or use some standard algorithm that can do it for you. For example
std::copy(array, array + 9, std::ostream_iterator<int>(std::cout, " "));
You'll need to do a loop to output each array element on its own.
The problem is that C++ doesn't always know the size of the array, so it can't default to outputting the whole thing as you would expect.
You need to iterate over the array and print each element like how you assigned value at each index. Since array decays to a pointer to the first element in the sequence, you are getting the address.
std::cout doesn't have an overload for int array[9], so this decays to a pointer (int*) and this is what you'll see displayed (something like 0x7fffe47142d0).
To print the ints in the array individually, you will need to use a loop construct (like the for- loop you are using for populating the array) and send each of the ints to std::cout in turn, perhaps with some whitespace to format them.
Once you get the hang of C++ and its standard library, you may want to investigate how to do this with std::copy(), but I suspect this is a bit advanced for your homework.
C++ decays array type to a pointer type when the value is passed as argument to a function. C++11 has std::array (and TR1 specifies std::tr1::array) which retains the size of the array. Here is your example modified to use std::array:
#include <array>
#include <iostream>
#include <ctime>
#include <stdlib.h>
template<typename T, std::size_t N>
std::ostream& operator<< (std::ostream& ostm, const std::array<T, N>& a)
{
for (auto const& x : a)
ostm << x << ' ';
return ostm;
}
int main ()
{
srand(time(NULL));
std::array<int, 9> array;
for (auto& x : array)
x = rand() % 101;
std::cout<< array << std::endl;
}