Как переместить аргументы в динамически выделяемую память?

#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 член a struct 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;
}