• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zadanie "stosowate" :)

Object Storage Arubacloud
0 głosów
972 wizyt
pytanie zadane 10 czerwca 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)

Cześć :)

Robię teraz takie oto zadanie:

Napisz program, który pozwoli użytkownikowi na wykonywanie podstawowych operacji na stosie. W tym celu zaimplementuj stos w oparciu o następujące struktury oraz funkcje:

struct stack_t
{
    int head;
    int capacity;
    int *data;
};
gdzie:

head - indeks pierwszej wolnej pozycji na stosie,
capacity - pojemność tablicy przydzielonej na stos,
data - wskaźnik na tablicę do przechowywania elementów stosu.
Przygotuj następujące funkcje, umożliwiające obsługę stosu:

int stack_init(struct stack_t **stack, int N);
int stack_push(struct stack_t *stack, int value);
int stack_pop(struct stack_t *stack, int *err_code);
void stack_display(const struct stack_t *stack);
void stack_free(struct stack_t *stack);
Deklaracje wszystkich funkcji oraz struktur umieść w pliku nagłówkowym stack.h, a definicje w pliku stack.c.

int stack_init(struct stack_t **stack, int N);
Funkcja przydziela pamięć na strukturę stack_t oraz tablicę N elementów i inicjuje jej pola odpowiednimi wartościami.

Funkcja zwraca wartość:

1 w przypadku przekazania błędnych danych,
2 w przypadku niepowodzenia alokacji pamięci lub
0 w przypadku sukcesu.
int stack_push(struct stack_t *stack, int value);
Funkcja dodaje element o wartości value do stosu stack. Jeżeli zabraknie miejsca w tablicy na dodanie nowej wartości value to funkcja powinna podwoić pojemność tablicy.

Funkcja zwraca:

0 w przypadku sukcesu,
1 w przypadku błędnych danych wejściowych lub
2 jeżeli nie uda się przydzielić pamięci (w takim przypadku nie powinna modyfikować tablicy).
int stack_pop(struct stack_t* stack, int *err_code);
Funkcja usuwa ostatnio dodany element ze stosu stack zwracając jego wartość. W przypadku błędu zwracana wartość jest nieistotna.

Do zmiennej err_code, o ile to możliwe, zapisany powinien zostać kod błędu:

0 w przypadku sukcesu,
1 w przypadku błędnych danych wejściowych,
2 jeżeli stos jest pusty.
void stack_free(struct stack_t* stack);
Funkcja zwalnia całą pamięć przydzieloną na stos. W przypadku błędnych danych funkcja nie podejmuje żadnej akcji.

void stack_display(const struct stack_t* stack);
Funkcja wyświetla wszystkie elementy ze stosu stack, w jednym wierszu, oddzielone spacjami. Pierwszym wyświetlonym elementem ma być ostatni dodany na stos.

W przypadku błędnych danych funkcja nie podejmuje żadnej akcji.

Napisz program, który pozwoli użytkownikowi na wykonywanie podstawowych operacji na stosie. Na początek program powinien zaalokować pamięć na stos, początkowo przyjmij pojemność stosu na 10 elementów.

Jeżeli udało się utworzyć listę, program powinien zapytać użytkownika o wybór operacji (liczba całkowita):

0 - Zakończenie działania prosgramu.

1 - Dodanie elementu do stosu; program pobiera od użytkownika wartość całkowitą, która ma zostać położona na stos.

2 - Zdjęcie elementu ze stosu; program powinien wyświetlić wartość zdjętego elementu.

Jeżeli stos jest pusty program powinien wyświetlić komunikat Stack is empty.
3 - wyświetlenie wartości wszystkich elementów znajdujących się na stosie.

Jeżeli stos jest pusty program powinien wyświetlić komunikat Stack is empty.
W przypadku podania innej wartości program powinien wyświetlić komunikat Incorrect input data i kontynuować działanie.

Jeżeli nie uda się zaalokować żądanego obszaru pamięci program powinien wyświetlić komunikat Failed to allocate memory i zwrócić kod błędu 8.

W przypadku wprowadzenia przez użytkownika błędnych znaków program powinien bezzwłocznie zakończyć działanie z kodem błędu 1 i komunikatem Incorrect input

Na tą chwilę skupiam się, aby przeszły testy funkcyjne, bo bez funkcji nie mam po co przechodzić do rozpisywania main(). Na tą chwilę jeżeli chodzi o funkcje mam tyle:

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


int stack_init(struct stack_t **stack, int N)
{
    if( stack == NULL || N <= 0 )
    {
        return 1;
    }
    *stack = (struct stack_t *) malloc (sizeof(struct stack_t ) );
    if( *stack == NULL )
    {
        return 2;
    }
    struct stack_t * point_on_struct;
    point_on_struct = *stack;
    ( point_on_struct->data) = (int *) malloc (sizeof(int) * N);
    if( (point_on_struct->data) == NULL  )
    {
        //free(point_on_struct);
        free(*stack);
        *stack = NULL;
        return 2;
    }
    ( point_on_struct -> capacity) = N;
    ( point_on_struct -> head ) = 0;
    return 0;
}

int stack_push(struct stack_t *stack, int value)
{
    if( stack == NULL )
    {
        return 1;
    }
    if( stack->head  == 0 )
    {
        stack->data = (int *) realloc(stack->data,(stack->capacity) * 2);
        if( stack->data == NULL )
        {
            free(stack);
            stack = NULL;
            return 2;
        }
    }
    int i = 0;
    i = stack->head;
    int * pointer_on_data = stack->data;
    *(pointer_on_data + i) = value;
    int * pointer_on_head = &(stack->head);
    *pointer_on_head = *pointer_on_head + 1;
    return 0;
}

int stack_pop(struct stack_t *stack, int *err_code)
{
    return 0;
}

void stack_display(const struct stack_t *stack)
{
    if( stack == NULL )
    {

    }
    else
    {
        int i = (stack -> head) - 1;
        while( i >= 0 )
        {
            int * pointer = stack->data;
            printf("%d ", *(pointer + i) );
            i--;
        }
    }
}
void stack_free(struct stack_t *stack)
{
    if( stack == NULL )
    {

    }
    else
    {
        free( (stack->data) );
        free(stack);
        stack = NULL;
    }
}

O ile ze stack_init nie było problemów, o tyle nie do końca wiem na co powinno wskazywać stack->head w funkcji stack_push, gdy stos jest pełny (dzięki temu będę wiedział, czy mam robić realloc-a na dwa razy więcej miejsca). Myślałem, że być może gdy stos jest pełny pokazuje na element o 1 większy od capacity. To jednak chyba nie to. Na pytanie do prowadzącego dostałem taką odpowiedź:

Dzień dobry,

proszę się przyjrzeć opisowi pól head i capacity:

head - indeks pierwszej wolnej pozycji na stosie,
capacity - pojemność tablicy przydzielonej na stos,
Skoro head wskazuje na pierwszą wolną pozycję na stosie, to na co będzie wskazywał, kiedy stos będzie pełny?

De facto czytałem to kilka razy pod rząd i dalej nie rozumiem co autor zadania chciał mi przekazać w ostatnim zdaniu. Domyślacie się może o co chodzi?

 

1 odpowiedź

0 głosów
odpowiedź 10 czerwca 2020 przez j23 Mędrzec (194,920 p.)
int stack_push(struct stack_t* stack, int value)
{
	if (stack == NULL) return 1;
	if(stack->capacity == stack->head) {
		/* tu zwiększasz pamięć */
	}

	*(stack->data + stack->head) = value;
	++stack->head;
	return 0;
}

 

komentarz 10 czerwca 2020 przez Hubertius Bywalec (2,970 p.)

Na chwilę obecną mam to rozpisane w takiej postaci:

int stack_push(struct stack_t *stack, int value)
{
    if( stack == NULL )
    {
        return 1;
    }
    if( stack->head  == stack->capacity  )
    {
        stack->data = (int *) realloc(stack->data,(stack->capacity) * 2);
        if( stack->data == NULL )
        {
            free(stack);
            stack = NULL;
            return 2;
        }
    }/*
    int i = 0;
    i = stack->head;
    int * pointer_on_data = stack->data;
    *(pointer_on_data + i) = value;
    int * pointer_on_head = &(stack->head);
    *pointer_on_head = *pointer_on_head + 1;
    */
     *(stack->data + stack->head) = value;
    ++stack->head;
    return 0;
}

Wyrzuca mi taką informację na pierwszym teście funkcyjnym:

PORAŻKA: Funkcja stack_push() powinna ustawić wartość pola size w strukturze na 40, a ustawiła na 20⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 500⏎
Wynik: PORAŻKA: Wartość pod indeksem 10 jest nieprawidłowa; powinno być 6, a jest 488513312⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 11 jest nieprawidłowa; powinno być -17, a jest 421141276⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 12 jest nieprawidłowa; powinno być 92, a jest 353769240⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 13 jest nieprawidłowa; powinno być 69, a jest 286397204⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 14 jest nieprawidłowa; powinno być -14, a jest 219025168⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 15 jest nieprawidłowa; powinno być -18, a jest 151653132⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 16 jest nieprawidłowa; powinno być 12, a jest 84281096⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 17 jest nieprawidłowa; powinno być -99, a jest 16909060⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 18 jest nieprawidłowa; powinno być 77, a jest 49⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 19 jest nieprawidłowa; powinno być 99, a jest 0⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎

 

komentarz 11 czerwca 2020 przez j23 Mędrzec (194,920 p.)

Robisz realloc, ale nie ustawiasz nowej wartości polu capacity.

komentarz 11 czerwca 2020 przez Hubertius Bywalec (2,970 p.)
edycja 11 czerwca 2020 przez Hubertius

Tak, poprawiłem to już. Przynajmniej nie czepia mnie się teraz o niepoprawny rozmiar.

Jednak dalej są błędy z zapisywaniem wartości. Sam zobacz:

TEST 10: Sprawdzanie poprawności działania funkcji stack_push⏎
#####START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END##########START##########END#####Wynik: PORAŻKA: Wartość pod indeksem 7 jest nieprawidłowa; powinno być 40, a jest 522190888⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 8 jest nieprawidłowa; powinno być 38, a jest 454827294⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 9 jest nieprawidłowa; powinno być 57, a jest 387455258⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 10 jest nieprawidłowa; powinno być 97, a jest 320083222⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 11 jest nieprawidłowa; powinno być -42, a jest 252711186⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 12 jest nieprawidłowa; powinno być -80, a jest 185339150⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 13 jest nieprawidłowa; powinno być -29, a jest 117967114⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Wynik: PORAŻKA: Wartość pod indeksem 14 jest nieprawidłowa; powinno być -17, a jest 50595078⏎
       Sprawdź funkcję testującą TEST10(void) z pliku unit_test_v2.c, w linii 505⏎
Analiza zasobów: PORAŻKA: Wykryto naruszenie granic bloku pamięci. [Uszkodzony został blok zaalokowany w stack.c:43 a samo uszkodzenie zauważono w trakcie wykonywania stack.c:93. Opis: Wykryto modyfikację obszaru pamięci za zaalokowanym blokiem (RVE_INVALID_TAIL_FENCE)]⏎

Oto mój kod funkcji:


int stack_push(struct stack_t *stack, int value)
{
    if( stack == NULL )
    {
        return 1;
    }
    if( stack->head   == stack->capacity  )
    {
        stack->capacity = stack->capacity  * 2;
        stack->data = (int *) realloc(stack->data, sizeof(int) * (stack->capacity) );
        if( stack->data == NULL )
        {
            free(stack);
            stack = NULL;
            return 2;
        }
    }
    int i = stack->head;
    int * pointer_on_data = stack->data;
    *(pointer_on_data + i) = value;
    int * pointer_on_head = &(stack->head);
    *pointer_on_head = *pointer_on_head + 1;

    // *(stack->data + stack->head) = value;
    //++stack->head;
    return 0;
}

P.S

Okej, dostałem jak coś odpowiedź od prowadzącego, że z funkcją realloc jest coś mocno nie tak.

komentarz 11 czerwca 2020 przez j23 Mędrzec (194,920 p.)
    int i = stack->head;
    int * pointer_on_data = stack->data;
    *(pointer_on_data + i) = value;
    int * pointer_on_head = &(stack->head);
    *pointer_on_head = *pointer_on_head + 1;

Po co ta ekwilibrystyka, skoro można to zapisać w dwóch linijkach (co też pokazałem)?

Co z realloc jest nie tak?

komentarz 11 czerwca 2020 przez Hubertius Bywalec (2,970 p.)

Generalnie dostałem taką odpowiedź od prowadzącego na mój obecny kod:

Proszę dalej się wczytywać w opis funkcji realloc, oraz dokładniej przeczytać secyfikację funkcji push, co się powinno stać w przypadku niepowodzenia alokacji pamięci?

Chyba czegoś nie rozumiem.  :(

komentarz 11 czerwca 2020 przez j23 Mędrzec (194,920 p.)

Popraw:

    if (stack->head == stack->capacity) {
        size_t cap = stack->capacity * 2;
        int* p = (int*)realloc(stack->data, sizeof(int) * cap);
        if (p == NULL) return 2;
        stack->capacity = cap;
        stack->data = p;
    }

 

komentarz 11 czerwca 2020 przez Hubertius Bywalec (2,970 p.)
edycja 11 czerwca 2020 przez Hubertius

Okej. Czyli chodziło o to, aby wartości dla stack->capacity i adres dla stack->data pozostały niezmienne w przypadku błędu realokacji. A w przypadku zwrócenia z funkcji 2 w samym main() zwolni się strukturę.

A co do funkcji stack_pop:

int stack_pop(struct stack_t* stack, int *err_code);
Funkcja usuwa ostatnio dodany element ze stosu stack zwracając jego wartość. W przypadku błędu zwracana wartość jest nieistotna.

Do zmiennej err_code, o ile to możliwe, zapisany powinien zostać kod błędu:

0 w przypadku sukcesu,
1 w przypadku błędnych danych wejściowych,
2 jeżeli stos jest pusty.

 

Jak będzie wyglądało usuwanie elementu? Okej, zwracam:

i = --stack->head

*(stack->data + i)

a stack->head zmniejszam tak, by:

--stack->head

 

Ponadto jak sprawdzić, czy stos jest pusty? Gdy stack->capacity == 0?

komentarz 11 czerwca 2020 przez j23 Mędrzec (194,920 p.)

Sprawdź pole head. Jeśli jest zero, to stos jest pusty.

Podobne pytania

0 głosów
1 odpowiedź 112 wizyt
pytanie zadane 21 marca 2023 w C i C++ przez bananen Nowicjusz (170 p.)
0 głosów
1 odpowiedź 315 wizyt
pytanie zadane 6 czerwca 2022 w C i C++ przez kacper1445 Gaduła (4,880 p.)

92,565 zapytań

141,416 odpowiedzi

319,599 komentarzy

61,950 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...