Операция стека с использованием языка c

может ли кто-нибудь помочь мне, почему этот код не работает? этот код не показывает ни вывода, ни ошибок.

#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;
}

может ли кто-нибудь помочь мне, почему этот код не работает?

Вам нужно выделить память для указателя структуры *s, прежде чем вы сможете присваивать значения его членам. Используйте struct stack *s; s = malloc(sizeof(struct stack));

Gaurav Pathak 14.04.2023 13:22

Интересно, почему вы не столкнулись с какой-либо ошибкой

Gaurav Pathak 14.04.2023 13:23

@GauravPathak Неопределенное поведение не определено ... может случиться все что угодно.

wohlstad 14.04.2023 13:25

Все основные компиляторы предупреждают вас об этом, когда вы запрашиваете предупреждения с повышенными правами, что должно быть по умолчанию. С Clang начните с -Wmost -Werror. С GCC начните с -Wall -Werror. В MSVC начните с /W3 /WX.

Eric Postpischil 14.04.2023 13:25

@GauravPathak: GCC и Clang по умолчанию не предупреждают об этом. Вы должны запросить дополнительные предупреждения.

Eric Postpischil 14.04.2023 13:26

Извините за мой быстрый комментарий, я хотел спросить, почему OP не получил Seg Fault или ошибку времени выполнения.

Gaurav Pathak 14.04.2023 13:28

@EricPostpischil На самом деле я имел в виду ошибку времени выполнения (это то, на что, как я думал, намекал GauravPathak). Разыменование uninitiazlied s может [обычно] вызвать ошибку нарушения прав доступа (seg-fault), но не обязательно, поскольку это UB.

wohlstad 14.04.2023 13:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
55
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Использование неинициализированного указателя 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;
}

Другие вопросы по теме