LINUX.ORG.RU

Не работает push() в стеке

 ,


1

1

Привет. Стек через массив. Не работает push(), скорее я где-то накосячил.
Должно в стеке в итоге быть 0 .. 9, а там фигня.

#include <stdio.h>
#include <stdlib.h>
#define SIZE 10

void push(int *stack, int *sp, int x);
int pop(int *stack, int *sp);

int main() {
	int *stack = malloc(sizeof(int) * SIZE);
	int *sp = stack;


	for (int i = 0; i < SIZE; i++)
		push(stack, sp, i);

	for (int i = 0; i < SIZE; i++)
		printf("%i\n", stack[i]);

	free(stack);

	return 0;
}


int pop(int *stack, int *sp) {
	return stack[*sp--];
}


void push(int *stack, int *sp, int x) {
	stack[*sp++] = x;
}

В чем ошибка?



Последнее исправление: CYB3R (всего исправлений: 1)
Ответ на: комментарий от Deleted

Я понимаю, я для себя, поэтому проверки не вставлял, а так ясное дело, что они нужны.

ChuCha
() автор топика
Ответ на: комментарий от Deleted

Без индексов:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 10

void push(int **sp, int x) { *(*sp)++ = x; }
int  pop(int **sp)         { return *(--*sp); }

int main() {
        int *stack = calloc(SIZE, sizeof(int));
        int **sp = &stack;

        for (int i = 0; i < SIZE; i++)
                push(sp, i);

        for (int i = 0; i < SIZE; i++)
                printf("%d\n", pop(sp));

        free(stack);

        return 0;
}
beastie ★★★★★
()

Буторно как-то. Не лучше ли так:

typedef struct _stackitem{
  int data;
  struct _stackitem *prev;
}stackitem;

stackitem *stack = NULL;

stackitem *push(int data){
  stackitem *new = malloc(sizeof(stackitem));
  if(!new) return NULL;
  new->data = data;
  new->prev = stack;
  stack = new;
  return stack;
}

int pop(int *data){
  if(!stack) return 0;
  *data = stack->data;
  stackitem *old = stack;
  stack = stack->prev;
  free(old);
  return 1;
}

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от beastie

Не велосипедь

Будешь смеяться, но я даже всякие "шагающие квадраты" для поиска 4-х и 8-связных областей велосипедил; построение изолиний и т.п. Захотелось.

Eddy_Em ☆☆☆☆☆
()

return stack[*sp--];
.
.
.
stack[*sp++] = x;

В чем ошибка?

должно пост и пре либо пре и пост а не пост и пост или пре и пре.

qulinxao ★★☆
()
Ответ на: комментарий от Deleted

одноглазый учит слепого бинокулярности

change from

   for (int i = 0; i < SIZE; i++)
                printf("%i\n", stack[i]);

        free(stack);

на

       for (int i = 0; i < SIZE; i++)
                printf("%i\n", stack[i]);

//test pop :)
	while(sp)
		printf("%i\n",pop(stack,&sp));

        free(stack);

и расcкажи ChuChaпочему выдачи различаютЬся

qulinxao ★★☆
()
Ответ на: одноглазый учит слепого бинокулярности от qulinxao

Да, у меня в функции pop() ошибка. Нужно return stack[--(*sp)];.

Но как у тебя получилось так сложно и так по-мудацки написать об этом? Вот над чем стоит поразмышлять на самом деле.

Deleted
()
Ответ на: комментарий от Deleted

Но как у тебя получилось так сложно и так по-мудацки написать об этом?

агриться на указания о ошибке естественная реакция у многих представителей популяции хомо.

qulinxao ★★☆
()
Ответ на: комментарий от qulinxao

А не ты ли не осилил многомерный массив через 1[m], а потом так же агрился? Но да, агрохомо ты себя не считаешь - это так мило.

TrueTsar1C
()
Ответ на: комментарий от TrueTsar1C

эээ по конкретней?

али ты про эмуляции(для лучшего понимания как указатели работают) на массиве int m[] реальной памяти и обращение не только

как index[m] но и indexA[m][m][m][m] - как многократое разыменование?

qulinxao ★★☆
()
Ответ на: комментарий от qulinxao

Да, да это ты. Русский для тебя родной? Ты абсолютно не умеешь излагать свои мысли по-русский.

Когда-то, мб полгод-год-полтора назад ты там в какой-то теме кукарекал про многократное разименование и выкатил пример, в котором ты точно так же сделал ошибку, ибо ты абсалютно не умеешь понимать/писать код, а умеешь только балаболить, ну и хотя как умеешь - даже этого не умеешь. После чего я тебя поправил и ты точно так же начал аргиться на меня, как пацан.

Причём пацану можно сделать скидку - твой выхлоп просто не читаем, а вот тебе нет.

TrueTsar1C
()

Держи. Тут еще обрати внимание на автоматическое расширение. Это можно убрать(в push в if'е просто возвращаешь -1).

#include <string.h>
#include <stdlib.h>

typedef struct stack {
    int * data;
    int * top;
    int * end;
} stack_t;

int
stack_init(stack_t * s, size_t n)
{
    memset(s, 0, sizeof(stack_t));
    s->data = malloc(sizeof(int) * n + 1);
    /* т.к. пишем под разные платформы, проверяем результат */
    if (!s->data) {
        return -1;
    }
    s->top = s->data;
    s->end = s->data + n;
    return 0;
}

int
stack_push(stack_t * s, int e)
{
    if (s->top == s->end) {
        size_t old_sz = s->end - s->data;
        size_t nw_sz = 1.5 * old_sz + 0.5;
        int * data = malloc(sizeof(int) * nw_sz + 1);
        /* т.к. пишем под разные платформы, проверяем результат */
        if (!data) {
            return -1;
        }
        s->data = memcpy(data, s->data, sizeof(int) * old_sz);
        s->top = s->data + old_sz;
        s->end = s->data + nw_sz;
    }
    *s->top++ = e;
    return 0;
}

int
stack_pop(stack_t * s, int * res)
{
    if (!res || s->top == s->data) {
        return -1;
    }
    *res = *(--s->top);
    return 0;
}

int
stack_top(stack_t * s, int * res)
{
    if (!res || s->top == s->data) {
        return -1;
    }
    *res = *s->top;
    return 0;
}

void
stack_destroy(stack_t *s)
{
    if (s->data) {
        free(s->data);
    }
}

Тестовый пример:

#include <stdio.h>

#define SIZE 10

int
dump_stack(stack_t * s)
{
    int *p = s->data;
    printf("base: %p\n", p);
    printf("top: +%d\n", (int)(s->top - p));
    printf("end: +%d\n|", (int)(s->end - p));
    for (;p != s->top; ++p) {
        printf("%d|", *p);
    }
    printf("#*");
    for (;p != s->end; ++p) {
        printf("%d*", *p);
    }
    printf("\n");
}

int
main()
{
    stack_t s;
    stack_init(&s, SIZE - 5);
    dump_stack(&s);

    int i;
    for (i = 0; i < SIZE; ++i) {
        stack_push(&s, i);
        dump_stack(&s);
    }

    int r = 0;
    while (stack_pop(&s, &r) == 0) {
        printf("%d\n", r);
        dump_stack(&s);
    }

    dump_stack(&s);
    stack_destroy(&s);

    return 0;
}

anonymous
()
Ответ на: комментарий от anonymous

Ну ты наговнокодил, извращенецъ! В твоём коде память течёт по-чёрному.

Если ты - тот анонимус, что мне незачёт поставил, то твоя оценка ничего не стоит и идёт в задний проход. Твой коммент о кодах возврата идёт туда же по причине глупости сего утверждения. В общем, fail.

А если личико покажешь, я, так и быть, разберу твой код и потыкаю тебя носом в твоё невежество. И код с несколькими стеками нарисую.

alexku
()
Ответ на: комментарий от alexku

Вы оба(или сколько вас там) хороши=)

Справедливости ради, у него править вроде меньше нужно.

Вообще удручает куча говнокода в треде.

forCe
()
Последнее исправление: forCe (всего исправлений: 1)

Ты K&R читал? Если нет, то надо.

К сожалению, в тех вариантах кода, что приведены в данной теме, много ошибок. Разных.

Что можно сказать в общем и целом. Делаешь структуру данных. Так, чтобы для описания состояния не требовались внешние переменные. Проектируешь набор операций и каждую операцию в отдельности. Думаешь об инвариантах(если не знаешь что это - гугли). Думаешь об обработке ошибок. Думаешь о памяти(кто владеет, кто выделяет, кто и когда удаляет). Реализуешь. Тестируешь. Прогоняешь valgrind'ом(например) для поиска утечек и пр. проблем. Если что, дебажишь gdb. А дальше, чем больше практики, тем лучше.

forCe
()
Ответ на: комментарий от alexku

Ну ты наговнокодил, извращенецъ! В твоём коде память течёт по-чёрному.

Там всего-лишь забыт один free при расширении стека. Твой же стек размазан по коду, не умеет множество инстансов, не умеет расширятся. Объективно вы оба неправы. Но его код правится в паре строк, твой нужно переписывать.

anonymous
()
Ответ на: комментарий от alexku

Ну ты наговнокодил, извращенецъ! В твоём коде память течёт по-чёрному.

Да, при расширении забылся free. Код толком не проверялся, этот участок дописывался позднее.

<         s->data = memcpy(data, s->data, sizeof(int) * old_sz);
---
>         memcpy(data, s->data, sizeof(int) * old_sz);
>         free(s->data);
>         s->data = data;

Твой же код вообще негоден.

Твой коммент о кодах возврата идёт туда же по причине глупости сего утверждения

Это не глупость. Есть определенные стандарты, которые ты нарушаешь. Без каких-то серьезных оснований.

anonymous
()
Ответ на: комментарий от anonymous

Это не глупость. Есть определенные стандарты, которые ты нарушаешь. Без каких-то серьезных оснований.

Чушь. Нет никаких стандартов на этот счёт. Есть необходимость и здравый смысл. Ну, ещё есть задний ум говнокодера.

Твой же код вообще негоден.

Ок, давай сравним годность кода. Ты ошибку с утечкой памяти исправил. Я добавляю проверку выделения памяти, которую просто опустил для упрощения кода (врядли в системе не найдётся килобайт 100 для демонстрации работы стека) и печать размера стека после инициализации.

int main(int argc, char **argv) {
  if(!(stack.begin = malloc(STACK_SIZE * sizeof(int))))
    return 1;
  stack.end = stack.begin + STACK_SIZE;
  stack.current = stack.begin;

  printf("Test stack, size = %d\n", STACK_SIZE);
...

А теперь проинициализируй стек размером 0 и расскажи, что будет в моём и твоём случае. В моём случае можешь вообще ничего не исправлять, только #define STACK_SIZE 0 сделай. А потом порассуждаем о годности кода.

alexku
()
Ответ на: комментарий от anonymous

Да, и ещё я не вкурил, к чему этот комментарий? Поясни.

/* т.к. пишем под разные платформы, проверяем результат */
alexku
()
Ответ на: комментарий от ChuCha

Издательство «Вильямс» 2009 год K&R страница 106, о приоритете операторов"++" и «*».

Больше НИКОГДА __ТАК__ не делай!

Twissel ★★★★★
()
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от alexku

Чушь. Нет никаких стандартов на этот счёт. Есть необходимость и здравый смысл. Ну, ещё есть задний ум говнокодера.

Стандарты есть. Есть тонны написанного кода. Есть POSIX и пр.

А теперь проинициализируй стек размером 0 и расскажи, что будет в моём и твоём случае.

Ты еще предложи на входе функций проверять указатель на NULL. Ненулевой размер является предусловием в данном случае. Думаю, что это разумно.

anonymous
()
Ответ на: комментарий от alexku

В моём случае можешь вообще ничего не исправлять

Ты думаешь, что malloc(0) вернет NULL? Никто тебе этого не гарантирует.

anonymous
()
Ответ на: комментарий от alexku

В моём случае можешь вообще ничего не исправлять

А в моем что нужно исправить? Разве что инициализацию стека, где просто для демонстрации(и только) было передано на 5 элементов меньше.

anonymous
()
Ответ на: комментарий от anonymous

Стандарты есть. Есть тонны написанного кода. Есть POSIX и пр.

Что в POSIX входит, то и стандартизировано. То, что пишешь ты сам, делаешь так как считаешь нужным. Вот если ты напишешь нечто настолько полезное, что оно будет включено в POSIX, то оно станет стандартом, что бы и как ты там не возвращал.

Ты еще предложи на входе функций проверять указатель на NULL. Ненулевой размер является предусловием в данном случае. Думаю, что это разумно.

С тобой всё ясно. Хеловордщик во всей красе.

Говнокодера, который не проверяет указатели на входе я буду валтузить мордой по его говнокоду до тех пор, пока у него на лбу не отпечатается «ПРОВЕРЯЙ УКАЗАТЕЛИ НА ВХОДЕ!». Да и вообще в критических местах необходимо проверять все входные параметры на допустимые значения. Потому что именно благодаря таким верящим в соблюдение предусловий хеловордщикам программы падают в непредсказуемых местах, а Союзы не долетают до МКС. Потому что на хеловордщика, верящего в то, что предусловия будут выполнены, найдётся хеловордщик, который не выполнит это предусловие. И частенько это один и тот же говнокодер.

alexku
()
Ответ на: комментарий от anonymous

Ты думаешь, что malloc(0) вернет NULL? Никто тебе этого не гарантирует.

Я знаю, что вернёт malloc(0). Ты, вместо того чтобы задавать глупые вопросы и что-то мямлить по гарантии, возьми и проверь поведение моего кода. Просто собери и запусти.

alexku
()
Ответ на: комментарий от anonymous

А в моем что нужно исправить? Разве что инициализацию стека, где просто для демонстрации(и только) было передано на 5 элементов меньше.

int
stack_push(stack_t * s, int e)
{
    if (s->top == s->end) {
        //Добавим 2, чтобы было что делить, если длина окажется равной 0.
        //Это небольшой изврат, но так мы избавляемся от двух проверок на 0
        //да и +- 1 к новому размеру тут не важен.
        size_t new_size = s->end - s->data + 2;
        size_t current_pos = s->top - s->data;

        //Увеличим размер в 1,5 раза
        new_size += new_size / 2; 

        int *tmp = realloc(s->data, new_size * sizeof(int));
        if(!tmp)
            return -1;

        s->data = tmp;
        s->end = s->data + new_size;
        s->top = s->data + current_pos;
    }

    *s->top++ = e;
    return 0;
}

Теперь можно создавать стек с нулевой длиной.

alexku
()
Ответ на: комментарий от alexku

Так будет правильнее

    if (s->top == s->end) {
        size_t current_pos = s->end - s->data;
        //Увеличим размер в 1,5 раза
        //Добавим 2, чтобы было что делить, если длина окажется равной 0.
        //Это небольшой изврат, но так мы избавляемся от двух проверок на 0
        //да и +- 1 к новому размеру тут не важен.
        size_t new_size = current_pos + (current_pos + 2) / 2;
...
alexku
()
Ответ на: комментарий от alexku

Что в POSIX входит, то и стандартизировано. То, что пишешь ты сам, делаешь так как считаешь нужным. Вот если ты напишешь нечто настолько полезное, что оно будет включено в POSIX, то оно станет стандартом, что бы и как ты там не возвращал.

Из-за таких как ты люди мучаются с разными API, путаются и делают глупые ошибки. Зачем тебе это?

Говнокодера, который не проверяет указатели на входе я буду валтузить мордой по его говнокоду до тех пор, пока у него на лбу не отпечатается «ПРОВЕРЯЙ УКАЗАТЕЛИ НА ВХОДЕ!».

Мда. Про предусловия, постусловия и инварианты ты явно не слышал. Быдлокодер, да еще и уверенный в своей правоте. Хуже сочетания не придумаешь.

Даже free не проверяет указатель на NULL.

Потому что именно благодаря таким верящим в соблюдение предусловий хеловордщикам программы падают в непредсказуемых местах, а Союзы не долетают до МКС.

Ты правда в это веришь?

Проверять нужно там, где нужно проверять. Если человек передает NULL в качестве указателя на стек, то он дурак.

anonymous
()
Ответ на: комментарий от alexku

Говнокодера, который не проверяет указатели на входе я буду валтузить мордой по его говнокоду до тех пор, пока у него на лбу не отпечатается «ПРОВЕРЯЙ УКАЗАТЕЛИ НА ВХОДЕ!».

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

anonymous
()
Ответ на: комментарий от anonymous

Из-за таких как ты люди мучаются с разными API, путаются и делают глупые ошибки. Зачем тебе это?

Избавь людей от глупости. Создай единый API для всего. Дай ответ на главный вопрос жизни, вселенной и всего такого.

Мда. Про предусловия, постусловия и инварианты ты явно не слышал.

То, что ты про них только слышал, это я уже понял.

Даже free не проверяет указатель на NULL.

RTFM, безграмотное чучело! Цитирую man 3 free специально для тебя.

The free function causes the allocated memory referenced by ptr to be made available for future allocations. If ptr is NULL, no action occurs.

Английский знаешь или перевести надо?

Ты правда в это веришь?

А ты веришь, что программы падают сами по себе? Так посмотри на этот код и убедись, что это не так.

alexku
()
Ответ на: комментарий от alexku

Так это не по адресу. Все свои удивления адресуйте тому, кто стек дампит.

извините - не отследил сразу, кто автор изначального творения.

просто подобное нельзя нигде использовать, и лучше бы сразу не писать.

MKuznetsov ★★★★★
()
Ответ на: комментарий от alexku

Английский знаешь или перевести надо?

Теперь в стандарты Си посмотри разных лет, которые до сих пор используются.

А ты веришь, что программы падают сами по себе?

Эта программа не падает

anonymous
()
Ответ на: комментарий от MKuznetsov

просто подобное нельзя нигде использовать, и лучше бы сразу не писать.

А чего там такого?

anonymous
()
Ответ на: комментарий от anonymous

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

Да, ты прав, ещё одну проверку надо добавить.

int pop(int *val) {
  if(!val || stack.current == stack.begin)
    return 0;

...

А можно ещё и в main проверку поменять, то есть, допустить возможность того, что stack.begin = NULL, и всё равно код останется рабочим.

int main(int argc, char **argv) {
//Эти строки можно закомментировать, и всё равно код будет работать корректно
  if((stack.begin = malloc(STACK_SIZE * sizeof(int)))) {
    stack.end = stack.begin + STACK_SIZE;
    stack.current = stack.begin;
  }

...
alexku
()
Ответ на: комментарий от anonymous

Теперь в стандарты Си посмотри разных лет, которые до сих пор используются.

Так расскажи нам о стандартах, где free() что-то делает с NULL. Я такого не знаю. Просвети.

Эта программа не падает

Ну как же не падает? Ты же допускаешь такой вызов

stack_init(&s, SIZE - 5);
То есть, можно предположить, что размер может быть любым. Значит, найдётся кто-то, кто его сделает нулевым. Я, например. И, например, так
stack_init(&s, SIZE - 10);
Но проверку на нулевой размер ты не делаешь. Почему? Собственно, переадресую твой вопрос тебе. Ты думаешь, что malloc(0) вернет NULL? Никто тебе этого не гарантирует. Более того, malloc возвращает вполне валидный указатель на память нулевой длины. Вот тут-то твой код и вылетает с сегфолтом предварительно засрав экран дампами чего-то там. А ты говоришь не падает.

alexku
()
Ответ на: комментарий от alexku

stack_init(&s, SIZE - 5);

Это не относится к коду стека, это тестовый пример, где размер был уменьшен после добавления функциональности с расширением стека. Да, можно сказать, что это неверный пример использования стека.

anonymous
()
Ответ на: комментарий от alexku

Так расскажи нам о стандартах, где free() что-то делает с NULL. Я такого не знаю. Просвети.

Был неправ.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.