Объявление указателя на структуру в C ++ автоматически выделяет память для его членов.Я ошибся? - PullRequest
4 голосов
/ 24 февраля 2012

Я написал следующий фрагмент кода и полагал, что он потерпит крах, если я попытаюсь получить доступ к членам структуры, для которой я даже не выделил память. Но я был очень удивлен, что C ++ автоматически выделил память для структуры. Это нормальное поведение? Для сравнения, если вы объявите указатель на объект, а затем попытаетесь получить доступ к любым членам, не создавая объект с оператором «new», программа будет аварийно завершена. Мне просто любопытно, почему это работает, когда я верю, что это не должно.

Это моя программа:

#include <stdio.h>

struct Produto
{
    int codigo;
    float preco;
};

int main()
{
    struct Produto* sabonete;
    sabonete->codigo = 654321;
    sabonete->preco = 0.85;

    printf( "Codigo = %i\n", sabonete->codigo );
    printf( "Preco = R$ %.2f\n", sabonete->preco );

    return 0;
}

ОС: Windows 7
Компилятор: MinGW GCC 4.6.1

Ответы [ 5 ]

11 голосов
/ 24 февраля 2012

C ++ не распределял память автоматически;указатель содержит произвольное значение, которое, как оказалось, является допустимым адресом в области памяти вашей программы, поэтому вы не получили ошибку сегмента.Ваша программа демонстрирует неопределенное поведение и может не сработать при следующем запуске.

Неопределенное поведение не гарантирует сбой, поэтому она называется неопределенной.

4 голосов
/ 24 февраля 2012

Вы столкнулись с Неопределенное поведение

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

C ++ совсем не выделяет вашу память, выпросто топать памятью, чтобы ничего не сломалось.

2 голосов
/ 24 февраля 2012

Нет, с точностью до наоборот. Этот указатель неинициализирован, и вы вызываете UB, разыменовывая его. Если вам нужен указатель, вы должны инициализировать его либо с помощью существующего указателя, либо с помощью вызова new (или, что еще лучше, поскольку это C ++, некоторый объект, который работает как контейнер для обработки выделения / уничтожения, то есть RAII) .

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

0 голосов
/ 24 февраля 2012

Если вас интересует, что «могло произойти» под капотом, учтите, что sabonete на вашей платформе имеет ширину 4 байта (в качестве указателя), и поскольку ваш main не объявлял параметры (что ОС пусть в любом случае доступно), может занимать то же пространство памяти, что обычно в обратном порядке параметра.

Это правда, он перезаписывает char ** argv, который указывает на массив указателей (он должен содержать как минимум 16 из них), который указывает на строки, содержащие части командной строки.

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

Но это не потому, что это нормально. Это потому, что вам повезло найти подходящее место для чего-то другого, что вас в этом случае не интересует.

0 голосов
/ 24 февраля 2012

Поскольку компилятор g ++ не инициализирует нераспределенный указатель на NULL, возможно, он указывает на некоторую часть памяти, которая содержит данные, которые на первый взгляд кажутся правильными.

Чтобы ответить на вопрос,да, это нормальное, но неопределенное поведение, когда вы не хотите выделять память для ваших объектов:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...