Как вернуть массив, не выделяя его, если размер неизвестен вызывающей стороне? - PullRequest
2 голосов
/ 05 августа 2010

Рассмотрим следующую функцию:

int get_something (int* array, int size);

Его цель - заполнить переданный массив [размер] данными из внешнего ресурса (запросы к ресурсу дороги). Вопрос в том, что делать, если ресурс имеет больше элементов, чем может обработать предоставленный массив? Каков наилучший подход?

Редактировать: Текущее решение добавлено:

Наш подход на данный момент следующий:

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

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

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

Если пользователь вызывает get_something () слишком поздно, и данные были очищены, мы генерируем состояние ошибки, поэтому пользователь знает, что он должен повторить запрос.

Ответы [ 7 ]

5 голосов
/ 05 августа 2010

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

2 голосов
/ 05 августа 2010

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

Это означает, что вам придется выделить память в вашей программе для хранения всех данных..

Проблема № 1 заключается в заполнении этого кэша.Я предполагаю, что вы это выяснили, и есть какая-то функция get_resource ();

проблема № 2 состоит в том, как создать API, чтобы позволить клиентскому / пользовательскому коду взаимодействовать с этими данными.

В вашем примере вы используете массив, выделенный клиентом, в качестве кэша, надеясь решить обе проблемы с 1 буфером, но это не решает проблему во всех случаях (следовательно, ваше размещение).Таким образом, вам действительно нужно разделить 2 задачи.

Модель № 1 должна обеспечивать функциональность итератора / курсора

iterator = get_something();  // Triggers caching of data from Resource
data = get_next_single_something( iterator );
status = release_something( iterator );

// The logic to release the data could be done automagically in get_next, 
// after returning the last single_something, if that is always the use case.

Модель # 2 - возвращать весь объект в буфере с ошибками,и пусть клиент управляет всем этим

data_type *pData=NULL;
unsigned size = get_something( &pData ); // Triggers caching of data from Resource
process( size, pData );
free( pData );
pData=NULL;

Модель # 3.Если вы состоите в браке с клиентским массивом, вы можете использовать Модель # 1 для одновременного возврата нескольких значений, , но , если есть другие значения, тогда get_something () придется построитькэша, и клиент все равно должен будет выполнить итерацию.

2 голосов
/ 05 августа 2010

Мой выбор - использовать ту же модель, что и fread () и превратить интерфейс в поток сортировок.

т.е.

  • либо заполнитьбуфер поднимает или помещает все элементы в него и возвращает количество фактически прочитанных элементов
  • поддерживает какое-то состояние, так что последующие вызовы получают только непрочитанные элементы
  • возвращают 0, как только все элементы имеютпрочитано
  • вернуть отрицательное число, если произошла ошибка.
2 голосов
/ 05 августа 2010

Используйте realloc. Ссылка .

1 голос
/ 05 августа 2010

выделяет массив динамически, т.е. используя malloc (), а затем в функции либо использует realloc (), либо освобождает предыдущий список и выделяет другой, заполняет его и возвращает новый размер.Для второго подхода вы можете использовать возвращаемое значение для возврата нового размера, но чтобы обновить адрес вызывающего массива, вам нужно изменить функцию так, чтобы она принимала int ** вместо int *

0 голосов
/ 05 августа 2010

Это зависит от того, как ваша программа должна справиться с этой ситуацией, я думаю.

Один из подходов может заключаться в том, чтобы заполнить массив до максимума и вернуть total количество элементов, которыеимеется в наличии.Таким образом, вызывающий абонент может проверить, нужно ли ему снова вызывать функцию (см. Ответ Марка Байерса).

Логика позади этого:

- Creates array with 100 items
- Calls your function and gets 150 returned
- Increases the array size or creates a second one
  and calls your function again with that array
- Repeats that unless the returned item count is
  equal or less the array size
0 голосов
/ 05 августа 2010

Можете ли вы проверить, сколько элементов имеет ресурс?Если это так, я бы сделал это, а затем скопировал массив в массив размером с ресурс.

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

http://www.devx.com/tips/Tip/13291

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...