Typedef неограниченный массив с плавающей точкой в ​​C - PullRequest
8 голосов
/ 29 ноября 2011

Я сделал typedef для массивов с плавающей точкой, например:

typedef float fooType[];

Чтобы я мог объявлять и инициализировать массивы с плавающей точкой статически следующим образом:

fooType myArray = {1.0, 2.0, 3.0}

Это отлично работает. Я могу сказать myArray[2] без проблем и вообще использовать мой fooType, как мне хотелось бы. В контексте моей программы очень ясно, что fooType является типом массива (на самом деле это гигантская таблица поиска), поэтому я не просто делаю typedef float fooType.

Как мне тогда объявить и использовать переменную для указания на bar и доступа к элементам bar? Я не могу объявить простую переменную, подобную этой:

fooType bar = myArray;

С тех пор ошибки с invalid initializer; Я не ожидал, что это сработает, так как компилятор не знает, сколько памяти выделить. Я попробовал несколько вещей с указателями:

fooType *bar = myArray; 

Это выдает предупреждение: initialization from incompatible pointer type и ошибки, когда я обращаюсь к элементам с bar[1] .. Это объявляет нормально, как я и ожидал, поскольку типы теперь совпадают:

fooType *bar = &myArray;

Но, как и выше, ошибки компилятора с invalid use of array with unspecified bounds, когда я говорю bar[1].

Это работает:

float *bar = myArray; 
float val = bar[3]; 

Но я не хочу этого, потому что теряю читабельность моего typedef.

Я давно похоронен в приятном ОО-мире (Java), поэтому я надеюсь понять из этого, что идиоматично в Си в этой ситуации. Я вполне готов изменить свое использование typedef в соответствии с соглашением, если нет прямого решения. Я чувствую, что есть, и это не сложно.

Спасибо

Ответы [ 3 ]

5 голосов
/ 29 ноября 2011

Проблема, с которой вы здесь сталкиваетесь, заключается в том, что массивы не являются указателями в C, а скорее распадаются на указатели на первый элемент при использовании в правой части оператора присваивания.Таким образом, если вы объявляете массив типа

fooType myArray = {1.0, 2.0, 3.0}

, тип myArray равен float[3], а & myArray равен (*float)[3], или «указатель на массив из 3 чисел с плавающей запятой».Таким образом, вы не можете просто сказать

fooType *bar = myArray;

Тип fooType* не является указателем на число с плавающей точкой ... поэтому это несовместимый тип указателя.Выполнение

fooType* bar = &myArray;

работает, но проблема, с которой вы сталкиваетесь, заключается в том, что bar[1] не является элементом в массиве myArray, так как сам bar является указателем.Вам нужно разыменовать bar как (*bar)[1] для доступа к элементу в myArray.Например:

typedef float fooType[];
fooType myArray = {1.0, 2.0, 3.0}
fooType* bar = &myArray;
(*bar)[1] = 5.0;

Наконец, имейте в виду, что с C вы не можете назначить один массив другому массиву ... так что вы можете сделать что-то вроде:

fooType bar = myArray;

Это восходит ко всей проблеме массивов и их распаду на указатели на первый элемент, а также к тому факту, что тип самого массива не совпадает с типом первого элемента в массиве.

В конце концов, вы можете просто захотеть ввести typedef для массива, а затем typedef для типов элементов массива, используя float, чтобы каждый, кто использует ваш код, знал, какой элемент одного типа принадлежит другому.

1 голос
/ 29 ноября 2011

Вы смешали C с Java.

Попробуйте изменить свой typedef на

typedef float *fooType;

Впоследствии, однако, вы не сможете инициализировать переменную типа fooType, например

fooType myArray = {1.0, 2.0, 3.0};

потому что fooType теперь является указателем.

0 голосов
/ 30 мая 2017

Использование Visual Studio 2013 Я обнаружил, что вы можете использовать конструкции, такие как в этом примере.Это также похоже на работу с Visual Studio 2015.

Обратите внимание, что для использования malloc() для создания массива fooType требуется указатель с разыменованным типом pfooType, а не тип fooType или*pfooType для компиляции.Я изменил typedef с float на double, а sizeof(*p2) изменил с 4 до 8 байт, как и ожидалось.

#include <malloc.h>

typedef float fooType[], *pfooType;

int xxmain2(void)
{
    fooType myArray = { 1.0, 2.0, 3.0 };   // define the array with its elements
    pfooType p = myArray;   // get a pointer to the array.
    int i;
    int  nElements = sizeof(myArray) / sizeof(*p);  // determine number of elements in the array.

    pfooType p2 = malloc(sizeof(*p2) * 5);  // malloc() an array of 5 elements.

    for (i = 0; i < 5; i++) p2[i] = (float)i * 10.0;  // initialize my malloced array.
    myArray[0] = *p;       // dereference pointer
    myArray[1] = p[1];     // use array subscripting with pointer

    for (i = 0, p = myArray; i < nElements; i++) *p++ = 0;   // increment the pointer to traverse the array.

    free(p2);
    return 0;
}

Я также обнаружил, что не могу создать указанный размермассив с чем-то вроде fooType myRay2[10]; (ошибка компиляции «ошибка C2087:« myRay2 »: отсутствует индекс») или что-то подобное.И fooType myRay2; выдает ошибку компиляции "error C2133: 'myRay2': неизвестный размер".

Таким образом, кажется, что единственный способ - использовать инициализацию для определения размера массива или malloc() для созданиямассив определенного размера, который затем требует free().

...