I want to use iterators with C++ arrays, but with raw pointers too.
I can do with a static vector:
#define SIZE 10
int vect[SIZE] = {0};
vect[3] = 5;
int* p = std::find(std::begin(vect), std::end(vect), 5);
bool success = p != std::end(vect);
How can be possible to do it with a raw pointer (maybe a heap allocated vector)?
Of course the compiler does not know the size of the data, so this code
int* pStart = vect;
std::find(std::begin(pStart), std::end(pStart), 5);
gives
error C2784: '_Ty *std::begin(_Ty (&)[_Size])' :
could not deduce template argument for '_Ty (&)[_Size]' from 'int *'
Is it possible to make begin() and end() aware of it?
Is it possible to make begin() and end() aware of it?
It's possible to implement std::begin for a pointer, but it is impossible to implement std::end (because as you say, the size is unknown), so it is a bit pointless.
However, you don't need either of those to use std::find:
int* p = std::find(pStart, pStart + SIZE, 5);
No it is not possible to use std::begin and std::end on a pointer. Unlike an array whose size is part of the type and therefor deducible a pointer does not hold the size of the thing it points to. In your case with a pointer you would have to use
std::find(pStart, pStart + SIZE, 5);
The way to avoid this though is to use std::vector when you are not going to know what the szie will be at compile time. It will manage the memory for you and provides begin and end member functions.
Here:
std::begin(pStart), std::end(pStart)
you're trying to take the beginning and end of a pointer. Nope!
Instead, you meant:
std::begin(vect), std::end(vect)
This is the same whether you use an array, or a std::array, or a std::vector, or a particularly large elephant — to get the bounds of a container, you need the container.
When I deal with naked arrays I rely on simple containers to make them compatible with C++'s general treatment of ranges.
For example:
#include <iostream>
#include <memory> // for std::unique_ptr
#include <algorithm> // for std::reverse
#include <numeric> // for std::iota
template<typename T>
class range_view {
public:
range_view(T* data, std::size_t size)
: m_data { data },
m_size { size } { }
const T* begin() const { return m_data; }
const T* end() const { return m_data + m_size; }
T* begin() { return m_data; }
T* end() { return m_data + m_size; }
private:
T* m_data;
std::size_t m_size;
};
int main() {
// this is your actual data
auto pdata = std::make_unique<int>(20);
// this is a handle you use to work with your data
auto data_view = range_view<int>(pdata.get(), 20);
// for example, you can fill it with numbers 0, ... , N - 1
std::iota(data_view.begin(), data_view.end(), 0);
// it is now compatible with c++'s range-based operators
std::cout << "my data...\n";
for(auto && item : data_view) std::cout << item << " ";
std::reverse(data_view.begin(), data_view.end());
std::cout << "\nreversed...\n";
for(auto && item : data_view) std::cout << item << " ";
std::cout << "\n";
}
Compile and run
$ g++ example.cpp -std=c++14
$ ./a.out
my data...
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
reversed...
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
You still have to worry about passing the correct dimension to the constructor, and it will fail miserably if the underlying pointer is deleted, but you had to worry about that anyway.
I want to use iterators with C++ arrays, but with raw pointers too.
You got it backwards. Raw pointers are iterators. They iterate over arrays.
You can just use them for all the things you would otherwise accomplish with std::begin and std::end. Most notably, you can pass them to C++ standard algorithms in <algorithm>.
A pointer itself cannot be iterated. Iterators cannot be iterated.
int* pStart = vect;
std::find(std::begin(pStart), std::end(pStart), 5);
Very loosely speaking, a pointer is just a number. What is the "begin" and "end" of a number? This piece of code makes as little sense as the following:
int i = 123;
std::find(std::begin(i), std::end(i), 5); // error
Is it possible to make begin() and end() aware of it?
A pointer may point to the beginning of some array. But that knowledge must be kept along with the pointer. You need to maintain a size or an end pointer along with a start pointer, and keep all that data together.
That's exactly what std::array and std::vector do for you.
While others answers already explains why you should revisit your design I want to state one option, that was not described earlier.
Your compiler diagnosis message almost clearly states that the compiler falls to deduce arguments and that arguments looks exactly like reference to С-style array.
Reference to C-style array doesn't decay to pointer, so you can pass reference to C-style array to std::begin and std::end in that particular case as an option:
#include <iostream>
#include <algorithm>
constexpr size_t SIZE = 10;
int main() {
int vect[SIZE] = {0};
vect[3] = 5;
int (&ref_to_vect)[SIZE] = vect; // declaring reference to C-array
// and using reference to C-array which doesn't decay to pointer opposite to passing array "by value" semantics
int* p = std::find(std::begin(ref_to_vect), std::end(ref_to_vect), 5);
bool success = p != std::end(vect);
std::cout << (success ? "Found 5" : "5 not found :(");
return 0;
}
Related
There are many design issues I have found with this, particularly with passing std::array<> to functions. Basically, when you initialize std::array, it takes in two template parameters, <class T and size_t size>. However, when you create a function that requires and std::array, we do not know the size, so we need to create template parameters for the functions also.
template <size_t params_size> auto func(std::array<int, params_size> arr);
Why couldn't std::array take in the size at the constructor instead? (i.e.):
auto array = std::array<int>(10);
Then the functions would look less aggressive and would not require template params, as such:
auto func (std::array<int> arr);
I just want to know the design choice for std::array, and why it was designed this way.
This isn't a question due to a bug, but rather a question why std::array<> was designed in such a manner.
std::array<T,N> var is intended as a better replacement for C-style arrays T var[N].
The memory space for this object is created locally, ie on the stack for local variables or inside the struct itself when defined as a member.
std::vector<T> in contrary always allocate it's element's memory in the heap.
Therefore as std::array is allocated locally, it cannot have a variable size since that space needs to be reserved at compile time. std::vector in the other hand has the ability to reallocate and resize since its memory is unbounded.
As a consequence, the big advantage of std::array in terms of performance is that it eliminates that one level of indirection that std::vector pays for its flexibility.
For example:
#include <cstdint>
#include <iostream>
#include <vector>
#include <array>
int main() {
int a;
char b[10];
std::vector<char> c(10);
std::array<char,10> d;
struct E {
std::array<char,10> e1;
std::vector<char> e2{10};
};
E e;
printf( "Stack address: %p\n", __builtin_frame_address(0));
printf( "Address of a: %p\n", &a );
printf( "Address of b: %p\n", b );
printf( "Address of b[0]: %p\n", &b[0] );
printf( "Address of c: %p\n", &c );
printf( "Address of c[0]: %p\n", &c[0] );
printf( "Address of d: %p\n", &d );
printf( "Address of d[0]: %p\n", &d[0] );
printf( "Address of e: %p\n", &e );
printf( "Address of e1: %p\n", &e.e1 );
printf( "Address of e1[0]:%p\n", &e.e1[0] );
printf( "Address of e2: %p\n", &e.e2);
printf( "Address of e2[0]:%p\n", &e.e2[0] );
}
Produces
Program stdout
Stack address: 0x7fffeb115ed0
Address of a: 0x7fffeb115eb0
Address of b: 0x7fffeb115ea6
Address of b[0]: 0x7fffeb115ea6
Address of c: 0x7fffeb115e80
Address of c[0]: 0x1cad2b0
Address of d: 0x7fffeb115e76
Address of d[0]: 0x7fffeb115e76
Address of e: 0x7fffeb115e40
Address of e1: 0x7fffeb115e40
Address of e1[0]:0x7fffeb115e40
Address of e2: 0x7fffeb115e50
Address of e2[0]:0x1cad2d0
Godbolt: https://godbolt.org/z/75s47T56f
Not an answer, really, because I used to despise std::array<> for the same reasons as you — anything with Monadic qualities are not good design (IMNSHO).
Fortunately, C++20 has the solution: a dynamic std::span<>.
#include <array>
#include <iostream>
#include <span>
namespace detail
{
void print( const std::span<const int> & xs )
{
for (size_t n = 0; n < xs.size(); n++)
std::cout << xs[n] << " ";
}
}
void print( const std::span<const int> & xs )
{
std::cout << "{ ";
detail::print( xs );
std::cout << "}\n";
}
void add( const std::span<int> & xs, int n )
{
for (int & x : xs)
x += n;
}
int main()
{
std::array<int,5> xs { 1, 2, 4, 6, 10 };
add( xs, 1 );
print( xs );
}
Notice that the span itself is const in all cases, but the elements themselves are modifiable unless they too are tagged const. This is exactly what an array is like.
std::span is a C++20 object. I know that MS and maybe others had a array_view in older versions of their libraries.
tl;dr
Use std::array only to declare your array object. Pass it around with a dynamic std::span.
std::array vs C array
The use-case for std::array is actually very narrow: encapsulate a fixed-size array as a first-class container object (one that can be copied, not just referenced).
At first blush this doesn’t seem to be much of an improvement over standard C-style arrays:
typedef int myarray[10]; // (1)
using myarray = std::array<int,10>; // (2)
void f( myarray a );
But it is! The difference is in what f() actually gets:
For a C-style array, the argument is just a pointer — a reference to the caller’s data (that you can modify!). You know the size of the referenced array (10), but writing code to get that size is not straight-forward even with the usual C array-size idiom (sizeof(myarray)/sizeof(a[0]), since sizeof(a) is the size of a pointer).
For the std::array, the argument value is an actual local copy of the caller’s data. If you want to be able to modify the caller’s data then you need to be explicit about declaring the formal argument as a reference type (myarray & a) or just to avoid an expensive copy (const myarray & a). This falls in line with how other C++ objects are passed. And though the size is still 10, your code can query the size of the array with the usual C++ container idiom: a.size()!
The usual way C overcomes this is to clutter the call site and formal argument lists with information about the array size so that it doesn’t get lost.
int f( int array[], size_t n ) // traditional C
{
printf( "There are %zu elements.\n", n );
recurse with f( array, n );
}
int main(void)
{
int my_array[10];
f( my_array, ARRAY_SIZE(my_array) );
The std::array way is cleaner.
int f( std::array<int,10> & array ) // C++
{
std::cout << "There are " << array.size() << " elements.\n";
recurse with f( array );
}
int main()
{
std::array<int,10> my_array;
f( my_array );
But while cleaner, it is significantly less flexible than the C array, simply because its length is fixed. A caller cannot pass a std::array<int,12> to the function, for example.
I’ll refer you to the other good answers here to consider more about container choice when handling arrayed data.
If you have a problem with std::array and you think std::span is a solution, now you will have two problems.
More seriously, without knowing what kind of conceptual operation is func it is difficult to tell what is the right alternative.
First, if you want or can exploit to know the size at compile-time there is nothing cooler than what you are trying to avoid.
template<std::size_t N>
void func(std::array<int, N> arr); // add & or && or const& if appropiate
Imagine it, knowing the size at compile time can allow you and the compiler to do all sorts of tricks, like unrolling loops completely or verifying logic at compile time (e.g. if you know the size must be smaller or bigger than a constant).
Or the coolest trick of all, not needing to allocate memory for any auxiliary operation inside func (because you know the size of the problem a priori).
If you want a dynamic array, use (and pass) a std::vector.
void func(std::vector<int> dynarr); // add & or && or const& if appropiate
But then you force your caller to use std::vector as the container.
If you want a fixed array, and it will work with everything,
template<class FixedArray>
void func(FixedArray dynarr); // add & or && or const& if appropiate
Ask yourself, how specific is your function such that you really really want to make it work with any size of std::array but not with std::vector?
Why specifically ints even?
template<class ArithmeticRange>
void func(ArithmeticRange dynarr); // add & or && or const& if appropiate
There are a few contiguous containers and ranges in C++ std. They serve different purposes. There are also a few techniques for passing them around.
I'll try to be exhaustive.
std::array<int, 7>
this is a buffer of 7 ints. They are stored within the object itself. Putting an array somewhere is putting enough storage for exactly 7 ints in that location (plus possible padding for alignment reasons, but that is at the end of the buffer).
You use this when, at compile time, you know exactly how big something is, or need to know.
std::vector<int>
this object holds ownership of a buffer of ints. The memory that holds those ints is dynamically allocated and can change at runtime. The object itself is usually 3 pointers in size. It has some strategies to grow that avoids doing N^2 work when you keep adding 1 element at a time to it.
This object can be efficiently moved -- it will steal the buffer if the old object is marked (by std::move or other ways) as being safe to steal state from.
std::span<int>
This represents an externally owned sequence of ints, possibly stored in a std::array or owned by a std::vector, or stored somewhere else. It knows where in memory it starts and when it ends.
Unlike the two above, it is not a container, but a range or a view of the contents. So you can't assign spans to each other (the semantics are confusing), and you are responsible to ensure that the source buffer lasts "long enough" that you don't use it after it is gone.
span is often used as a function argument. In your case, it probably solves most of your problem -- it lets you pass arrays of different sizes to a function, and within that function you can read or write the values.
span followed pointer semantics. That means const std::span<int> is like a int*const -- the pointer is const, but the thing pointed to is not! You are free to modify the elements in const std::span<int>. In comparison, std::span<const int> is like a int const* -- the pointer is not const, but the thing pointed to is. You are free to change what range of elements the span refers to in std::span<const int>, but you aren't allowed to modify the elements themselves.
A final technique is auto or templates. Here we implement the body of the function in the header (or equivalent) and leave the type unconstrained (or, constrained by concepts).
template<std::size_t N>
int total0( std::array<int, N> const& elems ) {
int r = 0;
for (int e:elems) r+=e;
return r;
}
int total1( std::vector<int> const& elems ) {
int r = 0;
for (int e:elems) r+=e;
return r;
}
int total2( std::span<int const> elems ) {
int r = 0;
for (int e:elems) r+=e;
return r;
}
int total3( auto const& elems ) {
int r = 0;
for (int e:elems) r+=e;
return r;
}
template<class Ints>
int total4( Ints const& elems ) {
int r = 0;
for (int e:elems) r+=e;
return r;
}
notice these all have the same implementation.
total3 and total4 are identical; you need a more modern compiler to use total3 syntax.
total1 and total2 allow you to split the implementation into a cpp file away from the header file. Also, code generation isn't done for different arguments.
total0, total3 and total4 all result in different code to be generated based on the type of the arguments. This can cause binary bloat issues, especially if the body was more complex than shown, and causes build time problems in larger projects.
total1 won't work with a std::array directly. You can do total1({arr.begin(), arr.end()}) which would copy the contents to a dynamic vector before using the code.
Finally, note that span<int> is the closest you get to the C way of arr[], size. Span is, in essence, a pointer-to-first and length pair, with utility code wrapping it.
The main purpose of a C++11 std::array<> is to be a decent replacement for C-style arrays [], especially when they're declared with new and dismissed with delete[].
The main goal here is to get an official, managed object that serves as an array, while maintaining as constant expressions everything that can be.
Principal issues with regular arrays is that since they're not actually objects, one cannot derivate a class from them (forcing you to implement iterators) and are a pain when you copy classes that uses them as object properties.
Since new, delete and delete[] return pointers, you need each time either to implement a copy constructor that will declare another array them copy its content or maintaining your own dynamic reference counter on it.
From this perpective, std::array<> is a good way to declare purely static arrays that will be managed by the language itself.
I'm learning about pointers and I can't get this code to work. Here's what I have so far:
void incrementArray(int* a[]) {
for(auto& x : a) {
++x;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int array[] = {0,1,2,3,4,5,6,7,8,9};
for(auto x : array) {
cout << x << '\n';
}
incrementArray(&array);
for(auto x : array) {
cout << x << '\n';
}
}
I'm getting the following error:
'incrementArray' : cannot convert parameter 1 from 'int (*)[10]' to
'int *[]'
What can I do to fix my code?
C-style arrays have funny syntax. To pass the array to a function, use int a[] This does not copy the array and changes to the array inside the function will modify the external array. You only need to call incrementArray(array); no & needed
You could try using std::array class which follows more normal syntax.
you have a pointer as a parameter (a reference to an array), but you wish to modify the actual thing it's pointing to, so you gotta change *a, not a.
You could use an array, vector, list, etc object that would have methods already associated to them that do most of the manipulation you could want
What you are trying to do will not work since the signature of a function taking int a[] as an argument does not contain the necessary length information needed to write a for-each loop (i.e. to instantiate the begin() and end() templates needed to use the for-each syntax). GCC's warning says this fairly clearly:
Error:(14, 19) cannot build range expression with array function parameter 'a' since
parameter with array type 'int *[]' is treated as pointer type 'int **'
I thought this might be do-able with a template, but . . .
EDIT:
It can be done with templates, just took me a moment to wrap my head around the syntax. Here is your example in working condition:
template <size_t N>
void incArray(int (&a)[N]) {
for(auto& x : a) {
++x;
}
}
int main(int argc, const char * argv[])
{
int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto x : array) {
cout << x << " ";
}
cout << endl;
incArray(array);
for (auto x : array) {
cout << x << " ";
}
cout << endl;
return 0;
}
There are a couple approaches you could take to increment the elements of an array, all of which require knowing where to start and where to end. The simple way of doing what you want is to just pass the start and end address pointers, but you could also pass a start address with some offset. Since you are using a C-Style array, your int element has and address int*, so your std::begin(array) is an int* to the first element while std::end(array) points to the address of the location after your last allocated element. In your program, the std::end() address points to the memory location after your 10th allocated element. If you had an array with a size allocation (int other_arr[40]), std::end() will point to the first address after the allocation (std::end(other_arr) would be std::begin(other_arr)+41). C++ has recently introduced non-member std::begin() and std::end() in the <iterator> library, which returns a pointer to the respective element locations in your C-Array.
#include <algorithm> // std::copy
#include <iostream> // std::cout
#include <iterator> // std::begin
void increment_elements(int* begin, const int* end) {
while (begin != end) {
++(*begin);
++begin;
}
}
// An increment functor for std::transform
int increase_element(int i) {
return ++i;
}
int main() {
int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (const int x : array) {
std::cout << x << ' ';
}
std::cout << '\n';
increment_elements(std::begin(array), std::end(array));
// Another way to write your print statement above
std::copy(std::begin(array),
std::end(array),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
// Transform array elements through increase_element()
// and print result to cout.
std::transform(std::begin(array),
std::end(array),
std::ostream_iterator<int>(std::cout, " "),
increase_element);
std::cout << '\n';
}
The generalized version of the increment_elements() function can be found in the <algorithm> library as the function std::transform() documented here.
Since you are learning now, here are some habits that you can start to utilize:
Do not use using namespace std; at the global level. By pulling everything in the standard library into the global namespace, you "pollute" it with functionality that can be called if a function call for it exists, since it doesn't require a std:: prefix qualification. Say you were to write a function that calculated the euclidean distance between two (x,y) points, double distance(Point* p1, Point* p2). You decide to use any of the STL containers, such as <vector>. The containers utilize the <iterator> library, which has its own std::distance(T*, T*) function to calculate the distance between two addresses in memory. By bringing std into the global namespace by using namespace std;, you now have 2 functions with the same signature in the same namespace, that do 2 completely different things. This is very bad yet easily avoidable. This general guideline is probably unnecessary for small projects, but I still recommend you just don't ever do it for any project. Ever.
const or const T& your read only operations. When doing operations where you are pulling data for reading and you don't want to modify the data, initialize using const or const T&. const by itself is sufficient for primitive datatypes (int, float, double, char), but non-primitives will require const T& (T is the type). Values that are of type const T& (called const referenced) are read-only (const) and directly accessed (&).
as in the title is it possible to join a number of arrays together without copying and only using pointers? I'm spending a significant amount of computation time copying smaller arrays into larger ones.
note I can't used vectors since umfpack (some matrix solving library) does not allow me to or i don't know how.
As an example:
int n = 5;
// dynamically allocate array with use of pointer
int *a = new int[n];
// define array pointed by *a as [1 2 3 4 5]
for(int i=0;i<n;i++) {
a[i]=i+1;
}
// pointer to array of pointers ??? --> this does not work
int *large_a = new int[4];
for(int i=0;i<4;i++) {
large_a[i] = a;
}
Note: There is already a simple solution I know and that is just to iteratively copy them to a new large array, but would be nice to know if there is no need to copy repeated blocks that are stored throughout the duration of the program. I'm in a learning curve atm.
thanks for reading everyone
as in the title is it possible to join a number of arrays together without copying and only using pointers?
In short, no.
A pointer is simply an address into memory - like a street address. You can't move two houses next to each other, just by copying their addresses around. Nor can you move two houses together by changing their addresses. Changing the address doesn't move the house, it points to a new house.
note I can't used vectors since umfpack (some matrix solving library) does not allow me to or i don't know how.
In most cases, you can pass the address of the first element of a std::vector when an array is expected.
std::vector a = {0, 1, 2}; // C++0x initialization
void c_fn_call(int*);
c_fn_call(&a[0]);
This works because vector guarantees that the storage for its contents is always contiguous.
However, when you insert or erase an element from a vector, it invalidates pointers and iterators that came from it. Any pointers you might have gotten from taking an element's address no longer point to the vector, if the storage that it has allocated must change size.
No. The memory of two arrays are not necessarily contiguous so there is no way to join them without copying. And array elements must be in contiguous memory...or pointer access would not be possible.
I'd probably use memcpy/memmove, which is still going to be copying the memory around, but at least it's been optimized and tested by your compiler vendor.
Of course, the "real" C++ way of doing it would be to use standard containers and iterators. If you've got memory scattered all over the place like this, it sounds like a better idea to me to use a linked list, unless you are going to do a lot of random access operations.
Also, keep in mind that if you use pointers and dynamically allocated arrays instead of standard containers, it's a lot easier to cause memory leaks and other problems. I know sometimes you don't have a choice, but just saying.
If you want to join arrays without copying the elements and at the same time you want to access the elements using subscript operator i.e [], then that isn't possible without writing a class which encapsulates all such functionalities.
I wrote the following class with minimal consideration, but it demonstrates the basic idea, which you can further edit if you want it to have functionalities which it's not currently having. There should be few error also, which I didn't write, just to make it look shorter, but I believe you will understand the code, and handle error cases accordingly.
template<typename T>
class joinable_array
{
std::vector<T*> m_data;
std::vector<size_t> m_size;
size_t m_allsize;
public:
joinable_array() : m_allsize() { }
joinable_array(T *a, size_t len) : m_allsize() { join(a,len);}
void join(T *a, size_t len)
{
m_data.push_back(a);
m_size.push_back(len);
m_allsize += len;
}
T & operator[](size_t i)
{
index ix = get_index(i);
return m_data[ix.v][ix.i];
}
const T & operator[](size_t i) const
{
index ix = get_index(i);
return m_data[ix.v][ix.i];
}
size_t size() const { return m_allsize; }
private:
struct index
{
size_t v;
size_t i;
};
index get_index(size_t i) const
{
index ix = { 0, i};
for(auto it = m_size.begin(); it != m_size.end(); it++)
{
if ( ix.i >= *it ) { ix.i -= *it; ix.v++; }
else break;
}
return ix;
}
};
And here is one test code:
#define alen(a) sizeof(a)/sizeof(*a)
int main() {
int a[] = {1,2,3,4,5,6};
int b[] = {11,12,13,14,15,16,17,18};
joinable_array<int> arr(a,alen(a));
arr.join(b, alen(b));
arr.join(a, alen(a)); //join it again!
for(size_t i = 0 ; i < arr.size() ; i++ )
std::cout << arr[i] << " ";
}
Output:
1 2 3 4 5 6 11 12 13 14 15 16 17 18 1 2 3 4 5 6
Online demo : http://ideone.com/VRSJI
Here's how to do it properly:
template<class T, class K1, class K2>
class JoinArray {
JoinArray(K1 &k1, K2 &k2) : k1(k1), k2(k2) { }
T operator[](int i) const { int s = k1.size(); if (i < s) return k1.operator[](i); else return k2.operator[](i-s); }
int size() const { return k1.size() + k2.size(); }
private:
K1 &k1;
K2 &k2;
};
template<class T, class K1, class K2>
JoinArray<T,K1,K2> join(K1 &k1, K2 &k2) { return JoinArray<T,K1,K2>(k1,k2); }
template<class T>
class NativeArray
{
NativeArray(T *ptr, int size) : ptr(ptr), size(size) { }
T operator[](int i) const { return ptr[i]; }
int size() const { return size; }
private:
T *ptr;
int size;
};
int main() {
int array[2] = { 0,1 };
int array2[2] = { 2,3 };
NativeArray<int> na(array, 2);
NativeArray<int> na2(array2, 2);
auto joinarray = join(na,na2);
}
A variable that is a pointer to a pointer must be declared as such.
This is done by placing an additional asterik in front of its name.
Hence, int **large_a = new int*[4]; Your large_a goes and find a pointer, while you've defined it as a pointer to an int. It should be defined (declared) as a pointer to a pointer variable. Just as int **large_a; could be enough.
One of the interview questions asked me to "write the prototype for a C function that takes an array of exactly 16 integers" and I was wondering what it could be? Maybe a function declaration like this:
void foo(int a[], int len);
Or something else?
And what about if the language was C++ instead?
In C, this requires a pointer to an array of 16 integers:
void special_case(int (*array)[16]);
It would be called with:
int array[16];
special_case(&array);
In C++, you can use a reference to an array, too, as shown in Nawaz's answer. (The question asks for C in the title, and originally only mentioned C++ in the tags.)
Any version that uses some variant of:
void alternative(int array[16]);
ends up being equivalent to:
void alternative(int *array);
which will accept any size of array, in practice.
The question is asked - does special_case() really prevent a different size of array from being passed. The answer is 'Yes'.
void special_case(int (*array)[16]);
void anon(void)
{
int array16[16];
int array18[18];
special_case(&array16);
special_case(&array18);
}
The compiler (GCC 4.5.2 on MacOS X 10.6.6, as it happens) complains (warns):
$ gcc -c xx.c
xx.c: In function ‘anon’:
xx.c:9:5: warning: passing argument 1 of ‘special_case’ from incompatible pointer type
xx.c:1:6: note: expected ‘int (*)[16]’ but argument is of type ‘int (*)[18]’
$
Change to GCC 4.2.1 - as provided by Apple - and the warning is:
$ /usr/bin/gcc -c xx.c
xx.c: In function ‘anon’:
xx.c:9: warning: passing argument 1 of ‘special_case’ from incompatible pointer type
$
The warning in 4.5.2 is better, but the substance is the same.
There are several ways to declare array-parameters of fixed size:
void foo(int values[16]);
accepts any pointer-to-int, but the array-size serves as documentation
void foo(int (*values)[16]);
accepts a pointer to an array with exactly 16 elements
void foo(int values[static 16]);
accepts a pointer to the first element of an array with at least 16 elements
struct bar { int values[16]; };
void foo(struct bar bar);
accepts a structure boxing an array with exactly 16 elements, passing them by value.
& is necessary in C++:
void foo(int (&a)[16]); // & is necessary. (in C++)
Note : & is necessary, otherwise you can pass array of any size!
For C:
void foo(int (*a)[16]) //one way
{
}
typedef int (*IntArr16)[16]; //other way
void bar(IntArr16 a)
{
}
int main(void)
{
int a[16];
foo(&a); //call like this - otherwise you'll get warning!
bar(&a); //call like this - otherwise you'll get warning!
return 0;
}
Demo : http://www.ideone.com/fWva6
I think the simplest way to be typesafe would be to declare a struct that holds the array, and pass that:
struct Array16 {
int elt[16];
};
void Foo(struct Array16* matrix);
You already got some answers for C, and an answer for C++, but there's another way to do it in C++.
As Nawaz said, to pass an array of N size, you can do this in C++:
const size_t N = 16; // For your question.
void foo(int (&arr)[N]) {
// Do something with arr.
}
However, as of C++11, you can also use the std::array container, which can be passed with more natural syntax (assuming some familiarity with template syntax).
#include <array>
const size_t N = 16;
void bar(std::array<int, N> arr) {
// Do something with arr.
}
As a container, std::array allows mostly the same functionality as a normal C-style array, while also adding additional functionality.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
int arr2[5] = { 1, 2, 3, 4, 5 };
// Operator[]:
for (int i = 0; i < 5; i++) {
assert(arr1[i] == arr2[i]);
}
// Fill:
arr1.fill(0);
for (int i = 0; i < 5; i++) {
arr2[i] = 0;
}
// Check size:
size_t arr1Size = arr1.size();
size_t arr2Size = sizeof(arr2) / sizeof(arr2[0]);
// Foreach (C++11 syntax):
for (int &i : arr1) {
// Use i.
}
for (int &i : arr2) {
// Use i.
}
However, to my knowledge (which is admittedly limited at the time), pointer arithmetic isn't safe with std::array unless you use the member function data() to obtain the actual array's address first. This is both to prevent future modifications to the std::array class from breaking your code, and because some STL implementations may store additional data in addition to the actual array.
Note that this would be most useful for new code, or if you convert your pre-existing code to use std::arrays instead of C-style arrays. As std::arrays are aggregate types, they lack custom constructors, and thus you can't directly switch from C-style array to std::array (short of using a cast, but that's ugly and can potentially cause problems in the future). To convert them, you would instead need to use something like this:
#include <array>
#include <algorithm>
const size_t N = 16;
std::array<int, N> cArrayConverter(int (&arr)[N]) {
std::array<int, N> ret;
std::copy(std::begin(arr), std::end(arr), std::begin(ret));
return ret;
}
Therefore, if your code uses C-style arrays and it would be infeasible to convert it to use std::arrays instead, you would be better off sticking with C-style arrays.
(Note: I specified sizes as N so you can more easily reuse the code wherever you need it.)
Edit: There's a few things I forgot to mention:
1) The majority of the C++ standard library functions designed for operating on containers are implementation-agnostic; instead of being designed for specific containers, they operate on ranges, using iterators. (This also means that they work for std::basic_string and instantiations thereof, such as std::string.) For example, std::copy has the following prototype:
template <class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last,
OutputIterator result);
// first is the beginning of the first range.
// last is the end of the first range.
// result is the beginning of the second range.
While this may look imposing, you generally don't need to specify the template parameters, and can just let the compiler handle that for you.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
std::array<int, 5> arr2 = { 6, 7, 8, 9, 0 };
std::string str1 = ".dlrow ,olleH";
std::string str2 = "Overwrite me!";
std::copy(arr1.begin(), arr1.end(), arr2.begin());
// arr2 now stores { 1, 2, 3, 4, 5 }.
std::copy(str1.begin(), str1.end(), str2.begin());
// str2 now stores ".dlrow ,olleH".
// Not really necessary for full string copying, due to std::string.operator=(), but possible nonetheless.
Due to relying on iterators, these functions are also compatible with C-style arrays (as iterators are a generalisation of pointers, all pointers are by definition iterators (but not all iterators are necessarily pointers)). This can be useful when working with legacy code, as it means you have full access to the range functions in the standard library.
int arr1[5] = { 4, 3, 2, 1, 0 };
std::array<int, 5> arr2;
std::copy(std::begin(arr1), std::end(arr1), std::begin(arr2));
You may have noticed from this example and the last that std::array.begin() and std::begin() can be used interchangeably with std::array. This is because std::begin() and std::end() are implemented such that for any container, they have the same return type, and return the same value, as calling the begin() and end() member functions of an instance of that container.
// Prototype:
template <class Container>
auto begin (Container& cont) -> decltype (cont.begin());
// Examples:
std::array<int, 5> arr;
std::vector<char> vec;
std::begin(arr) == arr.begin();
std::end(arr) == arr.end();
std::begin(vec) == vec.begin();
std::end(vec) == vec.end();
// And so on...
C-style arrays have no member functions, necessitating the use of std::begin() and std::end() for them. In this case, the two functions are overloaded to provide applicable pointers, depending on the type of the array.
// Prototype:
template <class T, size_t N>
T* begin (T(&arr)[N]);
// Examples:
int arr[5];
std::begin(arr) == &arr[0];
std::end(arr) == &arr[4];
As a general rule of thumb, if you're unsure about whether or not any particular code segment will have to use C-style arrays, it's safer to use std::begin() and std::end().
[Note that while I used std::copy() as an example, the use of ranges and iterators is very common in the standard library. Most, if not all, functions designed to operate on containers (or more specifically, any implementation of the Container concept, such as std::array, std::vector, and std::string) use ranges, making them compatible with any current and future containers, as well as with C-style arrays. There may be exceptions to this widespread compatibility that I'm not aware of, however.]
2) When passing a std::array by value, there can be considerable overhead, depending on the size of the array. As such, it's usually better to pass it by reference, or use iterators (like the standard library).
// Pass by reference.
const size_t N = 16;
void foo(std::array<int, N>& arr);
3) All of these examples assume that all arrays in your code will be the same size, as specified by the constant N. To make more your code more implementation-independent, you can either use ranges & iterators yourself, or if you want to keep your code focused on arrays, use templated functions. [Building on this answer to another question.]
template<size_t SZ> void foo(std::array<int, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<int, 10> arr2;
foo(arr1); // Calls foo<5>(arr1).
foo(arr2); // Calls foo<10>(arr2).
If doing this, you can even go so far as to template the array's member type as well, provided your code can operate on types other than int.
template<typename T, size_t SZ>
void foo(std::array<T, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<float, 7> arr2;
foo(arr1); // Calls foo<int, 5>(arr1).
foo(arr2); // Calls foo<float, 7>(arr2).
For an example of this in action, see here.
If anyone sees any mistakes I may have missed, feel free to point them out for me to fix, or fix them yourself. I think I caught them all, but I'm not 100% sure.
Based on Jonathan Leffler's answer
#include<stdio.h>
void special_case(int (*array)[4]);
void anon(void){
int array4[4];
int array8[8];
special_case(&array4);
special_case(&array8);
}
int main(void){
anon();
return 0;
}
void special_case(int (*array)[4]){
printf("hello\n");
}
gcc array_fixed_int.c &&./a.out will yield warning:
array_fixed_int.c:7:18: warning: passing argument 1 of ‘special_case’ from incompatible pointer type [-Wincompatible-pointer-types]
7 | special_case(&array8);
| ^~~~~~~
| |
| int (*)[8]
array_fixed_int.c:2:25: note: expected ‘int (*)[4]’ but argument is of type ‘int (*)[8]’
2 | void special_case(int (*array)[4]);
| ~~~~~~^~~~~~~~~
Skip warning:
gcc -Wno-incompatible-pointer-types array_fixed_int.c &&./a.out
How do I reliably get the size of a C-style array? The method often recommended seems to be to use sizeof, but it doesn't work in the foo function, where x is passed in:
#include <iostream>
void foo(int x[]) {
std::cerr << (sizeof(x) / sizeof(int)); // 2
}
int main(){
int x[] = {1,2,3,4,5};
std::cerr << (sizeof(x) / sizeof(int)); // 5
foo(x);
return 0;
}
Answers to this question recommend sizeof but they don't say that it (apparently?) doesn't work if you pass the array around. So, do I have to use a sentinel instead? (I don't think the users of my foo function can always be trusted to put a sentinel at the end. Of course, I could use std::vector, but then I don't get the nice shorthand syntax {1,2,3,4,5}.)
In C array parameters in C are really just pointers so sizeof() won't work. You either need to pass in the size as another parameter or use a sentinel - whichever is most appropriate for your design.
Some other options:
Some other info:
for C++, instead of passing a raw array pointer, you might want to have the parameter use something that wraps the array in a class template that keeps track of the array size and provides methods to copy data into the array in a safe manner. Something like STLSoft's array_proxy template or Boost's boost::array might help. I've used an array_proxy template to nice effect before. Inside the function using the parameter, you get std::vector like operations, but the caller of the function can be using a simple C array. There's no copying of the array - the array_proxy template takes care of packaging the array pointer and the array's size nearly automatically.
a macro to use in C for determining the number of elements in an array (for when sizeof() might help - ie., you're not dealing with a simple pointer): Is there a standard function in C that would return the length of an array?
A common idiom mentioned in GNU Libstdc++ documentation is the lengthof function:
template<typename T, unsigned int sz>
inline unsigned int lengthof(T (&)[sz]) { return sz; }
You can use it as
int x[] = {1,2,3,4,5};
std::cerr << lengthof(x) << std::endl;
Warning: this will work only when the array has not decayed into a pointer.
How about this?..
template <int N>
void foo(int (&x)[N]) {
std::cerr << N;
}
You can either pass the size around, use a sentinel or even better use std::vector. Even though std::vector lacks initializer lists it is still easy to construct a vector with a set of elements (although not quite as nice)
static const int arr[] = {1,2,3,4,5};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
The std::vector class also makes making mistakes far harder, which is worth its weight in gold. Another bonus is that all C++ should be familiar with it and most C++ applications should be using a std::vector rather than a raw C array.
As a quick note, C++0x adds Initializer lists
std::vector<int> v = {1, 2, 3, 4};
You can also use Boost.Assign to do the same thing although the syntax is a bit more convoluted.
std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);
or
std::vector<int> v;
v += 1, 2, 3, 4;
c provides no native support for this. Once an array is passed out of its declared scope, its size is lost.
You can pass the size with the array. You can even bundle them into a structure if you always to to keep the size, though you'll have some bookkeepping overhead with that.
I also agree that Corwin's method above is very good.
template <int N>
void foo(int (&x)[N])
{
std::cerr << N;
}
I don't think anybody gave a really good reason why this is not a good idea.
In java, for example, we can write things like:
int numbers [] = {1, 2, 3, 4};
for(int i = 0; i < numbers.length(); i++)
{
System.out.println(numbers[i]+"\n");
}
In C++ it would be nice instead of saying
int numbers [] = {1, 2, 3, 4};
int size = sizeof(numbers)/sizeof(int);
for(int i = 0; i < size; i++)
{
cout << numbers[i] << endl;
}
We could take it a step further and go
template <int N>
int size(int (&X)[N])
{
return N;
}
Or if that causes problems I suppose you could write explicitly:
template < int N >
int size(int (&X)[N])
{
int value = (sizeof(X)/sizeof(X[0]));
return value;
}
Then we just have to go in main:
int numbers [] = {1, 2, 3, 4};
for(int i = 0; i < size(numbers); i++)
{
cout << numbers[i] << endl;
}
makes sense to me :-)
An array expression will have its type implicitly converted from "N-element array of T" to "pointer to T" and its value will be the address of the first element in the array, unless the array expression is the operand of either the sizeof or address-of (&) operators, or if the array expression is a string literal being used to initialize another array in a declaration. In short, you can't pass an array to a function as an array; what the function receives is a pointer value, not an array value.
You have to pass the array size as a separate parameter.
Since you're using C++, use vectors (or some other suitable STL container) instead of C-style arrays. Yes, you lose the handy shorthand syntax, but the tradeoff is more than worth it. Seriously.
Now, you can use C++11's extent and rank.
By example:
#include <iostream>
#include <type_traits>
int main()
{
int a[][3] = {{1, 2, 3}, {4, 5, 6}};
std::cout << "\nRank: : " << std::rank<decltype(a)>::value;
std::cout << "\nSize: [_here_][]: " << std::extent<decltype(a), 0>::value;
std::cout << "\nSize: [][_here_]: " << std::extent<decltype(a), 1>::value;
std::cout << "\nSize: [][]_here_: " << std::extent<decltype(a), 2>::value;
}
prints:
Rank: : 2
Size: [_here_][]: 2
Size: [][_here_]: 3
Size: [][]_here_: 0
You need to pass the size along with the array, just like it is done in many library functions, for instance strncpy(), strncmp() etc. Sorry, this is just the way it works in C:-).
Alternatively you could roll out your own structure like:
struct array {
int* data;
int size;
};
and pass it around your code.
Of course you can still use std::list or std::vector if you want to be more C++ -ish.
Since c++11, there is a very convenient way:
static const int array[] = { 1, 2, 3, 6 };
int size = (int)std::distance(std::begin(array), std::end(array))+1;