Zadanie na kod niestrukturalny, z użyciem goto

1

Mam takie zadanie: Napisz w języku C program rysujący "choinki". Liczba poziomów powinna być pobierana z klawiatury. UWAGA: Program należy napisać NIESTRUKTURALNIE - to znaczy nie wolno używać "struktur sterujących" - pętli, else, sekwencji (czyli nie można użyć nawiasów { oraz } poza rozpoczęciem i zakończeniem maina). Za to można (a nawet trzeba) używać goto.
zacząłem coś takiego, ale nie wiem czy to dobra droga i w tym punkcie utknąłem . macie jakieś rady?


#include <stdio.h>

int main()
{
    start:
    printf("podaj liczbe poziomow");
    int x;
    scanf("%d", &x);
    int temp = x;
    int p;
    int r = 1;
  
    
    
    
    empty:
   
    p = x - 1;
    printf(" ");
    x--;
    if(p == 1)
       goto draw;
    goto empty;
    
       
    draw:
       printf("*");
       if(r == x )
        goto newline;
    
    
    
  
    
    goto start;
    
    
    newline:
     printf("/n");
     x = temp - 1;
     goto empty;
     
    
    return 0;
}

6
maksym572285 napisał(a):

Za to można (a nawet trzeba) używać goto.
...
macie jakieś rady?

Zmień źródło nauki programowania! Wyjdzie ci to na dobre.

To zadanie naprawdę powinno mieć tytuł: naucz się jak robić źle i nabierz złych praktyk.

0

Mi się to zadanie podoba.
Chociaż faktycznie niespecjalnie do nauki.

( lol ale walnąłem dubla, chyba musiałem cofnąć do poprzedniej karty )

1
MarekR22 napisał(a):

To zadanie naprawdę powinno mieć tytuł: naucz się jak robić źle i nabierz złych praktyk.

A może o to chodzi? Najpierw zrób w stylu lat 60, żebyś docenił cały postęp, jaki się od tamtej pory dokonał?

Chociaż czemu na tym poprzestawać? Nie lepiej to napisać w asemblerze?

3

Nie radze tego oddawac jako swoje, chocby dlatego ze to nie jest poprawne C i jest spora szansa ze nawet sie nie skompiluje poza gcc. Ale bylem ciekawy na ile trudno bedzie spelnic tak idiotyczne wymamagania. Okazalo sie ze bardzo prosto. Jak zrozumiesz co tu sie dzieje to powinno byc bardzo prosto napisac to nieco czytelniej i zgodnie ze standardem.

$ cat t.c
#include <stdio.h>
int main() {
  int loops;
  char character;
  void* returnAddress;
  int levels;
  scanf("%d", &levels);
  int level = 0;
cnt1:
  void* addr[2] = {&&cnt2, &&end};
  goto *addr[level == levels];
cnt2:
  loops = levels - 1 - level;
  character = ' ';
  returnAddress = &&return1;
  goto print;
return1:
  loops = level * 2 + 1;
  character = '*';
  returnAddress = &&return2;
  goto print;
return2:
  printf("\n");
  level++;
  goto cnt1;
print:
  int i = 0;
print_cnt1:
  void* print_addr[2] = {&&print_cnt2, returnAddress};
  goto *print_addr[i == loops];
print_cnt2:
  printf("%c", character);
  i++;
  goto print_cnt1;
end:
  return 0;
}
$ gcc -Wall -Wextra t.c && ./a.out
5
    *
   ***
  *****
 *******
*********

Co do idiotycznosci zadania - no jest durne, ale moze np. przedmiot nazywa sie "wprowadzenie do assemblera". Prosciej cos takiego napisac w C niz sie zafixowac na jakims konkretnym assemblerze i potem myslec ze wszedzie jest tak samo.

1
MarekR22 napisał(a):
maksym572285 napisał(a):

Za to można (a nawet trzeba) używać goto.
...
macie jakieś rady?

Zmień źródło nauki programowania! Wyjdzie ci to na dobre.

To zadanie naprawdę powinno mieć tytuł: naucz się jak robić źle i nabierz złych praktyk.

No nie koniecznie.

Spodziewam się że nauczyciel zadał dwa zadania, napisz ten sam program jeden używając tylko pętli i bez goto, a drugi bez pętli i z goto. Wynikiem pewnie ma być porównanie czemu programowanie strukturalne jest lepsze.

0
Riddle napisał(a):
MarekR22 napisał(a):
maksym572285 napisał(a):

Za to można (a nawet trzeba) używać goto.
...
macie jakieś rady?

Zmień źródło nauki programowania! Wyjdzie ci to na dobre.

To zadanie naprawdę powinno mieć tytuł: naucz się jak robić źle i nabierz złych praktyk.

No nie koniecznie.

Spodziewam się że nauczyciel zadał dwa zadania, napisz ten sam program jeden używając tylko pętli i bez goto, a drugi bez pętli i z goto. Wynikiem pewnie ma być porównanie czemu programowanie strukturalne jest lepsze.

Ale goto przydaje się w programowaniu niskopoziomowym np. jądra systemu operacyjnego

0

Jedyne zastosowanie jakie ma to wyjście z wielowarstwowej pętli elegancko lub żeby obsłużyć zwalnianie zasobów w jednym miejscu, a nie replikowanie tych samych czynności przy każdym wyjściu funkcji z błędem. Tak tego wszystkiego można uniknąć przy pomocy RAII, w kernelu można używać C++, ale bez std library, czyli same namespace, RAII, class.

2

Specyficzne zadania dopraszają się o specyficzne odpowiedzi... zatem napisałem makro, które enkapsuluje pętlę używającą goto:

#include <stdio.h>

#define LOOP(iter, start_, stop_, code) \
iter = start_;\
begin ## iter:\
if(iter > stop_) goto end ## iter;\
code;\
iter+=1;\
goto begin ## iter;\
end ## iter:


int main() {
    printf("Podaj ilość poziomów: ");
    int levels;
    scanf("%d", &levels);

/*
    int i, j, k;
    for(i=1; i<=levels; i++)
    {
        for(j=1;j<=levels-i; j++)
        {
            printf(" ");
        }
        for(k=1; k<=2*i-1; k++)
        {
            printf("*");
        }
        printf("\n");
    }

*/
    int i, j, k;
    LOOP(
        i,
        1, 
        levels,
        LOOP(j, 1, levels-i, printf(" "));LOOP(k, 1, 2*i-1, printf("*"));printf("\n");
    )
}
1

Bez goto: https://godbolt.org/z/cqGj4763o
Wersja goto: https://godbolt.org/z/9qMe49hf3

#include <stdio.h>
#include <string.h>

const char pine_shoot[] = "**********************************************************";

int main()
{
    int level, i;
    if (scanf("%d", &level) == 1 && (int)strlen(pine_shoot) >= level * 2 + 1) {
        i = 0;
        for_loop:
            printf("%*.*s\n", level + i, 2 * i + 1, pine_shoot);
            ++i;
        if (i < level)
            goto for_loop;
    }
}
0

Mogę Ci tak ogólnie podopwiedzieć, że żeby samemu zrobić while za pomocą goto i if, należy umieścić w programie dwie etykiety, jedną przed całą pętlą i drugą po niej, natomiast między nimi po kolei skok do etykiety końcowej w razie niespełnienia warunku, ciało pętli, i skok do etykiety początkowej.

1

Niestety nie spełnia (bo używa klamr - przeoczyłem to).

#include <stdio.h>

void print_chars(int count, char c) {
    if(count > 0) {
        printf("%c", c);
        print_chars(count - 1, c);
    }
}

void draw_tree(int space, int stars, int height) {
    if(height > 0) {
        print_chars(space, ' ');
        print_chars(stars, '*');
        printf("\n");
        draw_tree(space - 1, stars + 2, height - 1);
    }
}

int main() {
    int height;
    printf("Podaj wysokosc choinki: ");
    scanf("%d", &height);

    draw_tree(height - 1, 1, height);

    return 0;
}

by ChatGPT

0
jarekr000000 napisał(a):

Niestety nie spełnia (bo używa klamr - przeoczyłem to).

#include <stdio.h>

void print_chars(int count, char c) {
    if(count > 0) {
        printf("%c", c);
        print_chars(count - 1, c);
    }
}

void draw_tree(int space, int stars, int height) {
    if(height > 0) {
        print_chars(space, ' ');
        print_chars(stars, '*');
        printf("\n");
        draw_tree(space - 1, stars + 2, height - 1);
    }
}

int main() {
    int height;
    printf("Podaj wysokosc choinki: ");
    scanf("%d", &height);

    draw_tree(height - 1, 1, height);

    return 0;
}

by ChatGPT

Jakby jedynym problemem były klamry to można by użyć return, tzn.:

#include <stdio.h>

void print_chars(int count, char c) {
    if (count <= 0)
        return;
    printf("%c", c);
    print_chars(count - 1, c);
}

void draw_tree(int space, int stars, int height) {
    if (height <= 0)
        return;
    print_chars(space, ' ');
    print_chars(stars, '*');
    printf("\n");
    draw_tree(space - 1, stars + 2, height - 1);
}

int main() {
    int height;
    printf("Podaj wysokosc choinki: ");
    scanf("%d", &height);

    draw_tree(height - 1, 1, height);

    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1