0

can anyone help me why this code is not working? this code is not showing any output nor any error.

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

can anyone help me why this code is not working?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 2
    You need to allocate memory to the structure pointer `*s` before you can assign values to its members. Use `struct stack *s; s = malloc(sizeof(struct stack));` – Gaurav Pathak Apr 14 '23 at 11:22
  • I wonder why you didn't encounter any error – Gaurav Pathak Apr 14 '23 at 11:23
  • 3
    @GauravPathak Undefined behavior is undefined ... anything can happen. – wohlstad Apr 14 '23 at 11:25
  • 1
    All of the major compilers warn you about this when you request elevated warnings, which should be your default. With Clang, start with `-Wmost -Werror`. With GCC, start with `-Wall -Werror`. With MSVC, start with `/W3 /WX`. – Eric Postpischil Apr 14 '23 at 11:25
  • 1
    @GauravPathak: GCC and Clang do not warn about this by default. You have to request additional warnings. – Eric Postpischil Apr 14 '23 at 11:26
  • Sorry for my quick comment, I wanted to ask why OP didn't get Seg Fault or runtime error – Gaurav Pathak Apr 14 '23 at 11:28
  • @EricPostpischil I was actually referring to a runtime error (that's what I thought GauravPathak was hinting towards). Dereferencing uninitiazlied `s` might [typically] cause an access violation error (seg-fault), but not necessarily as it is UB. – wohlstad Apr 14 '23 at 11:31

3 Answers3

2

Using the uninitialized pointer s for accessing memory

struct stack* s;
s->size = 5;
s->top = -1;

invokes undefined behavior.

You could allocate an object of the type struct stack dynamically and assign its address to the pointer s. But there is no great sense to allocate the object dynamically.

It is simpler to write

struct stack s = { 5, -1, malloc( 5 * sizeof(int) ) };

Then the function isEmpty that can also be defined simpler like

int isEmpty( const struct stack *ptr ) 
{
    return ptr->top == -1;
}

is called like

if ( isEmpty( &s ) ) {

When the stack will not be required any more you need to free the allocated memory for the integer array like

free( s.arr );

Pay attention to that it is much better to declare the structure stack using a unsigned integer type for the data members size and top. For example

struct stack 
{
    size_t size;
    size_t top;
    int *arr;
};

To allocate an object of the structure type dynamically you could write a separate function as for example

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

and in main you can write

struct stack *s = create_stack( 5 );
//...    

In this case the function isEmpty will look like

int isEmpty( const struct stack *ptr ) 
{
    return ptr->top == 0;
}

and a similar function as for example isFull will look like

int isFull( const struct stack *ptr ) 
{
    return ptr->top == ptr->size;
}

The functions are called in main like

if ( isEmpty( s ) ) {
//...

and

if ( isFull( s ) ) {
//...
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

The problem is the following lines:

struct stack* s;
s->size = 5;
s->top = -1;
s->arr = (int*)malloc(s->size * sizeof(int));

By definition of the -> operator, the line

s->size = 5;

is equivalent to:

(*s).size = 5;

This means that your code is attempting to dereference the object pointed to by s and assign one of its members a value. For this to work, the pointer s must be pointing to a valid object. However, this is not the case. You never assigned a value to s, so it is most likely not pointing to a valid object.

In order to make s point to a valid object, you have several options. You could create a local variable and make s point to that object:

int main( void )
{
    struct stack object;

    struct stack *s = &object;
    s->size = 5;
    s->top = -1;
    s->arr = malloc( s->size * sizeof(int) );

    [...]

Or you could allocate the necessary memory using malloc and make s point to that memory:

int main( void )
{
    struct stack *s = malloc( sizeof *s );
    s->size = 5;
    s->top = -1;
    s->arr = malloc( s->size * sizeof(int) );

    [...]

Or you may want to make s not a pointer, but a normal object:

int main( void )
{
    struct stack s;
    s.size = 5;
    s.top = -1;
    s.arr = malloc( s->size * sizeof(int) );

    [...]

In contrast to C++, in C, it is not necessary (and also not recommended) to cast the return value of malloc.

Also, it is generally a good idea to check the return value of malloc, because otherwise, if malloc ever returns NULL, your program will likely crash. It would be better to exit with an error message, when malloc returns NULL, for example like this:

s.arr = malloc( s->size * sizeof(int) );
if ( s.arr == NULL )
{
    fprintf( stderr, "Memory allocation error!\n" );
    exit( EXIT_FAILURE );
}

Additionally, you should generally free the memory when you no longer need it.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

You can simply make s not a pointer, so that the code would become as follows:

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