Указание массива на указатель?

Можно ли 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 поплавки, и вы можете это использовать. Позволяет эффективно компилировать пакет вашей структуры и выделять из кучи только то, что вам нужно.