Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Mnożenie tablicy[3][3] przez tablice[3][3]

hym23 08 Cze 2012 20:50 1697 7
  • #1 08 Cze 2012 20:50
    hym23
    Poziom 17  

    Witam mam taki problem mam napisana funkcję która mnoży mi dwie tablic[3][3] przez siebie,
    Za pierwszym razem kiedy wprowadzam do kodu dwie tablice[3][3] wynik daje mi poprawny czyli
    ------------------------
    np
    tablica1
    2 2 2
    2 2 2
    2 2 2
    *
    tablica2
    1 1 1
    1 1 1
    1 1 1
    =
    wynik
    6 6 6
    6 6 6
    6 6 6
    ------------------------------------------------------------

    Po czym ponownie wprowadzam do tej samej funkcji wynik[3][3] (otrzymany z pierwszego mnożenia) i nowa tablice[3][3] i wypisuje mi błędy.

    wynik pierwszego mnożenia
    6 6 6
    6 6 6
    6 6 6
    *
    nowa tablica
    1 1 1
    1 1 1
    1 1 1
    =
    wynik z Błędami
    12 30 84
    12 30 84
    12 30 84

    powinno być
    18 18 18
    18 18 18
    18 18 18
    ----------------------------------------------------------

    Podejrzewam, że jest błąd w zmiennych globalnych ale nie chcę niszczyć całego programu a jedynie zmodyfikować funkcję ale nie mam pojęcia jak …???

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0 7
  • #2 09 Cze 2012 01:01
    gaskoin
    Poziom 38  

    Masz pierwszą naukę na swojej drodze. Gdzie się tylko da, to należy stosować zmienne lokalne.

    Spójrz co robisz:

    w funkcji mnożenia ustawiasz wynik[wiersz][kolumna] = 0;

    A przekazujesz wynik jako parametr, który to jest zerowany jako zmienna globalna. Ten kod nie nadaje się do analizy tylko do usunięcia i napisania tego "normalnie" w C przy użyciu zmiennych lokalnych. Jeśli chcesz uzyskać wynik, należy przekazać tablicę, do której się go przekazuje poprzez wskaźnik. Ewentualnie można utworzyć taką tablicę w funkcji (malloc) i zwrócić do niej wskaźnik. Na dłuższą metę jednak to nie przejdzie (nie znamy wymiarów tablicy).

    A jeśli chcesz używać C++ to napisz klasy opisujące macierze i wtedy możesz sobie zwrócić w wyniku mnożenia macierz.

    0
  • #3 09 Cze 2012 15:38
    Krzysztof Gustaw
    Poziom 23  

    Witam!
    Przekazywanie tablic w języku "C" odbywa się tylko poprzez wskaźniki tak więc nie mogą być stosowane jako parametry funkcji i wartości zwracane przez funkcje (mam na myśli tablice sensu stricte) ale można zastosować pewne obejście wykorzystując możliwość użycia jako parametrów funkcji jak też wartości zwracanych przez nie zmiennych typu struct. Jeśli taką tablicę obudujesz strukturą bądź unią (klasy wystepują w języku "C++") to możesz bezpośrednio przekazywać tak zdefiniowane typy jako zmienne. Przykład:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #4 09 Cze 2012 18:09
    beluosus
    Poziom 25  

    Krzysztof Gustaw napisał:
    Przekazywanie tablic w języku "C" odbywa się tylko poprzez wskaźniki tak więc nie mogą być stosowane jako parametry funkcji i wartości zwracane przez funkcje

    To jak nazwiesz to?
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #5 09 Cze 2012 20:10
    Krzysztof Gustaw
    Poziom 23  

    Witam!
    Do Kolego Beluosus
    Oops, słuszna uwaga!
    Otóż miałem na myśli to, że generalnie parametry do funkcji przekazywane są poprzez wartość, zatem w funkcji wywoływanej tworzone są na stosie kopie tychże. Powoduje to, że operacje w funkcji wywoływanej nie zmieniają bezpośrednio danych, które przekazała funkcja wywołująca np:

    Jakaś funkcja f1 wywołująca f2:

    Funkcja wywołująca:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    funkcja wywoływana:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    W opisanym powyżej tandemie, do funkcji f2 zostal przekazany parametr a będący zmienną lokalna funkcji f1. Otóż wartość zmiennej a nie została zmieniona przez funkcję f2 pomimo operacji zmieniającej, bo została ona przekazana przez wartość, zatem wszystkie operacje wewnątrz funkcji f2() wykonywane są na kopii. Natomiast zmienne tablicowe jako całość (bądź część) zostają przekazywane do funkcji ZAWSZE przez wskaźnik, chyba,że przekazywany jest pojedynczy, konkretny element.
    W konsekwencji każda zmiana wartości elementów zmiennej tablicowej (a nie pojedynczego elementu) w funkcji wywoływanej zostanie odzwierciedlona w funkcji wywołującej na co chciałem zwrócic uwagę. W opisanym przez Ciebie przykładzie jest tak:
    W funkcji main zadeklarowałeś tablicę dwuwymiarową o 3 wierszach i 3 kolumnach, a w funkcji f() jako parametr została zadeklarowana tablica trzywierszowa o nieznanej z góry liczbie kolumn (jest to oczywiście poprawne).
    Następnie funkcji f() przypisujesz jakąś wartość elementowi znajdującemu się na przecięciu wiersza 2 i kolumny 1, tu: 123. Ale w tym przypadku zmieniasz zawartość tablicy funkcji main (a nie lokalnego parametru funkcji f), o co nie zawsze chodzi.
    Generalnie tablice (jako całość bądź fragmenty zawierające wiecej niż 1 element) przekazywane są (niejawnie, ale zawsze) poprzez wskaźniki, konkretnie jako wskaźnik do pierwszego elementu tablicy.
    Nie mówimy tu o pojedynczym elemencie wyznaczonym jednoznacznie w podanym przez Ciebie przykładzie, bo wówczas taki element jest traktowany jako zmienna typu "jakiśtam" a to co innego.

    A teraz to:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    W programie Kolegi Beluosus, po wywołaniu funkcji f1(), została zmieniona zawartość tablicy w funkcji main, a w moim przykładzie, dzięki opakowaniu zmiennej tablicowej w struct, zawartość zmiennej tablicowej moja_tablica, zadeklarowanej w funkcji main i będącej parametrem wywołania funkcji f nie została zmieniona co było moim celem.

    P.S.
    Oczywiście, problem ten można rozwiązać w "C++" tworząc odpowiednie klasy i zdefiniować operatory i funkcje. Oops, przepraszam metody :D

    0
  • #6 09 Cze 2012 22:40
    gaskoin
    Poziom 38  

    Krzysztof przecież przekazując jako parametr tablicę w ten sposób:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    wyobraź sobie, że dupa jest tożsamama ze wskaźnikiem i powyższą funkcję można napisać tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    lub tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    czy tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Analogicznie dla dwuwymiarowych tablic, więc z łaski swojej - nie pociskaj :) W takim przypadku tylko wskaźnik jest kopią lokalną i jak słusznie zauważyłeś nie mogę sobie do niego przypisać innego adresu (tzn mogę, ale nic to nie zmieni), ale mogę za to dowolnie zmieniać wartości na jakie wskazuje. W związku z tym robienie struktury do przekazania tablicy jest deczko bez sensu. Niby masz trochę racji w tym co piszesz, ale trochę namieszałeś :)

    Krzysztof Gustaw napisał:
    Natomiast zmienne tablicowe jako całość (bądź część) zostają przekazywane do funkcji ZAWSZE przez wskaźnik


    To nie jest jakaś magiczna właściwość, po prostu nazwa tablicy jest wskaźnikiem na jej pierwszy element.

    0
  • #7 10 Cze 2012 01:47
    Krzysztof Gustaw
    Poziom 23  

    Witam!
    Do Kolegi gaskoin:
    A'propos przedstawionych przez Ciebie serii przykładowych funkcji, zależności pomiędzy wskaźnikami i tablicami są mi dobrze znane. Wskaźniki i tablice są bardzo ściśle ze soba powiązane i można ich zapisy traktować zamiennie nawet w jednym wyrażeniu, np funkcja strncmp(char *dst, char *src, int n) kopiująca do bufora dst n znaków z src nie dopisuje znaku '\0' na koniec kopiowanego ciągu, więc w razie potrzeby stosuję zapis:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    A teraz dalej:
    ..."wskaźnik jest kopią lokalną i jak słusznie zauważyłeś nie mogę sobie do niego przypisać innego adresu (tzn mogę, ale nic to nie zmieni), ale mogę za to dowolnie zmieniać wartości na jakie wskazuje"...
    Ale mi chodzi o to, żeby funkcja, której parametrem jest tablica bądź tablice NIE ZMIENIAŁA mi bezpośrednio zawartości tablicy zadeklarowanej w funkcji wywołującej która już ma wpisane jakieś dane, a która to tablica z kolei jest przekazana jako parametr do funkcji wywoływanej, tylko operowała na ich kopiach. W ten sposób można ustrzec się od nieoczekiwanych a często wręcz szkodliwych efektów ubocznych sprawiających różne "tajemnicze" problemy, które ciężko potem wychwycić, "są bowiem rzeczy o jakich się fizjologom nie sniło :)". Dzięki zaproponowanemu przeze mnie podejściu można definiować różnego rodzaju operacje np arytmetyczne na wektorach, macierzach itd. bez obawy o to, że coś się namiesza w tablicach funkcji wywołującej, chyba, że czyni sie to z pełną świadomością. Błędy takie są naprawdę trudne do znalezienia i usunięcia w rozbudowanych programach.

    przykład:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Spróbuj teraz zmodyfikować program i przekazywać tablice, czy jako "czyste czy jako wskaźniki, jako parametry, które jak wiemy tak naprawdę są wskaźnikami (oczywiście bez pomocniczych zmiennych tablicowych aby przechować wyniki "gdzieś na boku", co dodatkowo zaciemnia program) a zobaczysz co się stanie, zwłaszcza, że kolejność opracowywania parametrów jest w języku "C" nieokreślona. A opisany w listingu powyżej przypadek jest trywialny...
    Zaznaczam, że to rozwiązanie można stosować w przypadku tablic o znanych z góry wymiarach. Kiedy jeden z wymiarów jest nieznany to, niestey, proponowana przeze mnie metoda na nic i wówczas trzeba posługiwać się wskaźnikami ze wszystkimi wynikającymi z tego konsekwencjami (trzeba się pilnować!), chyba że istnieje rozwiązanie, którego nie znam (chociaż, może operacje deklarować w odrebnym pliku a pośrednie i pomocnicze tablice w tymże pliku deklarować z atrybutem "static" ?)
    Cały czas chodzi mi o hermetyzację tablic, która może rowiązać wiele problemów.
    P.S.
    Nadmieniam, że proponowane rozwiązanie jest tylko moją propozycją jak też przedstawieniem innego sposobu przekazywania tablic a który komuś może rozwiązać jego problemy wynikające ze szkodliwych modyfikacji tablic w miejscach w których najmniej może się tego spodziewać. Polepsza po prostu hermetyzację.
    Pozdrówka!
    K.G.

    0
  • #8 10 Cze 2012 11:37
    gaskoin
    Poziom 38  

    Krzysztof Gustaw napisał:
    ..."wskaźnik jest kopią lokalną i jak słusznie zauważyłeś nie mogę sobie do niego przypisać innego adresu (tzn mogę, ale nic to nie zmieni), ale mogę za to dowolnie zmieniać wartości na jakie wskazuje"...
    Ale mi chodzi o to, żeby funkcja, której parametrem jest tablica bądź tablice NIE ZMIENIAŁA mi bezpośrednio zawartości tablicy zadeklarowanej w funkcji wywołującej która już ma wpisane jakieś dane, a która to tablica z kolei jest przekazana jako parametr do funkcji wywoływanej, tylko operowała na ich kopiach.


    Dlatego parametry można deklarować ze słówkiem const :) Wtedy kompilator zabroni Ci cokolwiek wpisywać do parametru (czy nawet na elementy na jakie wskazuje). Robienie takiej struktury to dodatkowy zbędny kod i zaciemnianie czytelności. Struktury są dobre do przekazywania parametrów tylko w dwóch przypadkach - gdy same coś sobą reprezentują (np opisują liczbę zespoloną, figurę geometryczną, etc.), lub gdy parametrów jest bardzo dużo (dużo tzn koło 4 i więcej).

    Ja tylko ostrzegam przed takimi nawykami. Język C sam daje od siebie to co Ty zrobiłeś strukturą. Trochę zbaczamy z tematu, a autor już chyba sobie pomnożył te macierze :).

    0