Почему эти три способа отличаются в коде C? - PullRequest
4 голосов
/ 28 февраля 2011

У меня есть проблемы с этим кодом.Обратите внимание на комментарии.Почему это?

struct node
{
    struct node *left;
    struct node *right;
    int value;
};

static struct node root2;

int main()
{    
    struct node *root = (struct node *) malloc(sizeof(struct node));

    assert(root->left == NULL);   /* not failed. Why? */ 
    assert(root->right == NULL);  /* not failed. Why? */

    assert(root2.left == NULL);   /* not failed. Why? */
    assert(root2.right == NULL);  /* not failed. Why? */

    struct node root1;
    assert(root1.left == NULL);   /* this failed. Why? */
    assert(root1.right == NULL);  /* this failed. Why? */

    free(root);

    return 0;
}

Ответы [ 3 ]

9 голосов
/ 28 февраля 2011

С root1 вы объявили локальный экземпляр узла, и он будет в стеке.Вы не инициализируете его, поэтому он будет содержать мусор.

С root2 вы объявили глобальный экземпляр.Код запуска по умолчанию очистит память, занимаемую глобалами.

При использовании root он будет существовать в куче и содержать мусор.Это просто удача, содержит ли занятая память 0 или нет.Если вы используете calloc вместо malloc, он очистит память для вас.

4 голосов
/ 28 февраля 2011

Дело 1:

struct node *root = (struct node *) malloc(sizeof(struct node));
assert(root->left == NULL);   /* not failed. Why? */ 
assert(root->right == NULL);  /* not failed. Why? */

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

Случай 2:

static struct node root2;

Глобальные переменные обнуляются по умолчанию. Я думаю, что это гарантированное поведение, так что это правильно.

Дело 3:

struct node root1;
assert(root1.left == NULL);   /* this failed. Why? */
assert(root1.right == NULL);  /* this failed. Why? */

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

0 голосов
/ 28 февраля 2011

Когда вы выделяете новый узел, его сыновья по умолчанию не равны NULL. Они получают значения мусора.
Кроме того, макрос assert отключен, если на момент включения assert.h макрос с именем NDEBUG уже был определен. Это позволяет кодировщику включать много вызовов assert в исходный код при отладке программы, а затем отключить все из них для рабочей версии, просто добавив строку вроде:

#define NDEBUG

в начале своего кода, до включения assert.h.

Например:

#undef NDEBUG  
#include <assert.h>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...