logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[c++] C++: Znaczenie `double** data` i przekazywanie do funkcji w klasie matrix

noopS 18 Sty 2009 00:19 2580 7
REKLAMA
  • #1 6015181
    noopS
    Poziom 18  
    Posty: 229
    Pomógł: 23
    Ocena: 29
    witam

    mam takie pytanie analizuję właśnie kod który zamieściłem poniżej
    jest to plik nagłówkowy o nazwie matrix.h jakiegoś nie znanego mi autora zastanawia mnie w nim;

    1. co oznacza linijka
     double** data 

    co my w tym miejscu tworzymy?
    2. i jeszcze jak przekazać argument do funkcji w classie która wykorzystuję tę zmienna data

    
    
    #include<math.h>
    
    typedef enum{false,true} bool;
    
    void swap(double* a,double* b)			//zamiana zmiennych 
    {
       double tmp;
       tmp=(*a);
       (*a)=(*b);
       (*b)=tmp;
    }
    
    class matrix
    {
    
    private:
    	int row,col;				//
    	double** data;
    public:
    	matrix();
    	matrix(int,int);
    	~matrix();
    
    	int getrow();
    	int getcol();
    	void setrow(int);			//ustawia row
    	void setcol(int);			//ustawia col
    	void setdata(double**);
    
    	matrix swapcols(int,int);		//zamien kolumny
    	matrix swaprows(int,int);		//zamien wiersze
    	matrix concat(matrix);			
    	matrix copy();				//kopiuj
    	matrix transpose();			//transponowanie
    	matrix add(matrix);			//dodaj
    	matrix multiply(double);		//mnozenie
    	matrix multiply(matrix);		//mnozenie
    	matrix inverse(double,int*);		//odwroc
    	double det(double);			//wyznacznik
    	int rank(double);
    };
    
    
    matrix::matrix()
    {
    	int i;
    	for(i=0;i<=col;i++);
    	data[i]=new double[row+1];
    }
    
    matrix::matrix(int r,int c)
    {
    	int i;
    	for(i=0;i<=c;i++)
    	data[i]=new double[r+1];
    	row=r;
    	col=c;
    }
    
    matrix::~matrix()				//destruktor
    
    {
    	int i;
    	for(i=0;i<=col;i++)
    	delete data[i];
    }
    
    int matrix::getrow()				//zwraca ile wierszy
    {
    	return row;
    }
    
    int matrix::getcol()				//kolumn
    {
    	return col;
    }
    
    void matrix::setrow(int r)			//ustaiwa wiersze
    {
    	row=r;
    }
    
    void matrix::setcol(int c)			//kolumny
    {
    	col=c;
    }
    
    void matrix::setdata(double** d)		//wypełnia macierz
    {
    	int i,j;
    	for(i=1;i<=row;i++)
    	for(j=1;j<=col;j++)
    	data[i][j]=d[i][j];
    }
    
    matrix matrix::swapcols(int p,int q)		//zamienia kolumny
    {
    	int i,j;
    	double tmp;
    	matrix b=matrix(row,col);
    	for(i=0;i<=row;i++)
    	for(j=0;j<=col;j++)
    	b.data[i][j]=data[i][j];
    	for(i=0;i<=row;i++)
    	{
    		tmp=b.data[i][p];
    		b.data[i][p]=b.data[i][q];
    		b.data[i][q]=tmp;
    	}
    	return b;
    }
    
    matrix matrix::swaprows(int p,int q)		//zamienia wiersze
    {		
    	int i,j;
    	double tmp;
    	matrix b=matrix(row,col);
    	for(i=0;i<=row;i++)
    	for(j=0;j<=col;j++)
    	b.data[i][j]=data[i][j];
    	for(i=0;i<=row;i++)
    	{
    		tmp=b.data[p][i];
    		b.data[p][i]=b.data[q][i];
    		b.data[q][i]=tmp;
    	}
    	return b;
    }
    
    matrix matrix::concat(matrix b)			//rozszerzenie macierzy o kolumny i wiersze
    {
    	int i,j;
    	matrix c=matrix(row,col+b.col);
    	for(i=0;i<=c.row;i++)
    	for(j=0;j<=col;j++)
    	c.data[i][j]=data[i][j];
    	for(i=0;i<=c.row;i++)
    	for(j=col+1;j<=c.col;j++)
    	c.data[i][j]=b.data[i][j];
    	return c;
    }
    
    matrix matrix::copy()
    {
    	int i,j;
    	matrix b=matrix(row,col);
    	for(i=0;i<=row;i++)
    	for(j=0;j<=col;j++)
    	b.data[i][j]=data[i][j];
    	return b;
    }
    
    matrix matrix::transpose()
    {
    	int i,j;
    	matrix b=matrix(col,row);
    	b.row=col;
    	b.col=row;	
    	for(j=0;j<=col;j++)
    	for(i=0;i<=row;i++)
    	b.data[i][j]=data[j][i];
    	return b;
    }
    
    matrix matrix::add(matrix b)
    {
    	int i,j;
    	matrix c=matrix(row,col);
    	c.row=row;
    	c.col=col;
    	for(i=0;i<=row;i++)
    	for(j=0;j<=col;j++)
    	c.data[i][j]=data[i][j]+b.data[i][j];
    	return c;
    }
    
    matrix matrix::multiply(double x)
    {
    
    	int i,j;
    	matrix c=matrix(row,col);
    	c.row=row;
    	c.col=col;
    	for(i=0;i<=row;i++)
    	for(j=0;j<=col;j++)
    	c.data[i][j]=data[i][j]*x;
    	return c;
    }
    
    matrix matrix::multiply(matrix b)
    {
    	int i,j,k;
    	double s;
    	matrix c=matrix(row,b.col);
    	c.row=row;
    	c.col=b.col;
    	for(i=0;i<=c.row;i++)
    	{
    		for(k=0;k<=c.col;k++)
    		{
    			s=0.0;
    			for(j=0;j<=col;j++)
    			s+=data[i][j]*b.data[j][k];
    			c.data[i][k]=s;
    		}
    	}
    	return c;
    }
    
    
    matrix matrix::inverse(double eps,int* err)
    {
    	int i,j,k,l;
    	double maxA,d,e;
    	matrix b=matrix(row,row);
    	int* M;
    	M=new int[row+1];
    	(*err)=0;
    	for(i=1;i<=row;i++){
    	maxA=0.0;
    	for(j=i;j<=row;j++){
    	d=b.data[j][i];
    	if(fabs(maxA)<fabs(d)){
    	maxA=d;
    	k=j;
    	}
    }
    if(fabs(maxA)<eps) {
    (*err)=1;
    break;
    }
    M[i]=k;
    b.data[k][i]=1.0;
    for(j=1;j<=row;j++){
    d=(double)(b.data[k][j]/maxA);
    b.data[k][j]=b.data[i][j];
    b.data[i][j]=d;
    }
    for(j=1;j<=row;j++)
    if(j!=i){
    d=b.data[j][i];
    b.data[j][i]=0.0;
    for(l=1;l<=row;l++){
    e=d*b.data[i][l];
    b.data[j][l]-=e;
    }
    }
    }
    for(i=row;i>=1;i--){
    k=M[i];
    if(k!=i)
    for(j=1;j<=row;j++){
    d=b.data[j][i];
    b.data[j][i]=b.data[j][k];
    b.data[j][k]=d;
    }
    }
    delete M;
    return b;
    }
    
    double matrix::det(double eps)
    {
    	int i,j,k,m;
    	double s,t;
    	m=0;
    	for(i=1;i<=row;i++)
    	{
    	t=fabs(data[i][i]);
    	k=i;
    	for(j=i+1;j<=row;j++)
    	if(fabs(data[j][i])>t) 
    	{
    		t=fabs(data[j][i]);
    		k=j;
    	}
    	
    	if(t<eps)
    	{
    		return 0.0;
    	}
    
    	if(i==k)
    	t=data[i][i];
    	else
    	{
    		m=(m+1)%2;
    		for(j=row;j>=i;j--)
    		{
    			t=data[k][j];
    			data[k][j]=data[i][j];
    			data[i][j]=t;
    		}
    	}
    	t=(double)(1/t);
    	for(j=i+1;j<=row;j++)
    	{
    		s=-data[j][i]*t;
    		for(k=i+1;k<=row;k++)
    		data[j][k]+=data[i][k]*s;
    	}
    	}
    	s=1.0;
    	for(i=1;i<=row;i++)
    	s*=data[i][i];
    	if(m==0) return s;
    	else return -s;
    	}
    	
    	int matrix::rank(double e){
    	int i,j,k,r;
    	int imax,jmax;
    	bool pivot;
    
    	for(j=1;j<=col+1;j++) data[0][j]=(double)j;
    
    	i=1;
    
    do{
    
    	imax=i;
    	for(k=i+1;k<=row;k++) if (fabs(data[k][i])>fabs(data[imax][i])) imax=k;
    	pivot=true;
    	if(fabs(data[imax][i])>e)
    	for(j=1;j<=col+1;j++) swap(&data[i][j],&data[imax][j]);
    	else{
      jmax=i;
      for(k=i+1;k<=col;k++) if(fabs(data[i][k])>fabs(data[i][jmax])) jmax=k;
    
      if(fabs(data[i][jmax])>e)
          for(k=0;k<=row;k++) swap(&data[k][i],&data[k][jmax]);
      else pivot=false;
      }
      if(pivot){
      for(j=i+1;j<=col+1;j++) data[i][j]/=(double)data[i][i];
       data[i][i]=1.0;
      for(k=i+1;k<=row;k++){
       for(j=i+1;j<=col+1;j++) data[k][j]-=data[i][j]*data[k][i];
        data[k][i]=0.0;
       }
       i++;
       }
       }
       while(!(!pivot||i>row||i>col));
       r=i-1;
       return r;
       }
    
    
  • REKLAMA
  • #2 6015839
    paczek86
    Poziom 14  
    Posty: 44
    Pomógł: 11
    Ocena: 2
    noopS napisał:
    witam
    1. co oznacza linijka
     double** data 

    co my w tym miejscu tworzymy?


    Jest to wskaźnik do tablicy dwuwymiarowej, która przechowuje elementy macierzy. Zrobiono to akurat w ten sposób, aby macierz mogła mieć dynamiczny rozmiar, podawany jako parametry konstruktora. W konstruktorze właśnie następuje inicjalizacja tej tablicy.

    Jednak uwaga, w kodzie konstruktora jest poważny błąd dotyczący braku inicjalizacji kolumn, poniżej dodałem odpowiednią linijkę wraz z komentarzem.
    matrix::matrix() 
    
    matrix::matrix(int r,int c) 
    { 
       int i; 
       data = new double *[c+1]; //brakowało tej linijki
       for(i=0;i<=c;i++) 
       data[i]=new double[r+1]; 
       row=r; 
       col=c; 
    }


    Poza tym, ten kod ma sporo innych niedociągnięć, m.in. metody
    void setrow(int);         //ustawia row 
    void setcol(int);         //ustawia col 

    nie zmieniają rozmiaru tablicy z elementami macierzy, co spowoduje błędy przy wywoływaniu innych metod operujących na tej tablicy.

    Tyle zauważyłem "na szybko", bardzo prawdopodobne, że w pozostałych metodach również są tego rodzaju problemy, dlatego radzę porządnie przeanalizować i przetestować ten kod.
  • REKLAMA
  • #4 6020574
    noopS
    Poziom 18  
    Posty: 229
    Pomógł: 23
    Ocena: 29
    Ok już mi się trochę cała sytuacja rozjaśniła. Dziękuję bardzo.


    Mam jeszcze jedno pytanie. Jak w takim razie mam przekazać tablicę do tej klasy. Na pewno nie zadziała zwykłe przekazanie adresu jej początku. Czy moglibyście powiedzieć jak to zrobić??

    Bardzo proszę o pomoc
  • REKLAMA
  • REKLAMA
  • #6 6028682
    noopS
    Poziom 18  
    Posty: 229
    Pomógł: 23
    Ocena: 29
    Jeszcze jedno pytanie bo mam problem otóż tak

    tworze w main coś takiego
    
    main()
    {
     double tablica[3][3];
     matrix macierz;
     
     macierz.setrow(3);
     macierz.setcol(3);
    
     macierz.set(tablica);
    
     return 0;
    }
    


    i wyświetla się komunikat ze nie może dokonać konwersji z double* do double** gdzie leży błąd i co robię nie tak
  • #7 6029110
    paczek86
    Poziom 14  
    Posty: 44
    Pomógł: 11
    Ocena: 2
    noopS napisał:
    wyświetla się komunikat ze nie może dokonać konwersji z double* do double** gdzie leży błąd i co robię nie tak


    Tak nie da się tego przekazać, gdyż funkcja set musi "znać" drugi rozmiar tablicy (czyli jej definicja musiałaby wyglądać tak):
    void setdata(double [][3]); 

    Takie podejście uniemożliwia jednak dynamiczne ustalanie wymiaru macierzy.

    Dlatego, nie modyfikując obecnej metody set, należy utworzyć dynamiczną "tablicę" pomocniczą i to właśnie ją przekazać jako parametr do metody set. Jak to wygląda, obrazuje poniższy kod:
    int main() {
    	   int i;
    	    
    	   double tablica[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; //wlasciwa tablica, ktora chcemy przekazac
    	   double **tmptab = new double *[3]; //pomocnicza "tablica" dynamiczna
    	   for (i=0; i<3; ++i) {
    			tmptab[i] = new double[3];
    			
    			for (int j=0; j<3; ++j) 
    				tmptab[i][j]=tablica[i][j];
    
    	   }
    
    	   matrix m = matrix(2,2);
    	   m.setdata(tmptab);
    	   //m.multiply(2.0);
    
    	   for (i=0; i<3; ++i)  //zwolnienie przydzielonej dla pomocniczej tablicy pamieci
    		   delete tmptab[i];
    
    	   delete tmptab;
    	   
    	   return 0;
    }
  • #8 6030498
    bobbyAIR
    Poziom 20  
    Posty: 267
    Pomógł: 41
    Ocena: 5
    Jeszcze taka uwaga, że plik na początku powinien wyglądać tak:
    
    extern "C"{
    #include<math.h>
    }
    
    //typedef enum{false,true} bool; 
    


    typ bool w C++ jest wbudowany

Podsumowanie tematu

✨ W dyskusji omówiono znaczenie wskaźnika podwójnego `double** data` w klasie matrix, który reprezentuje dynamicznie alokowaną dwuwymiarową tablicę przechowującą elementy macierzy. Konstruktor klasy powinien inicjalizować tę tablicę, tworząc tablicę wskaźników na wiersze, a następnie alokując pamięć dla każdego wiersza. Zwrócono uwagę na błąd w oryginalnym kodzie, gdzie brakowało inicjalizacji tablicy wskaźników. Metody `setrow` i `setcol` zmieniają jedynie wartości rozmiarów, nie dostosowując dynamicznie alokowanej pamięci, co może prowadzić do błędów. Przekazywanie statycznej tablicy dwuwymiarowej do funkcji oczekującej `double**` nie działa bezpośrednio, ponieważ tablica statyczna jest inaczej reprezentowana w pamięci. Aby przekazać dane do metody `setdata`, należy utworzyć dynamiczną tablicę wskaźników (tablicę wskaźników na wiersze), skopiować do niej dane ze statycznej tablicy, a następnie przekazać wskaźnik do tej dynamicznej struktury. Dodatkowo zasugerowano poprawki dotyczące nagłówków i użycia typu bool, który jest wbudowany w C++ i nie wymaga definicji przez enum.
Wygenerowane przez model językowy.
REKLAMA