Drobna pomoc w macierzach

0

Witam mam mały problem z moim programem ale najpierw przedstawię to co miałem zrobić:
Napisać program który zawiera w paru funkcjach następujące rzeczy:

  • wprowadzanie rozmiaru macierzy kwadratowej ( żeby N=M ); [u mnie w głównym programie]
  • randomowe wypisanie tablicy do tablicy wskaznikowej (z dynamiczna alokacja danych, ale moze być też bez); [w funkcji macierz]
  • wypisanie tablicy na ekran; [w funkcji wypisanie]
  • policzenie sumy liczb z: a> przekątnej macierzy, b> sumy nad przekątna, c> sumy pod przekątna [w funkcji sumowanie]

a tutaj mój program

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

int macierz(int**);
int wypisanie(int**);
int sumowanie();

int N, M;
int **tab;
int i, j;
int skos, nad, pod;

int main ()
{
    printf("\n Podaj liczbe kolumn oraz wierszy swojej macierzy KWADRATOWEJ: ");
    scanf("%d", &N);
    M=N;

    macierz();
    wypisanie();
    sumowanie();

    for(i=0; i<M; i++)      // CZYSZCZENIE TABLICY przez funkcje free
    free(tab[i]);
    free(tab);
system("pause");
return 0;
}


int macierz(int**)
{

    tab=(int**)malloc(N*sizeof(int *));     // ODWOLANIE DO WSKAZNIKOW PRZEZ malloc
    for(i=0; i<M; i++)
    {
        tab[i]=(int*)malloc(M*sizeof(int));
    }

    srand((unsigned int) time(NULL));
        for (i=0; i<N; i++)
            for (j=0; j<M; j++)
                tab[i][j] = rand() % 10; // dzielone przez dziesiec lczby calkowite do 10

}

int wypisanie(int**)
{
        for(i=0;i<N;i++)
    {
        for(j=0; j<M; j++)
        {
            printf("%3d ", tab[i][j]);
        }
        printf("\n");
    }

}

int sumowanie()
{
        skos = nad = pod = 0;

        for (i=0; i<N; i++){
        for (j=0; j<M; j++)
        {
            if (i<j) nad+=tab[i][j];
            if (i==j) skos+=tab[i][j];
            if (i>j) pod+=tab[i][j];
        }
        }

        printf("a)\tSuma liczb macierzy nad przekatna jest rowna: %d\n",nad); 
        printf("b)\tSuma liczb macierzy na przekatnej jest rowna: %d\n",skos);
        printf("c)\tSuma liczb macierzy pod przekatna jest rowna: %d\n",pod); 

} 
0

A jaki jest problem i co oznacza (int**) ?

0

Problem w tym ze zapomnialem jak wczytac poprawnie funkcję w programie, a wydaje mi się że (int**) tworzy wskaznik tablicy ale niejestem pewien

0

@siti02, co rozumiesz przez "wczytać" funkcję? Wywołać?

@notexists, z tego, co wiem, zapis int** jest dozwolony, ale nie znam wszystkich reguł, dlatego się nie wypowiem (lepiej wygooglować, niż słuchać mnie w tym zakresie ;) ).

0

Od dawna nie używałem C++, więc mogę się mylić, ale chyba (int**) nie ma sensu. W nawiasie wpisujemy argumenty funkcji, czyli co najmniej typ i nazwa zmiennej, pod którą ten argument będzie widoczny w tej funkcji. Sugeruję usunąć...

Patrząc na kod z góry w dół, jeżeli jakaś funkcja jest wywoływana w danym miejscu, to musi ona być już znana, czyli
a) zdefiniowana wcześniej: umieść funkcję main jako ostatnią funkcję w swoim programie
lub
b) zadeklarowana wcześniej: nad funkcją main dodaj deklaracje funkcji, których używasz, czyli np. int sumowanie();.

2

int macierz(int**)
funkcja ani nie zwraca żadnej wartości ani nie przyjmuje argumentu - brak nazwy.
Pewnie chciałeś zwracać wskaźnik do tablicy, a przyjmować jako argument wielkość tablicy??

0

@Michał tak wywołać

@notexists udało się gdy wstawiłem main na koniec i usunełem (int**) to program działa poprwanie

Ale moje pytanie bo już dawnozapomniałem czy w tej postaci mój program uzywa wskazników ?

poprawiony kod

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

int macierz();
int wypisanie();
int sumowanie();

int N, M;
int **tab;
int i, j;
int skos, nad, pod;

int macierz()
{

    tab=(int**)malloc(N*sizeof(int *));     // ODWOLANIE DO WSKAZNIKOW PRZEZ malloc
    for(i=0; i<M; i++)
    {
        tab[i]=(int*)malloc(M*sizeof(int));
    }

    srand((unsigned int) time(NULL));
        for (i=0; i<N; i++)
            for (j=0; j<M; j++)
                tab[i][j] = rand() % 10; // dzielone przez dziesiec lczby calkowite do 10

}

int wypisanie()
{
        for(i=0;i<N;i++)
    {
        for(j=0; j<M; j++)
        {
            printf("%3d ", tab[i][j]);
        }
        printf("\n");
    }

}

int sumowanie()
{
        skos = nad = pod = 0;

        for (i=0; i<N; i++){
        for (j=0; j<M; j++)
        {
            if (i<j) nad+=tab[i][j];
            if (i==j) skos+=tab[i][j];
            if (i>j) pod+=tab[i][j];
        }
        }

        printf("a)\tSuma liczb macierzy nad przekatna jest rowna: %d\n",nad);  // w 1 funkcji
        printf("b)\tSuma liczb macierzy na przekatnej jest rowna: %d\n",skos);  // w 2 funkcji
        printf("c)\tSuma liczb macierzy pod przekatna jest rowna: %d\n",pod);  // w 3 funkcjis

}

int main ()
{
    printf("\n Podaj liczbe kolumn oraz wierszy swojej macierzy KWADRATOWEJ: ");
    scanf("%d", &N);
    M=N;

    macierz();
    wypisanie();
    sumowanie();

    for(i=0; i<M; i++)      // CZYSZCZENIE TABLICY przez funkcje free
    free(tab[i]);
    free(tab);
system("pause");
return 0;
}
0

@właśnie o to mi właśnie chodziło

0

czyli reasumując program działa poprawne ale jedno pytanie czy tablica jest tworzona za pomocą wskaznika?

1
  1. int ** to wskaźnik na wskaźnik, może być interpretowany jako tablica dwuwymiarowa, choć są lepsze sposoby.
  2. tak, Twój program używa wskaźników.
  3. alokacja pamięci i jej zwalnianie jest technicznie rzecz biorąc okej.
  4. dlaczego mówisz kompilatorowi, że Twoje funkcje zwracają int, skoro nic nie zwracają?
  5. zmienne globalne są złe. Bardzo złe.
  6. formatuj to jako tako, bo trochę kupa Ci z kodu wyszła.
0

@pingwindyktator 1. co do kodu wiem ze nie jest zbytnio fajny ale moj wykladowca poswiecil glowna uwage na zajeciach na wskazniki i musialem gdzies je wykorzystac niestety.. -.-
2. dobrze usuwam wiec przed funkcjami int-y tzn wszedzie przed: macierz(); wypisanie(); sumowanie();
3. wiec jak teraz ogarnac zmiene globalne by byly dostatecznie dobre :)?

0

Wskaźniki w C są jak najbardziej okej. Nigdy nie mówiłem, że nie.
"2. dobrze usuwam wiec przed funkcjami int-y tzn wszedzie przed: macierz(); wypisanie(); sumowanie();"
Nie rozumem Cię ani trochę.
Zmienne globalne prawie nigdy nie będą dobre. Powinno ich w ogóle nie być. Jak piszesz program wielowątkowy z jakąś główną flagą to możesz użyć zmiennych globalnych. W większości przypadków nie możesz, a już na pewno nie w tak prostym kodzie.

0

Kurcze poprawiłem to tak jak potrafiłem program odpala ale sie zawiesza gdzies pewnie dalem czegos za duzo albo czegos nie dopisalem przypuszczam ze przy funkcjach co o tym sądzicie?

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

int macierz();
int wypisanie();
int sumowanie();

int main ()
{
    int N, M;
    int **tab;
    int i;

    printf("\n Podaj liczbe kolumn oraz wierszy swojej macierzy KWADRATOWEJ: ");
    scanf("%d", &N);
    M=N;

    macierz();
    wypisanie();
    sumowanie();

    for(i=0; i<M; i++)      // CZYSZCZENIE TABLICY przez funkcje free
    free(tab[i]);
    free(tab);
system("pause");
return 0;
}

int macierz(int **tab, int N, int M)
{
    int i, j;

    tab=(int**)malloc(N*sizeof(int *));     // ODWOLANIE DO WSKAZNIKOW PRZEZ malloc
    for(i=0; i<M; i++)
    {
        tab[i]=(int*)malloc(M*sizeof(int));
    }

    srand((unsigned int) time(NULL));
        for (i=0; i<N; i++)
            for (j=0; j<M; j++)
                tab[i][j] = rand() % 10; // dzielone przez dziesiec lczby calkowite do 10

    return **tab;

}

int wypisanie(int **tab, int N, int M)
{
    int i, j;
    for(i=0;i<N;i++)
    {
        for(j=0; j<M; j++)
        {
            printf("%3d ", tab[i][j]);
        }
        printf("\n");
    }
    return 0;
}

int sumowanie(int **tab, int N, int M)
{
        int skos, nad, pod;
        int i, j;
        skos = nad = pod = 0;

        for (i=0; i<N; i++){
            for (j=0; j<M; j++)
            {
                if (i<j) nad+=tab[i][j];
                if (i==j) skos+=tab[i][j];
                if (i>j) pod+=tab[i][j];
            }
        }

        printf("a)\tSuma liczb macierzy nad przekatna jest rowna: %d\n",nad);
        printf("b)\tSuma liczb macierzy na przekatnej jest rowna: %d\n",skos);
        printf("c)\tSuma liczb macierzy pod przekatna jest rowna: %d\n",pod);

return 0;
} 
0

Skoro już masz funkcje, które przyjmują argumenty, to musisz je wywoływać z argumentami i ich deklaracje na górze też powinny mieć argumenty...

0

Ale jak już wstawiłem to w nastepujacy sposób:

int macierz(int **tab, int N, int M);
int wypisanie(int **tab, int N, int M);
int sumowanie(int **tab, int N, int M);

int main ()
{
    int N, M;
    int **tab;
    int i;

    printf("\n Podaj liczbe kolumn oraz wierszy swojej macierzy KWADRATOWEJ: ");
    scanf("%d", &N);
    M=N;

    macierz(int **tab, int N, int M);
    wypisanie(int **tab, int N, int M);
    sumowanie(int **tab, int N, int M); 

to w

main

przy macierz(int **tab, int N, int M);

 niechce kompilować ;/
1

macierz (tab, N, M);

1

No i dobrze, że nie chce...
Wywołujesz funkcję printf poprawnie - przekazując jej jako argument pewien tekst, czyli zakładam, że wiesz jak się wywołuje funkcje. Ciekawostka: deklaracja tej funkcji wygląda podobno tak:

 int printf(const char *format, ...);

To jest moment, w którym powinieneś rozróżniać czym się różni deklaracja funkcji od wywołania tej funkcji...

I teraz wracamy do Twojego problemu: wywołaj w funkcji main funkcje, zamiast próbować powtórzyć ich deklaracje...

0

w

main

zmienilem jak wyzej macierz (tab, N, M);

 ale nie wiem juz sam jak to powinno być przy tym deklarowaniu jak wywolywałem inne funkcje to zawsze tak wystarczalo ;/
2
  1. Rzecz pierwsza: ja bym ci radził zawsze inicjalizować zmienne (jakąś wartością, jakąś domyślną najlepiej), czyli: zamiast int N pisz int N = 0.

  2. Ponadto, zawsze radziłbym ci pisać deklaracje osobno w każdej linijce, czyli:
    zamiast

int N = 0, M = 0;

pisz

int N = 0;
int M = 0;

A to z uwagi tylko i wyłącznie na to, że tak łatwiej jest potem zobaczyć, gdzie jest błąd (w szczególności, jak już zaczniesz używać debuggera). :)

  1. Punkt widzenia @pingwindyktator -a odnośnie zmiennych globalnych zapamiętaj, bo to bardzo dobry punkt widzenia :) - używać ich jak najrzadziej.

  2. Nie bardzo rozumiem, po co tworzysz w tym programie zmienną M, można przecież wykorzystać dwa razy N, no ale może takie miałeś wytyczne może z poprzedniego zadania, czy od wykładowcy, nie wnikam. Jeśli jednak nie, to radziłbym ci usunąć M i napisać N. No, chyba, że planujesz w przyszłości zmienić ten program, żeby działał dla dowolnej macierzy. :)

  3. Pochwalę twój kod, że ładnie wyodrębniłeś funkcje, a w programie głównym zostawiłeś tylko to, co niezbędne. :)

  4. Przepraszam, ale w zasadzie nie pamiętam już, co miałeś źle. Chyba chodziło tylko o brak argumentów.

  5. Funkcja wypisanie zwraca int (0), a nie byłoby bardziej naturalnie void?

  6. Według mnie dobrze byłoby, byś miał alokację pamięci na tym samym poziomie, co zwalnianie pamięci (albo oba w main, albo oba w oddzielnych funkcjach). To może nie jest istotne z punktu widzenia poprawności, ale według mnie poprawia czytelność. I ustrzeże cię przed błędami.

  7. Co do deklaracji funkcji:

Z funkcjami w C można się obchodzić na 3 sposoby:

  • deklaracja,
  • definicja,
  • wywołanie.

Deklaracja funkcji wygląda tak: void funkcja(int parametr); lub bez nazwy parametru int funkcja(int);, co jest równoważne. Spotkałem się też z określeniem "zapowiedź" funkcji. Deklarację funkcji należy umieścić PRZED jej wywołaniem - w przypadku twojego programu to oznacza, że przed funkcją main.

Definicja funkcji wygląda tak: void funkcja(int parametr) { ... } (wielokropek to różne czynności). Definicję funkcji można umieścić po funkcji main, można też przed. I można przed, i po deklaracji. :)

Wywołanie funkcji wygląda tak: funkcja(10);. Jeżeli funkcja zwraca wartość, np. int, to można połączyć to z przypisaniem: int a = funkcja(10);.

Na koniec: sam się trochę nauczyłem o dynamicznej alokacji dzięki twojemu programowi. ;)

EDIT: program poprawiłem, zobacz, uruchom, sprawdź, czy działa - obejrzyj też zmiany (niewielkie): http://ideone.com/JcpKxY

0

Przepraszam że po takim czasie pisze ale miałem małe problemy z dostawcą internetu..:/

@Michał Bodziony Bardzo dziękuję za pomoc, ta parę poprawek a zmiana znacząca bo program w końcu działa poprawnie tzn tak jak miałem w moich założeniach jeszcze raz dziękuje i Pozdrawiam :)

temat można zamknąć uzyskałem pomoc jaką oczekiwałem :)

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