rusyska55011
@rusyska55011

Как присвоить динамическому массиву типа void* значение в Си?

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

void* value = (void*)malloc(sizeof(void*) * 2);
	
value[1] = 10; // Ошибка
*(value + 1) = 10; // Ошибка
	
*((int*)value + 1) = 10; // Работает
  • Вопрос задан
  • 413 просмотров
Пригласить эксперта
Ответы на вопрос 5
@res2001
Developer, ex-admin
Нельзя выделить память для произвольного типа, т.к. размер произвольного типа - произвольный. Память всегда выделяется конкретного размера.

В вашем примере вы выделяете память для двух указателей (void*). На всех распространенных платформах указатель, не важно на какой тип он ссылается, имеет один и тот же размер.
Нельзя сделать разъименование void*, т.к. это указатель с неопределенным типом - компилятор не знает какого типа данные лежат по адресу в указателе, а следовательно не может с ними корректно работать. Для нормальной работы нужно привести указатель к какому-нибудь типу и потом уже можно делать разъименование (ваш 3 пример).

Ваш пример не корректен для х64 платформы, т.к. sizeof(void*) там 8 байт, а sizeof(int) - 4 байта.
Вы mallocом выделяете 16 байт памяти (2 указателя), а в 3 присваивании (которое работает) присваиваете значение 10 старшей половине первого указателя. В общем выглядит как бред.
Для х32 - корректен, т.к. тут sizeof(void*) == sizeof(int)

Для копирования двух массивов произвольного типа и размера, нужно знать размер массива в байтах (не в элементах). Можно не знать тип, но знать размер необходимо - иначе ничего не поучится. Выделяете память заданного размера, приводите указатель к char* и побайтово копируете (memcpy).
Приводить к int* и копировать intы в этом случае нельзя, т.к. массив может быть, например 3 байта или 33, тогда при копировании через приведение к int* вы неминуемо выйдете за границу массива.
Ответ написан
Комментировать
@dima20155
you don't choose c++. It chooses you
Во-первых, malloc возвращает void *, поэтому приводить ничего не нужно.

value[1] = 10; // Ошибка
*(value + 1) = 10; // Ошибка

Данные выражения вызывают ошибку потому что sizeof(void) не определен.
https://stackoverflow.com/questions/1666224/what-i...
Вы не можете скопировать массив не зная размер его элемента и количество элементов или исходный размер массива в байтах.

Собственно, потому memcpy и требует одним из параметров размер.
Ответ написан
Комментировать
wataru
@wataru
Разработчик на С++, экс-олимпиадник.
Если это произвольный тип, то какой у него размер? Какими значениями вы его заполнять-то пытаетесь?

А так, скорее всего вам подойдет функция memset. Какими-нибудь нулями все заполнить - отлично можно. Хоть там int, хоть char, хоть float.
Ответ написан
CityCat4
@CityCat4 Куратор тега C
//COPY01 EXEC PGM=IEBGENER
malloc потому и возвращает void, потому что ответственность за то, какого типа будет массив - на программисте.

Если нужно заполнить его фиксированным значением - есть memset()
Если нужно заполнить нулями - обычное дело перед тем, как начать работу со строками - есть calloc()
Если нужно расписать его структурным типом - ну определи структуру, потом приведи массив к типу структуры и циклом пробегись
Ответ написан
Комментировать
@Xiran
Что вообще значит
динамический массив типа void*
?
Например:
void **ptrArr = malloc(sizeof(*ptrArr) * N);

// ...

free(ptrArr);

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

Вы просто где-то отдельно выделяете память для int'ов, char'ов, и т. д., и записываете указатели в этот массив, по необходимости расширяя его (тут, на мой взгляд, лучше проявит себя список).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы