Nauka programowania w C - analiza programu.

0

Witam Serdecznie.
Na wstępie przepraszam z góry za swoje może dość infantylne pytanie ale dopiero zaczynam uczyć się programowania (5 dzień). Póki co poznałem nieco język, wszystkie pętle, zmienne etc. Jakiś tam prosty program potrafię napisać. Teraz jestem na etapie analizowania prostych gotowych programów i nie mogę sobie poradzić z jednym. Zupełnie nie wiem co za co odpowiada. Program opiera się na pętlach "while". Rysuje on odwrócony pusty trójkąt, dokładnie taki:

0

Ale jakie jest pytanie?

0

Przepraszam, przez pomyłkę kliknąłem wyślij i nie dodałem reszty posta a Ty na niego odpowiedziałeś i nie mogłem edytować zatem w tym poście zamieszczam wszystko to co powinno być w pierwszym zatem można uznać że temat zaczyna się od tego posta. Załącznik jest w pierwszym.

Witam Serdecznie.
Na wstępie przepraszam z góry za swoje może dość infantylne pytanie ale dopiero zaczynam uczyć się programowania (5 dzień). Póki co poznałem nieco język, wszystkie pętle, zmienne etc. Jakiś tam prosty program potrafię napisać. Teraz jestem na etapie analizowania prostych gotowych programów i nie mogę sobie poradzić z jednym. Zupełnie nie wiem co za co odpowiada. Program opiera się na pętlach "while". Rysuje on odwrócony pusty trójkąt, dokładnie taki jak w załączniku. A tak wygląda kod programu:

 
#include <stdio.h>
#include <conio.h>

int main ()
{
    int i,j,x;
    i=1;
    printf("Ile gwiazdek?");
    scanf("%d",&x);
    j=x;
    while(j>=0) {
                printf(" ");
                j--;
                }
                printf("*\n");
                
                while(i<=x) {
                            j=x;
                            while(j>=i) {
                            printf(" ");
                           j--;
                           }
                           j=1;
                           printf("*");
                           
                           while(j<i) {
                                      printf(" ");
                                      j++;
                                      }
                                      printf("*\n");
                                      i++;
                                      }
                                      i=1;
                                     
                                      while (i<=x+2) {
                                            printf("*");
                                            i++;
                                            }
           fflush(stdin);
           getch();
           return 0;
           }

Pierwszą pętlę while rozumiem, przed pętlą j przyjmuje wartość x a następnie dopóki j jest większe równe od 0 drukuje spacje zmniejszając j za każdym razem o jeden aż do momentu aż j wyniesie 0. Innymi słowami ta pętla rysuje mi tak jakby tą pustą linię pionową (tak mi się przynajmniej wydaje). Reszty póki co nie rozumiem. Czy dobrze myślę że j to jest licznik po kolumnach a i to licznik po wierszach? I jakby ktoś mógł wyjaśnić na jakiej zasadzie działają pozostałe pętle, tylko tak łopatologicznie, dla osoby zielonej. Będę bardzo wdzięczny i jeszcze raz przepraszam za takie, zapewne banalne dla Was pytania ale każdy stawiał kiedyś pierwsze kroki. Mam niby klika kursów ale są one kiepskie i napisane takim językiem jakby odbiorca miał już co najmniej średnie pojęcie o programowaniu.
Pozdrawiam.

Aha, te wczytywania z klawiatury itd wszystko rozumiem zatem tego tłumaczyć nie trzeba. Tylko i wyłącznie jak działają te pętle. Aaa i ostatnią pętlę wydaje mi się że rozumiem. ona rysuje tą ostatnią linię poziomą, czyli że tak powiem postawę trójkąta.

0
#include <stdio.h>
#include <conio.h>

int main ()
{
    int i,j,x;
    i=1;
    printf("Ile gwiazdek?");
    scanf("%d",&x);
    j=x;

    //Pętla rysująca pierwszy wiersz (tylko jedna gwiazdka)
    while (j>=0) {
        printf(" ");
        j--;
    }
    printf("*\n");

    while (i<=x) {
        j=x;
        while (j>=i) {
            printf(" "); //Wypisuje spacje przed pierwszą gwiazdką
            j--;
        }
        j=1;
        printf("*"); //Wypisuje pierwszą gwiazdkę 

        while (j<i) {
            printf(" "); //Spacje za pierwszą gwiazdką i przed drugą
            j++;
        }
        printf("*\n"); //Wypisuje drugą gwiazdkę 
        i++;
    }
    i=1;

    while (i<=x+2) {
        printf("*"); //Rysuje podstawę składającą się z x+2 gwiazdek
        i++;
    }
    fflush(stdin);
    getch();
    return 0;
}

Dodałem komentarze i dodatkowo sformatowałem kod, ale nie wiem czy jest wystarczająco łopatologicznie ;)

0

Ok, ta pierwsza linia rysuje faktycznie pierwszą gwiazdkę ale teraz patrzę, kompilując tylko ją, że ta gwiazdka jest w linii pierwszej, czyli na samym szczycie trójkąta. Zatem zmienna j czyta po wierszach? Jak to właściwie jest? Bo z tymi zmiennymi która co robi też mam problem. Ale analizując tą pierwszą linię i jej wynik wychodzi na to że to właśnie j leci po wierszach bo ta pierwsza pętla działa chyba w ten sposób że j przyjmuje wartość x i zaczyna rysować właśnie tą gwiazdkę na szczycie trójkąta, zmniejszając j aż do 0 czyli przesuwając się cały czas w lewą stronę. Nie wiem czy ja to dobrze rozumuję. Chcę po prostu połapać jak działają te zmienne, jak one się poruszają bo to chyba najważniejsze. Jak to załapię to z resztą myślę że sobie jakoś poradzę.

0

Użyj debuggera, dodaj sobie zmienne do watch i patrz jak się zmieniają obserwując konsolę. Programista równolegle z nauką programowania musi uczyć się też debugowania

0

@peter90 niczego się nie nauczysz z czytania cudzych kodów. Spróbuj sam takie coś napisać.

0

W kodzie jest mały bałagan. Raz w zmiennej j jest zapisane ile spacji już wypisano, a raz ile jeszcze trzeba wypisać.

0
lukasz1235 napisał(a)

W kodzie jest mały bałagan. Raz w zmiennej j jest zapisane ile spacji już wypisano, a raz ile jeszcze trzeba wypisać.

To pewnie dlatego nic z tego kodu nie rozumiem i wszystko mi się miesza. To jest program (kod) który dał nam wykładowca na zajęciach ale on tak tłumaczy że nikt go nie rozumie dlatego postanowiłem uczyć się programowania sam.

0

Ja napisałbym to tak:

#include <stdio.h>

int main ()
{
    int i,j,x;

    printf("Ile gwiazdek?");
    scanf("%d",&x);

    for (i=0; i<=x; i++)
        printf(" ");

    printf("*\n");
 
    for (i=1; i<=x; i++) 
    {
        for (j=i; j<=x; j++)
            printf(" ");

        printf("*");
 
        for (j=1; j<i; j++)
            printf(" ");

        printf("*\n");
    }
 
    for (i=0; i<x+2; i++)
        printf("*");

    return 0;
}
0

Kod na pewno bardziej przejrzysty. Mógłbyś jeszcze powiedzieć jak przechodzą te zmienne "j" i "i"? Pierwsza pętla for rysuje tą jedną gwiazdkę tylko nie bardzo wiem jak. Ona jakoś przechodzi w dół sprawdzając warunki czy może porusza się w prawą stronę. Kurcze, największe problemy mam z tymi zmiennymi. Nie mogę tego za nic ogarnąć a bez tego to ani rusz.

Czy ta pierwsza pętla for idzie w ten sposób że dla i równego 0 i mniejszego równego x, rysuje w wierszu pierwszym spacje i w momencie gdy ten warunek przestaje być spełniany czyli i przekroczy wartość x, czyli na samym końcu rysuje gwiazdkę a następnie przechodzi do kolejnej linii? Nie wiem czy dobrze mówię, tak na zdrowy chłopski rozum trochę to biorę.

0

Pierwsza pętla wypisuje x+1 spacji (w zmiennej i jest zapisane ile spacji już zostało wypisanych, pętla jest przerywana w momencie gdy i jest większe od x), a za tą pętlą jest wypisywana gwiazdka i znak nowej linii.

0

Czyli tak jak myślałem. To x+1 spacji rozumiem dlatego że liczenie rozpoczyna się od 0 czyli jak x mam 5 to spacji będzie 6 (0, 1, 2 ... 6), o to chodzi?

Teraz najciekawsza jest dla mnie ta pętla środkowa czyli

 for (i=1; i<=x; i++) 
    {
        for (j=i; j<=x; j++)
            printf(" ");
 
        printf("*");
 
        for (j=1; j<i; j++)
            printf(" ");
 
        printf("*\n");
    }

Tu i jest ustawiane na wartość 1 i dopóki jest ono mniejsze równe x, zwiększam i. Czemu tu i ustawiamy na wartość 1? Dlatego że rozpoczynamy od drugiego wiersza (pierwszy wiersz wartość 0, drugi wiersz wartość 1) czy może z innego powodu? No i najważniejsze, w jaki sposób poruszają się te wewnętrzne pętle. Pierwsza pętla wewnętrzna rozumiem że rysuje spacje i gwiazdki po zewnętrznej stronie trójkąta, kolejna pętla rysuje spację wewnątrz trójkąta oraz prawy bok trójkąta. Tylko w jaki sposób te zmienne j, i, to obliczają (tzn pozycje na których co ma być), jaki jest przebieg tych zmiennych.

0

Chyba najłatwiej będzie jak będziesz wykonywał ten program w debuggerze krok po kroku i podglądał zmienne.

0

Próbowałem właśnie to zrobić ale korzystam z Dev c++ i coś mi to debudowanie nie wychodzi.

0

Dev-C++ to zuo. Wyrzuć to i zainstaluj coś normalnego.

0

Trochę OT się zrobi ale tylko jedno pytanie nie odnośnie tematu, jaki kompilator polecasz? Wiesz, ja jestem bardzo początkujący, jedynie co na razie mam to duże chęci do nauki programowania. Na uczelni używamy Dev'a dlatego ja go również zainstalowałem ale oczywiście nie muszę go używać jeśli jest coś lepszego. W końcu kto się lepiej zna na kompilatorach jak nie programiści :).

0

Może NetBeans albo Code::Blocks.

0

Można gdzieś znaleźć jakiś manual do tego netbeansa bo szukam i nic nie widzę a kompletnie nie ogarniam tego programu. Nie wiem co mam wybrać w tych opcjach "new project" i w ogóle co dalej, jak się w tym programie poruszać. Pierwszy raz widzę go na oczy.

No nic, odpuszczę Netbeans'a i zainstaluję Code::Blocks bo nie mam kompletnie zielonego pojęcia jak netbeansa skonfigurować. Jest zdecydowanie za bardzo skomplikowany. Brakuje w nim kompilatora który nie wie, trzeba doinstalować? pobrać? nie wiem skąd, robię niby według tych poradników co znalazłem i nadal nic. Jakiś dziwny ten program.

0

@peter90 a moze Eclipse CDT? To jest taka dystrybucja eclipse która ma wszystko do C++ preinstalowane :)

0

Ten CodeBlocks może być. Wszystko w nim ładnie działa, program się kompiluje. Problem jest jedynie z debuggerem a w zasadzie to na nim mi zależy najbardziej bo chcę prześledzić jak to wszystko działa (szkoda że na zajęciach tłumaczą nam to wszystko językiem ściśle technicznym, jakbyśmy mieli już nie wiadomo jakie pojęcie o programowaniu a o debugerze nie wspomnieli ani słowa, ja od Was dowiedziałem się że w ogóle takie coś istnieje). Mam nie aktywne żadne opcje. Moje Menu ---> Debug wygląda dokładnie tak jak na zdjęciu które daję w załączniku.

EDIT
Ok, z debuggerem sobie poradziłem. Okazuje się że nie można debugować pojedynczych plików lecz całe projekty. Teraz tylko pozostaje jedno pytanie, jak się nim posługiwać? Pytam bo włączyłem to debugowanie i w zasadzie to niczego się nie dowiedziałem. Aplikacja się uruchomiła, wpisałem ilość gwiazdek, narysowało trójkąt i tyle. Nic poza tym mi nie wyskoczyło i absolutnie nic się nie działo. To samo jak wybrałem opcje step to. Również nic. Jedynie na dole w zakładce Debugger pojawił mi się takie informacje:

Building to ensure sources are up-to-date
Build succeeded
Selecting target:
Debug
Adding source dir: C:\Users\Łukasz\Desktop\Projekty\simple
Adding source dir: C:\Users\Łukasz\Desktop\Projekty
Adding file: bin\Debug\simple.exe
Starting debugger:
done
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
Debugger name and version: GNU gdb 5.2.1
Warning: C:/Users/Ĺukasz/Desktop/Projekty/simple: No such file or directory.
Warning: C:/Users/Ĺukasz/Desktop/Projekty: No such file or directory.
Program exited normally.
Debugger finished with status 0

Jednak one mi absolutnie nic nie mówią na temat przebiegu programu a ja chcę się konkretnie dowiedzieć jak te pętle idą żeby zrozumieć zasadę ich działania.

0

Tego breakpoint'a mam dawać w każdej linii czy w jednym konkretnym miejscu? Pytam bo próbuję znaleźć jakieś informację jak to się robi i spotykam się z różnymi wskazówkami. Jedni piszę że w konkretnych miejscach, inni że po każdej linii kodu. Pogubić się można.

0

No ok, wstawiłem break'a odkąd chciałbym aby zaczął analizowanie tego kodu i w dalszym ciągu bez zmian. Uruchamiam debugowanie, odpala się program, wpisuję liczbę gwiazdek, rysuje, kończy i tyle. Nic poza tym mi się nie pojawia i absolutnie nic się nie dzieje.

0

Słuchajcie, udało mi się jakoś koło 17 odpalić debuggera w Visual Studio C++ 2008. Doszedłem już jak kompilować w nim programy w C więc jest dobrze. Debugger działa. Dzięki niemu zrozumiałem na czym to wszystko polega i jak przebiegają pętle i z jakimi wartościami.

Nawet słuchajcie zrobiłem sobie już kilka rysunków, oczywiście figury puste w środku żeby było trudniej. Narysowałem między innymi kwadrat, prostokąt gdzie wczytywałem z klawiatury wysokość i szerokość i teraz skończyłem robić romb. Wiem że pewnie dla Was wyda się to śmieszne, pisanie takich rzeczy ale dla mnie na początek to jest naprawdę dużo. Szczególnie że już trochę to zaczynam łapać.

Tylko mam jeden problem. Robię jeszcze sporo błędów i muszę często puszczać sobie debugowanie, sprawdzać czemu jest źle i dopiero kombinować i poprawiać. Myślicie że jak będę więcej ćwiczył to w końcu dojdę do wprawy i będę takie rzeczy robił bez najmniejszego problemu? Takie właśnie sprawdzanie i popełnianie błędów na początku to normalna rzecz? Bo może to ze mną jest w dalszym ciągu coś nie tak. Już sam nie wiem ...

0

Dopiero zacząłeś naukę, to normalne, że musisz poświęcić problemowi więcej czasu. Z doświadczeniem przyjdzie wprawa. Ważne jest to, że masz zapał, pokorę i poznałeś debugger -- to naprawdę sporo na początek, i znacząco przyspieszy naukę. :)

peter90 napisał(a)

Takie właśnie sprawdzanie i popełnianie błędów na początku to normalna rzecz?

Takie sprawdzanie i poprawianie błędów to normalna rzecz na co dzień, nie tylko na początku. Nawet doświadczeni programiści często zmagają się z takimi problemami, i często uciekają się do debuggera i „kombinowania”. Taka jest specyfika tego zajęcia, nie zrażaj się.

0

Staram się nie zrażać tylko myślałem że skoro tak trochę kombinuję i korzystam często z debuggera przy tak banalnych sprawach jakimi są proste rysunki z gwiazdek, to coś ze mną jest nie tak. Praktyczną naukę programowania zacząłem przed wczoraj. Wcześniej zapoznawałem się z teorią, sporo czytałem. Jestem dość mocno zdeterminowany do nauki tego języka bo wiem że jak dobrze nauczę się C, później przejdę do obiektówki (C++) to i z całą resztą sobie poradzę bo te dwa języki to chyba podstawa. No nic, zobaczymy, dziś już daję spokój bo siedzę nad tym programowaniem od godziny 8 rano i zrobiłem sobie w między czasie może ze 2h przerwy żeby coś zjeść. Wczoraj też siedziałem cały wieczór. Jutro też mam wolne więc sobie trochę posiedzę, pomęczę dalej to rysowanie a później przejdę może do jakichś algorytmów typu NWD, algorytm Euklidesa itp.

0

Witam.
Pojawił się pewien problem. Próbuję właśnie napisać program rysujący krzyż z x gwiazdek wczytanych z klawiatury. Wygląda to mniej więcej tak że podajemy liczbę gwiazdek z klawiatury, następnie pętla if sprawdza czy wczytana liczba jest liczbą parzystą, jeśli tak, wypluwa komunikat że wczytana liczba musi być nieparzysta (nieparzysta dlatego ponieważ tylko w takim wypadku da radę narysować symetryczny krzyż). Jeśli liczba jest nieparzysta wykonuje kolejne pętle, tym razem rysujące. Dałem dodatkową zmienną p która wylicza mi w którym miejscu ma rysować pionową linię i ją ładnie rysuje. Problem teraz mam z linią poziomą. Próbowałem to zrobić w tej pierwszej pętli dodając dodatkową pętlę for aby działało to w ten sposób że na początku rysuje mi pionowo p gwiazdek, później rysuje linię poziomą a następnie dalej p gwiazdek w pionie ale niestety tego chyba tak nie da się zrobić. Próbowałem też dodać dodatkową pętlę for poza tą pierwszą pętlą ale też mi to nie wychodzi i ta linia pozioma rysowana jest nie w połowie tej pionowej lecz na dole, pod linią pionową. Poniżej wklejam kod programu który rysuje tylko linię pionową. Mam nadzieję że coś podpowiecie bo krzyż niby prosta figura ale w zaprogramowaniu jej jednak jest cięższa od pozostałych.

 
#include <stdio.h>
#include <conio.h>

int main ()
{
    int i,j,x,p;

    printf("Ile gwiazdek?");
    scanf("%d",&x);

if (!(x&1)) {
	printf("Podaj nieparzysta liczbe gwiazdek");
}
else{
	p=(x/2);
	for (i=1; i<=x; i++) {
for (j=1; j<=p; j++)
printf(" ");
printf("*\n");
	}	
}
           fflush(stdin);
           getch();
           return 0;
           }

Aha, jeśli chodzi o tą zmienną p, wiem że liczba nieparzysta podzielona przez 2 daje liczbę nie całkowitą tylko ułamek ale chyba w takim wypadku automatycznie brana jest podłoga z tego dzielenia ponieważ program wykonuje się dobrze i jak np podam x=5 to p mam równe 2, jak podam x=9 to p mam równe 4 itd. Zatem dobrze wylicza i bierze podłogę z wyniku dzielenia x przez 2.

0

Podpowiem Ci, jak zrobić to samodzielnie:

  1. Bierzesz kartkę w kratkę i długopis.
  2. Rysujesz obwód prostokąta o bokach N na M i numerujesz każdą kratkę odpowiednio z lewej lub z góry.
  3. Patrzysz na kratkę 1x1 i myślisz, czy narysować wtedy * czy nie.
  4. Patrzysz na następną z prawej i znów, decydujesz czy narysować * - jak trzeba to rysujesz, itd.
  5. W końcu przechodzisz do następnej linijki i powtarzasz procedurę.
  6. Teraz najważniejsze, gdy już narysujesz wszystko co chciałeś, patrzysz w których kratkach znajdują się * i znajdujesz zależności - kiedy została narysowana linia pionowa, a kiedy pozioma.
  7. Później, w kodzie, w pętlach określasz odpowiedni warunek, kiedy zacząć poziomą rysować a kiedy stawiać gwiazdkę dla linii pionowej.
0
#include <stdio.h>
 
int main ()
{
	int i,j,x,p;
	printf("Ile gwiazdek?");
	scanf("%d",&x);
	if (x%2 != 0) {
		printf("Podaj nieparzysta liczbe gwiazdek");
	}
	else{
		p=(x/2);
		for (i=0; i<x; i++) {
			if(i==p){
				for (j=0; j<x; j++){
					printf("*");
				}
			}else{
				for (j=0; j<p; j++){
					printf(" ");
				}
			}
			printf("*\n");
		}        
	}
	return 0;
}
0

A czy te linie pionowa i pozioma powinny być narysowane jednocześnie czy każda osobno w osobnej pętli? Bo to też ma znaczenie. Chodzi mi o to czy np mając dany X=5, rysuję na środku dwie gwiazdki linii pionowej, następnie linię poziomą i dalej kończę pionową czy może najpierw w jednej pętli rysuję pionową i po jej narysowaniu w osobnej pętli poziomą?

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