[C] Dwuwymiarowe tablice i wyznacznik

Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

Moje zadanie : Stwórz dwuwymiarowe tablice A[3][3] i B[3][3].
Wypełnij te tablice liczbami całkowitymi z zakresu <0, 10> używając standard input. Potraktuj tablice jako macierze. Dodaj macierze A i B i zachowaj ich sumę w macierzy C. Policz wyznaczniki macierzy A, B i C. Wydrukuj wartości elementów tablic razem z wyznacznikami każdej tablicy. Użyj wskaźników.

Uwaga : Twój program powinien sprawdzić czy wprowadzone wartości są typu całkowitego. Jeśli nie są, powinien poinformować użytkownika o błędzie.

Mój kod programu, który do tej pory zrobiłem :

Kod: Zaznacz cały

#include<stdio.h>

void Wypełnij(int *h);

int main()
{
  int A[3][3], B[3][3];
  
  Wypełnij(&A);
  Wypełnij(&B);
  
  return 0;
}

void Wypełnij(int *h)
{
  int i, j, a[3][3];
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      do
      {
        printf("Wpisz liczbę całkowitą <0,10> dla a[%d][%d] = 
", i, j);
        scanf("%d
", &a);     
      }
      while(h<0 || h>10);
    }
  }
}
w funkcji Wypełnij mam błędy - chciałem zapośrednictwem jej wypełnić macierze A i B - chciałem użyć do tego wskaźnika - jak to zrobić? Moje drugie pytanie - jak zrobić, żeby program sprawdzał czy wprowadzone przez użytkownika liczby są typu całkowitego?
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

No to idziemy od gory:
1. Nie wiem skad wogole pomysl na uzywanie polskich liter w nazwach funkcji...
2. Przekazujesz do funkcji wskaznik na int. Moze to wiec odpowiadac zarowno jednej wartosci typu int (wskaznik na zwykla zmienna), lub tablicy elementow tego typu. Ty potrzebujesz przekazac tablice dwuwymiarowa, co nie moze nastapic poprzez taki zwykly wskaznik.
3. Nawet jesli funkcja bylaby ok, to jej wywolanie jest bledne. Powinienes wiedziec, ze nazwa tablicy (u ciebie A,B) jest rownoczesnie wskaznikiem na jej pierwszy element. Takze konstrukcja typu &A nie spelnilaby swojej roli (jest to bowiem pobranie adresu wskaznika).
4. W funkcja robisz na stosie dodatkowa tablice a. Pytanie - po co ci ona? Przeciez twoje tablice sa w main i musisz je przekazac do funkcji. Chyba, ze funkcja ma sobie pobrac dane do swojej wewnetrznej tablicy i wyjsc (czyli w gruncie rzeczy ma nie zrobic nic interesujacego).
5. Zamiast i++ i j++ mozesz pisac ++i i ++j. Tutaj nie odgrywa to zadnego znaczenia, jednak w jezykach obiektowych i iteratorach moze spowolnic dzialanie programu (powinienes wiedziec czym sie rozni pre- od postinkrementacji, dekrementacji).
6. Scanf'em pobierasz jedna dana typu calkowitego (%d) i znak nowej lini (po co?). Jednak gdzie chcesz ta dana zapisac - tego juz nikt nie wie. Zamiast podac adres konkretnej komorki tablicy (np. &a[0][0]), podajesz adres wskaznika do tablicy (podmieniasz to, na co wskazuje a, czyli 'przesuwasz wskaznik'; warto zauwazyc, ze wskaznik tablicowy jest zawsze staly, takze jest to kolejny juz blad). I odrazu mozna napisac, ze wczytujesz dane do tablicy lokalnej, ktora zniknie po zakonczeniu funkcji...
7. Warunek w petli while jest smieszny :) Porowujesz wartosc wskaznika, zamiast jakiejs danej. I moge ci zagwarantowac, ze ta petla jest nieskonczona, gdyz twoja zmienna nigdy nie bedzie miala takiego adresu (0...10). Moze chodzilo ci o (*h<0 || *h>10)? Jednak nadal jest to bez sensu, bo zadanie nie na tym polega...

Wiecej bledow juz chyba nie ma :)

Pozdrawiam.
6hokage
Użytkownik
Użytkownik
Posty: 268
Rejestracja: 24 mar 2009, o 13:06
Płeć: Mężczyzna
Podziękował: 1 raz
Pomógł: 35 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: 6hokage »

Odnośnie pytania o sprawdzenie czy dane są całkowite, może spróbuj wczytywane dane zapisywać jako float, potem w programie stwórz zmienną która będzie przechowywać część całkowitą tej liczby,
można to zrobić przez rzutowanie tzn. calkowita=(int)liczba. Potem porównaj obie wartości, jak są równe to znaczy, że wpisana liczba jest całkowita
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

Jak dla mnie bez sensu. Jedynym pelnym sprawdzeniem poprawnosci danych byloby wczytanie ciagu znakow (np. do bufora typu char[]) a nastepnie napisanie parsera, ktory samemu sprawdzi, czy dane sa ok. Wystarczy przeciez po pytaniu o liczbe wpisac np. 'a' i juz lipa, bo to ani float ani int (teoretycznie). Mozesz sie tez pobawic z wartoscia zwracana przez scanf (zwraca ilosc poprawnie wczytanych danych).

Pozdrawiam.
6hokage
Użytkownik
Użytkownik
Posty: 268
Rejestracja: 24 mar 2009, o 13:06
Płeć: Mężczyzna
Podziękował: 1 raz
Pomógł: 35 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: 6hokage »

Wcale nie bez sensu jeśli założyć, że wpisywane dane to liczby, a nie znaki, a o to koledze chodziło:
#include <stdio.h>

void main()
{
float a;
int b;
printf("podaj ");
scanf("%f",&a);
b=(int)a;
if(b==a) printf("
Tak");
else printf("
Nie");
printf("
%f %d",a,b);
}

Jak nie wierzysz to sprawdź, że ten program działa poprawnie i nie ucina rozwinięcia dziesiętnego wczytywanej liczby.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

No dobrze tak średnio zrozumiałem moje błędy - ale w dalszym ciągu nie mam pojęcia jak to poprawić (jestem poprostu słaby z programowania). Prosiłbym, żebyście mi jeszcze trochę jaśniej powiedzieli jak to poprawić i połączyć ten warunek na wpisywanie liczb całkowitych. Nie tylko mi chodziło, żeby program uważał za wpisywane znaki za błąd, ale również liczby wymierne itp.

Jak już to będę wiedział jak to poprawić, to myślę że z dalszą częścią zadania powinienem sobie poradzić. Chociaż mam jeszcze jedno pytanie : wiem, że można w bardzo prosty w sposób policzyć te wyznaczniki macierzy 3x3 nie używając ogólnego wzoru laplace'a, ale myślę że lepiej by było jakbym napisał funkcję dającą sobie radę w obliczeniu wszystkich wyznaczników kwadratowej macierzy - ponoć najlepszą metodą jest sprowadzenie macierzy do postaci Jordana i dopiero jej policzenia wyznacznika. Jak to zrobić?

A przepraszam za polskie litery - orginał mam po angielsku bo mam studia angielojęzyczne (i nie jestem już przyzwyczajony pisać programy po polsku) - chciałem poprostu żeby wszyscy zrozumieli dlatego wpisałem nazwy polskie i zapomniałem, że polskie litery nie powinno się pisać w programach.
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

6hokage:
Po pierwsze - main powinien zwracac wartosci typu int. Taka jest specyfikacja C. Po drugie - jesli zakladamy, ze dane sa poprawne, to nie widze sensu wlaczac w to operacji na float'ach... A tak wogole, to wydaje mi sie, ze nie do konca wiesz co robisz w tym kodzie. Co dokladnie wedlug ciebie robi linijka:

Kod: Zaznacz cały

if(b==a) // costam
?

Nighthunter24:
Zrob poprostu funkcje:

Kod: Zaznacz cały

void Wypelnij(int tablica[3][3]);
I w niej wypelniaj jej kolejne elementy, czyli:

Kod: Zaznacz cały

scanf("%d", &h[i][j]);
Podobnie ograniczenie rob od daj komorki, a nie od wartosci wskaznika na tablice:

Kod: Zaznacz cały

(h[i][j]<0 || h[i][j]>10)
To powinno ci starczyc na poczatek. Pozdrawiam.
Ostatnio zmieniony 28 mar 2009, o 15:26 przez soku11, łącznie zmieniany 1 raz.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

Ok, a powiedz mi w której części zadania będzie mi wygodniej użyć wskaźników? - muszę je gdzieś użyć (to jest jeden z warunków zadania).

Masz rację nie wiem co robię w tym kodzie - bo sam nie wiem do końca jak prawidłowo operować na tablicach wielowymiarowych z użyciem wskaźników. Dlatego właśnie o to się pytałem, żeby to zrozumieć i się nauczyć tego.

Teraz spróbuje dobrze wypełnić te tablice. Udało mi się :

Kod: Zaznacz cały

#include<stdio.h>

void Wypelnij(int tab[3][3]);

int main()
{
  int A[3][3], B[3][3];
  
  Wypelnij(A);
  Wypelnij(B);
  
  return 0;
}

void Wypelnij(int tab[3][3])
{
  int i, j;
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      do
      {
        printf("Wpisz liczbe calkowita <0,10> dla a[%d][%d] = ", i, j);
        scanf("%d", &tab[i][j]);     
      }
      while(tab[i][j]<0 || tab[i][j]>10);
    }
  }
  printf("
");
}
Ale teraz jak zrobić, żeby nie przyjmował liczb wymiernych - tzn. o mam napisać żeby sprawdzał, czy wprowadzone liczby przez użytkownika są typu integer, a jeśli nie są żeby wypisał błąd?
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

Ta funkcja przeciez przyjmuje wskazniki Moze nie ma tam gwiazdki, ale ogolnie tak jest. Tzn. gdybys w tej funkcji nie operowal na wskaznikach, to nie zmienilbys zawartosci tablicy w main (przekazywana by byla przez wartosc). Przeanalizuj kod:

Kod: Zaznacz cały

#include <stdio.h>

void fun(int a)
{
  ++a;
}

int main()
{
  int x=0;
  printf("Przed wywolaniem funkcji: x=%d
",x);
  fun(x);
  printf("Po wywolaniu funkcji: x=%d
",x);
  
  return 0;
}

Wartosc zmiennej sie nie zmienila, bo przekazano do funkcji JEJ KOPIE. U ciebie zawartosc tablicy po wywolaniu na pewno sie zmieni. Dzieje sie tak dlatego, ze tablice sa przekazywane przez wskaznik. Tzn. twoja funkcja przyjmuje wskaznik na tablice 3x3, a nie sama tablice (jest kopia wskaznika, a nie calej tablicy). Takze wydaje mi sie, ze nie ma co tutaj do tych wskaznikow dopisywac. Zawsze mozesz spytac prowadzacego, czy tak moze byc.

Co do kontroli poprawnosci danych, to mozesz sprawdzac co zwraca ci scanf, jak juz wczesniej zasugerowalem. Popatrz na ten kod:

Kod: Zaznacz cały

#include<stdio.h>

int main()
{
  int a=0;

  printf("Wynik scanf: %d
a=%d
",scanf("%d",&a),a);

  return 0;
}

Popatrz co zwraca dla liczb, a co dla liter.

Pozdrawiam.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

W twoim programie scanf zwraca dla cyfr : 1 a dla liter : 0.

Dobrze to co mam na górze (mój program) to jak wpiszę np: liczbę 10.5 czy 4.5 to program wariuje (cały czas coś wypisuje)- jak czegoś takiego się wystrzec - bo narazie to co mi zasugerowałeś a propo sprawdzenia typu to jakoś do mnie nie dociera - mógłbyś jakoś to prościej mi powiedzieć?
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

Heh prosciej nie umiem :)
Co do tych liczb zmiennoprzecinkowych, to poprostu chcesz wczytac liczbe dziesietna calkowita(%d). Program odczytuje ze strumienia wejsciowego np. 10.5. Pobiera 10 i reszte zostawia, bo to nie jest dla niego liczba. Tak wiec jak trafi na '.' nie moze nic wiecej zrobic, bo nie moze pobrac liczby dziesietnej. Konczy dzialanie. W nastepnym obiegu peli do..while znow trafia na '.' i nie moze przekonwertowac, wiec nic nie zapisuje. I tak w nieskonczonosc. Aby wiec sie pozbyc tego problemu trzeba pobrac oczekujace znaki ze strumienia wejsciowego. Nie bede tlumaczyl jak to zrobic, gdyz i tak pewnie nie zrozumiesz, wiec pokusze sie o zastosowanie BLEDNEJ, ale dzialajacej konstrukcji, tj:

Kod: Zaznacz cały

  scanf("costam");
  fflush(stdin); // wyczysc wejscie z pozostalych znakow
Teraz program nie bedzie wpadal w nieskonczona petle. Jednak podkreslam - rozwiazanie to nie jest do konca poprawne, bo funkcja fflush sluzy do innych celow.

Pozdrawiam.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

No jak nie umiesz mi prościej tego wytłumaczyć to bardzo bym cię prosił żebyś mi tą część programu napisał jeśli chodzi o kontrolę typu, a w razie czego jakby użytkownik wprowadził znak lub liczby typu 10.5 wypisał błąd, tak żeby po wypisaniu błędu prosił o podanie liczby dla tego elementu tablicy! Myślę, że to tak bardzo nie kosztuje - a wiele z takiego gotowego rozwiązania zrozumiem.

Jeśli chodzi o ten fflush to w tym przypadku jak sam mówiłeś nie spełnia tego co mój program ma robić.
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

Heh... skoro nie chce ci sie samemu myslec, to daje gotowa funkcje, ktora z wczytanego tekstu zwraca -1 jesli blad lub dana liczbe jesli jest ok.

Kod: Zaznacz cały

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

int getPositiveNumber(char* buffer);


int main()
{
  char buf[128];
  scanf("%127s",buf);
  printf("%d",getPositiveNumber(buf));

  return 0;
}

int getPositiveNumber(char* buffer)
{
  unsigned int i=0;
  unsigned int limit=0;

  if(buffer==NULL)
    return -1;

  limit=strlen(buffer);

  for(i=0;i<limit;++i)
    if(buffer[i]<'0' || buffer[i]>'9')
      return -1;

  return atoi(buffer);
}


Pozdrawiam.
6hokage
Użytkownik
Użytkownik
Posty: 268
Rejestracja: 24 mar 2009, o 13:06
Płeć: Mężczyzna
Podziękował: 1 raz
Pomógł: 35 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: 6hokage »

Pytasz mnie co robi linijka if(b==a), oraz po co wprowadzać floaty skoro dane są poprawne. Twoje pytania udowadniają , że wogóle nie sprawdziłeś mojego programu, nie wiesz o co dokładnie pytał twórca tematu, oraz że żaden z ciebie profesjonalny programista choć wiedzę masz dużą.
Koleś pytał się, jak sprawdzić czy uzytkownik wpisuje liczby całkowite, czyli
jak sprawdzić czy ich rozwinięcie po przecinku składa się z samych zer.
Bo np. ktoś może wpisać 5.3333 - liczba niecałkowita ale nadal liczba dlatego
zapisuję ją jako typ float, bo inaczej program utnie jej końcówkę po przecinku
jeżeli zapiszę jako int i wtedy w żaden sposób się nie dowiem czy wpisana liczba była całkowita. Potem robię rzutowanie b=(int)a. Wiesz co to jest wogóle rzutowanie? Ta instrukcja przypisuje b wartość całkowitą liczby a, bo ucina tę część bajtów liczby a która oznacza cyfry po przecinku. Gdybyś napisał np. d=(float)j , a j jest typu double, to ta instrukcja rzutowania utnie od końca taką ilość bajtów liczby j żeby ją skrócić do float-a.
Liczba b zatem to wartość całkowita liczby a, jeśli liczba a jest całkowita to jej
wartość całkowita jest jej równa, kapujesz? Stąd linijka if(b==a) printf("Tak")
Bo jesli b==a to a musi być całkowita, a jak nie to na pewno nie jest całkowita. Np. a=6.333 to b=6, a=0.7432 to b=0, bo b jest typu int.
Powtarzam, włącz mój program i sprawdź co on robi!
Powtarzam, gościu się pytał jak sprawdzić czy liczby które wczytuje są całkowite, LICZBY, LICZBY, nie znaki bo tego początkującemu programiście nikt normalny by nie zadał, chyba że on tak sam z własnej woli, ale nic na to nie wskazywało.
A uwagi typu "mein powinien zwracać int a nie void" to wsadź se w buty, pisze void bo potem nie trzeba pisać return 0, i tak wiem, niektóre kompilatory tego nie akceptują, ale nowoczesne tak i mi to wystarcza.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

Mnie się wydaje, że jak użytkownik wpiszę liter - to też powinien sprawdzać czy ta wartość jest typu integer (całkowita), nie tylko liczby rzeczywiste. Tak przynajmniej wynika to z treści programu jaką otrzymałem na zajęciach.
Przepraszam za nieporozumienie 6hokage - powinienem zadać takie pytanie wtedy : jak zrobić żeby program sprawdzał czy wprowadzona wartość przez użytkownika jest typu całkowitego?

Narazie sobie odpuściłem tą część programu i napisałem pozostałe oprócz obliczania wyznacznika.

Oto mój obecny kod :

Kod: Zaznacz cały

#include<stdio.h>

void Wypelnij(int tab[3][3]);
void Wypisz(int tab[3][3]);

int main()
{
  int i, j, A[3][3], B[3][3], C[3][3];
  
  
  Wypelnij(A);
  Wypelnij(B);
  
  printf("Macierz A sklada sie z nastepujacych elementow : \n");
  Wypisz(A);
  
  printf("Macierz B sklada sie z nastepujacych elementow : \n");
  Wypisz(B);
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      C[i][j]=A[i][j]+B[i][j];
    }
  }
  
  printf("Macierz C sklada sie z nastepujacych elementow : \n");
  printf("\n");
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      printf("a[%d][%d] = ", i, j);
      printf("%d", C[i][j]);
      printf("\n");	
    }
  }
 
  return 0;
}

void Wypelnij(int tab[3][3])
{
  int i, j;
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      do
      {
        printf("Wpisz liczbe calkowita <0,10> dla a[%d][%d] = ", i, j);
        scanf("%d", &tab[i][j]);   
      }
      while(tab[i][j]<0 || tab[i][j]>10);
    }
  }
  
  printf("\n");
}

void Wypisz(int tab[3][3])
{
  int i, j;
  
  printf("\n");
     
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      printf("a[%d][%d] = ", i, j);
      printf("%d",tab[i][j]);
      printf("\n");	
    }
  }
  
  printf("\n");
}
No dobra w tradycyjny (czytaj mnożenie po skosie) sposób wiem jak policzyć te wyznaczniki macierzy 3x3 ale wolałbym napisać funkcję która oblicza wyznacznik dla każdej macierzy kwadratowej nxn. Stąd moje pytanie : Powiedz cie mi jak krok po kroku jak napisać funkcję przekształcającą daną macierz w postać Jordana (bo ponoć to jest najprostsza metoda w programowaniu do obliczenia wyznaczników a nie metoda laplace'a)? Wypadałoby żeby ta funkcja już była na wskaźnikach - no bo w treści zadania jest powiedziane żeby użyć wskaźników (tzn. poprostu chodzi żeby gdzieś je użyć; a że soku11 mi zasugerował żeby wypełnić tablice bez wskaźników, no to teraz wypadałoby je tu zrobić).
Ostatnio zmieniony 28 mar 2009, o 19:20 przez Nighthunter24, łącznie zmieniany 1 raz.
ODPOWIEDZ