Pointers vs vectors for arrays c++ - c++

In the case I am creating an 'array' on stack in c++, is it better to initialise an empty vector with a reserved number of elements and then pass this to a function like foo() as a reference as below. Or is it better to set an array arrb of size nelems, then using a pointer p_arrb to the address of the first element increment the pointer and assign some value?
#include <iostream>
#include <vector>
void foo(std::vector<int>& arr){
int nelems = arr.capacity();
for (int i = 0; i < nelems; i++){
arr[i] = i;
}
}
int main()
{
int nelems;
std::cout << "Type a number: "; // Type a number and press enter
std::cin >> nelems;
std::vector<int> arr;
arr.reserve(nelems); // Init std lib vector
foo(arr);
int arrb[nelems];
int* p_arrb = &(arrb[0]); // pointer to arrb
for (int i = 0; i < nelems; i ++){
*(p_arrb++) = i; // populate using pointer
}
p_arrb -= nelems; // decrement pointer
return 0;
}
It seems people prefer the use of vector as it is standardised and easier to read? Apart from that, is there any performance benefit to using vector instead of a basic pointer in this case where I do not need to change the size of my vector/array at any point in the code?

What you should use depends on the exact goal you have. In general the best approach is to avoid using "raw arrays" (both dynamic and static) wherever possible.
If you need dynamic array, use std::vector. If you need static array, use std::array.

You can't use the arrb variant because the size of an array must be a compile-time constant in C++, but you are trying to use a runtime size here.
If your compiler is compiling this, then it is doing so only because it supports these so-called variable-length arrays as a non-standard extension. Other compilers will not support them or have differing degree of support or behavior. These arrays are optionally-supported in C, but even there they are probably not worth the trouble they cause.
There is no way to allocate a runtime-dependent amount of memory on the stack in C++ (except if you misuse recursive function calls to simulate it).
So yes, you should use the vector approach. But as discussed in the comments under the question, what you are doing is wrong and causes undefined behavior. You need to either reserve memory and then emplace_back/push_back elements into the vector or you need to resize the vector to the expected size and then you may index it directly. Indexing a vector outside the the range of elements already created in it causes undefined behavior.

Related

How to dynamically allocate a 2D std::array in C++ or why I should not use it?

I want to malloc an array in my code, and its size should be defined at runtime.
I tried like this:
#include <iostream>
#include <array>
int main(){
int M=4,N=3,P=5;
M=N+P;
std::array<std::array<double,M>,N> arr;
}
But MSVC told me:
a variable with non-static storage duration cannot be used as a non-type argument
I don't find the answer to this in stackoverflow.(The existing question seem not to solve my problem...)
How to dynamically allocate a 2D std::array in C++?
I know I could use std::vector to solve this. But the vector memory size needs to be organized by myself and this would be used many times in my project. And I want to use C++ type code rather than C type...Maybe there is a method to turn a 2D array in C type to std::array, but I can't find it by Google...
So I ask this question...
I mean the M and N should be got dynamically(not changed,but I can only know it in runtime...),like:
#include <iostream>
int main(){
int a=3;
int b=4;
int rowCount=a+b;
int colCout=b-a;
int** a = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
{
a[i] = new int[colCount];
}
}
I know where is my mistake. I fell into a logical question... If I don't use push_back,the vector works well. If I use it, the array doesn't work, too.
I think the capcity of vector is bigger than its size, I want to avoid this. But another question: How to limit the capacity of std::vector to the number of element show I should use my allocator or std::vector::shrink_to_fit() to avoid it...(There is no guarantee in C++17 if you use reserve(n))
The dynamically allocated array container in C++ is std::vector. std::array is for specifically compile-time fixed-length arrays.
https://cppreference.com is your friend!
But the vector memory size needs to be organized by myself
Not quite sure what you mean with that, but you specify the size of your std::vector using the constructor.
std::vector<std::vector<int>> arr(N);
If you need some special allocator (not just new/malloc), then you can also specify a custom allocator.
Your whole program that you propose is not good C++. A C++ solution would look like:
#include <vector>
int main() {
int a = 3;
int b = 4;
unsigned int rowCount = a + b;
unsigned int colCount = b - a;
std::vector<std::vector<int>> matrix(rowCount);
for (auto& row : matrix) {
row.resize(colCount);
}
}
std::array, like an actual array in C++, requires a constant size. It's what gives it any advantage at all over std::vector.
For a technical explanation as to how that requirement is implemented, remember that template parameters are required to be compile-time constants (since it changes how the code is generated, again at compile-time).
Anyway, you want to use std::vector here. If you know the size you want, give it as a constructor parameter.

How can I make my dynamic array or vector operate at a similar speed to a standard array? C++

I'm still quite inexperienced in C++ and i'm trying to write sum code to add numbers precisely. This is a dll plugin for some finite difference software and the code is called several million times during a run. I want to write a function where any number of arguments can be passed in and the sum will be returned. My code looks like:
#include <cstdarg>
double SumFunction(int numArgs, ...){ // this allows me to pass any number
// of arguments to my function.
va_list args;
va_start(args,numArgs); //necessary prerequisites for using cstdarg
double myarray[10];
for (int i = 0; i < numArgs; i++) {
myarray[i] = va_arg(args,double);
} // I imagine this is sloppy code; however i cannot create
// myarray{numArgs] because numArgs is not a const int.
sum(myarray); // The actual method of addition is not relevant here, but
//for more complicated methods, I need to put the summation
// terms in a list.
vector<double> vec(numArgs); // instead, place all values in a vector
for (int i = 0; i < numArgs; i++) {
vec.at(i) = va_arg(args,double);
}
sum(vec); //This would be passed by reference, of course. The function sum
// doesn't actually exist, it would all be contained within the
// current function. This is method is twice as slow as placing
//all the values in the static array.
double *vec;
vec = new double[numArgs];
for (int i = 0; i < (numArgs); i++) {
vec[i] = va_arg(args,double);
}
sum(vec); // Again half of the speed of using a standard array and
// increasing in magnitude for every extra dynamic array!
delete[] vec;
va_end(args);
}
So the problem I have is that using an oversized static array is sloppy programming, but using either a vector or a dynamic array slows the program down considerably. So I really don't know what to do. Can anyone help, please?
One way to speed the code up (at the cost of making it more complicated) is to reuse a dynamic array or vector between calls, then you will avoid incurring the overhead of memory allocation and deallocation each time you call the function.
For example declare these variables outside your function either as global variables or as member variables inside some class. I'll just make them globals for ease of explanation:
double* sumArray = NULL;
int sumArraySize = 0;
In your SumFunction, check if the array exists and if not allocate it, and resize if necessary:
double SumFunction(int numArgs, ...){ // this allows me to pass any number
// of arguments to my function.
va_list args;
va_start(args,numArgs); //necessary prerequisites for using cstdarg
// if the array has already been allocated, check if it is large enough and delete if not:
if((sumArray != NULL) && (numArgs > sumArraySize))
{
delete[] sumArray;
sumArray = NULL;
}
// allocate the array, but only if necessary:
if(sumArray == NULL)
{
sumArray = new double[numArgs];
sumArraySize = numArgs;
}
double *vec = sumArray; // set to your array, reusable between calls
for (int i = 0; i < (numArgs); i++) {
vec[i] = va_arg(args,double);
}
sum(vec, numArgs); // you will need to pass the array size
va_end(args);
// note no array deallocation
}
The catch is that you need to remember to deallocate the array at some point by calling a function similar to this (like I said, you pay for speed with extra complexity):
void freeSumArray()
{
if(sumArray != NULL)
{
delete[] sumArray;
sumArray = NULL;
sumArraySize = 0;
}
}
You can take a similar (and simpler/cleaner) approach with a vector, allocate it the first time if it doesn't already exist, or call resize() on it with numArgs if it does.
When using a std::vector the optimizer must consider that relocation is possible and this introduces an extra indirection.
In other words the code for
v[index] += value;
where v is for example a std::vector<int> is expanded to
int *p = v._begin + index;
*p += value;
i.e. from vector you need first to get the field _begin (that contains where the content starts in memory), then apply the index, and then dereference to get the value and mutate it.
If the code performing the computation on the elements of the vector in a loop calls any unknown non-inlined code, the optimizer is forced to assume that unknown code may mutate the _begin field of the vector and this will require doing the two-steps indirection for each element.
(NOTE: that the vector is passed with a cost std::vector<T>& reference is totally irrelevant: a const reference doesn't mean that the vector is const but simply puts a limitation on what operations are permitted using that reference; external code could have a non-const reference to access the vector and constness can also be legally casted away... constness of references is basically ignored by the optimizer).
One way to remove this extra lookup (if you know that the vector is not being resized during the computation) is to cache this address in a local and use that instead of the vector operator [] to access the element:
int *p = &v[0];
for (int i=0,n=v.size(); i<n; i++) {
/// use p[i] instead of v[i]
}
This will generate code that is almost as efficient as a static array because, given that the address of p is not published, nothing in the body of the loop can change it and the value p can be assumed constant (something that cannot be done for v._begin as the optimizer cannot know if someone else knows the address of _begin).
I'm saying "almost" because a static array only requires indexing, while using a dynamically allocated area requires "base + indexing" access; most CPUs however provide this kind of memory access at no extra cost. Moreover if you're processing elements in sequence the indexing addressing becomes just a sequential memory access but only if you can assume the start address constant (i.e. not in the case of std::vector<T>::operator[]).
Assuming that the "max storage ever needed" is in the order of 10-50, I'd say using a local array is perfectly fine.
Using vector<T> will use 3 * sizeof(*T) (at least) to track the contents of the vector. So if we compare that to an array of double arr[10];, then that's 7 elements more on the stack of equal size (or 8.5 in 32-bit build). But you also need a call to new, which takes a size argument. So that takes up AT LEAST one, more likely 2-3 elements of stackspace, and the implementation of new is quite possibly not straightforward, so further calls are needed, which take up further stack-space.
If you "don't know" the number of elements, and need to cope with quite large numbers of elements, then using a hybrid solution, where you have a small stack-based local array, and if numargs > small_size use vector, and then pass vec.data() to the function sum.

Return 2d array from C++

Inside a function, I make a 2d array that fills itself from a text file and needs to get returned to main. The array stays a constant size through the whole program.
I know this is something that gets asked a lot, but I always seem to get one of two answers:
Use std::vector or std::array or some other STD function. I don't really understand how these work, is there any site actually explaining them and how they act compared to normal arrays? Are there any special #includes that I need?
Or
Use a pointer to the array, and return the pointer. First, on some of the answers to this it apparently doesn't work because of local arrays. How do I tell when it does and doesn't work? How do I use this array back in the main function?
I'm having more trouble with the concept of pointers and std::things than with the actual code, so if there's a website you know explains it particularly well, feel free to just put that.
Not necessarily the best solution, but the easiest way to get it working with vectors. The advantages are that you don't need to delete memory (happens automatically) and the array is bounds-checked in debug mode on most compilers.
#include <vector>
#include <iostream>
using array2D = std::vector< std::vector< int > >;
array2D MyFunc(int x_size, int y_size)
{
array2D array(y_size, vector< int >(x_size));
int i = 0;
for (int y = 0; y < array.size(); y++)
{
for (int x = 0; x < array[y].size(); x++)
{
// note the order of the index
array[y][x] = i++;
}
}
return array;
}
int main()
{
array2D bob = MyFunc(10, 5);
for (int y = 0; y < bob.size(); y++)
{
for (int x = 0; x < bob[y].size(); x++)
{
cout << bob[y][x] << "\n";
}
}
}
Live example:
http://ideone.com/K4ilfX
Sounds like you are new to C++. If this is indeed the case, I would suggest using arrays for now because you probably won't be using any of the stuff that STL containers give you. Now, let's talk about pointers.
You are correct that if you declare a local array in your function, the main function won't have access to it. However, this is not the case if you dynamically allocate the array using the new keyword. When you use new to allocate your array, you essentially tell the compiler to reserve a chunk of memory for your program. You can then access it using a pointer, which is really just the address of that chunk of memory you reserved. Therefore, instead of passing the entire array to the main function, all you need to do is pass a pointer (address) to that array.
Here are some relevant explanations. I will add to them as I find more:
Dynamic Memory
The easiest way to create a 2d array is as follows:
char (*array)[10];
array = new array[5][10];
Two dimensional arrays can be tricky to declare. The parenthesis above in the variable declaration are important to tell the compiler array is a pointer to an array of 10 characters.
It is really essential to understand pointers with C and C++ unless using the std:: collections. Even then, pointers are widely prevalent, and incorrect use can be devastating to a program.

Can I determine the size/length of an array in C++ without having to hardcode it?

I am basically looking for some sort of "dynamic" way of passing the size/length of an array to a function.
I have tried:
void printArray(int arrayName[])
{
for(int i = 0 ; i < sizeof(arrayName); ++i)
{
cout << arrayName[i] << ' ';
}
}
But I realized it only considers its bytesize and not how many elements are on the array.
And also:
void printArray(int *arrayName)
{
while (*arrayName)
{
cout << *arrayName << ' ';
*arrayName++;
}
}
This has at least printed me everything but more than what I expected, so it doesn't actually work how I want it to.
I reckon it is because I don't exactly tell it how big I need it to be so it plays it "safe" and throws me some big size and eventually starts printing me very odd integers after my last element in the array.
So I finally got this work around, yet I believe there is something better out there!:
void printArray(int *arrayName)
{
while (*arrayName)
{
if (*arrayName == -858993460)
{
break;
}
cout << *arrayName << ' ';
*arrayName++;
}
cout << '\n';
}
After running the program a few times I realized the value after the last element of the array that I have input is always: -858993460, so I made it break the while loop once this value is encountered.
include <iostream>
include <conio.h>
using namespace std;
// functions prototypes
void printArray (int arrayName[], int lengthArray);
// global variables
//main
int main ()
{
int firstArray[] = {5, 10, 15};
int secondArray[] = {2, 4, 6, 8, 10};
printArray (firstArray,3);
printArray (secondArray,5);
// end of program
_getch();
return 0;
}
// functions definitions
void printArray(int arrayName[], int lengthArray)
{
for (int i=0; i<lengthArray; i++)
{
cout << arrayName[i] << " ";
}
cout << "\n";
}
Thank you very much.
TL;DR answer: use std::vector.
But I realized it [sizeof()] only considers its bytesize and not how many elements are on the array.
That wouldn't be a problem in itself: you could still get the size of the array using sizeof(array) / sizeof(array[0]), but the problem is that when passed to a function, arrays decay into a pointer to their first element, so all you can get is sizeof(T *) (T being the type of an element in the array).
About *arrayName++:
This has at least printed me everything but more than what I expected
I don't even understand what inspired you to calculate the size of the array in this way. All that this code does is incrementing the first object in the array until it's zero.
After running the program a few times I realized the value after the last element of the array that I have input is always: -858993460
That's a terrible assumption and it also relies on undefined behavior. You can't really be sure what's in the memory after the first element of your array, you should not even be accessing it.
Basically, in C++, if you want to know the size of a raw array from within a function, then you have to keep track of it manually (e. g. adding an extra size_t size argument), because of the way arrays are passed to functions (remember, they "decay into" a pointer). If you want something more flexible, consider using std::vector<int> (or whatever type of objects you want to store) from the C++ standard library -- it has a size() method, which does exactly what you want.
1st try
When arrays are passed into functions they decay to pointers. Normally, using sizeof on an array would give you its size in bytes which you could then divide by the size in bytes of each element and get the number of elements. But now, since you have a pointer instead of an array, calling sizeof just gives you the size of the pointer (usually 4 or 8 bytes), not the array itself and that's why this fails.
2nd try
The while loop in this example assumes that your array ends with a zero and that's very bad (unless you really did use a zero as a terminator like null-terminated strings for example do). If your array doesn't end with a zero you might be accessing memory that isn't yours and therefore invoking undefined behavior. Another thing that could happen is that your array has a zero element in the middle which would then only print the first few elements.
3rd try
This special value you found lurking at the end of your array can change any time. This value just happened to be there at this point and it might be different another time so hardcoding it like this is very dangerous because again, you could end up accessing memory that isn't yours.
Your final code
This code is correct and passing the length of the array along with the array itself is something commonly done (especially in APIs written in C). This code shouldn't cause any problems as long as you don't pass a length that's actually bigger than the real length of the array and this can happen sometimes so it is also error prone.
Another solution
Another solution would be to use std::vector, a container which along with keeping track of its size, also allows you to add as many elements as you want, i.e. the size doesn't need to be known at runtime. So you could do something like this:
#include <iostream>
#include <vector>
#include <cstddef>
void print_vec(const std::vector<int>& v)
{
std::size_t len = v.size();
for (std::size_t i = 0; i < len; ++i)
{
std::cout << v[i] << std::endl;
}
}
int main()
{
std::vector<int> elements;
elements.push_back(5);
elements.push_back(4);
elements.push_back(3);
elements.push_back(2);
elements.push_back(1);
print_vec(elements);
return 0;
}
Useful links worth checking out
Undefined behavior: Undefined, unspecified and implementation-defined behavior
Array decay: What is array decaying?
std::vector: http://en.cppreference.com/w/cpp/container/vector
As all the other answers say, you should use std::vector or, as you already did, pass the number of elements of the array to the printing function.
Another way to do is is by putting a sentinel element (a value you are sure it won't be inside the array) at the end of the array. In the printing function you then cycle through the elements and when you find the sentinel you stop.
A possible solution: you can use a template to deduce the array length:
template <typename T, int N>
int array_length(T (&array)[N]) {
return N;
}
Note that you have to do this before the array decays to a pointer, but you can use the technique directly or in a wrapper.
For example, if you don't mind rolling your own array wrapper:
template <typename T>
struct array {
T *a_;
int n_;
template <int N> array(T (&a)[N]) : a_(a), n_(N) {}
};
You can do this:
void printArray(array<int> a)
{
for (int i = 0 ; i < a.n_; ++i)
cout << a.a_[i] << ' ';
}
and call it like
int firstArray[] = {5, 10, 15};
int secondArray[] = {2, 4, 6, 8, 10};
printArray (firstArray);
printArray (secondArray);
The key is that the templated constructor isn't explicit so your array can be converted to an instance, capturing the size, before decaying to a pointer.
NB. The wrapper shown isn't suitable for owning dynamically-sized arrays, only for handling statically-sized arrays conveniently. It's also missing various operators and a default constructor, for brevity. In general, prefer std::vector or std::array instead for general use.
... OP's own attempts are completely addressed elsewhere ...
Using the -858993460 value is highly unreliable and, in fact, incorrect.
You can pass a length of array in two ways: pass an additional parameter (say size_t length) to your function, or put a special value to the end of array. The first way is preferred, but the second is used, for example, for passing strings by char*.
In C/C++ it's not possible to know the size of an array at runtime. You might consider using an std::vector class if you need that, and it has other advantages as well.
When you pass the length of the array to printArray, you can use sizeof(array) / sizeof(array[0]), which is to say the size in bytes of the whole array divided by the size in bytes of a single element gives you the size in elements of the array itself.
More to the point, in C++ you may find it to your advantage to learn about std::vector and std::array and prefer these over raw arrays—unless of course you’re doing a homework assignment that requires you to learn about raw arrays. The size() member function will give you the number of elements in a vector.
In C/C++, native arrays degrade to pointers as soon as they are passed to functions. As such, the "length" parameter has to be passed as a parameter for the function.
C++ offers the std::vector collection class. Make sure when you pass it to a function, you pass it by reference or by pointer (to avoid making a copy of the array as it's passed).
#include <vector>
#include <string>
void printArray(std::vector<std::string> &arrayName)
{
size_t length = arrayName.size();
for(size_t i = 0 ; i < length; ++i)
{
cout << arrayName[i] << ' ';
}
}
int main()
{
std::vector<std::string> arrayOfNames;
arrayOfNames.push_back(std::string("Stack"));
arrayOfNames.push_back(std::string("Overflow"));
printArray(arrayOfNames);
...
}

Assign a pointer to an array

I am trying to create an array that generates random values, then assign a pointer to that array in order to use it in other functions.
Question 1: Is this the right approach?
Question 2: When I run the code below, my pointer function generates values inconsistent with what the actual array's value is. What am I doing wrong?
int size = 100;
int theray[size];
for(int i=0; i<size; i++)
{
theray[i] = (rand()%100);
}
//Output array
cout<<"The array: ";
for(int j=0; j<size; j++)
{
cout<<theray[j]<<" ";
}
cout<<endl;
int (*parray)[100] = &theray;
cout<<"The array pointer: ";
for(int k=0; k<size; k++)
{
cout<<*parray[k]<<" ";
}
Question 1: is this the right approach?
No. The right approach is to use std::vector<int> if size is not known at compile time1, and std::array<int, size> if it is2. There is no need for pointers here.
void foo(const std::vector<int>& v)
{
// do stuff with v
}
...
std::vector<int> v(size); // vector with size elements
// do something with v
// pass v to a function
foo(v);
Question 2: when I run the code below, my pointer function generates values inconsistent with what the actual array's value is. What am I doing wrong?
If you use C++ idioms you won't even encounter this problem, so I consider the question moot. However, in your case you have a problem of operator precedence: be explicit about applying de-reference * before access []:
cout<< (*parray)[k] << " ";
1 As shown in the example, you can use an std::vector as a fixed size array, where the size need not be known at runtime. Just bear in mind that it is possible to change it's size after construction.
2In your example, size is not a compile time constant so you cannot use std::array. However, if you had declared it as const int size = 100; then it would be considered a compile time constant.
Your code is a bit off in three ways. First, there is no need to use &theray. Array names already reference a memory address. You can simply assign the pointer to theray. Second, you're declaring an array of 100 pointers. Based on your description, it sounds like you just want one pointer that points to the array. Your declaration should just be int *parray instead of int *parray [100]. Finally, once you have a pointer to the array, you can access elements of the array the same way you would with the original array, only with the name of the pointer, instead of the name of the array. Try changing your last block of code (starting with the pointer declaration to this:
int *parray;
parray = theray;
cout<<"The array pointer: ";
for(int k=0; k<size; k++)
{
cout<<parray[k]<<" ";
}
Question 1
Is this the right approach?
Usually not. It depends on what you are trying to achieve.
For high level semantics you'd in most cases use std::vector<int> or, if the size is fixed and you are using C++11, std::array<int, size>. If you actually have to go down to the pointer level, you'd usually write it like this:
int *parray = theray;
cout<<"The array pointer: ";
for(int k=0; k<size; k++)
{
cout<<parray[k]<<" ";
}
This works because arrays will degrade to pointers, and the […] subscripts work on these pointers just like they work on the original arrays.
Question 2
When I run the code below, my pointer function generates values inconsistent with what the actual array's value is, what am I doing wrong?
*parray[k] gets interpreted as *(parray[k]) while you intend to use it as (*parray)[k].
Question 1: is this the right approach?
No. Use std::vector<> for arrays whose size can change dynamically (at run-time). Prefer avoiding pointers and manual memory management.
Question 2: when I run the code below, my pointer function generates values inconsistent with what the actual array's value is. What am I doing wrong?
First of all, the fact of creating pointers so you can pass the array to a function. This is not necessary. Here is how I would use classes from the C++ Standard Library to write that program (in C++11):
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
// Sample function that prints the vectors's content
void foo(std::vector<int> const& v)
{
copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, " "));
}
int main()
{
// Populate the vector...
size_t sz = 10;
std::vector<int> v(sz);
generate(begin(v), end(v), [] () { return rand() % 100; });
// Pass it to a function...
foo(v);
}