Sumowanie przekątnych tablicy i wyświetlanie wyniku

0

Witam,

mam problem z wykonaniem pewnego programu. Mianowicie mam napisać program, który sumuje przekątne tablicy i wyświetla ich sumę. Dla przekątnej idącej od górnego lewego boku do prawego dolnego jest łatwe, gdyż jest warunek (i==j), jednak mam problem z drugą stroną (prawy górny bok, do lewego dolnego). Próbowałem wielu manipulacji w kodzie, niestety jedyne co udało mi się osiągnąć to suma, która była powielona tyle razy, jaki rozmiar miała dana tablica.
Poniżej wklejam kod.
Pozdrawiam i liczę na podpowiedź.

 void suma_przekatnych_L_P (int tab[N][M], int n, int m)
{
    int i,j;
    int suma=0;
    for (i=0;i<n;i++)
        for (j=0;j<m;j++)
            if (i==j)
                suma+=tab[i][j];
                printf("\nSuma przekatnej od lewej do prawej wynosi:%d",suma);
}

void suma_przekatnych_P_L (int tab[N][M], int n, int m)
{
    int i,j,a=i,b=m;
    int suma=0;
    for (i=0;i<n;i++)
        for (j=0;j<m;j++)
            suma+=tab[m-1-i][j];
                printf("\nSuma przekatnej od prawej do lewej wynosi:%d",suma);
}
1
  1. Według jakiej zasady decydujesz, jakie wcięcie ma mieć linia? Kiedyś takie niechlujstwo Cię kopnie w tyłek, jak sam nie będziesz umiał zrozumieć, jaki jest przepływ sterowania w programie…
  2. Współrzędne na przeciwprzekątnej sumują się do wymiaru macierzy mniej jeden, czyli warunek, jaki chcesz, to if (n - 1 == i + j).
  3. U ciebie możliwe jest, że n ≠ m, a tymczasem pojęcie „przekątnej” ma sens tylko dla macierzy kwadratowych…
0

Ad.1 Nie zrozumiałem Cie. "Jakie wcięcie ma mieć linia?"
Ad.2 Próbowałem to uwzględnić od wartości końcowych macierzy, jednak nieskutecznie, a na warunek nie potrafiłem wpaść.
Ad.3 Moje niedopisanie. Macierz jest kwadratowa, jednak sądziłem, że tak trywialna rzecz jest oczywista.

0
  1. Różne linie mają u Ciebie różne wcięcia (wcięcie to odstęp od lewej krawędzi) — doskonale, tak ma być. W większości przypadków wielkość wcięcia wskazuje na to, pod jaką strukturę kontrolną (np. for, if itd.) podlegają — doskonale, tak ma być. A potem w pierwszej funkcji printf jest na poziomie suma+=, chociaż nie należy do tego samego ifa i raczej powinien być na wysokości deklaracji zmiennych… Podobnie w drugiej funkcji, wcięcie printfa nie ma żadnego sensu.
  2. No to już masz.
  3. Ale najwyraźniej nie jest, bo Twój kod wyraźnie jest przygotowany na macierze prostokątne — przyjmujesz dwie osobne wartości (nm) na wymiary tejże macierzy. Oprócz tego, dublujesz informacje — z jednej strony masz z góry zadane NM jako rozmiary tej macierzy, a z drugiej przyjmujesz to jeszcze raz jako nm) — to konstrukcja tylko czekająca na błąd. Zwłaszcza, że podobieństwo między nazwami stałych a nazwami parametrów jest olbrzymie.
0
  1. Czyli chodzi tutaj o czytelność i estetykę programu - staram się cały czas tego nauczyć, jednak jak widać programowanie idzie mi dość topornie.
  2. Za warunek ogromnie dziękuję.
  3. Na samym początku użyłem #define N 5 i #define M 5 - zaraz po uwzględnieniu bibliotek, a co do ( n i m ) oraz ( N i M ). Tak zostało nam to wytłumaczone na zajęciach laboratoryjnych i na tym bazuję. Jak wspomniał wykładowca "tak zostało to przyjęte"
0

1. Estetyka jak estetyka, czytelność na tym traci. U Ciebie trzeba czytać program, liczyć nawiasy itd. A to, co się wykonuje w jaki sposób, powinno być widoczne na pierwszy rzut oka. Ponadto, dobrze jest sobie wyrabiać nawyk stawiania nawiasów klamrowych nawet przy jednolinijkowych instrukcjach — zbyt łatwo jest przerabiając kod zapomnieć o ich dodaniu. Ostatecznie, gdyby to był mój kod, sformatowany byłby tak:

void suma_przekatnych_L_P (int tab[N][M], int n, int m) {
    int i;
    int j;
    int suma=0;

    for (i=0; i<n; i++) {
        for (j=0; j<m; j++) {
            if (i==j) {
                suma+=tab[i][j];
            }
        }
    };

    printf("\nSuma przekatnej od lewej do prawej wynosi:%d",suma);
};

void suma_przekatnych_P_L (int tab[N][M], int n, int m) {
    int i;
    int j;
    int a = i;
    int b = m;
    int suma=0;

    for (i=0; i<n; i++) {
        for (j=0; j<m; j++) {
            suma+=tab[m-1-i][j];
        }
    };

    printf("\nSuma przekatnej od prawej do lewej wynosi:%d",suma);
}

3. To „tak zostało przyjęte” odnosiło się do czegoś innego — zapewne do deklarowania stałych zaraz za załączaniem bibliotek czy nazywaniem ich wielkimi literami. Nie ma — niezależnie od kontekstu — sensu w dublowaniu rzeczy o tym samym znaczeniu (czyli u Ciebie nN), bo to tylko proszenie się o pomyłkę, gdy zmieni się jedno i zapomni o drugim. Jeśli jednak Was tak uczą — to Was źle uczą. Vide zasada DRY.

0

Na pewno wezmę Twoje uwagi do serca i zacznę je stosować. Zależy mi na tym aby dobrze się nauczyć programowania, jednak będzie to długa i ciężka droga. Za pomoc z tablicami ogromnie dziękuję. Widzę też, że każdą zmienną deklarujesz oddzielnie. Czyli idąc zasadą DRY zmienne n oraz m są zbędne i do deklarowania warunków mogę użyć zmiennych N i M ?

0

Tak. W ten sposób od razu widzę, ile mam zmiennych i jakie, nie muszę się wpatrywać w poszukiwaniu przecinków. Niemal zawsze używa się też znacznie dłuższych i bardziej opisowych nazw, więc to też sporo ułatwia.

Zgodnie z zasadą DRY zmienne nm są zbędne, jako że muszą w każdym sensownym programie wynosić tyle samo, co NM, więc należy się ich pozbyć, by zmniejszyć ryzyko pomyłki. Dodatkowo, jako że Twój program ma sens tylko dla macierzy kwadratowych (o ile nie robi czegoś innego jeszcze), to dodatkowo jedna ze stałych NM jest niepotrzebna — bo obie będą musiały wynosić tyle samo.

0

Więc od dzisiaj zaczynam również to stosować.

Reszta programów ma wyszczególnione dla rozmiaru NxM, jednak spełnią się również dla macierzy kwadratowych, dlatego wolałem zostawić wymiar NxM, aby było to zgodne z poleceniem. Zawsze też mogę zdefiniować, że M=N. Jednak pod względem estetyki i przejrzystości lepiej byłoby przyjąć jedną wartość dla tych zadań opartych na macierzach?

0

Tak. Przede wszystkim, zmniejsza to liczbę potencjalnych błędów.

Twój program do działania wymaga następujących tożsamości: n == m; m == M; n == N; N == m. Nie zapewnia jednak żadnej z nich — konkretniej, kompilator ich nie pilnuje. Więc jeśli zmienisz swój kod tak, że się te wartości rozejdą, to program się skompiluje, ale albo się będzie wysypywał z dziwnymi błędami, albo co gorsza zwracał nieprawidłowe wyniki. I wtedy będziesz musiał żmudnie dochodzić do tego, co jest nie tak.
Każde założenie, które jest konieczne do poprawnego działania programu, powinno być zapisane jawnie w sposób, który umożliwia jego weryfikację możliwie wcześnie — najlepiej na etapie kompilacji.

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