Как проверить, инициализирована ли выделенная память или нет - PullRequest
3 голосов
/ 30 ноября 2011

Я получаю указатель int* i, о котором я знаю только то, что его память выделена, но я не уверен, что он был инициализирован каким-то целым числом или нет.

Если я попытаюсь преуменьшить это, что произойдет?Другими словами, как я должен проверить, инициализирован ли он или нет?Если это не так, я бы хотел назначить целое значение этому адресу;в противном случае я ничего не делаю.

Ответы [ 5 ]

5 голосов
/ 30 ноября 2011

Определить «инициализировано».Всегда будет какое-то значение, и вы не сможете определить, является ли это значение мусором или целым числом, потому что любые 32 бита будут давать какое-то значение.Вы можете разыменовать это, хотя, нет проблем.

0 голосов
/ 30 ноября 2011

Вы также можете переопределить malloc таким образом, чтобы он выделил блок памяти и инициализировал его сразу нулевыми байтами, используя такой макрос:

#define malloc(p, size) do {if (p != NULL) {p=malloc(size); memset(p, 0, size);}} while(0);

Или, если вы предпочитаете, malloc можно переопределить в терминах calloc:

#define malloc(p, elCount , elSize) do {if (p != NULL) {p=calloc(elCount,elSize);}} while(0);

Используя такую ​​конструкцию, вы будете уверены, что любой программист, использующий malloc (), также правильно инициализирует память, так что указатель на данные мусора не отображается.

0 голосов
/ 30 ноября 2011

i обычно является именем целочисленного (обычно int) объекта.Вызов указателя i сбивает с толку.

Итак, давайте предположим, что у вас есть

int *p;

Вы говорите "его память выделена".Вы имеете в виду память для самого объекта-указателя (которая выделяется при объявлении p), или вы имеете в виду память для int объекта, на который он указывает?

В любом случае вы не можетескажите, была ли она инициализирована или нет.

Если p имеет статическую продолжительность хранения, то его начальное значение (при отсутствии явного инициализатора) является нулевым указателем;это ни на что не указывает.В противном случае его начальное значение является мусором, и вы не можете безопасно сделать с ним что-либо , кроме как присвоить ему какое-либо действительное значение.

Если, с другой стороны, вы имеете в виду, что pбыл инициализирован, чтобы указывать на некоторый int объект, но этот объект мог или не мог быть инициализирован, тогда у вас есть похожая проблема.Если у вас есть:

int *p;
p = malloc(sizeof *p);
if (p == NULL) {
    /* malloc() failed! */
    exit(EXIT_FAILURE);
}

, то p указывает на выделенный объект int, но значение этого объекта является мусором.В большинстве систем вы можете безопасно получить доступ к значению (*p) - но в этом нет никакого смысла.Но возможно, что int имеет представлений ловушек ;в этом случае простое обращение к значению *p ведет к неопределенному поведению и может привести к сбою вашей программы.А оптимизирующий компилятор может делать неожиданные вещи в присутствии неопределенных объектов; может предположить , что оно было инициализировано для некоторого значения, и не беспокоиться о фактическом извлечении сохраненного значения.

Не существует специального значения, маркера или флага для неинициализированного int объекта,Вы, программист, должны убедиться, что у любого объекта есть действительное значение, прежде чем пытаться получить к нему доступ.(Некоторые языки отслеживают эти вещи для вас; C не является одним из этих языков. Конечно, многие реализации этих языков написаны (очень тщательно) на C.)

Итак, вызадавая неправильный вопрос.Если вы не знаете, был ли объект инициализирован, решение состоит в том, чтобы выяснить (логически, когда вы пишете код, а не во время выполнения программы), был ли он инициализирован.Лучший способ сделать это обычно состоит в том, чтобы был инициализирован .

Если вы пытаетесь сделать что-то вроде следующего псевдокода:

 if (/* *p has been initialized */) {
     do something with *p;
 }
 else {
     do something else;
 }

тогда вы делаете это неправильно.Вместо:

/* Ensure p points to a valid int object */
*p = some_value;
/* Now you *know* *p has been initialized */
do something with *p;
0 голосов
/ 30 ноября 2011

Хорошая практика программирования включает присвоение NULL указателям, которые неинициализированы.Если вы обрабатываете указатель откуда-то еще, обычно проверяют, что он не равен NULL.В вашем случае:

if (i != NULL)
  *i = the_int_you_assign;

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

0 голосов
/ 30 ноября 2011

Я получаю указатель int * i, о котором я знаю только, что его память выделен, но я не уверен, что он был инициализирован к некоторому целому числу или нет.

Если я был выделен как указатель, а не инициализирован, вы получите нарушение сегмента. Если бы я был выделен и инициализирован к некоторому целому числу X ... т.е.

int X = SOMEVALUE;

    int* i;
    i = &X; // It would seem silly to malloc a single int...

Тогда он инициализируется, ЕСЛИ и только если X был инициализирован. Если вы знаете некоторые ожидаемые границы для значения, на которое оно указывает, то рекомендуется использовать проверку границ перед использованием ...

Если я попытаюсь прекратить это, что произойдет? Другими словами, как я должен проверить, инициализирован ли он или нет? Если это не так, я бы хотел назначить целое значение этому адресу; в противном случае я ничего не делаю.

Моя обычная практика - инициализировать указатели на 0 или NULL, пока у меня не появится реальная ценность для их кормления. До вызова функции * X * alloc некоторой сортировки ... Затем, если она где-нибудь, я бы попробовал использовать ее ... Я делаю ...

if (myPtr == NULL)
{
 printf("Run failure handling code...\r\n");
 return FUNC_FAILED_CONST;
}

Но мне нужно больше информации, чтобы узнать вашу ситуацию ...

...