I'm trying to make a generic function which will dynamically allocate 2D structure. Number of elements in every row doesn't have to be same for all rows. Structure is represented as a container type, whose elements are again of a container type (for example a set of lists). The type of elements of that inner container can also be arbitrary. Containers only support the begin, end, and size functions. Iterator operations must be supported for all iterator types. The function should first dynamically allocate the space for storing the 2D structure by the continuous allocation procedure, and then rewrite the elements of the structure it has accepted into the dynamic structure. The function returns a double pointer through which the elements of this structure can be accessed.
#include <iostream>
#include <set>
#include <list>
#include <vector>
template < typename tip >
auto Make2DStructure(tip mat) {
using tip_objekta = typename std::decay < decltype(mat[0][0]) > ::type;
tip_objekta ** dynamic_mat = nullptr;
int rows = 0, total = 0;
for (auto i: mat) {
rows++;
for (auto j: i)
total++;
}
int columns[rows];
int k = 0;
for (auto i: mat) {
int num_of_colums = 0;
for (auto j: i)
num_of_colums++;
columns[k] = num_of_colums;
k++;
}
try {
dynamic_mat = new tip_objekta * [rows];
dynamic_mat[0] = new tip_objekta[total];
for (int i = 1; i < rows; i++)
dynamic_mat[i] = dynamic_mat[i - 1] + columns[i];
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns[i]; j++)
dynamic_mat[i][j] = mat[i][j];
} catch (...) {
delete[] dynamic_mat[0];
delete[] dynamic_mat;
throw std::bad_alloc();
}
return dynamic_mat;
}
int main() {
std::vector<std::vector<int>>mat{
{1,2},
{3,4,5,6},
{7,8,9}
};
int columns[3]={2,4,3};
try {
int ** dynamic_mat = Make2DStructure(mat);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < columns[i]; j++)
std::cout << dynamic_mat[i][j] << " ";
std::cout << std::endl;
}
delete[] dynamic_mat[0];
delete[] dynamic_mat;
} catch (...) {
std::cout << "Problems with memory";
}
return 0;
}
How could I modify this to work without indexing inside Make2DStrucure()?
Also, if I used std::set<std::list<int>> instead of std::vector<std::vector<int>> in main function I would have deduction problems. How could I modify this to work for different outside and inside container?
Here's one way to accomplish what you want:
#include <iterator>
#include <type_traits>
template <typename tip>
auto Make2DStructure(tip&& mat) {
// create an alias for the value type:
using value_type = std::decay_t<decltype(*std::begin(*std::begin(mat)))>;
// allocate memory for the return value, the pointer-pointer:
value_type** rv = new value_type*[mat.size()]; // C++17: std::size(mat)
// Calculate the number of values we need to allocate space for:
size_t values = 0;
for(auto& inner: mat) values += inner.size(); // C++17: std::size(inner)
// allocate the space for the values:
value_type* data = new value_type[values];
// loop over the outer and inner container and keep the index running:
size_t idx = 0;
for(auto& inner : mat) {
// assign the outer pointer into the flat data block:
rv[idx++] = data;
for(auto& val : inner) {
// assign values in the data block:
*data++ = val;
}
}
return rv;
}
With the use of std::size where indicated, this would work with plain arrays too, not only the container classes.
Related
I have a problem with function that takes: array, size of that array and function (or lambda), and then sort given array depending of what function given in argument returns. For example:
int a1[] = {1,2,3,4,5,6};
part(a1,6,isEven); // where isEven is simple function for checking if element is even
Should return:
[ 2 4 6 1 5 3 ]
I already write this like that, where im retur new, sorted array:
template <typename T, typename FUN>
size_t part(T* arr, size_t size, FUN f) {
T new_arr[size] = {};
int first = 0;
int last = size - 1;
int index = 0;
bool changed = false;
for(int i = 0; i < size; i++){
if(f(arr[i])){
new_arr[first] = arr[i];
first++;
} else {
if(!changed){index = i;}
new_arr[last] = arr[i];
last--;
}
}
for(int j = 0; j < size; j++){
std::cout << new_arr[j] << " ";
}
return new_arr;
}
But I have to do this without using any other array. And it has to be done in one loop.
You were nearly there.
You must not use an additional array. But in line T new_arr[size] = {}; you try to do this. And, this will not work, because this is a VLA (Variable Lenth Array). VLAs are not part of the C++ language. Some compilers accept VLAs as extension, but, if you tell them to compile C++, then also those will reject it. In C++ the size of an array must be known at compile time. It must be a constant.
So, since you anyway work with pointers, you can also use new to allocate temporary memory. Then simply replace the above line with T* new_arr = new T[size]{};
And, you must not forget to delete the allocated memory. Or, you could copy the new data at the end of the function to the original and then delete the temporaray memory there.
So, in my opinion not the best approach. Anyway, the C++ standard library has the functions partition and stable_partition.
Anyway. Please see below:
#include <iostream>
#include <algorithm>
template <typename T, typename FUN>
T* part(T* arr, size_t size, FUN f) {
T* new_arr = new T[size]{};
int first = 0;
int last = size - 1;
int index = 0;
bool changed = false;
for (int i = 0; i < size; i++) {
if (f(arr[i])) {
new_arr[first] = arr[i];
first++;
}
else {
if (!changed) { index = i; }
new_arr[last] = arr[i];
last--;
}
}
return new_arr;
}
int main() {
int data[]{ 1,2,3,4,5,6 };
int *p = part(data, (sizeof(data) / sizeof(data[0])), [](const int i) {return i % 2 == 0; });
for (int i = 0; i < (sizeof(data) / sizeof(data[0])); ++i)
std::cout << p[i] << ' ';
delete[]p;
}
I am learning C++ with experiencein mostly Python, R and SQL.
The way arrays (and vectors which differes somehow from 1d-arrays? and matrices which are 2d-arrays?) work in C++ seems quite different as I cannot specify the size of dimension of the array with an argument from the function.
A toy-example of my goal is some thing like this:
Have a function my_2d_array which takes two arguments M and N and returns a matrix or 2d-array of dimension (MxN) with elements indicating the position of that element. E.g. calling my_2d_array(4,3) would return:
[[00, 01, 02],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]]
The main function should execute my_2d_array and be able to potentially perform calculations with the result or modify it.
This is my attempt (with errors):
int my_2d_array(int N, int M) {
int A[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i][j] = element;
}
}
return A;
}
void main() {
int N, M;
N = 4;
M = 3;
int A[N][M] = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i][j] << " ";
}
std::cout << "\n";
}
}
One (1) dimensional attempt of #JustLearning's suggestion:
int my_array(int N) {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
int N = 4;
int A[N] = my_array(N);
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << A[i] << " ";
}
}
You can use a 2d vector like this
vector<vector int> A;
It works the same way as a 2d array
Welcome to C++! Your function my_2d_array has a couple of issues:
the return type is int, however you are attempting to return an array of ints.
the identifier of an array in C++ is actually a pointer to the first element of that array. Therefore, when you return A, you must be aware of how it should be passed to a new variable in the main part of the code. In particular, your code is passing a reference to a temporary variable A, which is not permitted or safe.
In addition, in C++, unless you know what you're doing, main should always return an int:
int main() { ... }
What is not clear from your question is whether you are attempting to implement your own "array" class, or simply want to use arrays already established in the standard. For the latter, std::array is a good place to start. The advantage is that you can return std::arrays from functions like you return ints or doubles.
std::arrays are good if you plan to work with arrays of fixed size, as the size becomes part of the type: std::array<int, 3> my_array;. Then you can fill it in manually or with member functions of the class (see dox linked above).
If for some reason you prefer to work with arrays of dynamical size (sizes that will change during running your program), std::vector is the way to go.
Finally, if you are actually learning C++ by attempting to implement a container MyArray, you should specify that in your question and be a bit more specific in what help you need.
Here's a working example in 1d:
#include <iostream>
#include <array>
template <int N>
std::array<int, N> my_array() {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
const int N = 4;
std::array<int, N> arr = my_array<N>();
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << arr[i] << " ";
}
}
Since the size of a std::array is included it its type, you need to create a function template, which is basically a function that works for different types. (In C++, std::array<int, 3> and std::array<int, 4> are considered different types.)
In order to use this in main, the index is promoted to a const int, as plain ints can vary during run time, and therefore are not suitable for defining types. (In C++ jargon, look up constant expressions).
Finally, note that both the return type and the type of the variable that receives the value returned by the function must be std::array, not int as you tried in your 1d code.
Following your comment, I can see why you are confused in your attempts to use a matrix in code.
There are many types of containers in C++. Many of them you can find in the standard library (std::vector, std::list, std::set, ...), others you can create yourself or use other libraries. Plain arrays (like int a[5]) are a somewhat unique case because they come from C and are part of the language itself.
A plain array lives on the stack (not very important but you might want to read up on stack vs heap allocations), and refers to a contiguous region of memory.
If you declare some array a like int a[5], you get a region of 5 integers one after the other, and you can point to the first one by just writing a. You can access each of them using a[i] or, equivalently, *(a+i).
If you declare a like int a[5][3], you now get a region of 15 integers, but you can access them slightly differently, like a[i][j], which is equivalent to *(a+i*3+j).
The important thing to you here is that the sizes (5 and 3) must be compile-time constants, and you cannot change them at runtime.
The same is true for std::array: you could declare a like std::array<std::array<int, 3, 5> a and get a similar region of 15 integers, that you can access the same way, but with some convenience (for example you can return that type, whereas you cannot return a plain array type, only a pointer, losing the size information in the process).
My advice is not to think of these arrays as having dimensionality, but as simple containers that give you some memory to work with however you choose. You can very well declare a like std::array<int, 15> a and access elements in a 2D way by indexing like this: a[i*3+j]. Memory-wise, it's the same.
Now, if you want the ability to set the sizes at runtime, you can use std::vector in a similar way. Either you declare a like std::vector<std::vector<int>> a(5, std::vector<int>(3)) and deal with the nested vectors (that initialization creates 5 std::vector<int> of size 3 each), or you declare a as a single vector like std::vector<int> a(15) and index it like a[i*3+j]. You can even make your own class that wraps a vector and helps with the indexing.
Either way, it's rare in C++ to need a plain array, and you should generally use some kind of container, with std::vector being a good choice for a lot of things.
Here is an example of how your code would look like using vectors:
#include <vector>
#include <string>
#include <iostream>
std::vector<std::string> my_2d_array(int N, int M) {
std::vector<std::string> A(N*M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i*M+j] = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
std::vector<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i*M+j] << " ";
}
std::cout << "\n";
}
}
And here is a very crude example of a Matrix class used to wrap the vectors:
#include <vector>
#include <string>
#include <iostream>
template<typename T>
class Matrix {
public:
Matrix(int rowCount, int columnCount) : v(rowCount*columnCount), columnCount(columnCount) {}
T& operator()(int row, int column) {
return v[row*columnCount + column];
}
private:
std::vector<T> v;
int columnCount;
};
Matrix<std::string> my_2d_array(int N, int M) {
Matrix<std::string> A(N, M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A(i, j) = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
Matrix<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A(i, j) << " ";
}
std::cout << "\n";
}
}
I wanted to create a matrix with vectors. In the below code, I created a vector with each entry containing a pointer to another vector(myvector) that acts as columns. I push random values to the myvector (i.e. columns). But when I try to access the values of arrays, it pops an compile error saying "error: no match for 'operator*' (operand type is 'std::vector<int>') at the cout statement. I wonder how do I access the values. I'm pretty sure this is a naive question.
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
std::vector<vector<int>*> main;
for(int j=0; j<3; j++){
vector<int> *myvector = new vector<int>;
main.push_back(myvector);
}
main[0]->push_back(1);
main[0]->push_back(4);
main[1]->push_back(6);
main[1]->push_back(7);
main[1]->push_back(8);
main[2]->push_back(3);
for(int j=0; j<3; j++){
for(uint32_t i=0; i<main[j]->size(); i++)
std::cout<<main[j][i]<<" ";
cout<<"\n";
}
return 0;
}
You could just have done
vector<vector<int>> main;
each index of vector main represents another vector
so to push a number in the first column you can do
main[0].push_back = (_number_)
To access a number in first row in first column we can do main[0][0]
This example shows both the syntax you where looking for, and also an example of how you should use std::vector without new/delete.
#include <iostream>
#include <vector>
#include <memory>
// using namespace std; <== teach yourself NOT to do this.
// https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice
void access_pointers_in_2d_vector()
{
std::vector<std::vector<int>*> values; // don't call your variables main!
for (int j = 0; j < 3; j++)
{
std::vector<int>* myvector = new std::vector<int>;
values.push_back(myvector);
}
values[0]->push_back(1);
values[0]->push_back(4);
values[1]->push_back(6);
values[1]->push_back(7);
values[1]->push_back(8);
values[2]->push_back(3);
for (int j = 0; j < 3; j++)
{
for (uint32_t i = 0; i < values[j]->size(); i++)
{
//==================================================================
// this is the syntax you're looking for
// first dereference the pointer then use operator[]
std::cout << (*values[j])[i] << " ";
//==================================================================
}
std::cout << "\n";
}
// don't forget to cleanup your memory!
// if you typed new somewhere then there should
// ALWAYS be a matching delete in your code too!
for (int j = 0; j < 3; j++)
{
delete values[j]; // <<==== !!!!!!!
}
}
// for dynamic memory managment new/delete aren't recommended anymore.
// use std::unique_pointer (or if your design really requires it std::shared_ptr)
void using_unique_pointer()
{
// If you really need pointers, use std::unique_ptr
// it will prevent you from introducing memory leaks
const std::uint32_t size = 3ul;
std::vector<std::unique_ptr<std::vector<int>>> values(size);
for (auto& p : values)
{
p = std::make_unique<std::vector<int>>();
}
values[0]->push_back(1);
values[0]->push_back(4);
values[1]->push_back(6);
values[1]->push_back(7);
values[1]->push_back(8);
values[2]->push_back(3);
// output loop is same as for normal pointers.
// no need to call delete, std::unique_ptr will do that for you
}
void without_pointers()
{
// However your whole code in idiomatic c++ should look like this.
// https://en.cppreference.com/w/cpp/container/vector/vector constructor (10)
// https://en.cppreference.com/w/cpp/language/range-for these loops avoid bugs related to
// letting indices go out of bounds.
std::cout << "\nusing (nested) initializer list and range based for loops : \n";
std::vector<std::vector<int>> rows{ {1,4}, {6,7,8}, {3} };
for (const auto& row : rows)
{
for (const auto& value : row)
{
std::cout << value << " ";
}
std::cout << "\n";
}
}
int main()
{
access_pointers_in_2d_vector();
using_unique_pointer();
without_pointers();
return 0;
}
I'm working on graph implementations in C++ and came across an implementation for an adjacency matrix that mostly made sense to me. The implementation uses an "init" function to initialize the matrix:
void init(int n) {
numVertex = 0;
numEdge = 0;
mark = new int[n]; //initialize mark array
for (int i = 0; i < numVertex; i++) {
mark[i] = 0;
}
matrix = (int**) new int*[numVertex]; //make matrix
for (int i = 0; i < numVertex; i++) {
matrix[i] = new int[numVertex];
}
for (int i = 0; i < numVertex; i++) { //mark all matrix cells as false
for (int j = 0; j < numVertex; j++) {
matrix[i][j] = 0;
}
}
}
The line I'm confused about is:
matrix = (int**) new int*[numVertex]; //make matrix
What does the (int**) aspect do? Why would I choose to use this instead of matrix = new int**[numVertex];?
Thanks so much!
(int**)value is a C-style cast operation.
Notes:
Don't use those in C++, it tends to cause or hide problems, like mismatches between right and left side of an assignment.
The code is relatively low quality, proper C++ would rather use std::vector.
The code is also not complete, so little can be said with certainty about how it functions.
Note that matrix = new int**[numVertex]; as mentioned by you would create (for this example) a 3D array, because you'd have numVertex entries of int**.
The (int**) cast does not accomplish much, if anything at all, because if matrix is of type int**, there is no need for the cast (you get back an int** already from the new).
If column dimension is fixed, you can use vector of array there.
godbolt
wandbox
#include <vector>
#include <array>
#include <iostream>
#include <iomanip>
template<typename T, int col>
using row_templ = std::array<T,col>;
template<typename T, int col, template <typename,int> typename U = row_templ>
using mat_templ = std::vector<U<T,col>>;
int main()
{
constexpr int numVertex = 30;
constexpr int numEdge = 30;
constexpr int numCol = numVertex;
int numRow = numEdge;
using row_t = row_templ<int, numCol>; // alias to the explicit class template specialization
using mat_t = mat_templ<int, numCol>;
auto make_mat = [&](){ return mat_t(numRow); }; // define a maker if lazy
mat_t my_mat(numRow);
mat_t my_mat2 = make_mat(); // or just use our maker
// Due to that default allocator uses value initialization, a.k.a T().
// At this point, all positions are value init to int(), which is zero,
// from value init of array<int, col>() by the default allocator.
// numVertex x numEdge is one solid contaguous chunk and now ready to roll.
// range for
for (row_t r : my_mat) {
for (int n : r) {
std::cout << std::setw(4) << n;
}
std::cout << '\n';
}
// classic for
for (int i = 0; i < numRow; ++i) {
for (int j = 0; j < numCol; ++j) {
std::cout << std::setw(4) << (my_mat2[i][j] = i*numRow + numCol);
}
std::cout << '\n';
}
}
I'm trying to create a program that will display bar graphs with * the maximum number of * can be 40. I have everything working but had a question with the code. Is there a better way as you can see I have to go back to the original address twice using:
p_bar_length = p_bar_length - size;
Is there a better way to do this?
#include <iostream>
using namespace std;
const int MAX_SPLATS = 40;
void bar_chart(double values[], int size)
{
double largest = values[0]; //assign first element to be the largest
//Find the largest value
for (int i = 1; i < size; i++)
{
if (largest < values[i]) // check to see if there is something larger
{
largest = values[i];
}
}
// Find the number of spalts to use
// with the precent based on the largest value
int* p_bar_length = new (nothrow) int[size];
for (int i = 0; i < size; i++)
{
*p_bar_length = (values[i] / largest) * MAX_SPLATS;
p_bar_length++; // Go to next memory address
}
// Go back to the orignal memory address
p_bar_length = p_bar_length - size;
// Pritnt the correct number of splats
for (int i = 0; i < size; i++)
{
for (int j = 0; j < *p_bar_length; j++)
{
cout << "*";
}
p_bar_length++;
cout << endl;
}
// Go back to the orignal memory address
p_bar_length = p_bar_length - size;
delete[] p_bar_length;
}
int main()
{
double values[6] = { 22, 40, 28, 26, 14, 46};
int val_size = 6;
bar_chart(values, val_size);
system("pause");
return 0;
}
Since this is C++, the best way is not to use pointers; instead, use a std::vector.
That said, you can also always treat a pointer as an array and just access p_bar_length[i] for a given position 0 <= i < length instead of incrementing the pointer.
Rather than incrementing the pointer, use the array index:
p_bar_length[i] = (values[i] / largest) * MAX_SPLATS;
or use pointer arithmetic:
*(p_bar_length + i) = (values[i] / largest) * MAX_SPLATS;
You do not need the first for loop if you use std::max_element from <algorithm>.
You do not need the second for loop if you calculate the bar length in the third for loop.
Something like this:
void bar_chart(double values[], int size)
{
//Find the largest value
double largest = *std::max_element(values, values + size);
// Print the correct number of splats
for (int i = 0; i < size; i++)
{
int p_bar_length = (values[i] / largest) * MAX_SPLATS;
cout << string(p_bar_length, '*') << endl;
}
}
That way you don't need the p_bar_length array at all. It is only a simple int.
Edit: And you could even replace the inner for loop (example modified)
Since you tagged this as C++ I would recommend using the standard library.
Your program is more C than C++, but if c is ok for you there is not much to improve.
On the other hand, using vector and algorithm you don't need to mess around with pointers. And using C++11 it removes the rough edges previously associated with templates and iterators.
A quick shot:
#include <iostream>
#include <vector>
#include <algorithm>
const int MAX_SPLATS = 40;
template <typename C>
void bar_chart(const C& values)
{
if (std::distance(values.begin(), values.end())<1)
return; // do some error handling
auto largest = *std::max_element(values.begin(), values.end());
// Find the number of splats to use with the percent based on
// the largest value
std::vector<int> bars(values.size());
std::transform(values.begin(), values.end(), bars.begin(),
[=] (double d) { return (d/largest)*MAX_SPLATS; });
// Print the correct number of splats
std::for_each(bars.begin(), bars.end(),
[](int val){ std::cout << std::string(val, '*') << std::endl; });
}
int main()
{
std::vector<double> values = { 22, 40, 28, 26, 14, 46 };
bar_chart(values);
std::cin.get();
return 0;
}
Make another copy of the pointer to use within your loop. Much less error prone.
int* p_bar_length = new (nothrow) int[size];
int* p = p_bar_length;
for (int i = 0; i < size; i++)
{
*p = (values[i] / largest) * MAX_SPLATS;
p++; // Go to next memory address
}
P.S. Why are you using nothrow? Since you're not checking the value you get back from new, an exception will be much nicer than the mess you'll have when you get back a NULL pointer.
You could treat p_bar_length as an array and just use consistent notation
int* p_bar_length = new (nothrow) int[size];
for (int i = 0; i < size; i++)
{
p_bar_length[i] = (values[i] / largest) * MAX_SPLATS;
}
How about two in one?
int* p_bar_length = new (nothrow) int[size];
for (int i = 0; i < size; i++)
{
*p_bar_length = (values[i] / largest) * MAX_SPLATS;
for (int j = 0; j < *p_bar_length; j++) cout << "*";
cout << endl;
p_bar_length++; // Go to next memory address
}
This is rather similar to the post from #mkaes, but goes one step further. Instead of using std::transform to create a vector of the proper lengths, then std::for_each to create a string the proper length from each of those, this creates a string directly from the input, and writes the strings directly from std::transform:
#include <iostream>
#include <array>
#include <algorithm>
#include <string>
#include <iterator>
const int MAX_SPLATS = 40;
template <typename C>
void bar_chart(const C& values)
{
if (std::distance(values.begin(), values.end())<1)
return; // do some error handling
auto largest = *std::max_element(values.begin(), values.end());
std::transform(values.begin(), values.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[=](double d) { return std::string((d/largest)*MAX_SPLATS, '*');} );
}
int main() {
std::array<double, 6> values = {22, 40, 28, 26, 14, 46};
bar_chart(values);
return 0;
}
Since it's using C++11 anyway, I decided to also use an std::array since it seems to fit nicely for the job at hand.