On a project I'm working on, I need some dynamic allocation due to the size of the used data not been known in advance. std::vector seems perfect for this use case. However, due to the software environnement, I can not use "modern" C++ in the headers. I would like to convert this vectors array to be used in fuction with compliant headers.
Quick example:
void func(int tab[][]/*Vector can not be used here*/){/*Do things*/}
int main(){
std::vector<int> vecTab[6/*Fixed, prior known, dimension*/];
//Adding a random number of values in each vector (equal number in each one)
//Transformation of vecTab
func(vecTabMod);
return 1;
}
There is a lot of similar questions on this site, none of them really adressing bi-dimensionnal arrays.
Bonus point: no reallocation, access through pointers
You'll need to copy the data pointers into a separate array so that the type and layout matches what the funciton expects. This can be done without heap allocation since the size of this array is fixed.
int* vecTabMod[6];
std::transform(std::begin(vecTab), std::end(vecTab), std::begin(vecTabMod),
[](auto& v) { return v.data(); });
func(vecTabMod);
std::vector is worst choice for this soultion!
Using dynamic arrays is better.
Anyway you can use this code:
#include <vector>
#include <iostream>
int func(uint32_t firstDimensionSize, uint32_t* secoundDimensionSizes, int** tab){
int sum = 0;
for(uint32_t i = 0; i < firstDimensionSize; i++){
for(uint32_t j = 0; j < secoundDimensionSizes[i]; j++){
sum += tab[i][j];
}
}
return sum;
}
int main(){
std::vector<int> vecTab[6];
vecTab[0].push_back(2);
vecTab[0].push_back(5);
vecTab[3].push_back(43);
// Calculate count of elements in non dynamically arrays
uint32_t firstDimensionSize = (sizeof(vecTab) / sizeof((vecTab)[0]));
uint32_t* secoundDimensionSizes = new uint32_t[firstDimensionSize];
int**tab = new int*[firstDimensionSize];
for(uint32_t i = 0; i < firstDimensionSize; i++){
secoundDimensionSizes[i] = vecTab[i].size();
tab[i] = &(vecTab[i][0]);
}
std::cout << func(firstDimensionSize, secoundDimensionSizes, tab) << std::endl;
delete[] secoundDimensionSizes;
delete[] tab;
system("pause");
}
Related
We know that when using a contiguous block of memory we can easily get an iterator (here &arra[0] or arra) and pass the iterators to std::sort.
for instance:
int arra[100];
for (int i = 0; i < 100; i++) {
arra[i] = rand() % 32000;
}
for (int i = 0; i < len; i++)std::cout << arra[i]<<" ";
std::sort(arra,arra+100);
Now if I have a heap allocated array, say, like arr here:
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
I don't know whether I can get an iterator for this array, so can I use std::sort for this array at all?
if not, are there any workarounds to using std::sort on such an array?
Pointers do meet criteria of RandomAccessIterator which is required by std::sort. It doesn't matter if they point to stack memory or heap memory, as long as they point to the same (contiguous) array. So you can simply use:
std::sort(arr, arr + len);
This being said, std::vector is probably a better choice for allocating an array on the heap. It will save you the headache of managing memory on your own.
Yes, you can use std::sort in the same way in both cases, std::sort does not know or care how the memory was allocated.
In the C++ Library, Iterators are basically Fancy Pointers. As such, it is standard-compliant to just increment the pointer to the end of the array to get the "end" pointer:
#include<algorithm>
#include<iostream>
int main() {
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
//Valid, Defined Behavior that works as expected
std::sort(arr, arr + len);
//alternative, to make the code easier to read:
//auto begin = arr;
//auto end = arr + len;
//std::sort(begin, end);
for(int i = 0; i < len; i++)
std::cout << arr[i] << std::endl;
}
However, some Compilers (like Visual Studio's compiler) recognize that this kind of code is inherently unsafe, because you're required to manually supply the length of the array. As a result, they will cause a (suppressible with a Compiler flag, if you need to) Compile-time error if you try to do this, and advise you use a compiler-provided utility instead:
#include<algorithm>
#include<iostream>
int main() {
int len;
len = 100;
int* arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = rand() % 32000;
}
//MSVC Specific Code!
auto begin = stdext::make_checked_array_iterator(arr, len);
auto end = arr + len;
std::sort(begin, end);
for(int i = 0; i < len; i++)
std::cout << arr[i] << std::endl;
}
For more on this particular quick of the Visual Studio compiler, see here: https://learn.microsoft.com/en-us/cpp/standard-library/checked-iterators?view=vs-2019
Can I use std::sort on heap allocated raw arrays?
Yes.
I don't know whether I can get an iterator for this array
You can.
A pointer to element is a random access iterator for arrays. In the case of an automatic array, the array name implicitly decays into a pointer that you can use as an iterator to beginning of the array. In the case of a dynamic array, the result of new[] is already a pointer i.e. an iterator to the beginning of the array. You can get the pointer to the end using pointer arithmetic just like in your example.
The only significant difference between an array variable, and a pointer to a dynamic array regarding the use of std::sort is that you cannot use std::end or std::size with a pointer like you could with an array variable. Instead, you need to separately know the size of the array. In this case you've stored the length in the variable len.
I am quite new to programming,so I really need help. I need to wrtie a function which produce 2d arrays with random values. here is my code:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
float randArray(int row, int column);
int main()
{
int r = 10, c = 8;
float fckMmd = randArray(r,c);
///printing the array:
for (int row=0; row<r; row++){
for (int column=0; column<c; column++){
cout << fckMmd[row][column] << " ";
}
cout << endl;
}
}
float randArray(int row, int column){
srand(time(NULL));
float *randArr;
randArr = new int [row][column];
for(int k=0; k<row; k++){
for(int kk=0; kk<column; kk++){
randArr[k][kk] = rand();
}
}
return randArr;
}
But I get the error mentioned above. Where is the problem? help me please
randArr is a float * but you try to allocate a 2d array in it. A 2d array is not the same thing as a pointer. Your function only returns 1 float as well. I suggest you use vectors (also so you don't leak memory). Furthermore you should only call srand ONCE, not every time, and be aware rand() returns an integer, not a floating point value.
std::vector<std::vector<float>> randArray(int row, int column)
{
std::vector<std::vector<float>> randArr(row);
for (auto& v : randArr)
{
v.resize(column);
}
for(int k=0; k<row; k++)
{
for(int kk=0; kk<column; kk++)
{
randArr[k][kk] = static_cast<float>(rand());
}
}
return randArr;
}
It's because fckMmd is only a float and not a pointer or array.
First:
float *randArr;
declares a pointer to float. You then do
randArr = new int [row][column];
which allocates memory for a 2D array of ints (incompatible types, technically you allocate memory for a pointer to arrays of type int[column]), hence the error.
You're better using a std::vector instead, or, if you want a manually-managed dynamically allocated 2D array, use float **randArr; instead, and allocate
float** randArr;
randArr = new float* [rows];
for(int i = 0; i < row; ++i)
randArr[i] = new float[col];
or
float (*randArr)[col]; // pointer to array float[col]
randArr = new float[row][col];
Other issues: most of the time, srand must be used only once in the program. It is a good idea to call it in main() and not bury it into a function, since you may end up calling the function multiple times.
Last issue: if you want speed, you're better off using a single flat array (or std::vector) and map from 2D to 1D and vice versa, since your data will be guaranteed to be contiguous and you'll have very few cache misses.
I'm using c++ and I want to use two dimensional dynamic array. I tried this:
#include<iostream.h>
using namespace std;
void main(){
int const w=2;
int size;
cout<<"enter number of vertex:\n";
cin>>size;
int a[size][w];
for(int i=0; i<size; i++)
for(int j=0; j<w; j++){
cin>>a[i][j];
}
}
but not worded.
and I tried this:
int *a = new a[size][w];
instead of
int a[size][w];
but not worked!
could you help me plz.
thanks a lot.
The correct approach here would be to encapsulate some of the standard containers, that will manage memory for you, inside a class that provides a good interface. The common approach there would be an overload of operator() taking two arguments that determine the row and column in the matrix.
That aside, what you are trying to create manually is an array of dynamic size of arrays of constant size 2. With the aid of typedef you can write that in a simple to understand manner:
const int w = 2;
typedef int array2int[w];
int size = some_dynamic_value();
array2int *p = new array2int[size];
Without the typedef, the syntax is a bit more convoluted, but doable:
int (*p)[w] = new int [size][w];
In both cases you would release memory with the same simple statement:
delete [] p;
The difference with the approaches doing double pointers (int **) is that the memory layout of the array is really that of an array of two dimensions, rather than a jump table into multiple separately allocated unidimensional arrays, providing better locality of data. The number of allocations is lower: one allocation vs. size + 1 allocations, reducing the memory fragmentation. It also reduces the potential from memory leaks (a single pointer is allocated, either you leak everything or you don't leak at all).
For a dynamic sized array you must dynamically allocate it. Instead of
int *a = new a[size][w];
Use
int** a = new int*[size];
for(int i = 0; i < size; i++)
a[i] = new int[w];
OP is saying he wants to create a 2 dimensional array where one dimension is already known and constant and the other dimension is dynamic.. Not sure if I got it right but here goes:
int main() {
const int w = 2;
int size = 10;
int* arr[w];
for (int i = 0; i < w; ++i)
arr[i] = new int[size];
//do whatever with arr..
//std::cout<<arr[0][0];
for (int i = 0; i < w; ++i)
for (int j = 0; j < size; ++j)
std::cout<<arr[i][j];
for (int i = 0; i < w; ++i)
delete[] arr[i];
return 0;
}
You can not do that in c++, please read about dynamic memory allocation
the code below should work
int* twoDimentionalArray = new [size*w]
Let's say I have a dynamic array:
int* p;
ifstream inFile("pop.txt");
int x;
while (inFile >> x)
{
// ????
}
How do I resize p so I am able to to fit x in as like an array. I don't want to use a vector or static array as I am trying to learn the language. I need to use pointers because I don't know the initial size. Any attempt is appreciated.
The simplest answer is that you should use higher level components than raw arrays and raw memory for the reading. That way the library will handle this for you. A simple way of reading a set of numbers into an application (without error handling) could be done with this simple code:
std::vector<int> data;
std::copy(std::istream_iterator<int>(inFile), std::istream_iterator<int>(),
std::back_inserter(data));
The code creates a couple of input iterators out of the stream to read int values, and uses a back_inserter iterator that will push_back onto the vector. The vector itself will manage growing the memory buffer as needed.
If you want to do this manually you can, you just need to allocate a larger chunk of memory, copy the first N elements from the old buffer, release the old buffer and continue reading until the larger buffer gets filled, at which point you follow the same procedure: allocate, copy, deallocate old, continue inserting.
You can't resize it. All you can do is allocate a new bigger array, copy everything over from the old array to the new array, then free the old array.
For instance (untested code)
int array_size = 10;
int* array = new int[array_size];
int array_in_use = 0;
int x;
while (in >> x)
{
if (array_in_use == array_size)
{
int* new_array = new int[2*array_size];
for (int i = 0; i < array_size; ++i)
new_array[i] = array[i];
delete[] array;
array = new_array;
array_size *= 2;
}
array[array_in_use++] = x;
}
It's tedious, and I'm not convinced it's a good thing for a beginner to be doing. You'd learn more useful stuff if you learned how to use vectors properly.
You could always use realloc(). It's a part of the C Standard Library, and the C Standard Library is a part of the C++ Standard Library. No need for tedious news and deletes.
#include <cstdlib>
#include <iostream>
#include <fstream>
int main(void)
{
int* array = nullptr;
unsigned int array_size = 0;
std::ifstream input("pop.txt");
for(int x; input >> x;)
{
++array_size;
int* array_failsafe = array;
array = static_cast<int*>(realloc(array, sizeof(x) * array_size));
if(array == nullptr)
{
std::cerr << "realloc() failed!" << std::endl;
free(array_failsafe);
return EXIT_FAILURE;
}
array[array_size-1] = x;
}
for(unsigned int i = 0; i < array_size; ++i)
{
std::cout << "array[" << i << "] = " << array[i] << std::endl;
}
free(array); // Don't forget!
return EXIT_SUCCESS;
}
I'm having problem with creating my 2D dynamic array in C++. I want it to have dynamic number (e.g. numR) of "rows" and fixed (e.g. 2) number of "columns".
I tried doing it like this:
const numC = 2;
int numR;
numR = 10;
double *myArray[numC];
myArray = new double[numR];
Unfortunately, it doesn't work. Is it possible to do it in such a way?
Of course I could use double **myArray and initialize it as if both dimensions are dynamic (with numC used as limiter in loop) but I would like to avoid it if possible.
Thanks in advance.
Is it possible to do it in such a way?
Yes:
double (*myArray)[numC] = new double[numR][numC];
// ...
delete[] myArray;
This may look a little unusual, but 5.3.4 ยง5 clearly states:
the type of new int[i][10] is int (*)[10]
Note that many programmers are not familiar with C declarator syntax and will not understand this code. Also, manual dynamic allocation is not exception safe. For these reaons, a vector of arrays is better:
#include <vector>
#include <array>
std::vector<std::array<double, numC> > vec(numR);
// ...
// no manual cleanup necessary
Replace std::array with std::tr1::array or boost::array, depending on your compiler.
Why not use a std::vector, and take advantage of its constructor:
std::vector<std::vector<int> > my2Darray(2, std::vector<int>(10));
my2Darray[0][0] = 2;
There needs to be a loop since you need to create an array for every column.
I think what you're after is:
double *myArray[numC];
for (int i = 0; i < numC; i++) {
myArray[i] = new double[numR];
}
// some code...
// Cleanup:
for (int i = 0; i < numC; i++) {
delete [] myArray[i];
}
This declares an array of pointers (to double) with numC elements, then creates an array of doubles with numR elements for each column in myArray. Don't forget to release the memory when you're done with it or you'll have memory leaks.
Your indexes should be row, then column.
double** myArray = new double*[numR];
for( unsigned int i = 0; i < numR; i++ ) {
myArray[i] = new double[numC];
}
Access row 2, column 5:
myArray[2][5];