Как определить, нужно ли выделять память в даном случае? Си
struct AB{
int a;
int b;
};
struct AB* init_AB(){
struct AB newAB;
newAB.a = 1;newAB.b = 2;
return &newAB;
}
int main(){
struct AB* newAB = init_AB();
printf("A:%d B:%d\n", newAB->a, newAB->b);
}
Вот абсолютно простой пример, пусть после printf я продолжаю использовать эту структру, просто любопытно, в какой момент времени ОС позволит зачистить эту память и моя программа упадет, как понять, нужно ли мне выделять с помощью calloc память под эту структуру или нет.
Ответы (2 шт):
Вы переходите перекресток на красный свет с закрытыми глазами и заткнутыми ушами.
Просто любопытно, в какой момент времени вас собьет машина и вы упадете... как понять, нужно ли вам переходить через перекресток на зеленый свет или нет?
Это - полная аналогия того, что делаете вы, и вашего вопроса. Только операционная система тут ни при чем, она не обязана "позволить зачистить" - просто ваша же программа воспользуется этим местом стековой памяти и что-нибудь туда запишет.
Естественно, если вы хотите поступать правильно, в соответствии со стандартом - вы обязаны выделять память динамически (или, например, объявив переменную как static). Иначе вы вступаете на скользкую дорожку неопределенного поведения - а оно на то и неопределенное, что иногда даже может сработать без неприятностей (ведь если бы неприятность гарантировалась - это было бы уже определенное поведение, правда?).
Ваш собственный способ работать не будет, так как все локальные переменные могут передаваться через стек. И все ваши усилия будут стёрты.
Чтобы разбираться что такое стек в Си я предлагаю книжный метод, как пользоваться. А так-же метод для гуру, чтобы точно знать как всё работает.
// gcc -Wall -Wextra -Wpedantic -std=c11 retsta.c -o retsta
struct AB{
int a;
int b;
};
// для функции уже выделено место в стеке,
// и вы имеете право записывать результат
void init_AB ( struct AB * pAB ) {
pAB->a = 1;
pAB->b = 2;
}
# include <stdint.h>
// гуру
// стек 2 для личных нужд
uint8_t stack [ 0x1000 ] ;
// аналог SP = Stack Pointer в ассебмлере
uint8_t * stackp = & stack [ 0 ] ;
struct AB * init_ABp ( void ) {
// место в стеке для результата
struct AB * result = ( struct AB * ) stackp ;
// сдвигаем стековый указатель
stackp += sizeof ( struct AB ) ;
result -> a = 1 ;
result -> b = 2 ;
return result ;
}
# include <stdio.h>
int main(){
// правильный способ, выделяем место в стеке
struct AB newAB ;
// и передаём указатель в функцию
init_AB ( & newAB ) ;
printf("A:%d B:%d\n", newAB.a, newAB.b);
// гуру
{ // запоминается точка входа стека
uint8_t * const stackback = stackp ;
struct AB * newABp = init_ABp ( ) ;
// результат храниться в личном стеке
printf("A:%d B:%d\n", newABp->a, newABp->b);
// здесь можно вызывать деструктор элементов в стеке
// ..
// восстанавливает стек
stackp = stackback ; }
}