Изменение размера char[x] до char[y] во время выполнения

Хорошо, я надеюсь, что объясню это правильно. У меня есть структура:

typedef struct _MyData
{
   char Data[256];
   int  Index;
} MyData;

Теперь я столкнулся с проблемой. Большую часть времени MyData.Data работает с 256, но в некоторых случаях мне нужно увеличить количество символов, которые оно может содержать, до разных размеров. Я не могу использовать указатель. Есть ли способ изменить размер данных во время выполнения? Как? Код ценится.

Спасибо

РЕДАКТИРОВАТЬ:

Хотя я очень благодарен за все комментарии, комментарии "возможно, попробуйте это..." или "сделайте это", или "то, что вы делаете не так...", не помогают. код здесь помощь Пожалуйста, если вы знаете ответ, напишите код.

а также:

1- не может использовать указатели. пожалуйста, не пытайтесь понять, почему, я просто не могу 2- структура вводится в память другой программы. вот почему. нет указателей.

извините за грубость здесь, но я задал вопрос здесь, потому что я уже попробовал все различные подходы, которые, как думала, могли бы работать Опять же, я ищу код. На данный момент меня не интересуют слова "может сработать..." или "ты обдумал это..."

еще раз спасибо и мои извинения

РЕДАКТИРОВАТЬ 2

Почему это было установлено как ответ?

11 ответов

Решение

Вы можете использовать гибкий член массива

typedef struct _MyData
{
   int  Index;
   char Data[];
} MyData;

Так что вы можете выделить нужное количество места

MyData *d = malloc(sizeof *d + sizeof(char[100]));
d->Data[0..99] = ...;

Позже вы можете освободить и выделить другой кусок памяти и сделать указатель на MyData укажите на это, когда у вас будет больше / меньше элементов в элементе гибкого массива (realloc). Обратите внимание, что вам также придется где-то сохранить длину.

Во времена до C99 нет гибкого элемента массива: char Data[] просто рассматривается как массив с неполным типом, и компилятор будет стонать об этом. Здесь я рекомендую вам два возможных выхода

  • Используя указатель: char *Data и сделать это указать на выделенную память. Это будет не так удобно, как использование встроенного массива, потому что вам, возможно, понадобится два выделения: одно для структуры и одно для памяти, на которую указывает указатель. Вместо этого вы также можете разместить структуру в стеке, если ситуация в вашей программе позволяет это.
  • Используя char Data[1] вместо этого, но обрабатывайте его так, как если бы он был больше, чтобы он перекрывал весь выделенный объект. Это формально неопределенное поведение, но это распространенный метод, поэтому его можно безопасно использовать с вашим компилятором.

Проблема здесь в том, что вы говорите: "Я не могу использовать указатель". Вам придется, и это все сделает намного проще. Эй, realloc даже копирует ваши существующие данные, что вы хотите больше?

Так почему вы думаете, что не можете использовать указатель? Лучше попытаться это исправить.

Вы бы перестроить структуру так

typedef struct _MyData
{
   int  Index;
   char Data[256];
} MyData;

И распределите экземпляры с помощью malloc/realloc следующим образом:

my_data = (MyData*) malloc ( sizeof(MyData) + extra_space_needed );

Это уродливый подход, и я бы не рекомендовал его (я бы использовал указатели), но это ответ на ваш вопрос, как это сделать без указателя.

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

Позвольте мне суммировать два важных момента, которые я вижу в этой теме:

  1. Структура используется для взаимодействия между двумя программами через некоторый механизм IPC
  2. Программа назначения не может быть изменена

Поэтому вы не можете изменить эту структуру каким-либо образом, потому что целевая программа застряла, пытаясь прочитать ее, как определено в данный момент. Боюсь, вы застряли.

Вы можете попытаться найти способы получить эквивалентное поведение или найти какой-то злой взлом, чтобы заставить целевую программу прочитать новую структуру (например, изменить двоичные смещения в исполняемом файле). Это все довольно специфично для конкретного приложения, поэтому я не могу дать гораздо лучшего руководства, чем это.

Вы можете написать третью программу, которая станет интерфейсом между ними. Он может принимать "длинные" сообщения, что-то с ними делать и передавать "короткие" сообщения в старую программу. Вы можете внедрить это между механизмами IPC довольно легко.

Вы можете сделать это следующим образом, не выделяя указатель для массива:

typedef struct _MyData
{
    int Index;
    char Data[1];
} MyData;

Позже вы выделяете так:

int bcount = 256;
MyData *foo;

foo = (MyData *)malloc(sizeof(*foo) + bcount);

Realloc:

int newbcount = 512;
MyData *resized_foo;

resized_foo = realloc((void *)foo, sizeof(*foo) + newbcount);

Проблема в том, как вы задаете вопрос. Не думайте о семантике C: вместо этого думайте как хакер. Объясните , как именно вы в настоящий момент вовлекаете свои данные в другой процесс, атакже как другая программа знает, где данные начинаются и заканчиваются. Другая программа ожидает строку с нулевым символом в конце? Если вы объявляете свою структуру с символом [300], происходит ли сбой другой программы?

Видите ли, когда вы говорите "передача данных" другой программе, вы можете [a] обманом заставить другой процесс скопировать то, что вы поставили перед ним, [b] обманом другой программы, чтобы позволить вам перезаписать ее обычно "частную" 'память, или [c] какой-то другой подход. Независимо от того, что имеет место, если другая программа может взять ваши большие данные, есть способ получить их.

Из того, что ты говоришь, похоже, что ты обязательно должен MyData как статический блок данных. В таком случае, я думаю, что единственный вариант, который вам доступен, - это каким-то образом (необязательно) связать эти структуры данных вместе, чтобы их можно было повторно собрать в другом процессе.

Вам понадобится и дополнительный член в MyDataнапример

typedef struct _MyData
{
   int  Sequence;
   char Data[256];
   int  Index;
} MyData;

куда Sequence идентифицирует нисходящую последовательность для повторной сборки данных (нулевой порядковый номер будет указывать на конечный буфер данных).

Вы не можете перерабатывать вручную.

Вы можете сделать несколько трюков, с которыми я работал, когда работал над простой системой хранения данных. (очень простая файловая система).

typedef struct
{
    int index ;     
    char x[250];
} data_ztorage_250_char;

typedef struct
{
    int index;      
    char x[1000];
} data_ztorage_1000_char;

int main(void)
{
      char just_raw_data[sizeof(data_ztorage_1000_char)];
      data_ztorage_1000_char* big_struct;
      data_ztorage_250_char* small_struct;
      big_struct = (data_ztorage_1000_char*)big_struct; //now you have bigg struct
      // notice that upper line is same as writing 
      // big_struct = (data_ztorage_1000_char*)(&just_raw_data[0]);

      small_struct = (data_ztorage_250_char*)just_raw_data;//now you have small struct

      //both structs starts at same locations and they share same memory
     //addresing data is 
      small_struct -> index = 250;
}

Как насчет действительно очень простого решения? Не могли бы вы сделать:

typedef struct _MyData
{
   char Data[1024];
   int  Index;
} MyData;

У меня такое чувство, что я знаю, что ваш ответ будет "Нет, потому что другая программа, которую я не контролирую, ожидает 256 байтов"... И если это действительно ваш ответ на мой ответ, то мой ответ становится: это невозможно,

Вы не указываете, для чего используется значение индекса.

Насколько я понимаю, вы передаете данные в другую программу, используя показанную структуру. Есть ли причина, по которой вы не можете разбить данные на куски по 256 байт, а затем соответственно установить значение индекса? например

Данные имеют размер 512 байт, поэтому вы отправляете одну структуру с первыми 256 байтами и индексом =0, затем другую со следующими 256 байтами в вашем массиве и индексом =1.

Я нахожу KIVПрикол вполне годный к употреблению. Хотя я бы посоветовал сначала изучить проблему с указателями.

Если вы посмотрите на реализации malloc
( проверьте эту статью IBM, Листинг 5: Псевдокод для основного распределителя),
Когда вы выделяете, менеджер памяти выделяет контрольный заголовок и
затем освободите место в соответствии с вашим размером.
Это очень похоже на высказывание:

typedef struct _MyData
{
   int  size;
   char Data[1]; // we are going to break the array-bound up-to size length
} MyData;

Теперь ваша проблема в том,
Как вы передаете такую ​​(не по размеру?) Структуру этому другому процессу?

Это подводит нас к вопросу,
Как другой процесс определяет размер этих данных?
Я бы ожидал length поле как часть общения.

Если у вас есть все это, что не так с передачей указателя на другой процесс?
Будет ли другой процесс определять разницу между указателем на структуру и указателем на выделенную память?

Другие вопросы по тегам