I am trying to write a variadic function that takes an unknown number of arguments and creates an array of the input type (Its a template function so if the input arguments are floats, it returns a float ptr and likewise for other data types)
I was thinking that I can use either NAN or INFINITY as a sentinel value because one of them theoretically would never be used in an array (at least for my purposes).
More or less the function looks like this
template<typename T>
T* arrayIt(T first, ...)
{
va_list ap;
va_start(ap, first);
T n = first, *array = (T*)malloc(sizeof(T));
int sz = 0;
while(!(isnan(n)) /* or infinite(n) */){
sz++; // inc array size
array = realloc(array, sizeof(T)*(sz+1)); // realloc
array[sz] = n;
n = va_arg(ap, T); // update temp
}
array[0] = sz; // store size of array
return (array + 1); //doing this places the first element at array[0]
// the size of the array is stored at array[-1]
}
The function works as planned with everything except ints.
I would like to know how to use the function this way using NAN as a sentinal.
I would also like to do this preferably without a macro.
i.e. int * a = arrayIt<int>(1,2,3,4,5,6,NAN);
Might not answer the exact question you're asking, but in C++11, you can just do this:
template <typename T, typename... Vals>
std::array<T, sizeof...(Vals)> arrayIt(Vals... vals) {
return std::array<T, sizeof...(Vals)>{static_cast<T>(vals)... };
}
To be used without a sentinel, like:
auto a = arrayIt<int>(1, 2, 3, 4, 5, 6);
Related
I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?
You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.
Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.
For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.
In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);
You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.
In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).
Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.
The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.
I am doing some very basic problems to get familiar with Template Metaprogramming. This one in particular is just to add up the values on the down-right diagonal of a square matrix (indexes of [0,0],[1,1], etc.). I have solved this in many ways with different constexpr functions, but I do not understand why one particular way fails. Code and error message below:
constexpr int DRsum(const int* starter, const size_t size, int itr = 0)
{
if(itr==size-1)
{
return *starter;
}
size_t sum = 0;
sum = *starter;
sum += DRsum(starter+size+1, size, itr+1);
return sum;
}
int main()
{
static const size_t size = 3;
static constexpr const int matrix[][size] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
static constexpr int const* baseptr = &matrix[0][0];
constexpr int sum = DRsum(baseptr, size);
}
The error message is as follows:
main.cpp|69| in constexpr expansion of 'DRsum((& matrix[0][0]), 3u, 0)'|
main.cpp|39| in constexpr expansion of 'DRsum((starter + ((((sizetype)size) + 1u) * 4u)),
((size_t)size), (itr + 1))'|
main.cpp|69|error: '* starter' is not a constant expression|
I am not sure why this is doing this, as I am new to Template Metaprogramming. I made a dummy function to test if the pointer dereference was the issue, and that worked out fine. My guess is that it might have to do with me passing in a pointer rather than a pointer to a constexpr pointer, but I'm not sure. Any help would be appreciated, Thanks.
Also, I have already solved this by means of just passing in the entire structure (just straight up a deep copy) but I would rather know how to pass things by shallow copy or pointer into constexpr functions. Thanks.
A 2D array (matrix) cannot be treated as a 1D array, so starter+size+1 results in undefined behavior. Usually undefined behavior is undefined so the program may work as expected, but when an undefined behavior happens within a structure that requires a constant expression, the program becomes ill-formed thus the compiler emits an error.
I don't think there is a simple fix because there is no well-defined way to access the whole 2D array through starter (even with std::launder), unless you change the signature of DRsum. For example, you can write DRsum as follows:
template <size_t size>
constexpr int DRsum(const int (*starter)[size], int itr = 0)
{
if (itr == size - 1)
{
return (*starter)[itr];
}
size_t sum = 0;
sum = (*starter)[itr];
sum += DRsum(starter + 1, itr + 1);
return sum;
}
then call it like constexpr int sum = DRsum(matrix);.
Suppose a n-dimensional array that is passed as template argument and should be traversed in order to save it to a file. First of all I want to find out the size of the elements the array consists of. Thereto I try to dereference the pointers until I get the first element at [0][0][0]...[0]. But I already fail at this stage:
/**
* #brief save a n-dimensional array to file
*
* #param arr: the n-level-pointer to the data to be saved
* #param dimensions: pointer to array where dimensions of <arr> are stored
* #param n: number of levels / dimensions of <arr>
*/
template <typename T>
void save_array(T arr, unsigned int* dimensions, unsigned int n){
// how to put this in a loop ??
auto deref1 = *arr;
auto deref2 = *deref1;
auto deref3 = *deref2;
// do this n times, then derefn is equivalent to arr[0]...[0], 42 should be printed
std::cout << derefn << std::endl;
/* further code */
}
/*
* test call
*/
int main(){
unsigned int dim[4] = {50, 60, 80, 50}
uint8_t**** arr = new uint8_t***[50];
/* further initialization of arr, omitted here */
arr[0][0][0][0] = 42;
save_array(arr, dim, 4);
}
When I think of this from a memory perspective I want to perform a n-indirect load of a given address.
I saw a related question that was asked yesterday:
Declaring dynamic Multi-Dimensional pointer
This would help me a lot as well. One comment states it is not possible since types of all expressions must be known at compile-time. In my case there's actually known everything, all callers of save_array will have n hardcoded before passing it. So I think it could be just a matter of defining stuff at the right place what I am yet not able to.
I know I am writing C-style code in C++ and there could be options to achieve this with classes etc., but my question is: Is it possible to achieve n-level pointer dereference by an iterative or recursive approach? Thanks!
First of all: Do you really need a jagged array? Do you want to have some sort of sparse array? Because otherwise, could you not just flatten your n-dimensional structure into a single, long array? That would not just lead to much simpler code, but most likely also be more efficient.
That being said: It can be done for sure. For example, just use a recursive template and rely on overloading to peel off levels of indirection until you get to the bottom:
template <typename T>
void save_array(T* arr, unsigned int* dimensions)
{
for (unsigned int i = 0U; i < *dimensions; ++i)
std::cout << ' ' << *arr++;
std::cout << std::endl;
}
template <typename T>
void save_array(T** arr, unsigned int* dimensions)
{
for (unsigned int i = 0U; i < *dimensions; ++i)
save_array(*arr, dimensions + 1);
}
You don't even need to explicitly specify the number of indirections n, since that number is implicitly given by the pointer type.
You can do basically the same trick to allocate/deallocate the array too:
template <typename T>
struct array_builder;
template <typename T>
struct array_builder<T*>
{
T* allocate(unsigned int* dimensions) const
{
return new T[*dimensions];
}
};
template <typename T>
struct array_builder<T**> : private array_builder<T*>
{
T** allocate(unsigned int* dimensions) const
{
T** array = new T*[*dimensions];
for (unsigned int i = 0U; i < *dimensions; ++i)
array[i] = array_builder<T*>::allocate(dimensions + 1);
return array;
}
};
Just this way around, you need partial specialization since the approach using overloading only works when the type can be inferred from a parameter. Since functions cannot be partially specialized, you have to wrap it in a class template like that. Usage:
unsigned int dim[4] = { 50, 60, 80, 50 };
auto arr = array_builder<std::uint8_t****>{}.allocate(dim);
arr[0][0][0][0] = 42;
save_array(arr, dim);
Hope I didn't overlook anything; having this many indirections out in the open can get massively confusing real quick, which is why I strongly advise against ever doing this in real code unless absolutely unavoidable. Also this raw usage of new all over the place is anything but great. Ideally, you'd be using, e.g., std::unique_ptr. Or, better yet, just nested std::vectors as suggested in the comments…
Why not just use a data structure like tree with multiple child nodes.
Suppose you need to store n dimensional array values, create a node pointing to the first dimension. Say your first dimension length is 5 then you have 5 child nodes and if your 2nd dimension size is 10. Then for each of these 5 node you have 10 child nodes and so on....
Some thing like,
struct node{
int index;
int dimension;
vector<node*> children;
}
It will be easier to traverse through tree and is much cleaner.
My question is simple, if I have a matrix created on the stack rather than on the heap, such as int matrix[10][10], how can I pass it by reference? Or, pass it in a way that it doesn't pass the whole matrix as argument, but just its pointer or reference, or whatever. I use C++11.
void proc(/*WHAT GOES HERE?*/ matrix, int n){
matrix[n-1][n-1] = 7;
}
int main(){
int matrix[10][10];
proc(matrix, 10);
return 0;
}
You simply need:
// By reference:
void proc_ref(int (&matrix)[10][10]); // first dimension must have a size of 10
// By pointer:
void proc_ptr(int (*matrix)[10], int n); // n is the size of the first dimension
In the first case, matrix will be a reference to an array of 10 array of 10 ints ("reference to int[10][10]"), in the second case matrix will be a pointer to an array of 10 int ("pointer to int[10]").
In both cases you can use it like you want in proc:
matrix[i][j] = 42;
The second version allows passing matrix of various size such as int[14][10] or int[12][10] (as long as the second dimension as a size of 10). It also allows passing dynamically allocated array of array of 10 int:
int (*p)[10] = new int[42][10];
proc_ref (p); // Error
proc_ptr (p, 42); // Ok
int m[24][10];
proc_ref (p); // Error
proc_ptr (p, 24); // Ok
If you want to only allow square matrix declared with automatic storage duration, use the reference versions.
Note: You have to specify the second dimension of your matrix at compile time. If you want to be "generic" you could use a template:
template <size_t N>
void proc (int (&matrix)[N][N]);
Also, if you are using c++11, you should use std::array which is much more convenient while still doing exactly what you want (no dynamic allocation):
template <typename T, size_t N>
using matrix_t = std::array<std::array<T, N>, N>;
template <typename T, size_t N>
void proc (matrix_t<T, N> &matrix) {
matrix[N - 1][N - 1] = 7;
}
int main () {
matrix_t<int, 10> matrix;
proc(matrix);
}
Array might decay to pointer. You can declare the parameter type as a pointer (to array) like:
void proc(int (*matrix)[10], int n){
matrix[n-1][n-1] = 7;
}
Note the dimension won't be reserved when array decaying to pointer, means you might pass int [11][10] to proc() in this case.
If you don't want this, you can declare the parameter type as reference like:
void proc(int (&matrix)[10][10], int n){
matrix[n-1][n-1] = 7;
}
Only int[10][10] could be passed here.
So I have a function that takes a variable length argument list, for example:
int avg(int count,...){
//stuff
}
I can call it with avg(4,2,3,9,4); and it works fine. It needs to maintain this functionality.
Is there a way for me to also call it with an array instead of listing the variables? For example:
avg(4,myArray[5]) such that the function avg doesn't see any difference?
No there is no such way. You can however make two functions, one that takes a variable number of arguments, and one that takes an array (or better yet, an std::vector). The first function simply packs the arguments into the array (or vector) and calls the second function.
void f() {}
template<typename T, std::size_t N>
void f(T array[N])
{
}
template<typename T, typename... Args>
void f(const T& value, const Args&... args)
{
process(value);
f(args...);
}
No. Since pointers are essentially unsigned integers it would not be able to tell the difference between a memory address and an unsigned integer. Alternatively (as I am sure you wanted to avoid), you would have to do:
avg( 4, myArray[ 0 ], ..., myArray[ 3 ] );
... where ... is myArray at positions 1 and 2 if you wanted to conform with the same parameters as your previous function. There are other ways to do this, such as using C++ vectors.
You can easily do it
struct{int arr[100];}p;
double avg2(int count,int* arr){
memcpy(&p,arr,count*sizeof(int));
return avg(count,p);
}
Better approach would be get rid of variadic arguments. This was inherited from C and it is a good practice to avoid it as much as possible.
Now your example avg(4,myArray[5]) is a bit fuzzy. I assume, that first argument defines how much items must be taken from array and second argument you planned to pass just an array. I assume this index operator is typo or limping method showing array size.
So you expect something like this:
int avg(int count, ...)
{
int sum = 0;
std::va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
sum += va_arg(args, int);
}
va_end(args);
return sum / count;
}
template <size_t N, size_t... I>
int avg_helper(size_t count, const int (&arr)[N], std::index_sequence<I...>)
{
return avg(count, arr[I]...);
}
template <size_t N>
int avg(int count, const int (&arr)[N])
{
if (count > N)
throw std::invalid_argument { "to large count passed" };
return avg_helper(count, arr, std::make_index_sequence<N> {});
}
https://godbolt.org/z/7v1n7zaWq
Now note that in overload resolution variadic function is match as a last one. So when compiler can match template it will select it instead variadic function.
Note there is a trap. If you will pass a pointer (for example array decay) variadic argument function will kick in again. So as protection I've added extra overload which will trigger static_assert warning about array decay.