Установка первых двух байтов блока памяти в качестве указателя или NULL при одновременном доступе к остальной части блока - PullRequest
1 голос
/ 27 апреля 2010

Предположим, у меня есть блок памяти как таковой:

void *block = malloc(sizeof(void *) + size);

Как установить указатель на начало блока, при этом все еще имея возможность доступа к оставшемуся зарезервированному пространству? По этой причине я не хочу просто присваивать блоку другой указатель или NULL.

Ответы [ 6 ]

4 голосов
/ 27 апреля 2010

Как мне установить первые два байта блока как NULL или указать где-нибудь?

Это не имеет никакого смысла, если вы не работаете на 16-битной машине.

Исходя из того, как вы звоните malloc(), вы планируете, чтобы первые N байтов были указателем на что-то другое (где N может быть 2, 4 или 8, в зависимости от того, выполняете ли вы на 16-, 32- или 64-разрядной архитектуре). Это то, что вы действительно хотите сделать?

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

void** ptr = block;

Однако было бы намного элегантнее определить ваш блок с помощью struct (это может содержать синтаксические ошибки; я не запускал его через компилятор):

typedef struct {
    void* ptr; /* replace void* with whatever your pointer type really is */
    char[1] data; } MY_STRUCT;

MY_STRUCT* block = malloc(sizeof(MY_STRUCT) + additional);
block->ptr = /* something */
2 голосов
/ 27 апреля 2010
memset(block, 0, 2);

memset можно найти в string.h

1 голос
/ 27 апреля 2010

Поместить первые два байта выделенного блока памяти в 0 легко. Есть много способов сделать это, например:

((char*)block)[0] = 0;
((char*)block)[1] = 0;

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

Вы можете поместить что-нибудь в первые два байта вашего выделенного блока, это ничего не изменит для доступа к следующим байтам. Единственное отличие состоит в том, что оператор манипуляции со строками C использует в качестве соглашения, что строки заканчиваются байтом 0. Затем, если вы сделаете что-то вроде strcpy((char*)block, target), оно немедленно прекратит копирование, если первый байт равен нулю. Но вы все равно можете сделать strcpy((char*)block+2, target).

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

((void**)block)[0] = your_pointer;

Вы получаете доступ к остальной части блока, как хотите, просто получите его адрес и продолжайте. Вы можете сделать это, например, с помощью.

void * pointer_to_rest = &((void**)block)[1];

PS: я не рекомендую такие игры указателя. Они очень подвержены ошибкам. Ваш лучший ход, вероятно, будет следовать методу struct, предложенному @ Anon.

0 голосов
/ 03 февраля 2015

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

((void**)block)[0] = your_pointer;

, где вы приводили указатель на блок в виде массива, а затем использовали синтаксис скобок для обработки арифметики и разыменования указателя, было самым чистым решением для копирования нового значения в это «поле» указателя блока.

0 голосов
/ 27 апреля 2010

Я догадываюсь о том, что вы пытаетесь спросить, но ваша формулировка настолько сбивает с толку, что я могу быть совершенно неправ. Я предполагаю, что вам нужен указатель, который указывает на «первые 2 байта» выделенного вами блока, а затем другой указатель, который указывает на оставшуюся часть блока.

Указатели не несут информации о размере блока памяти, на который они указывают, поэтому вы можете сделать это:

void *block = malloc(sizeof(void *) + size);
void *first_two_bytes = block;
void *rest_of_block = ((char*)block)+2;

Теперь first_two_bytes указывает на начало выделенного вами блока, и вы должны просто обращаться с ним, как если бы он указывал на область памяти длиной 2 байта.

И rest_of_block указывает на часть блока, начинающуюся с 3-х байтов, и вы должны обращаться с ней так, как если бы она указывала на область памяти на 2 байта меньше, чем вы выделили.

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

0 голосов
/ 27 апреля 2010
void *block = malloc(sizeof(void *) + size); // allocate block
void *ptr = NULL; // some pointer
memcpy(block, &ptr, sizeof(void *)); // copy pointer to start of block
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...