This question already has answers here:
Pointer vs Array in function definition: what is the difference between void fct1(int *p) and void fct1(int p[])?
(2 answers)
Closed 9 years ago.
I was told there actually is a difference between a T*[] and a T** and that a two dimensional array does not decay into T** as shown here: std::array to pointer access violation error
However.. If they are not the same, then why can't I declare BOTH of these functions?
template<typename T>
void Transpose(T** Data, std::size_t Size)
{
for (int I = 0; I < Size; ++I)
{
for (int J = 0; J < I; ++J)
{
std::swap(Data[I][J], Data[J][I]);
}
}
}
template<typename T>
void Transpose(T* Data[], std::size_t Size)
{
for (int I = 0; I < Size; ++I)
{
for (int J = 0; J < I; ++J)
{
std::swap(Data[I][J], Data[J][I]);
}
}
}
The compiler says that its already declared.. Any ideas?
It's because in function argument lists, T* data[] is just another way to write T** data.
To distinguish between arrays and pointers, you can do the following:
template<typemane T> void Transpose(T** data, ...) { ... }
template<typename T, int N> void Transpose(T* (&data)[N], ...) { ... }
However in your case, you don't not use that distinction anyway, so you can just write the first version and omit the second. The automatic decay of array to pointer when calling the function will make it work on arrays as well.
T*[] and T** are the same when they're used as function parameters.
Related
What is the syntax for declaring a pointer to an aligned type? Is there ever ambiguity between a pointer to an aligned array of objects and a pointer to an array of objects, each of which is aligned?
For example, how would I implement foo without a using or a typedef?
template <class T, int N>
using Aligned alignas(N) = T;
void foo(Aligned<float, 64>* vals, int size)
{
for (int i = 0; i != size; ++i)
vals[i] *= 2.0f;
}
// the above seems a bit ambiguous -- maybe it could be a pointer to
// floats that are each 64 byte aligned? -- but it gives the same
// code as the following so it seems to be doing the right thing
void bar(float* vals, int size)
{
vals = (float*)__builtin_assume_aligned(vals, 64);
for (int i = 0; i != size; ++i)
vals[i] *= 2.0f;
}
I have the following code which could not be complied.
using namespace std;
void f(int);
template<typename T1, size_t N>
void array_ini_1d(T1 (&x)[N])
{
for (int i = 0; i < N; i++)
{
x[i] = 0;
}
}
What is the proper way to pass the array if the main is something like below.
int main()
{
int a;
cin >> a;
int n = a / 4;
f(n);
return 0;
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
error: no matching function to call to array_ini_1d..............
The problem is that variable size arrays are not supported by c++, and is only supported as compilers extension. That means, the standard doesn't say what should happen, and you should see if you can find in compiler's documentation, but I doubt that such corner cases are documented.
So, this is the problem :
int arr[n];
The solution is to avoid it, and use something supported by c++, like for example std::vector.
I don't think the compiler can deduce the size of a variable-length array in a template. Also, don't forget to forward declare f before you use it. Variable-length arrays are a GCC extension and you should get a warning regarding their use.
You may declare your function like this:
template <typename A, size_t N> void f(A a[N]) {
for(size_t i = 0; i < N; i++)
cout << a[i];
}
However, the problem is that when you call the function, the compiler won't deduce the template parameters, and you will have to specify them explicitly.
char arr[5] = {'H', 'e', 'l', 'l', 'o'};
int main()
{
//f(arr); //Won't work
f<char, sizeof(arr)/sizeof(arr[0])>(arr);
cout << endl;
return 0;
}
Unfortunately, that ruins the very idea...
UPD: And even that code does NOT work for an array that has variable length, for the length is calculated at runtime, and the template parameters are defined at compilation time.
UPD2: If using std::vector you may create it initialized:
vector<int> arr(n, 0);
Or you may fill it with fill from <algorithm> when needed:
std::fill(arr.begin(), arr.end(), 0);
As you use Variable length array (VLA) (compiler extension), compiler cannot deduce N.
You have to pass it by pointer and give the size:
template<typename T>
void array_ini_1d(T* a, std::size_t n)
{
for (std::size_t i = 0; i != n; ++i) {
a[i] = 0;
}
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
Or use std::vector. (no extension used so). Which seems cleaner:
template<typename T>
void array_ini_1d(std::vector<T>& v)
{
for (std::size_t i = 0, size = v.size(); i != n; ++i) {
a[i] = 0; // or other stuff.
}
}
void f(int n)
{
std::vector<int> arr(n); // or arr(n, 0).
array_ini_1d(arr);
}
Template parameters must be resolved at compile-time.
There is no way that a function template with parameter size_t N can match any sort of array or other container whose size comes from a run-time input.
You will need to provide another version of the array_1d_ini which does not have the size as a template parameter.
template<typename T, size_t N>
void f(T* a)
{
/* add your code here */
}
int main()
{
int a[10];
f<int, 10>(a);
return 0;
}
After some trial and error I found a way to malloc a 2D array so it is contiguous in memory, equivalent to the non-dynamic case.
int numRows =2;
int numCols = 4;
int (*p)[numCols];
p = (int (*)[numCols]) malloc(sizeof(int)*numRows*numCols);
So p is now basically the same as if I had done int p[2][4] - except it's on the heap instead of the stack.
2 Questions:
Do I just need to call free(p) to free the memory? No looping?
How would I convert this to using new, instead of malloc?
I tried
p = new (int (*)[4])[2];
But that gave the error:
error: cannot convert int (**)[4] to int (*)[4] in assignment
Here's a class template that uses one std::vector to hold a contiguous buffer, and size-aware proxy objects to access array elements dimension-by-dimension:
template<typename T>
class TwoDArray {
private:
std::size_t n_rows;
std::size_t n_cols;
std::vector<T> buf;
public:
class OneDArrayProxy {
private:
T *rowptr;
std::size_t colsize;
public:
OneDArrayProxy(const T *rp, std::size_t cs) : rowptr(const_cast<T *>(rp)), colsize(cs) {}
T const &operator[](std::size_t index) const {
return rowptr[index];
}
T &operator[](std::size_t index) {
return rowptr[index];
}
std::size_t size() const { return colsize; }
};
TwoDArray(std::size_t rows, std::size_t cols) : n_rows(rows), n_cols(cols), buf(rows * cols) {}
TwoDArray() : TwoDArray(0, 0) {}
OneDArrayProxy operator[](std::size_t index) const {
return OneDArrayProxy(&buf[index * n_cols], n_cols);
}
std::size_t rows() const { return n_rows; }
std::size_t columns() const { return n_cols; }
};
Usage example:
int main()
{
TwoDArray<int> arr(9, 5);
for (std::size_t i = 0; i < arr.rows(); i++) {
for (std::size_t j = 0; j < arr.columns(); j++) {
arr[i][j] = i * 10 + j;
}
}
for (std::size_t i = 0; i < arr.rows(); i++) {
// you can use the array element's 'size()' function instead of 'columns()'
for (std::size_t j = 0; j < arr[i].size(); j++) {
std::cout << arr[i][j] << " ";
}
std::cout << std::endl;
}
}
You can't do that in C++. Your malloc() code is perfectly valid C, but not valid C++. And it won't work with new.
C++ requires array types to have constant size, C allows arrays types of dynamic size. There is only an exception for 1D arrays, which may be allocated with dynamic size in C++, but that's it. In a 2D array, the second size must be known at compile time.
This is the one point at which C is much more powerful than C++.
It takes a bit to convince g++ to follow the standard in this regard, but compiling this little program
#include <stdlib.h>
int main(int argc, char** args) {
int (*foo)[argc];
}
with g++ -pedantic -std=c++11 foo.cpp dutifully produces the error message:
foo.cpp: In function ‘int main(int, char**)’:
foo.cpp:4:17: warning: ISO C++ forbids variable length array ‘foo’ [-Wvla]
1) Yes, you could just call free()
But attention, you are doing pointer aliasing (2 pointers to different types, int and int[] with the same address), which can cause subtle optimisation bugs. And in C++ it's a very bad practice to use malloc(), and numcols should be const.
2) The way you can do this in C++ would be to use [<array>][2] if the size to be known at compile time:
array<array<int, 4>,2> a;
The more flexible alternative is to use vectors which allow for dynamic size and resizing:
vector <vector <int>> b(2, vector<int>(4));
3) With new you could also do :
p = new (int[2][4]);
The first dimension could also be variable, but the second has to be a constant. But I'd encourage you to use one of the standard containter alternative.
I have the following code which could not be complied.
using namespace std;
void f(int);
template<typename T1, size_t N>
void array_ini_1d(T1 (&x)[N])
{
for (int i = 0; i < N; i++)
{
x[i] = 0;
}
}
What is the proper way to pass the array if the main is something like below.
int main()
{
int a;
cin >> a;
int n = a / 4;
f(n);
return 0;
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
error: no matching function to call to array_ini_1d..............
The problem is that variable size arrays are not supported by c++, and is only supported as compilers extension. That means, the standard doesn't say what should happen, and you should see if you can find in compiler's documentation, but I doubt that such corner cases are documented.
So, this is the problem :
int arr[n];
The solution is to avoid it, and use something supported by c++, like for example std::vector.
I don't think the compiler can deduce the size of a variable-length array in a template. Also, don't forget to forward declare f before you use it. Variable-length arrays are a GCC extension and you should get a warning regarding their use.
You may declare your function like this:
template <typename A, size_t N> void f(A a[N]) {
for(size_t i = 0; i < N; i++)
cout << a[i];
}
However, the problem is that when you call the function, the compiler won't deduce the template parameters, and you will have to specify them explicitly.
char arr[5] = {'H', 'e', 'l', 'l', 'o'};
int main()
{
//f(arr); //Won't work
f<char, sizeof(arr)/sizeof(arr[0])>(arr);
cout << endl;
return 0;
}
Unfortunately, that ruins the very idea...
UPD: And even that code does NOT work for an array that has variable length, for the length is calculated at runtime, and the template parameters are defined at compilation time.
UPD2: If using std::vector you may create it initialized:
vector<int> arr(n, 0);
Or you may fill it with fill from <algorithm> when needed:
std::fill(arr.begin(), arr.end(), 0);
As you use Variable length array (VLA) (compiler extension), compiler cannot deduce N.
You have to pass it by pointer and give the size:
template<typename T>
void array_ini_1d(T* a, std::size_t n)
{
for (std::size_t i = 0; i != n; ++i) {
a[i] = 0;
}
}
void f(int n)
{
int arr[n];
array_ini_1d(arr);
}
Or use std::vector. (no extension used so). Which seems cleaner:
template<typename T>
void array_ini_1d(std::vector<T>& v)
{
for (std::size_t i = 0, size = v.size(); i != n; ++i) {
a[i] = 0; // or other stuff.
}
}
void f(int n)
{
std::vector<int> arr(n); // or arr(n, 0).
array_ini_1d(arr);
}
Template parameters must be resolved at compile-time.
There is no way that a function template with parameter size_t N can match any sort of array or other container whose size comes from a run-time input.
You will need to provide another version of the array_1d_ini which does not have the size as a template parameter.
template<typename T, size_t N>
void f(T* a)
{
/* add your code here */
}
int main()
{
int a[10];
f<int, 10>(a);
return 0;
}
void build() will create a 2D array whose size is determined at run time and pass it to modify() by reference.
void modify() will make some change of the array.
.h file:
void modify(______, int mySize);
void build(int size);
in .cpp file:
void modify(______, int mySize) {
for (int i = 0; i < mySize; i++)
for (int j = 0; j < mySize; j++)
myArray[i][j] = false;
}
void build(int size) {
bool myArray[size][size];
modify(______, size);
}
Can someone tell me what to put in these blanks? I tried many way to cast myArray but still not working. Thank you so much!
First, note that variable length arrays (VLAs) are not standard C++. The fact that this line compiles is due to a GCC compiler extension:
bool myArray[size][size];
It simply isn't valid C++. The dimensions of your array need to be compile time constants, yet here you're using arguments passed to your function build.
Anyway, to pass a VLA to a function, you have to continue using compiler extensions. However, as far as I've tested, these only work when compiling as C. The first option uses an extension that allows parameters to be used in other parameter declarations:
void modify(int mySize, bool array[][mySize]);
The second option, if you want mySize to be the second argument, also uses a compiler extension allowing forward declarations of parameters:
void modify(int mySize; bool array[][mySize], int mySize);
Here int mySize; is a parameter forward declaration.
Nonetheless, you really shouldn't be using variable length arrays. You can dynamically allocate arrays of variable length, like so:
void modify(bool** array, int mySize);
void build(int size) {
bool** myArray = new bool*[size];
for (int i = 0; i < size; i++) {
myArray[i] = new bool[size];
}
modify(myArray, size);
}
However, this is still not a recommended practice in C++. You should avoid dynamic allocation unless you really need it, and when you do need it you should manage it in some way. Here, you would need to remember to delete[] each element of myArray and myArray itself.
What you should really be using is the standard containers. A std::vector<std::vector<bool>> would suit you well here:
void modify(std::vector<std::vector<bool>>& array);
void build(int size) {
std::vector<std::vector<bool>> myArray(size, std::vector<bool>(size));
modify(myArray);
}
Now you don't even have to pass along the size.
Use it this way:
void modify(bool**& myArray, const int mySize)
{
for (int i = 0; i < mySize; i++)
for (int j = 0; j < mySize; j++)
myArray[i][j] = false;
}
void build(const int size)
{
// create the array
bool** myArray = new bool*[size];
for (int i=0; i<size; i++)
myArray[i] = new bool[size];
modify(myArray, size);
// release the array
for (int i=0; i<size; i++)
delete[] myArray[i];
delete[] myArray;
}