Nie jesteś zalogowany.
Jeśli nie posiadasz konta, zarejestruj je już teraz! Pozwoli Ci ono w pełni korzystać z naszego serwisu. Spamerom dziękujemy!

Ogłoszenie

Prosimy o pomoc dla małej Julki — przekaż 1% podatku na Fundacji Dzieciom zdazyć z Pomocą.
Więcej informacji na dug.net.pl/pomagamy/.

#1  2011-11-05 17:54:53

  Trin - Wredotka

Trin
Wredotka
Zarejestrowany: 2008-05-16

Problem z programem [wyznacznik macierzy..bleee]

Męczę się już trzeci tydzień z tym... żeby nie napisać bardzo brzydkiego słowa, cholernym programem.
Dla macierzy 2x2 liczy ladnie, dam mu 3x3 już krzyczy że naruszenie ochrony pamięci. Podejrzewam, że błąd leży w tych dwóch zagnieżdżonych for'ach ale ze mnie dupa, nie programista wiec mam kilka procent niepewności.
Tak się już do niego zraziłam, że nie kontaktuję co czytam jak patrzę w "kod". Tyle nerwów mi naszarpał że nawet patrzeć już nie chcę. Chcę tylko zrobić taki myk żeby działał i już nigdy więcej go nie otwierać.

Dla ciekawskich, struktura pliku wygląda tak:

2 <-rozmiar macierzy, poniżej macierz
3 4
5 6

Kod:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

using namespace std;

double** create_matrix (int stopien)
{
    double** macierz;
 
    if (stopien < 1) {
    cout<<"bledny rozmiar!"<<endl;
    exit (-1);
    }
    *macierz = (double*) calloc(stopien*stopien, sizeof(double));
    return macierz;
}

double det(double ** matrix, int n)
{
  double** minor;
  double sum=0.0;
  double sign=1.0;
  int i, nr_row, nr_col, nr_col_dop; //nr wiersza,nr kolumny, nr kolumny dopelnienia
  if(n==1) return matrix[0][0];
  if(n==2) return matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0];
  minor=create_matrix(n-1);
  for(i=0;i<n;i++)
  {
  /* skopiuj odp. podmacierz do minor */
  for (nr_col_dop = 0, nr_col = 0; nr_col_dop < n-1; nr_col_dop++, nr_col++)
        {
            nr_col += (nr_col == nr_col ? 1 : 0);  
            for (nr_row = 0; nr_row < n-1; nr_row++)
                minor[nr_row][nr_col_dop] = matrix[nr_row+1][nr_col];
        }
  sum+=sign*matrix[0][i]*det(minor,n-1);
  sign = -sign;
  };
  free(minor);
  return sum;
};

int main(int argc, char** argv)
{
    int rozmiar, x, i=0, j=0;
FILE *plik;
plik=fopen("macierz.txt", "r");
if(plik==NULL){
    cout<<"Podany plik nie istnieje"<<endl;
}
fscanf(plik, "%d", &rozmiar);
printf("\n");
printf("Rozmiar macierzy wynosi: %d x %d\n\n", rozmiar, rozmiar);
    double** matrix=new double*[rozmiar];
for(x = 0; x<=rozmiar; x++){
    matrix[x]=new double[rozmiar];
    }
    printf("Nasza macierz: \n");
    j=0;
    while(j<rozmiar){
    i = 0;
        while(i<rozmiar){
            fscanf(plik, "%lf", &matrix[i][j]);
            printf("%.2lf\t", matrix[i][j]);
            i++;
        }
      printf("\n");
      ++j;
    }
    printf("\n");
    printf("Wartosc wyznacznika macierzy wynosi: %lf\n", det(matrix, rozmiar));
fclose(plik);
return 0;
}

Jakiś mały hint dla blondyneczki?

Offline

 

#2  2011-11-05 18:29:41

  kamikaze - Administrator

kamikaze
Administrator
Zarejestrowany: 2004-04-16

Re: Problem z programem [wyznacznik macierzy..bleee]

Z tym jest chyba (chyba bo i dla rozmiaru 2 nie powinno działać) problem:

Kod:

double** matrix=new double*[rozmiar];

        for(x = 0; x<=rozmiar; x++){
                matrix[x]=new double[rozmiar];
        }

matrix ma rozmiar powiedzmy 2, więc masz tylko matrix[0] i matrzix[1], a w pętli spróbuje jeszcze ustawić matix[2]. Wszystko przez x<=rozmiar, powinno być "<" zamiast "<=".

Ostatnio edytowany przez kamikaze (2011-11-05 18:30:17)

Offline

 

#3  2011-11-05 21:38:33

  Trin - Wredotka

Trin
Wredotka
Zarejestrowany: 2008-05-16

Re: Problem z programem [wyznacznik macierzy..bleee]

Z tym tak - miałeś rację, ale nadal się wywala. Problem tkwi chyba w kopiowaniu elementów jednej macierzy do drugiej.

Offline

 

#4  2011-11-05 22:59:20

  kamikaze - Administrator

kamikaze
Administrator
Zarejestrowany: 2004-04-16

Re: Problem z programem [wyznacznik macierzy..bleee]

To też jest bez sensu:

Kod:

nr_col += (nr_col == nr_col ? 1 : 0);

Warunek zawsze jest true, coś tu jest nie tak. Można równie dobrze zastąpić to krótko:  nr_col++ . A to niesie ze sobą poważne konsekwencje:

Dla n = 3:

dla nr_col_dop = 0, nr_col = 0

nr_col = 1 (zwiększanie o 1)
minor[0][0] = matrix[1][1]
minor[1][0] = matrix[2][1]

nr_col_dop = 1, nr_col = 2 (zwiększanie w pętli, ale nr_col już jest 1, więc zwiększa się do 2)

nr_col = 3 (zwiększanie o 1)
minor[0][1] = matrix[1][3] < --- segfault (nie ma tej komórki, bo to macież 3x3, a nie 4x4)
minor[1][1] = matrix[2][3] < --- segfault ( — || — )

I błąd naruszenia ochrony pamięci znaleziony.

To chyba można zmienić:

Kod:

    for(i=0;i<n;i++)
    {
        /* skopiuj odp. podmacierz do minor */
        for (nr_col_dop = 0, nr_col = 0; nr_col_dop < n-1; nr_col_dop++, nr_col++)
        {
            nr_col += (nr_col == nr_col ? 1 : 0);  
            for (nr_row = 0; nr_row < n-1; nr_row++)
            minor[nr_row][nr_col_dop] = matrix[nr_row+1][nr_col];
        }
        sum+=sign*matrix[0][i]*det(minor,n-1);
        sign = -sign;
    };

na:

Kod:

        /* skopiuj odp. podmacierz do minor */
        for (nr_col_dop = 0, nr_col = 0; nr_col_dop < n-1; nr_col_dop++, nr_col++)
        {
            nr_col += (nr_col == nr_col ? 1 : 0);  
            for (nr_row = 0; nr_row < n-1; nr_row++)
            minor[nr_row][nr_col_dop] = matrix[nr_row+1][nr_col];
        }

    for(i=0;i<n;i++)
    {
        sum+=sign*matrix[0][i]*det(minor,n-1);
        sign = -sign;
    };

Bo tak jak jest obecnie to kopiuje się za każdym obrotem pętli, wygląda że nie potrzebnie. Najlepiej na kopiowanie zrobić oddzielną funkcję.

Offline

 

#5  2011-11-05 23:03:52

  Huk - Smoleńsk BULWA!

Huk
Smoleńsk BULWA!
Zarejestrowany: 2006-11-08

Re: Problem z programem [wyznacznik macierzy..bleee]

Do tego co podał Kamikaze należy dorzucić błąd w funkcji create_matrix, alokowałaś tam coś na kształt wektora zamiast macierzy 2D, pod spodem umieszczam kod który (chyba ;] ) alokuje poprawnie, aczkolwiek, jako że z calloc'a korzystałem pierwszy raz to mogę się mylić (nie wiem też czy możesz sobie macierz 2D z dealkokwać za pomocą po prostu "free(cośtam)", pewnie i tam trzeba by to zrobić z pętlą. Poniższy kod nie sypie się i wyznacznik drugiego poziomu zdaje się liczyć ok, ale trzeciego poziomu wyszedł mi niezbyt dobry - ale to już pewnie gdzieś błąd w samym algorytmie obliczającym.

Kod:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

using namespace std;

double** create_matrix (int stopien)
{
    double** macierz;

    if (stopien < 1)
    {
        cout<<"bledny rozmiar!"<<endl;
        exit (-1);
    }

    macierz=(double**) calloc(stopien*stopien,sizeof(double));
    for(int i=0;i<stopien;++i)
    {
        macierz[i] = (double*) calloc(stopien*stopien, sizeof(double));
    }
    return macierz;
}

double det(double ** matrix, int n)
{
    double** minor;
    double sum=0.0;
    double sign=1.0;
    int i, nr_row, nr_col, nr_col_dop; //nr wiersza,nr kolumny, nr kolumny dopelnienia
    if(n==1) return matrix[0][0];
    if(n==2) return matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0];
    minor=create_matrix(n-1);
    for(i=0;i<n;i++)
    {
        /* skopiuj odp. podmacierz do minor */
        for (nr_col_dop = 0, nr_col = 0; nr_col_dop < n-1; nr_col_dop++, nr_col++)
        {
            nr_col += (nr_col == nr_col ? 1 : 0);
            for (nr_row = 0; nr_row < n-1; nr_row++)
                minor[nr_row][nr_col_dop] = matrix[nr_row+1][nr_col];
        }
        sum+=sign*matrix[0][i]*det(minor,n-1);
        sign = -sign;
    };
    free(minor);
    return sum;
};

int main(int argc, char** argv)
{
    int rozmiar, x, i=0, j=0;
    FILE *plik;
    plik=fopen("macierz.txt", "r");
    if(plik==NULL)
    {
        cout<<"Podany plik nie istnieje"<<endl;
        return -1;
    }

    fscanf(plik, "%d", &rozmiar);
    printf("\n");
    printf("Rozmiar macierzy wynosi: %d x %d\n\n", rozmiar, rozmiar);
    double** matrix=new double*[rozmiar];

    for(x = 0; x<rozmiar; ++x)
    {
        matrix[x]=new double[rozmiar];
    }

    printf("Nasza macierz: \n");
    j=0;
    while(j<rozmiar)
    {
        i = 0;
        while(i<rozmiar)
        {
            fscanf(plik, "%lf", &matrix[i][j]);
            printf("%.2lf\t", matrix[i][j]);
            ++i;
        }
        printf("\n");
        ++j;
    }
    printf("\n");
    printf("Wartosc wyznacznika macierzy wynosi: %lf\n", det(matrix, rozmiar));
    fclose(plik);

    return 0;
}

Tak poza tym to radziłbym się zdecydować na używanie albo funkcji C albo C++, mieszanie calloc/malloc/cosalloc z new i delete to praktyka bardzo "bee" i łatwo można się na tym przejechać (jak się np. da delete na coś co było alokowane za pomocą calloc'a - wiem z doświadczenia ;] ) podobnie w przypadku wypisywania, raz używanie cout, a raz print'a też niebyt fajnie wygląda.

Pozdro.

Offline

 

#6  2011-11-05 23:22:19

  thalcave - prawie jak admin

thalcave
prawie jak admin
Skąd: odległa galaktyka
Zarejestrowany: 2007-05-17

Re: Problem z programem [wyznacznik macierzy..bleee]

Hmmm macierze to aż proszą się o użycie klas... Trin macie jakieś ograniczenie co do tego co możecie użyć w tym programie?


linux register user: 484281
"It's great to be here. It's great to be anywhere"
Keith Richards

Offline

 

#7  2011-11-05 23:37:28

  Trin - Wredotka

Trin
Wredotka
Zarejestrowany: 2008-05-16

Re: Problem z programem [wyznacznik macierzy..bleee]

thalcave napisał(-a):

Hmmm macierze to aż proszą się o użycie klas... Trin macie jakieś ograniczenie co do tego co możecie użyć w tym programie?

Niestety tak, facet zostawił nam "szkic" funkcji det i jazda. ->tzn oficjalnie mamy jeszcze nie wiedzieć co to klasy.
@up: obaj macie rację we wszystkim co mi napisaliście (dziękuję), ale były 3 wersje kodu okrawane z tego co zbędne, więc całość przypomina jakieś puzzle.

Ostatnio edytowany przez Trin (2011-11-05 23:38:41)

Offline

 

#8  2011-11-05 23:45:39

  thalcave - prawie jak admin

thalcave
prawie jak admin
Skąd: odległa galaktyka
Zarejestrowany: 2007-05-17

Re: Problem z programem [wyznacznik macierzy..bleee]

Trin to daj teraz cały kod jaki masz :) żebyśmy puzzli nie składali


linux register user: 484281
"It's great to be here. It's great to be anywhere"
Keith Richards

Offline

 

#9  2011-11-05 23:55:14

  Trin - Wredotka

Trin
Wredotka
Zarejestrowany: 2008-05-16

Re: Problem z programem [wyznacznik macierzy..bleee]

Teraz ten kod wywala jakiś armagedon w konsoli. Ja mam dość :<

Offline

 

#10  2011-11-06 07:21:20

  Huk - Smoleńsk BULWA!

Huk
Smoleńsk BULWA!
Zarejestrowany: 2006-11-08

Re: Problem z programem [wyznacznik macierzy..bleee]

Tym bardziej wrzuć tutaj to obczaimy ;] C/C++ ma to do siebie że nawet osoby doświadczone potrafią się często złapać na alokacji/dealokacji pamięci (przez to głównie, te języki są uważane za trudne).

Ostatnio edytowany przez Huk (2011-11-06 07:28:39)

Offline

 

#11  2011-11-06 13:56:35

  Trin - Wredotka

Trin
Wredotka
Zarejestrowany: 2008-05-16

Re: Problem z programem [wyznacznik macierzy..bleee]

Dobra, poprawiłam parę rzeczy, m.in zwalnianie tablicy.
Trochę zapuściłam żurawia do kodu kolegi, ale to są jaja jakieś. Poprawiłam też pętle itp.

Kod:

 #include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

using namespace std;

double** create_matrix (int stopien)
{
    double** macierz;
 
    if (stopien < 1) {
    cout<<"bledny rozmiar!"<<endl;
    exit (-1);
    }
    *macierz = (double*) calloc(stopien, sizeof(double));
    for(int i=0;i<stopien;++i)
    {
        macierz[i] = (double*) calloc(stopien, sizeof(double));
    }
    return macierz;
}


void matrix_free(double **macierz, int n){
    for(int i=0;i<n;++i){    //Zwolnienie pamięci
        delete [] macierz[i];
    }
    delete [] macierz;
}

double det(double ** matrix, int n)
{
  double** minor;
  double sum=0.0;
  double sign=1.0;
  int i, nr_row, nr_col, nr_col_dop; //nr wiersza,nr kolumny, nr kolumny dopelnienia
  if(n==1) return matrix[0][0];
  if(n==2) return matrix[0][0]*matrix[1][1]-matrix[0][1]*matrix[1][0];
  minor=create_matrix(n-1);
  for(i=0;i<n;i++)
  {
  /* skopiuj odp. podmacierz do minor */
  for (nr_col_dop = 0, nr_col = 0; nr_col_dop < n-1; nr_col_dop++, nr_col++)
        {
            nr_col += (nr_col == nr_col ? 1 : 0);  //do poprawy, te dwa fory cuchną...
            for (nr_row = 0; nr_row < n-1; nr_row++)
            minor[nr_row][nr_col_dop] = matrix[nr_row+1][nr_col];
        }
}
    for(i=0;i<n;i++)
    {
        sum+=sign*matrix[0][i]*det(minor,n-1);
        sign = -sign;
    };
  matrix_free(minor, n-1);
  return sum;
}

int main(int argc, char** argv)
{
    int rozmiar, x, i=0, j=0;
FILE *plik;
plik=fopen("macierz.txt", "r");
if(plik==NULL){
    cout<<"Podany plik nie istnieje"<<endl;
}
fscanf(plik, "%d", &rozmiar);
printf("\n");
printf("Rozmiar macierzy wynosi: %d x %d\n\n", rozmiar, rozmiar);
    double** matrix=new double*[rozmiar];
for(x = 0; x<rozmiar; x++){
    matrix[x]=new double[rozmiar];
    }
    printf("Nasza macierz: \n");
    j=0;
    while(j<rozmiar){
    i = 0;
        while(i<rozmiar){
            fscanf(plik, "%lf", &matrix[i][j]);
            printf("%.2lf\t", matrix[i][j]);
            i++;
        }
      printf("\n");
      ++j;
    }
    printf("\n");
    printf("Wartosc wyznacznika macierzy wynosi: %lf\n", det(matrix, rozmiar));
fclose(plik);
return 0;
}

a po kompilacji...

Kod:

 ania@debian:~/Desktop/project$ ./a.out 

Rozmiar macierzy wynosi: 3 x 3

Nasza macierz: 
1.00    2.00    3.00    
4.00    5.00    6.00    
7.00    8.00    9.00    

*** glibc detected *** ./a.out: free(): invalid pointer: 0xb763b4c0 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6(+0x6b281)[0xb7564281]
/lib/i686/cmov/libc.so.6(+0x6cad8)[0xb7565ad8]
/lib/i686/cmov/libc.so.6(cfree+0x6d)[0xb7568bbd]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb773e701]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0xb773e75d]
./a.out[0x8048a01]
./a.out[0x8048b70]
./a.out[0x8048d36]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb750fc76]
./a.out[0x8048881]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:09 1254409    /home/ania/Desktop/project/a.out
0804a000-0804b000 rw-p 00001000 08:09 1254409    /home/ania/Desktop/project/a.out
08e65000-08e86000 rw-p 00000000 00:00 0          [heap]
b7300000-b7321000 rw-p 00000000 00:00 0 
b7321000-b7400000 ---p 00000000 00:00 0 
b74f7000-b74f9000 rw-p 00000000 00:00 0 
b74f9000-b7639000 r-xp 00000000 08:07 636158     /lib/i686/cmov/libc-2.11.2.so
b7639000-b763b000 r--p 0013f000 08:07 636158     /lib/i686/cmov/libc-2.11.2.so
b763b000-b763c000 rw-p 00141000 08:07 636158     /lib/i686/cmov/libc-2.11.2.so
b763c000-b763f000 rw-p 00000000 00:00 0 
b763f000-b765c000 r-xp 00000000 08:07 488755     /lib/libgcc_s.so.1
b765c000-b765d000 rw-p 0001c000 08:07 488755     /lib/libgcc_s.so.1
b765d000-b7681000 r-xp 00000000 08:07 636142     /lib/i686/cmov/libm-2.11.2.so
b7681000-b7682000 r--p 00023000 08:07 636142     /lib/i686/cmov/libm-2.11.2.so
b7682000-b7683000 rw-p 00024000 08:07 636142     /lib/i686/cmov/libm-2.11.2.so
b7683000-b776c000 r-xp 00000000 08:07 700747     /usr/lib/libstdc++.so.6.0.13
b776c000-b7770000 r--p 000e9000 08:07 700747     /usr/lib/libstdc++.so.6.0.13
b7770000-b7771000 rw-p 000ed000 08:07 700747     /usr/lib/libstdc++.so.6.0.13
b7771000-b7779000 rw-p 00000000 00:00 0 
b778c000-b778f000 rw-p 00000000 00:00 0 
b778f000-b7790000 r-xp 00000000 00:00 0          [vdso]
b7790000-b77ab000 r-xp 00000000 08:07 284843     /lib/ld-2.11.2.so
b77ab000-b77ac000 r--p 0001a000 08:07 284843     /lib/ld-2.11.2.so
b77ac000-b77ad000 rw-p 0001b000 08:07 284843     /lib/ld-2.11.2.so
bfd90000-bfda5000 rw-p 00000000 00:00 0          [stack]
Przerwane

Czo to jest i z czym się je?
Wrzuciłam sobie też kod Huk'a, kompiluje się, liczy wyznacznik, dla 3x3 jakoś 0 pokazuje. Moja koncepcja jest taka, żeby wywalić na ekran ten minor, popatrzeć jak to skopiowało, bo te dwa fory o kant dupy można rozbić. Imo, w ich okolicy się wywala.

Offline

 

#12  2011-11-06 14:30:56

  NIC - Członek DUG

NIC
Członek DUG
Skąd: Wrocław
Zarejestrowany: 2006-12-25
Serwis

Re: Problem z programem [wyznacznik macierzy..bleee]

To są bardzo dobry błędy. Skompiluj program z opcją -g i wtedy możesz użyć adresów wypisywanych w tym dumpie w mistycznym programiku, który wyznali linię w kodzie gdzie takowy błąd wyskoczył.

Choć już na oko widać gdzie jest błąd :) "free(): invalid pointer" mówi samo za siebie.

Kod:

addr2line -f -e ./path/a.out $ADDRESS

gdzie $ADDRESS to ten hex zwracany w dumpie:
./a.out[0x8048a01]
./a.out[0x8048b70]
./a.out[0x8048d36]
...
./a.out[0x8048881]

np. addr2line -f -e a.out 0x8048a01
Jak widzisz masz kilka wskazań przy a.out co jest fajne, bo pokaże Ci drogę która doprowadziła do błędu: np. main() -> xx() --> zz --> detownik()

W miejscu błędów wyprintfuj wyniki pośrednie.


Jeszcze jedna rzecz... Wydziel z det() funcję minor. I printfuj tworzone kompletne minory, by mieć pewność że minory są poprawne.

Ostatnio edytowany przez NIC (2011-11-06 14:32:37)


Stronka-dom: http://titek.victorygames.pl
Jabber: nic@jabster.pl
Hobby: kompilowanie Linuksa, Bluetooth
Dystrybucja: żadna, bliski krewny LFS, składak

Offline

 

#13  2011-11-06 22:05:58

  Trin - Wredotka

Trin
Wredotka
Zarejestrowany: 2008-05-16

Re: Problem z programem [wyznacznik macierzy..bleee]

Masz wyobraźnię, jeśli myślisz że zrozumiem choć gram z tego co napisałeś :) Wątek bezcelowy bo mam większy mętlik niż miałam..
aaa tam, dzięki ale chyba się poddam.

Offline

 

#14  2011-11-07 10:13:37

  milyges - inż.

milyges
inż.
Skąd: Gorlice/Kraków
Zarejestrowany: 2006-04-09
Serwis

Re: Problem z programem [wyznacznik macierzy..bleee]

Kod:

 *macierz = (double*) calloc(stopien, sizeof(double));
    for(int i=0;i<stopien;++i)
    {
        macierz[i] = (double*) calloc(stopien, sizeof(double));
    }

*macierz = macierz[0]

chcialas chyba macierz = (double **)calloc(...);

I na bogów... nie mieszaj calloc z delete! użyj free() lub new

Offline

 

#15  2011-11-07 14:26:19

  Trin - Wredotka

Trin
Wredotka
Zarejestrowany: 2008-05-16

Re: Problem z programem [wyznacznik macierzy..bleee]

Nie wiem co chciałam, bo tak się kończy usilne podsuwanie sposobu który ciężko wpisać w kod.
Nadal nie działa, oddam mniej ambitną wersję, ale działającą.

Offline

 

Stopka forum

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson
To nie jest tylko forum, to nasza mała ojczyzna ;-)