C++ [] array operator with multiple arguments? - c++

Can I define in C++ an array operator that takes multiple arguments? I tried it like this:
const T& operator[](const int i, const int j, const int k) const{
return m_cells[k*m_resSqr+j*m_res+i];
}
T& operator[](const int i, const int j, const int k){
return m_cells[k*m_resSqr+j*m_res+i];
}
But I'm getting this error:
error C2804 binary operator '[' has too many parameters

Prior to C++23, you could not overload operator[] to accept multiple arguments. As a workaround, you instead can overload operator(). (See How do I create a subscript operator for a Matrix class? from the C++ FAQ.)
From C++23, as mentioned in a (deleted) answer by cigien, multiple subscript arguments can be passed to operator[] directly. See this demo from the cppreference page.

It is not possible to overload the [] operator to accept multiple arguments, but an alternative is to use the proxy pattern.
In two words: a[x][y], the first expression (a[x]) would return a different type, named proxy type, which would have another operator[]. It would call something like _storedReferenceToOriginalObject->At(x,y) of the original class.
You will not be able to do a[x,y], but I guess you wanted to overload the usual C++-style 2D array syntax anyway.

There's a nice little trick you can do with the uniform initialization syntax available in C++11. Instead of taking the index directly, you take a POD.
struct indices
{
std::size_t i, j, k;
};
T& operator[](indices idx)
{
return m_cells[idx.k * m_resSqr + idx.j * m_res + idx.i];
}
And then use the new syntax:
my_array<int> arr;
// ...
arr[{1, 2, 3}] = 42;

For completeness sake: There is a way to actually use the bracket operator with multiple arguments, if they are not basic data types,
namely by overloading the comma operator and not the bracket operator, see the following post about comma overloading:
https://stackoverflow.com/a/18136340/5836981
Disclaimer: in my opinion overloading the comma operator is error prone and renders code more obscure, and is worth considering only in more exotic cases. I added this answer because I came over an instance of this in some code and it took me a while to figure out that the key was not the [] operator (which cannot be overloaded with multiple arguments) but the ,operator.

Edit: as pointed in comment, in C++20 operator comma will be deprecated, so as the answer below.
You can't overload operator[], but you can fake it by overloading operator, instead.
Following your code it becomes:
T& operator,(const int i, const int j, const int k){
return m_cells[k*m_resSqr+j*m_res+i];
}
now you'll be able to call
something[1, 2, 3]
You can extend it using templates, templates with variadic arguments, std::pair or std::tuple depending on your use case and C++ version

N-dimensional arrays of arbitrary type and size in C++:
This answer is inspired by the answer of Pavel Radzivilovsky, thanks for that. I had a bit of a hard time realizing the implementation, as it was my first stab at recursive templates. I'd like to share what I have done such that others can understand more quickly than I did.
I have written a c++ template class to create a n-dimensional array of arbitrary type and size. It needs to be instantiated with the array type and the number of dimensions. The size can be changed dynamically. I've given below a bare (stripped) working version of how to create a multidimensional array of which the elements can be accessed through successive application of the operator[] (e.g. array[x][y][z]). This version can only handle arrays of dimension n>1. The main function shows how to create a 4-dimensional array of integers as an example.
EDIT: keep in mind that the example below is minimal for readability, in that it does not deallocate the array, nor does it do bounds checking on access. Adding this is trivial, and left to the programmer.
#include <stdio.h>
#include <stdlib.h>
template <typename T, int N>
struct array {
array<T,N>() : data(NULL), offset((int*) malloc(sizeof(int)*N)){}
array<T,N>(T *data, int *offset) : data(data), offset(offset){}
array<T,N-1> operator[](int i){return array<T,N-1>(&data[i*offset[N]], offset);}
bool resize(int *size){
offset[N-1] = 1;
int total_size = size[N-1];
for(int i = N-2; i >= 0; i--){
total_size *= size[i];
offset[i] = offset[i+1]*size[i+1];
}
return (data = (T*) realloc (data, total_size*sizeof(T)));
}
T *data;
int *offset;
};
template <typename T>
struct array<T,1>{
array<T,1>(T *data, int *offset) : data(data){}
T& operator[](int i){return data[i];}
T *data;
};
int main () {
array<int, 4> a;
// create array with dimensions [1][3][3][7]
int size[4] = { 1, 3, 3, 7 };
a.resize(size);
a[0][1][2][3] = 123;
return 0;
}
Enjoy.

Related

Why do brackets only use the last number in their parameters? [duplicate]

Can I define in C++ an array operator that takes multiple arguments? I tried it like this:
const T& operator[](const int i, const int j, const int k) const{
return m_cells[k*m_resSqr+j*m_res+i];
}
T& operator[](const int i, const int j, const int k){
return m_cells[k*m_resSqr+j*m_res+i];
}
But I'm getting this error:
error C2804 binary operator '[' has too many parameters
Prior to C++23, you could not overload operator[] to accept multiple arguments. As a workaround, you instead can overload operator(). (See How do I create a subscript operator for a Matrix class? from the C++ FAQ.)
From C++23, as mentioned in a (deleted) answer by cigien, multiple subscript arguments can be passed to operator[] directly. See this demo from the cppreference page.
It is not possible to overload the [] operator to accept multiple arguments, but an alternative is to use the proxy pattern.
In two words: a[x][y], the first expression (a[x]) would return a different type, named proxy type, which would have another operator[]. It would call something like _storedReferenceToOriginalObject->At(x,y) of the original class.
You will not be able to do a[x,y], but I guess you wanted to overload the usual C++-style 2D array syntax anyway.
There's a nice little trick you can do with the uniform initialization syntax available in C++11. Instead of taking the index directly, you take a POD.
struct indices
{
std::size_t i, j, k;
};
T& operator[](indices idx)
{
return m_cells[idx.k * m_resSqr + idx.j * m_res + idx.i];
}
And then use the new syntax:
my_array<int> arr;
// ...
arr[{1, 2, 3}] = 42;
For completeness sake: There is a way to actually use the bracket operator with multiple arguments, if they are not basic data types,
namely by overloading the comma operator and not the bracket operator, see the following post about comma overloading:
https://stackoverflow.com/a/18136340/5836981
Disclaimer: in my opinion overloading the comma operator is error prone and renders code more obscure, and is worth considering only in more exotic cases. I added this answer because I came over an instance of this in some code and it took me a while to figure out that the key was not the [] operator (which cannot be overloaded with multiple arguments) but the ,operator.
Edit: as pointed in comment, in C++20 operator comma will be deprecated, so as the answer below.
You can't overload operator[], but you can fake it by overloading operator, instead.
Following your code it becomes:
T& operator,(const int i, const int j, const int k){
return m_cells[k*m_resSqr+j*m_res+i];
}
now you'll be able to call
something[1, 2, 3]
You can extend it using templates, templates with variadic arguments, std::pair or std::tuple depending on your use case and C++ version
N-dimensional arrays of arbitrary type and size in C++:
This answer is inspired by the answer of Pavel Radzivilovsky, thanks for that. I had a bit of a hard time realizing the implementation, as it was my first stab at recursive templates. I'd like to share what I have done such that others can understand more quickly than I did.
I have written a c++ template class to create a n-dimensional array of arbitrary type and size. It needs to be instantiated with the array type and the number of dimensions. The size can be changed dynamically. I've given below a bare (stripped) working version of how to create a multidimensional array of which the elements can be accessed through successive application of the operator[] (e.g. array[x][y][z]). This version can only handle arrays of dimension n>1. The main function shows how to create a 4-dimensional array of integers as an example.
EDIT: keep in mind that the example below is minimal for readability, in that it does not deallocate the array, nor does it do bounds checking on access. Adding this is trivial, and left to the programmer.
#include <stdio.h>
#include <stdlib.h>
template <typename T, int N>
struct array {
array<T,N>() : data(NULL), offset((int*) malloc(sizeof(int)*N)){}
array<T,N>(T *data, int *offset) : data(data), offset(offset){}
array<T,N-1> operator[](int i){return array<T,N-1>(&data[i*offset[N]], offset);}
bool resize(int *size){
offset[N-1] = 1;
int total_size = size[N-1];
for(int i = N-2; i >= 0; i--){
total_size *= size[i];
offset[i] = offset[i+1]*size[i+1];
}
return (data = (T*) realloc (data, total_size*sizeof(T)));
}
T *data;
int *offset;
};
template <typename T>
struct array<T,1>{
array<T,1>(T *data, int *offset) : data(data){}
T& operator[](int i){return data[i];}
T *data;
};
int main () {
array<int, 4> a;
// create array with dimensions [1][3][3][7]
int size[4] = { 1, 3, 3, 7 };
a.resize(size);
a[0][1][2][3] = 123;
return 0;
}
Enjoy.

Using [][] operator with vectors?

I have created a one dimensional vector of int, how may I treat it like 2 dimensional one?
While I can write arr[1]; I can't write arr[1][2];
Why I need this:
Instead of defining a vector of vectors [3x5] I defined a vector whose length is 15, so every time I have a function that takes coordinations of a place in matrix I have to call another function which converts those into one dimensional value, which is really annoying.
Assuming you want to treat a 1D array of size N as a 2D array with M columns, then you can write a helper function that computes the 1D index given 2D indexes:
auto in = [M] (int i, int j) { return i * M + j; };
and then use it like this:
arr[in(i,j)];
This is at least preferable to saying arr[i * M + j] everywhere, which is error prone.
Ideally, you would wrap this 1D array into a class that supports 2D indexing.
It seems to me that the best solution is avoid at all the double operator[] and define an at() function that receive two indexes.
Anyway, if you really (really!) want a double operator[] solution, the first one has to return an object with requested data and support the second operator[]
I propose the following skeletal example, where a arr2d (with compile time known dimension) is based over a mono-dimensional std::array.
#include <array>
#include <iostream>
template <typename T, std::size_t Dim1, std::size_t Dim2>
class Arr2d
{
private:
using int_arr_t = std::array<T, Dim1 * Dim2>;
int_arr_t arr{};
public:
struct foo
{
int_arr_t & arr;
std::size_t const i1;
T & operator[] (std::size_t i2)
{ return arr[i1*Dim1 + i2]; }
T const & operator[] (std::size_t i2) const
{ return arr[i1*Dim1 + i2]; }
};
foo operator[] (std::size_t i1)
{ return {arr, i1}; }
foo const operator[] (std::size_t i1) const
{ return {arr, i1}; }
};
int main ()
{
Arr2d<int, 2, 3> a2d;
a2d[1][2] = 3;
std::cout << a2d[1][2] << std::endl;
}
As you can see, the arr2d::operator[] return a foo object containing a reference to the std::array and the first index.
The foo::operator[] complete the job, returning a reference (or a constant reference, according the case) to the right element inside the original std::array.
But, I repepeat: i prefer a couple of at() functions in Arr2d
T & at (std::size_t i1, std::size_t i2)
{ return arr[i1*Dim1 + i2]; }
T const & at (std::size_t i1, std::size_t i2) const
{ return arr[i1*Dim1 + i2]; }
The use of the comma operator was deprecated inside square brackets with C++20. This will in the future enable to write something like m[i, j] for matrix access.
Until then your only chance is to use a member function like at.
A clever and not recommended approach is to have operator[] return some kind of row proxy that has a operator[] on its own to perform the indexing. That is shown here.
Note that storing the row_proxy can lead to dangling pointers which is why operator[]is only implemented for rvalue references.

c++ Pass an array instead of a variable length argument list

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.

Implementing the A(:,k)=b; Matlab-like syntax in a C++ matrix library

I have developed an expression templates-based C++ matrix class of my own. I have overloaded the () operator so that I can read or write element matrices as, for example,
cout << A(i,j) << endl;
and
A(i,j)=b;
respectively.
I have also implemented a Range class to enable Matlab-like reads as
cout << A(Range(3,5),Range(0,10)) << endl;
The template Matrix class is exemplified as
template <typename OutType>
class Matrix
{
private:
int Rows_; //number of Rows
int Columns_; //number of Columns
OutType *data_; //row-major order allocation
public:
// --- Access operators
inline OutType & operator()(const int i, const int j) { return data_[IDX2R(i,j,GetColumns())]; }
inline OutType operator()(const int i, const int j) const { return data_[IDX2R(i,j,GetColumns())]; }
// --- SubExpressions - Range Range
inline Expr<SubMatrixExpr<const OutType*,OutType>,OutType> operator()(Range range1, Range range2)
{ typedef SubMatrixExpr<const OutType*,OutType> SExpr;
return Expr<SExpr,OutType>(SExpr(data_,Rows_,Columns_,range1.numelements_,range2.numelements_,range1.start_,range1.step_,range2.start_,range2.step_),
range1.numelements_,range2.numelements_);
}
}
I would now like to enable Matlab-like assignments as
A(Range(3,5),Range(0,10))=B;
where B is an appropriate matrix.
I think that, to achieve the Matlab-like syntax above, two possibilities would be
overloading the () operator, so that it returns an array of pointers, and then overloading the = operator so that the latter could act between an array of pointers and a Matrix;
exploit the already performed overload of the () operator indicated above and overloading the = operator so that the latter could act between an expression and a Matrix.
Maybe the first option is not very convenient, especilly for very large matrices.
Am I correct? Are there other more efficient/effective possibilities using perhaps more sophisticated C++ features (e.g., move semantics)?
Thank you very much for your help.
I think your best bet is to have a non-const version of operator()(Range, Range) return a proxy object that has an overloaded assignment operator that knows how to assign to a range (back into the original matrix for example).

Write the prototype for a function that takes an array of exactly 16 integers

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