безопасное изменение размера структур

#c #struct #malloc

#c #структура #malloc

Вопрос:

Я хотел бы получить несколько советов о безопасных способах работы со структурами, когда размер определенных элементов неизвестен во время кода.

Например, у меня есть структура с именем «Channel». Эта структура имеет имя элемента «AudioSourceOBJ», которое является указателем на массив другого типа структуры с именем «AudioSource». Я не буду знать, сколько аудиоисточников у меня будет на канал, пока программа не будет запущена. Я разбираюсь с этим следующим образом.

объект канала

 struct channelobj {

        AudioUnitSampleType *leftoutput;
    AudioUnitSampleType *rightoutput;
    AudioSourceOBJ *audioSource;



};
  

аудиоисточник

 struct audiosourceobj {


    AudioUnitSampleType   *leftoutput;
    AudioUnitSampleType   *rightoutput;


};
  

создание структур переменного размера

 void createInputs(ChannelOBJ channel,int numAudioInputs)
{
    channel->audioSource=(AudioSourceOBJ *)malloc(numAudioInputs * sizeof(AudioSourceOBJ));

    for (int i=0;i<numAudioInputs;i  )
    {
        AudioSourceOBJ obj;
        obj=newAudioSourceOBJ();
        channel->audioSource[i]=obj;

    }
}
  

Я думаю, это нормально?

Проблема, с которой я сейчас сталкиваюсь, заключается в том, что, хотя я могу назначить память для правильного количества аудиообъектов в моей структуре канала, массивы leftoutput и rightoutput в структуре audiosource будут установлены только позже в программе. Они будут заполнены ограниченным объемом данных и, вероятно, будут меняться в размере и содержимом на протяжении всего срока службы приложения.

Придется ли мне полностью переназначать канал, содержащий аудиоисточник, каждый раз, когда я хочу внести изменения в один аудиообъект?

Какой безопасный способ сделать это или есть лучший подход?

Ответ №1:

«Придется ли мне полностью переназначать канал, содержащий аудиоисточник, каждый раз, когда я хочу внести изменения в один аудиообъект?»

Нет. Вы могли бы, например, заменить левый выходной сигнал i -го источника звука следующим образом:

 free(channel->audioSource[i].leftoutput);
channel->audioSource[i].leftoutput = malloc(newSize * sizeof(AudioUnitSampleType));
  

Или даже:

 AudioUnitSampleType *tmp = realloc(channel->audioSource[i].leftoutput,
    newSize * sizeof(*tmp));
if (tmp == 0) { /* handle the error */ }
channel->audioSource[i].leftoutput = tmp;
  

Кстати, если вы не публикуете реальный код, возможно, что ответы будут содержать ошибки из-за ошибок в ваших примерах.

Кажется, в вашем коде есть некоторая путаница между указателями и объектами, например, channel параметр имеет тип ChannelOBJ , тогда вы используете его как указатель. Это ошибка или ChannelOBJ определение типа для struct channelobj* ? Обычно лучше не скрывать, что что-то является указателем, используя typedef.

Если AudioUnitSampleType также является типом указателя, то мой первый фрагмент кода выше является неполным, поскольку тогда также было бы необходимо освободить старые объекты, на которые указывают элементы массива, и выделить новые. Второй должен освободить старые структуры или выделить новые в зависимости от того, увеличивается или уменьшается размер.

Комментарии:

1. Да, ChannelOBJ является определением типа для структуры channelobj. Почему вы предлагаете не использовать typedef в этом случае?

2. @dubbeat: потому что C — это не Java;-p. На самом деле, потому что людям часто нужно знать, является ли данный тип «действительно» указателем или нет, всякий раз, когда они просматривают код, который воздействует на него. Например, мне нужно было знать, что такое AudioUnitSampleType , чтобы писать свои фрагменты кода. Даже если вы используете ChannelOBJ как полностью непрозрачный тип для клиентов вашего API, и это то, что отображается в файлах заголовков, которые они используют, я бы использовал struct channelobj* в качестве параметра при реализации функции, потому что в функции мне нужно знать, что это указатель (использовать -> вместо . ).

3. Итак, скрытие этого ChannelOBJ указателя может быть полезной абстракцией для клиентов вашего API, если они будут рассматривать его как бессмысленный дескриптор и использовать его только для передачи в ваши функции. Но это бесполезная абстракция, как только вы попадаете внутрь createInputs функции, она просто скрывает то, что мне (читателю или программисту) нужно знать. Абстракции должны скрывать то, что мне не нужно знать.

4. спасибо за подробное объяснение.

Ответ №2:

Нет, вам не придется изменять размер выделенного блока AudioSourceObj структур. leftoutput и rightoutput — это просто указатели фиксированного размера (не массивы переменного размера), которым можно присвоить адрес, выполнив отдельный malloc :

 channel->audioSource[i].leftoutput = malloc(5 * sizeof(AudioUnitSampleType));