Указание массива на указатель?
Можно ли typedef массив?
У меня есть набор векторных функций, которые все принимают указатель на float, который представляет собой массив из трех поплавков. Я могу typedef float * vec3_t, однако он не позволит мне создать объект, просто установив его равным массиву в скобках.
typedef float* vec3_t;
vec3_t a = {1,1,1}; // Does not work
vec3_t b = (float[]){1,1,1}; // Works
float c[] = {1,1,1}; // Works
void f(vec3_t x);
f({1,1,1}); // Error
f((float[]){1,1,1}; // OK
Может кто-нибудь объяснить, почему это работает таким образом?
Ответы
Ответ 1
Указатель и массив - это не одно и то же. Хотя они часто ведут себя одинаково, есть существенные различия, один из которых вы только что обнаружили.
Что делает ваш код на самом деле
Я заменил тип typedefed на реальный тип, чтобы упростить объяснение.
float c[] = {1,1,1};
Вы просто создали и инициализировали массив
f({1,1,1});
Код выше не является ни значением lvalue, ни rvalue. Синтаксис {val1,...,valn}
- это не что иное, как инициализатор и не может использоваться здесь.
float* b = (float[]){1,1,1};
Здесь вы создали и инициализировали массив, а , затем сохранили его местоположение в указателе.
f((float[]){1,1,1};
Этот случай совпадает с приведенным выше, но вместо сохранения указателя вы передаете его как аргумент функции.
float* a = {1,1,1};
Вы пытаетесь записать три переменные в ячейку памяти, которая еще не выделена.
В общем случае {valn,...,valn}
является инициализатором. В этот момент вам нечего инициализировать. Следовательно, этот синтаксис недействителен. Вы пытаетесь влить газ в канистру, которая еще не была изготовлена.
Пока я понимаю, чего вы хотели достичь, вы, кажется, недооцениваете всю концепцию памяти и указателей. Представьте себе этот код, который (в некоторой грязной логике) является эквивалентом того, что вы пытаетесь сделать:
float* a = NULL;
a[0] = 1;
a[1] = 1;
a[2] = 1;
Что произойдет, если вы выполните этот код?
Итак, теперь вы знаете, почему компилятор запрещает его.
Ответ 2
У вас есть много разных функций, сложенных в ваш код, поэтому не совсем понятно, что вы подразумеваете под "почему это работает таким образом". Что конкретно "this"?
Во всяком случае, чтобы "typedef a array" вам пришлось набирать массив, а не указатель
typedef float vec3_t[3];
после чего вы сможете сделать
vec3_t a = { 1, 1, 1 };
Остальная часть вашего кода не имеет ничего общего с типизацией массива. Вы просто обнаружили составной буквенный синтаксис, который идет как (non-scalar-type) { initializers }
и создает безымянный временный объект данного типа. Часть (non-scalar-type)
является важной частью синтаксиса составного литерала. Вы не можете его пропустить.
Итак, вместо того, чтобы делать
vec3_t a = { 1, 1, 1 };
f(a);
если вы не хотите иметь именованный массив a
, вы можете просто сделать
f((vec3_t) { 1, 1, 1 });
или
f((float [3]) { 1, 1, 1 });
или
f((float []) { 1, 1, 1 });
с тем же эффектом.
Ответ 3
Массив не является указателем. Массив имеет базовый указатель. Но в любом случае наиболее подходящая структура данных для того, что вы пытаетесь достичь, будет примерно такой:
struct{
float x;
float y;
float z;
} myFloat3;
Массивы удобны для структур переменной длины и т.д., но не самый эффективный выбор, так как вы ЗНАЕТЕ, что у вас 3 поплавки, и вы можете это использовать. Позволяет эффективно компилировать пакет вашей структуры и выделять из кучи только то, что вам нужно.