Как я уже сказал в комментарии, variable
представляет собой массив указателей, а не указатель на массив.
Чтобы оставить без изменений, variable
myFunction
должен быть повторно объявлен принять Type **
аргумент, так что вы можете назвать его как myFunction(variable)
.
не
Однако, когда вы называете это так, тип аргумента функции больше не массив, а указатель (в выражении, кроме декларации или операндов sizeof
или одноместный &
, массив распадается к указатель на тип элементов), поэтому вы теряете информацию о размере массива.
Чтобы исправить это, классическое решение C-стиля должно добавить дополнительный аргумент функции, чтобы вы могли рассказать ему, что такое количество аргументов.
void myFunction(Type **arr_to_ptrs, size_t ptr_count);
Тем не менее с C, если вы гарантировать, что вы всегда будете вызывать функцию с аргументом, который объявлен как массив или что-то решает в массив на уровне языка (в отличие от указателя, который может быть используется как массив через динамическое распределение), вы можете определить макрос для вычисления количества элементов.
#define myFunction_1arg(x) myFunction(x, sizeof x/sizeof x[0])
Опять же, все, что вы используете в качестве аргумента myFunction_1arg
макрос должен быть массивом на уровне языка. Использование указателя, поскольку его аргумент, вероятно, нарушит вашу программу.
С C++, почти каждое использование родных массивов может быть в более общем и безопасно решать с std::vector
и менее в целом с std::array
.
Однако, если вы действительно хотите придерживаться встроенных массивов, вы все равно можете использовать некоторые функции C++. Программа ниже может дать вам представление.
#include <iostream>
#include <cstddef>
const char a[]="ab"; // array
const char *ap[]={"aa", "bb", nullptr}; // array of pointers
const char (*pa)[3]=&a; // pointer to array of three elements
// This function takes an array (by reference).
template <typename T, size_t sz> void f(T (&arr)[sz]){
std::cout << "array-templated f(): addr=" << static_cast<const void *>(arr) << ", size=" << sz << '\n';
}
// This function takes a pointer (by lvalue reference).
template <typename T> void f(T *const &arr){
std::cout << "lvalue-ref-pointer-templated f(): addr=" << static_cast<const void *>(arr) << ", unspecified size\n";
}
// This function takes a pointer (by rvalue reference).
template <typename T> void f(T *const &&arr){
std::cout << "rvalue-ref-pointer-templated f(): addr=" << static_cast<const void *>(arr) << ", unspecified size\n";
}
// This function takes a pointer and its size (by value).
template <typename T> void f(T *arr, size_t sz){
std::cout << "pointer-templated f(): addr=" << static_cast<const void *>(arr) << ", manual size=" << sz << "\n";
}
int main(){
f(a);
f(ap);
f(pa);
std::cout << '\n';
f(0+a);
f(0+ap);
f(0+pa);
std::cout << '\n';
f(a, 1); // You can lie here, but you shouldn't
f(ap, 10); // You can lie here, but you shouldn't
f(pa, 100); // You can lie here, but you shouldn't
std::cout << '\n';
f(0+a, 1); // You can lie here, but you shouldn't
f(0+ap, 10); // You can lie here, but you shouldn't
f(0+pa, 100); // You can lie here, but you shouldn't
std::cout << '\n';
auto *p=a;
auto *pp=ap;
auto *pa2=pa; // pa2 and pa are the same type: pa is already a pointer
f(p);
f(pp);
f(pa2);
std::cout << '\n';
f(p, 1); // You can lie here, but you shouldn't
f(pp, 10); // You can lie here, but you shouldn't
f(pa2, 100); // You can lie here, but you shouldn't
std::cout << '\n';
f(0+p, 1); // You can lie here, but you shouldn't
f(0+pp, 10); // You can lie here, but you shouldn't
f(0+pa2, 100); // You can lie here, but you shouldn't
}
Выход для этой программы несколько похож на приведенный ниже.
array-templated f(): addr=0x40106d, size=3
array-templated f(): addr=0x602070, size=3
lvalue-ref-pointer-templated f(): addr=0x40106d, unspecified size
rvalue-ref-pointer-templated f(): addr=0x40106d, unspecified size
rvalue-ref-pointer-templated f(): addr=0x602070, unspecified size
rvalue-ref-pointer-templated f(): addr=0x40106d, unspecified size
pointer-templated f(): addr=0x40106d, manual size=1
pointer-templated f(): addr=0x602070, manual size=10
pointer-templated f(): addr=0x40106d, manual size=100
pointer-templated f(): addr=0x40106d, manual size=1
pointer-templated f(): addr=0x602070, manual size=10
pointer-templated f(): addr=0x40106d, manual size=100
lvalue-ref-pointer-templated f(): addr=0x40106d, unspecified size
lvalue-ref-pointer-templated f(): addr=0x602070, unspecified size
lvalue-ref-pointer-templated f(): addr=0x40106d, unspecified size
pointer-templated f(): addr=0x40106d, manual size=1
pointer-templated f(): addr=0x602070, manual size=10
pointer-templated f(): addr=0x40106d, manual size=100
pointer-templated f(): addr=0x40106d, manual size=1
pointer-templated f(): addr=0x602070, manual size=10
pointer-templated f(): addr=0x40106d, manual size=100
Вы должны указать размер рядом с указателем. Нет никакого способа обойти это, кроме использования ['array_view'] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3851.pdf), который может быть включен в будущее STL –
'variable' - это массив указателей, а не указатель на массив. Чтобы оставить 'переменную' неизменной,' myFunction' должен быть переопределен для принятия аргумента 'Type **', – Paulo1205
Почему 'variable' является массивом' Type * ', является' Type' polymorphic? – fredoverflow