LINUX.ORG.RU

Размер malloc для структуры с char * в Си

 


1

2

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

Но если у меня в структуре char *, т.е. какая-то строка размер которой я пока что не знаю, как выделять память с malloc?

Ответ на: комментарий от XMs

Не, это понятно для одной строки. А допустим есть структура:

typedef struct str_struct
{
	int		size;
	char	*str;
}	str_struct;

И я хочу сделать массив таких структур в куче. А потом заполнять строки. Каким образом мне делать malloc для каждого экземпляра структуры?

dffrwpv
() автор топика
Ответ на: комментарий от dffrwpv
str_struct *struct_array = calloc(sizeof(str_struct) * N);

Память под строки выделяешь отдельно:

int str_struct_set_string(str_struct *my_struct, char *string)
{
    assert(my_struct);
    assert(string);
    size_t count = strlen(string);
    int res = malloc(count);
    if (res == NULL)
        return NULL;
    memcpy(my_struct->str, string, count);
    my_struct->size = (int)count;
}

Терминальный нуль в примере не копирую, так как у тебя есть отдельное поле под размер

XMs ★★★★★
()

Так же и выделять, у тебя в структуре указатель на данные, а не сами данные и размер структуры будет одинаков что с char * указывающем на 1 байт что на 1гигабайт. Выделяешь память под структуру как обычно, выделяешь память под строку, передаёшь указатель на строку в указатель на строку в структуре. Удалять в обратном порядке, сначала строку, потом структуру.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от dffrwpv

Я тут подумал и, кажется, понял, что тебе нужно:

typedef struct
{
    size_t size;
    // Остальные служебные поля
} my_struct;

void *my_struct_set_string(void **mystruct, char *str)
{
    assert(mystruct);
    assert(str);
    size_t count = strlen(str);
    …
    
    my_struct *tmp = realloc(*mystruct, sizeof(my_struct) + count);
    if (tmp == NULL)
        return NULL;
    *mystruct = tmp;
    tmp->size = count;
    …
    memcpy(tmp + 1, str, count);
    return tmp;
}

char *my_struct_get_string(void *mystruct, size_t *count)
{
    assert(mystruct);
    assert(count);
    my_struct *metainfo = mystruct;
    void *data = metainfo + 1;
    *count = metainfo->size;
    return data;
}

…

size_t arraysize = get_array_size();
void *mystructs[arraysize];
for (size_t i = 0; i < arraysize; ++i)
{
    …
}

XMs ★★★★★
()
Последнее исправление: XMs (всего исправлений: 2)
Ответ на: комментарий от pihter

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

Не заметил реакции, изиняюся ^.^

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от XMs

Спасибо, понял как все работает. Все оказывается очень просто :)

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

dffrwpv
() автор топика
Ответ на: комментарий от dffrwpv

а уже строки в каждом экземпляре выделять с помощью strdup.

Не забудь освобождать память после strdup() через free(), иначе можно наплодить утечек памяти.

А если все те строки которыми ты оперируешь являются ASCII 8-bit и ограничены длиной в 2-4 kB (2048-4096 символов) можно значительно упростить код и избежать кучи реаллокаций, используя:

#define MAX_STRING_LENGTH (2048)

typedef struct
{
	int size;
	char str[MAX_STRING_LENGTH];
} str_struct;
EXL ★★★★★
()
Ответ на: комментарий от EXL

Можно много чего сделать чтобы не текло, но совет исключительно вредный - вот именно ТАК не надо делать никогда (я про fixed 2k size). По многим соображениям.

bugfixer ★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
Ответ на: комментарий от bugfixer

ТАК не надо делать никогда (я про fixed 2k size). По многим соображениям.

Так озвучь их.

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

EXL ★★★★★
()
Ответ на: комментарий от EXL

ТС не упомянул какого вида там у него строки

Именно. Если Вы SSO в примитивной форме задумали - то как мин нужна статистика по real usage. Может у товарища строчки меньше 10 символов обычно? Overhead на пустом месте - сами посчитайте. А если не дай бог у него строка больше 2k попадётся - всё, привет.

bugfixer ★★★★
()
struct some {
  char *string;
}

struct some object;
object.string = malloc(sizeof(char)*1000);
free(object.string);

Но если строки небольшие, то сделай просто массив фиксированного размера. Например char string [201] (не забудь про null-terminator). Даже если реально будет нужно 50 символов из 200, системные вызовы будут стоить дороже + лишние пляски с проверкой malloc и выполнением free. (Пиши аналог конструктора и деструктора структуры)

zx_gamer ★★
()
Ответ на: комментарий от zx_gamer

если строки небольшие, то сделай просто массив фиксированного размера

можно вообще извратиться как в std::string - пока мало байт, они хранятся inplace, а при росте уже выделяется доп.буфер.

в случае ТС, на 64-х бит, для хранения «hello» (5 байт+1 терминатор=6), используется size_t длина плюс указатель на куда-то = 16 байт и ещё в hip заимствуется. И к этому всему имеется шанс сорвать кеши - структура в одном месте, данные строки в непредсказуемо другом.

MKuznetsov ★★★★★
()

Кажется я первый кто понял вопрос ТС-а (upd: не, не первый). Да, чтобы тебе сделать malloc тебе нужно будет либо задать фиксированный массив максимальной длины для строки, а это нередко бывает когда всё же предел существует для строки, иногда он несколько байт, иногда сотни байт, но часто предел существует

И да, когда чистишь, сначала free строк внутри структуры, потом сама структура

Если ты хочешь динамическую длину, увы, придется сделать второй malloc для это строки после создания структур

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

Начиная с банальных ASN и так далее

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)