Указатель структуры в C - PullRequest
       4

Указатель структуры в C

0 голосов
/ 28 января 2019

Проблема структуры.

Я написал код, реализующий стек.Если я передаю sqStack * sq этой функции init_stack (), код заканчивается ошибкой.Как видно из комментария следующего кода.Но потом я узнал, что если я передаю sqStack & sq в функцию init_stack (), код работает.Кто-нибудь может мне объяснить?Спасибо!

#include <stdio.h>
#include <stdlib.h>

#define init_size 10
#define increment 1

typedef struct sqStack
{
    int* top;
    int* base;
    int stack_size;
}sqStack;

int init_stack(sqStack* sq)
{
    if(sq->base==NULL)
    {
       sq->base = (int*)malloc(init_size*sizeof(int));
    }
    if(sq->base==NULL) exit(-1);
    sq->stack_size=init_size;
    sq->top=NULL;
    sq->top=sq->base;
    return 1;
}
int push(sqStack* sq, int e)
{
    if(sq==NULL) exit(-1);
    if(sq->top-sq->base==sq->stack_size)
    {
        int* q = (int*)realloc(sq->base,  
        (init_size+increment)*sizeof(int));
        if(q==NULL) exit(-1);
        sq->base=q;
        sq->stack_size += increment;
        sq->top=sq->base+sq->stack_size;

    }
    *sq->top++=e;//Thread 1: EXC_BAD_ACCESS  If I pass sqStack* sq to this function, error occurs. But if I pass sqStack &sq, the code works.


    return 1;
}

int pop(sqStack* sq,int*e)
{
    if(sq==NULL) exit(-1);  
    if(sq->base==sq->top)  exit(-1);   
    sq->top-=1;   
    *e=*sq->top;   
    return 1;    
}

int empty(sqStack* sq)
{
    if(sq->base==sq->top) return 1;
    else return 0;
}


int main()
{
    sqStack* sq;
    init_stack(sq);
    push(sq,1);
    int e=
    pop(sq,e);
    printf("%d\n",*e);
/* sqStack sq;
    init_stack(&sq);
    push(&sq,1);
    int e;
    pop(&sq,&e);
    printf("%d\n",e);*/
    return 0;
}

В любом случае вывод равен 1.

Ответы [ 2 ]

0 голосов
/ 28 января 2019

Решение проблемы

Проблема заключается в том, что вы резервируете память для sq в качестве указателя .Почему это проблематично?

Ну, у нас есть место только для адреса до sqStack.Если мы передаем sq на init_stack(), мы разыменовываем sq.Это ни к чему не приводит, так как мы инициализировали его как указатель, и, таким образом, если мы попытаемся присвоить значения его полям, у нас не останется места для этого!

Как решить проблему?Просто инициализируйте sq как sqStack вместо указателя на него:

sqStack sq;
init_stack(&sq);  /* pass by reference here */
/* code continued */

Предложение

Кроме того, я думаю, что лучше использовать struct было бы

typedef struct sqStack {
  int *elements;
  int top;
}

Таким образом, вы можете использовать верх как средство для отслеживания размера вашего стека и просто хранить элементы в специально выделенном массиве.Нажатие будет выглядеть как

void push(sqStack *sq, int element) {
  sq->top++;
  if (sq->top - 1 == 0) {
    /* we need to allocate space */
    sq->elements = malloc(sizeof(int));
  } else {
    /* we need to reallocate space */
    sq->elements = realloc(sq->elements, sq->top * sizeof(int));
  }
  sq->elements[sq->top - 1] = element;
}

... и аналогичным образом пересматривать другие функции.Но это только предположение.

0 голосов
/ 28 января 2019

Здесь вы разыменовываете неинициализированный (висячий) указатель:

sqStack* sq;
init_stack(sq);

(в init_stack ()):

if(sq->base==NULL)
   ...

, что немедленно приводит к неопределенному поведению.

Лучше сделать это следующим образом:

sqStack sq;
init_stack(&sq);

Теперь вы правильно выделите место для sqStack в стеке вашего процесса и передадите указатель на это пространство на init_stack().Каждый раз, когда вы хотите передать указатель на эту структуру (например, в pop и push), вы должны использовать &sq сейчас.

В качестве альтернативы, вы можете динамически распределять память для sqStack, как это:

sqStack *sq = malloc(sizeof(sqStack));
init_stack(sq);

, который также резервирует память (на этот раз в куче).

Третий вариант - оставить распределение структуры для функции init_stack().В этом случае вам нужно передать двойной указатель на init_stack, чтобы в него можно было записать адрес (проверка ошибок добавляется самостоятельно):

int init_stack(sqStack** _sq) {
    sqStack* sq;
    sq = *_sq = malloc(sizeof(sqStack));
    sq->base = malloc(init_size*sizeof(int));
    ...

и в вашем основном:

sqStack *sq;
init_stack(&sq);
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...