может ли кто-нибудь помочь мне, почему этот код не работает? этот код не показывает ни вывода, ни ошибок.
#include <stdio.h>
#include <stdlib.h>
struct stack {
int size;
int top;
int* arr;
};
int isEmpty(struct stack* ptr) {
if (ptr->top == -1) {
return 1;
}
else {
return 0;
}
}
int main()
{
struct stack* s;
s->size = 5;
s->top = -1;
s->arr = (int*)malloc(s->size * sizeof(int));
if (isEmpty(s)) {
printf("Stack is Empty.");
}
else {
printf("Stack is not Empty");
}
return 0;
}
может ли кто-нибудь помочь мне, почему этот код не работает?
Интересно, почему вы не столкнулись с какой-либо ошибкой
@GauravPathak Неопределенное поведение не определено ... может случиться все что угодно.
Все основные компиляторы предупреждают вас об этом, когда вы запрашиваете предупреждения с повышенными правами, что должно быть по умолчанию. С Clang начните с -Wmost -Werror
. С GCC начните с -Wall -Werror
. В MSVC начните с /W3 /WX
.
@GauravPathak: GCC и Clang по умолчанию не предупреждают об этом. Вы должны запросить дополнительные предупреждения.
Извините за мой быстрый комментарий, я хотел спросить, почему OP не получил Seg Fault или ошибку времени выполнения.
@EricPostpischil На самом деле я имел в виду ошибку времени выполнения (это то, на что, как я думал, намекал GauravPathak). Разыменование uninitiazlied s
может [обычно] вызвать ошибку нарушения прав доступа (seg-fault), но не обязательно, поскольку это UB.
Использование неинициализированного указателя s
для доступа к памяти
struct stack* s;
s->size = 5;
s->top = -1;
вызывает неопределенное поведение.
Вы можете выделить объект типа struct stack
динамически и присвоить его адрес указателю s
. Но нет большого смысла размещать объект динамически.
проще написать
struct stack s = { 5, -1, malloc( 5 * sizeof(int) ) };
Тогда функция isEmpty
, которую также можно определить проще, например
int isEmpty( const struct stack *ptr )
{
return ptr->top == -1;
}
называется как
if ( isEmpty( &s ) ) {
Когда стек больше не потребуется, вам нужно освободить выделенную память для целочисленного массива, например
free( s.arr );
Обратите внимание, что гораздо лучше объявить стек структуры, используя беззнаковый целочисленный тип для элементов данных size
и top
. Например
struct stack
{
size_t size;
size_t top;
int *arr;
};
Чтобы динамически выделить объект типа структуры, вы можете написать отдельную функцию, например
struct stack * create_stack( size_t size )
{
struct stack &s = malloc( sizeof( *s ) );
if ( s != NULL )
{
s->size = 0;
s->top = 0;
s->arr = NULL;
if ( size != 0 )
{
s->arr = malloc( size * sizeof( int ) );
if ( s->arr != NULL )
{
s->size = size;
}
else
{
free( s );
s = NULL;
}
}
}
return s;
}
и в основном вы можете написать
struct stack *s = create_stack( 5 );
//...
В этом случае функция isEmpty
будет иметь вид
int isEmpty( const struct stack *ptr )
{
return ptr->top == 0;
}
а аналогичная функция как например isFull
будет выглядеть
int isFull( const struct stack *ptr )
{
return ptr->top == ptr->size;
}
Функции вызываются в основном как
if ( isEmpty( s ) ) {
//...
и
if ( isFull( s ) ) {
//...
Проблема в следующих строках:
struct stack* s;
s->size = 5;
s->top = -1;
s->arr = (int*)malloc(s->size * sizeof(int));
По определению оператора ->
линия
s->size = 5;
эквивалентно:
(*s).size = 5;
Это означает, что ваш код пытается разыменовать объект, на который указывает s
, и присвоить одному из его членов значение. Чтобы это работало, указатель s
должен указывать на действительный объект. Однако, это не так. Вы никогда не присваивали значение s
, поэтому, скорее всего, оно не указывает на допустимый объект.
Чтобы заставить s
указывать на действительный объект, у вас есть несколько вариантов. Вы можете создать локальную переменную и указать s
на этот объект:
int main( void )
{
struct stack object;
struct stack *s = &object;
s->size = 5;
s->top = -1;
s->arr = malloc( s->size * sizeof(int) );
[...]
Или вы можете выделить необходимую память с помощью malloc
и указать s
на эту память:
int main( void )
{
struct stack *s = malloc( sizeof *s );
s->size = 5;
s->top = -1;
s->arr = malloc( s->size * sizeof(int) );
[...]
Или вы можете сделать s
не указателем, а обычным объектом:
int main( void )
{
struct stack s;
s.size = 5;
s.top = -1;
s.arr = malloc( s->size * sizeof(int) );
[...]
В отличие от C++, в C нет необходимости (, а также не рекомендуется ) приводить возвращаемое значение malloc
.
Кроме того, как правило, рекомендуется проверять возвращаемое значение malloc
, потому что в противном случае, если malloc
когда-либо вернет NULL
, ваша программа, скорее всего, выйдет из строя. Лучше выйти с сообщением об ошибке, когда malloc
возвращает NULL
, например так:
s.arr = malloc( s->size * sizeof(int) );
if ( s.arr == NULL )
{
fprintf( stderr, "Memory allocation error!\n" );
exit( EXIT_FAILURE );
}
Кроме того, вы обычно должны free
память, когда она вам больше не нужна.
Можно просто сделать s
не указателем, чтобы код стал таким:
#include <stdio.h>
#include <stdlib.h>
struct stack {
int size;
int top;
int* arr;
};
int isEmpty(struct stack ptr) {
if (ptr.top == -1) {
return 1;
}
else {
return 0;
}
}
int main()
{
struct stack s;
s.size = 5;
s.top = -1;
s.arr = malloc(s.size * sizeof(int));
if (isEmpty(s)) {
printf("Stack is Empty.");
}
else {
printf("Stack is not Empty");
}
return 0;
}
Вам нужно выделить память для указателя структуры
*s
, прежде чем вы сможете присваивать значения его членам. Используйтеstruct stack *s; s = malloc(sizeof(struct stack));