#c #pointers #memory-management #realloc
#c #указатели #управление памятью #перераспределить
Вопрос:
Мне трудно понять, как работать с указателями памяти. У меня есть два указателя (name, adress, optionalInfo), которые указывают на ранее выделенную MyMemory. Размер этих строк может варьироваться. Они хранятся в MyMemory следующим образом:
-------------------------------------------------------------------
| int ID 4Bytes | name 6bytes | adress 8Bytes| optionalInfo 8Bytes|
-------------------------------------------------------------------
Допустим, мне нужно увеличить или уменьшить размер имени и изменить его. Как я могу правильно использовать realloc, чтобы не потерять нужную мне информацию? Как я могу переместить свои аргументы в память, чтобы освободить место для нового имени? Мне нужно использовать наименьший объем памяти.
Это моя структура, изменять ее запрещено.
struct myStruct{
char* name;
char* adress;
char* optionalInfo;
void* myMemory;
};
РЕДАКТИРОВАТЬ: размер MyMemory известен. Name, adress и optionalInfo в этой структуре являются указателями на строки, хранящиеся в MyMemory
Комментарии:
1.
void *tmp = realloc (myMemory, currentsize * 2 * sizeof *myMemory); if (!tmp) { /* handle error */ } myMemory = tmp; ; currentsize *= 2;
(что удвоит количествоmyMemory
указателей)2. Я не уверен, что понимаю. Кажется, вы спрашиваете о данных, на которые указывает
myMemory
член astruct myStruct
, но вы описываете их в терминах тех же идентификаторов, которые используются другими членамиstruct myStruct
. Имеют ли эти другие члены какое-либо отношение к задаче, которую вы пытаетесь выполнить?3. Я подумал, что, возможно
name
, элементы и т. Д. Указывают на пространство, на котороеmyMemory
указывает, но в этом случае их типы немного удивительны и, по-видимому, несовместимы с конкретным примером представленного макета.4. Эта структура кажется противоречивой. Вместо одной структуры, содержащей данные о N вещах, лучше всего создать N структур, представляющих одну вещь каждая. Другими словами,
char* name
и так далее, тогда есть массивmyStruct
. Если кто-то заставляет вас использовать эту структуру, они навязывают вам довольно сложный дизайн.5. Размер
myMemory
не имеет значения. Вы можетеmalloc
использовать любой размер, который хотите. Однакоsizeof(myStruct)
в этой восхитительно странной форме исправлено. Это не изменится. Размер выделенных подэлементов является произвольным и должен быть указан в вашемmalloc()
calloc()
вызове or .
Ответ №1:
Давайте рассмотрим вопрос с точки зрения этого расположения памяти…
------------------------------------------------------------------- | int ID 4Bytes | name 6bytes | adress 8Bytes| optionalInfo 8Bytes| -------------------------------------------------------------------
… игнорирование того, как это может относиться к членам struct myStruct
, отличным от myMemory
.
Допустим, мне нужно увеличить или уменьшить размер имени и изменить его. Как я могу правильно использовать realloc, чтобы не потерять нужную мне информацию?
До тех пор, пока вы realloc
используете размер, по крайней мере, такой же большой, как уже занимаемые данные, никакие данные не будут потеряны при перераспределении. Ни один из них не будет перемещен относительно начального адреса блока. Обратите внимание, однако, что перераспределенный блок может находиться в другом месте, чем исходный, и если это так, то исходный блок будет освобожден и к нему больше нельзя будет обращаться.
Как я могу переместить свои аргументы в память, чтобы освободить место для нового имени?
Наиболее очевидным инструментом для этой работы будет memmove()
функция. Итак, предположим, что вы хотите увеличить размер области с надписью «name» с 6 байт, скажем, до 10 байт, без перезаписи каких-либо других данных, сначала вам нужно перераспределить:
void *temp = realloc(x.myMemory, old_size 4);
Поскольку realloc()
успех не гарантируется, вы не должны обновлять x.myMemory
указатель до тех пор, пока не убедитесь, что он был успешным:
if (temp) { // if temp is non-null
Затем вы можете переместить данные адреса и optionalInfo в большее пространство, чтобы освободить место для дополнительной информации об имени:
memmove(((char *)temp) new_offset_of_address_data,
((char *)temp) old_offset_of_address_data,
combined_size_of_address_and_optionalInfo_data);
Приведение к типу char *
необходимо, потому что арифметика указателей определяется в терминах единиц указываемого типа и, следовательно, вообще не определена для указателей на void
.
Не забудьте назначить новый указатель на вашу структуру:
x.myMemory = temp;
}