Matrislerde işlem yapma fonksiyonu

Merhaba, Verilen matris elemanlarını bir kare matrise yerleştirip ardından oluşan matrislere gerekli işlemleri yapan bir fonksiyon yazmak istiyorum.
Verilen elemanlar double tipinde.
Pointer kullanarak yapmaya çalıştım:

#include <stdio.h>
#include <string.h>

void Add(double* A, double* B, double* C, int N) {
    int i, j, k = 0;
    double** matrisA;
    matrisA = malloc(sizeof(double*) * N * N);
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            matrisA[i][j] = A[k];
            k++;
        }
        j = 0;
    }
}
int main() {
    double A[] = { 5, 2, 4, 2, 4, 6, 1, 2, 8 };
    double B[] = { 1, 5, 8, 3, 5, 6, 4, 7, 9 };
    double C[9];

    Add(A, B, C, 3);
}

Visual Studio üzerinde kod hata vermiyor ama çalıştırınca “… üzerinde özel durum oluştu: 0xC0000005: 0xCDCDCDCD konumuna yazma erişimi ihlali” hatası alıyorum.
Sebebi nedir?, teşekkürler.

Çaılştırdıktan sonra alttaki hataları gösteren kısımda 2 tane uyarı çıktı.

  1. ‘malloc’ tanımsız; int döndüren extern olduğu varsayılıyor

  2. ‘=’: ‘double **’, yöneltme düzeyi sayısı bakımından ‘int’ ile aynı değil

Dostlar sorunu pointer kullanmadan direkt dizi oluşturmayı deneyerek çözdüm. Şu şekilde;

#include <stdio.h>
#include <string.h>

void Add(double* A, double* B, double* C, int N) {
	int i, j, k = 0;
	double amatris[3][3];
	double bmatris[3][3];
	double cmatris[3][3];
	for (i = 0; i < N; i++) {
		for (j = 0; j < N; j++) {
			amatris[i][j] = A[k];
			bmatris[i][j] = B[k];
			cmatris[i][j] = A[k] + B[k];
			k++;
		}
		j = 0;
	}
	k = 0;
	for (i = 0; i < N; i++) {
		for (j = 0; j < N; j++) {
			C[k]=cmatris[i][j];
			
			k++;
		}
		j = 0;
	}
	
}


int main() {
	int i;
	double A[] = { 5, 2, 4, 2, 4, 6, 1, 2, 8 };   double B[] = { 1, 5, 8, 3, 5, 6, 4, 7, 9 };   double C[9];

	for(i=0;i<9;i++){
		Add(A, B, C, 3);
		printf("\t%lf", C[i]);
	}
		}

Şu an var olan sorun da:
Fonksiyon içindeki

double amatris[3][3];
	double bmatris[3][3];
	double cmatris[3][3];

kısmındaki 3’lerin yerine N yazdığım zaman şu hataları alıyorum:

stdlib dahil edilmemiş.

Merhabalar,

Bunlara gerek var mı hocam, zaten fonksiyona A, B ve C geçiriyorsunuz?

^Dolayısıyla bu kısma da gerek yok.

k = 0;
for (i = 0; i < N; i++) {
	for (j = 0; j < N; j++) {
		C[k] = A[k] + B[k]; //cmatris[i][j];		
		k++;
	}
	j = 0; //buna da gerek yok aslında
}

Bu kısım yeterli oluyor, C[k] = A[k] + B[k] diyerek.

Burası da C’ye A ve B’yi 9 kere ekliyor, ekleme işlemini dışarı alsak daha iyi heralde.

1 Beğeni

Dipnot:

Eğer iki boyutlu* bir array malloc'lamak istiyorsak (diyelim MxN olsun şekli), öncelikle ilk boyut için yer ayırmalıyız, sonrasında da diğer boyut için tek tek yer ayırmalıyız, yani:

double** matrisA;
// Önce ilk boyut için M tane yer ayırırız
matrisA = malloc(sizeof(double*) * M); 
for (i = 0; i < M; i++) {
    // Sonra, ayırdığımız her M pointer için ikinci boyut kadar daha ayırırız
    matrisA[i] = malloc(sizeof(double) * N)
    for (j = 0; j < N; j++) {
        matrisA[i][j] = ...

*: iki (veya daha fazla) boyutlu array’ler ya dümdüz yani 1 boyutlu olarak temsil edilip elemanlara ulaşma işlemleri indeks matematiğiyle yapılır (sizin ikinci çözümünüzde yaptığınız), ya da pointer to pointer to .... pointer şeklinde temsil edilip [.][.]...[.] şeklinde elemanlara ulaşılır (yukardaki malloc mevzusu).

Tabii her malloc bi’ free ister ki sızmasın :d
İşiniz bittiğinde şu lazım yani:

for (i = 0; i < M; i++) {
    free(matrisA[i]);
}
free(matrisA);
1 Beğeni

Hocam sağ olun. Sıradan cevap vereyim;
Evet gerek yok dediğiniz yerler C=A+B için gerekli değil.
Ama birkaç fonksiyon daha yazmam gerekiyor.

Verilen NxN’lik A ve B matrislerine göre, C = A + B hesaplanır.
Verilen NxN’lik A ve B matrislerine göre, C = A – B hesaplanır.
Verilen NxN’lik A ve B matrislerine göre, C = A * B hesaplanır.
Verilen NxN’lik A ve B matrislerine göre, C = A^T hesaplanır.
Verilen NxN’lik A matrisine göre, computes det(A) hesaplanır.
Verilen NxN’lik A matrisinin tersi hesaplanır, C = inv(A)

Verilen A ve B matris elemanları tek boyutlu dizi şeklinde.

double A = { 5, 2, 4, 2, 4, 6, 1, 2, 8 };
double B = { 1, 5, 8, 3, 5, 6, 4, 7, 9 };

Bu yüzden önce matris formuna çevirmem gerekiyor.

Aynen öyle, düzeltiyorum hemen.

Şu anda tek problem;
double amatris[3][3]; bu ifadede sıkıntı çıkmazken,
double amatris[N][N]; bu ifadede aşağıdaki hataları vermesi:

Evet ben matrisin tamamı için boyut ayırmışım ama o boyutu elemanların konulacağı kadar boyutlara ayırmamışım. Galiba çok fazla bilgisayar başında kaldığım için yapıyorum bu hataları.
Sanırım bu işlemi yapınca sorun çözülecek.
Aklımda kalan tek soru işareti şu;

Son bir tavsiye istiyorum, bu işlemler için,

matrisleri dizi şeklinde mi oluşturmalıyım yoksa pointer, malloc yöntemiyle mi?
Teşekkür ederim ^^

Hocam bu compiler’a özgü bir hata olsa gerek. C99 ve sonrasında variable-length array’e izin var (variable length compile-time’da belliyse tabii). gcc ve clang ile denedim, bir uyarı/hata yok.

Eğer Visual Studio’da devam etmek istiyorsanız, malloc kullanmanız gerekir.

1 Beğeni

malloc üzerinden devam ediyorum şimdi yazmaya çok sağ olun.

1 Beğeni

@anon18277073 Kodun tamamını yazdım, çalışır durumda şu an. Bi şey kaldı sadece örnek olsun diye bi kod parçası bırakayım;

 double** matrisyap(double* x,double **matris, int n){
 int i,j,k=0;
 matris=(double**)malloc(sizeof(double*)*n);
 for(i=0;i<n;i++){
 matris[i]=(double*)malloc(sizeof(double)*n);
}
 for(i=0;i<n;i++){
 	for(j=0;j<n;j++){
 	matris[i][j]=x[k];
 	k++;
 		
	 }
 }
 	
	
return matris;
		
}

Bunun gibi 7 tane fonksiyon var. fonksiyonların içinde malloc kullanılıyor. fonksiyonun sonunda da ‘malloc’ ile yer açılan değişken pointerı return ile döndürülüyor. Şimdi ben free fonksiyonunu returndan önce kullansam değeri dönderemem. returndan sonra kullansam program o satırı okumaz.
Fonksiyon kullanıldıktan sonra içerisinde malloc ile tahsis edilen bellek fonksiyon bittikten sonra tekrar sisteme kendiliğinden verilir mi?
main’in içinde de kullanamıyorum değişken orada tanımlı olmadığı için.
main’in sonunda kullandığım fonksiyonlar da dahil olmak üzere tahsis ettiğim bütün bellekleri tekrar sisteme verecek bi komut var mı?
Teşekkür ederim.

Yok verilmez hocam, çünkü malloc ile heap’te hafıza ayırıyoruz, siz manuel olarak geri verene kadar veya program bitip de işletim sistemi geri verene kadar o hafıza ayrılmış olarak duruyor orada.

Hocam bu signature biraz tutarsız (fazla) değil mi: hem yeni, elde etmek istediğiniz matris’i fonksiyona geçiriyorsunuz, hem de fonksiyondan onu döndürüyorsunuz; birini tercih etmek gerekir.

Eğer ilkini tercih edip fonkisyonu void yaparsanız, zaten malloc’lanan kısma erişiminiz, bu fonksiyona gönderdiğiniz matris değişkeni üzerinden olur ve işiniz bittiğinde freelersiniz.

Ama fonksiyona geçirmeyip yalnız döndürmek isterseniz de zaten main’de (veya başka bir yerde) illaki bu fonksiyonu çağırıp döndürdüğü değeri bir değişkene atıyorsunuzdur. Bunu yaptığınız zaman hafızanın o kısmına bu değişkenler vasıtasıyla da erişebiliyorsunuz, dolayısıyla onlar üzerinden free’leyebilirsiniz.

Yani,

// main veya herhangi bir yerde:
...
// Döneni karşıladık, artık bu eleman o kısımdan sorumlu
double** matris_a = matrisyap(x, n);

// Bir takım işlemler
...
...

//Sonra da free'leriz
for (i = 0; i < n; ++i) {
    free(matris_a[i]);
}
free(matris_a);

Bu bilinen ve C’nin uzerine gelen butun dillerin bir sekilde cozmeye calistigi bir sorun:

Fonksiyon calisan bir kaynak dondurmek zorunda, bunu kapatmanin sorumlulugu da kullanana kaliyor.

Cozumleri arasinda kaynagi fonksiyona disaridan paslamak (malloc ve free edildigi seviye ayni olsun) ve C++ var.

Hayir, cunku modern isletim sistemleri bunu zaten yapiyor.


Ama ben zaten alternatif bir veri yapisi onermek istiyorum:

double *

Yine malloc ile dinamik alloke ediliyor lakin satirlara veya sutunlara pointer’lar yerine butun sayilari yanyana tutuyor. [i][j] elemanina ulasmak icin arr[i * M + j] kullaniliyor. Daha buyuk boyutlara da kompleksite artisi olmadan scale edebiliyor: [i][j][k] <=> arr[i*M*N + j*N + k].

Tek malloc, tek free, tek millet,.

Bu arada malloc’un degerini cast etmeyiniz.

1 Beğeni

O hâlde bu alanı temizlemek adına yapmam gereken bir şey yok, çünkü programı kapattığımda boşa çıkacak zaten.

Bunu pek anlayamadım. Kaynağı fonksiyona dışarıdan paslamak ne demek?

Bu bilgi için sağ olun gerektiğinde çok işime yarayacak.

Bunu da anlayamadım malloc’un değeri derken fonksiyonun kendisinden mi yoksa açtığı alanın içindeki değerden mi bahsettiniz? :slight_smile: Gerçi cast etmek terimine pek hakim olmadığım için olayı yanlış yorumlamış da olabilirim.

Hocam bunun sebebi daha doğrusu bu fonksiyonu kullanmamın sebebi her fonksiyonun içinde matris oluşturmak yerine matrisyap fonksiyonunda tek bir matris yapma kodu yazıp bunu matris oluşturmam gereken yerlerde kullanmak. Örneğin;

 void Multiply(double *A, double *B, double *C, int N){
  int i,j,k=0;
  double D[9];
  double** matrisa;
  matrisa= matrisyap(A,matrisa,N);
  double** matrisb;
  matrisb= matrisyap(B,matrisb,N);
   double** matrisd;
  matrisd= matrisyap(D,matrisd,N);
  for(i=0; i<N; i++){
      for(j=0; j<N; j++){            
          for(k=0; k<N; k++){
              matrisd[i][j] += matrisa[i][k] * matrisb[k][j];
  	      }
 	  }
   }
   k=0;
   for(i=0;i<N;i++){
 		for(j=0;j<N;j++){
 		  C[k]= matrisd[i][j];
 	 	  k++;
		}
	}
}

Evet işte aradığım cevap buydu. Her fonksiyonumun döndürdüğü değer, main içindeki boş double C[9]; dizisine yazılıyor. Programın sonuna free(C); ifadesini eklersem burayı boşaltmış olurum o zaman.

@anon18277073 Kodlardaki birkaç mantık hatasının da sebebi şu, Yaptığım şey bir ödev aslında. Birkaç fonksiyon yazmam istenmiş ve bu fonksiyonlar hocanın elindeki main(){....} kodlarıyla kontrol edilecek. Benim main(){....} bunun içindeki kodlara müdahale etme hakkım yok. İstenen şey matris üzerinde işlem yapmam ama matris elemanları A[3][3] yerine A[9] şeklinde veriliyor mainde.
Bu yüzden her seferinde elemanları A[i][j] biçiminde bir matrise aktarmak,
Ardından gerekli işlemleri yapmak ve sonrasında da tekrardan A[i] şeklindeki diziye return etmek durumunda kalıyorum.

Açıklayıcı olması adına programın tamamını aşağıya bırakıyorum göz gezdirmek isterseniz buyrun;

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
double** matrisyap(double* x,double **matris, int n);
void Add(double *A, double *B, double *C, int N);  
void Subtract(double *A, double *B, double *C, int N);
void Multiply(double *A, double *B, double *C, int N);
void Transpose(double *A, double *C, int N);
double Determinant(double *A, int N);
double Inverse(double *A, double *C, int N);
int main(){
 double A[] = {5, 2, 4, 2, 4, 6, 1, 2, 8}; 
 double B[] = {1, 5, 8, 3, 5, 6, 4, 7, 9};
 double C[9];
 double grade  = 100.0;    
 
   /* C = A + B */ 
        Add(A, B, C, 3);
         if (C[0] != 6 || C[1] != 7 || C[2] != 12 ||
		 	 C[3] != 5 || C[4] != 9 || C[5] != 12 ||
			 C[6] != 5 || C[7] != 9 || C[8] != 17) grade -= 7.5;
			 
	/* C = A - B */
		Subtract(A, B, C, 3);
		  if (C[0] != 4 || C[1] != -3 || C[2] != -4 ||
		   	  C[3] != -1 || C[4] != -1 || C[5] != 0 ||
		 	  C[6] != -3 || C[7] !=  -5 || C[8] != -1) grade -= 7.5; 
			 
	/* C = A * B */
	   Multiply(A, B, C, 3);
	      if (C[0] != 27 || C[1] != 63 || C[2] != 88 ||
	    	  C[3] != 38 || C[4] != 72 || C[5] != 94 ||
	      	  C[6] != 39 || C[7] != 71 || C[8] != 92) grade -= 20;
	      	  
	/* C = A' */   
	 	Transpose(A, C, 3);  
		  if (C[0] != 5 || C[1] != 2 || C[2] !=  1 ||   
		 	  C[3] != 2 || C[4] != 4 || C[5] !=  2 ||
			  C[6] != 4 || C[7] != 6 || C[8] !=  8) grade -= 7.5;
 			  
  	/* det(A) */
	  	if (Determinant(A, 3) != 80) grade -= 7.5; 
 
	/* det(B) */
		if (Determinant(B, 3) != -4) grade -= 7.5; 
 
 	/* C = inv(A) */
    	if (Inverse(A, C, 3) == 0) {
       			 if (C[0] != 0.250 || C[1] != -0.100 || C[2] != -0.0500 ||
        		     C[3] != -0.1250 || C[4] != 0.450 || C[5] != -0.2750 ||
         		     C[6] != 0 || C[7] != -0.100 || C[8] != 0.2000) grade -= 15;
        } 
    else grade -= 15;
    
 	/* C = inv(B) */   
	 	if (Inverse(B, C, 3) == 0){
		      if (C[0] != -0.7500 || C[1] != -2.7500 || C[2] != 2.5000 ||
			      C[3] !=  0.7500 || C[4] !=  5.7500 || C[5] != -4.5000 ||
				  C[6] != -0.2500 || C[7] != -3.2500 || C[8] != 2.5000) grade -= 15;
			   }
		else grade -= 15; 
 
    A[0]=A[1]=A[2]=A[3]=A[4]=A[5]=A[6]=A[7]=A[8]=0.0;   if (Inverse(A, C, 3) != -1) grade -= 5; 
 
 
  printf("Notunuz: %.2f\n", grade);
  }
  
  //Okulnabilirlik açısından fonksiyonları aşağıya yazdım.
  
  
//Bu fonksiyonu tek boyutlu dizi olarak verilen matris elemanlarını NxN matris formatına çevirmek için oluşturdum.
 double** matrisyap(double* x,double **matris, int n){
 int i,j,k=0;
 matris=(double**)malloc(sizeof(double*)*n);
 for(i=0;i<n;i++){
 matris[i]=(double*)malloc(sizeof(double)*n);
}
 for(i=0;i<n;i++){
 	for(j=0;j<n;j++){
 	matris[i][j]=x[k];
 	k++;
 		
	 }
 }
 	
	
return matris;
		
}

  /* C = A + B */ 
void Add(double *A, double *B, double *C, int N){
  int i,j,k=0;
  double** matrisa;
  matrisa= matrisyap(A,matrisa,N);
  double** matrisb;
  matrisb= matrisyap(B,matrisb,N);
   for(i=0;i<N;i++){
 		for(j=0;j<N;j++){
 		C[k]= matrisa[i][j]+matrisb[i][j];
 		k++;
		}
 	} 
}

  /* C = A - B */
void Subtract(double *A, double *B, double *C, int N){
  int i,j,k=0;
  double** matrisa;
  matrisa= matrisyap(A,matrisa,N);
  double** matrisb;
  matrisb= matrisyap(B,matrisb,N);
   for(i=0;i<N;i++){
 		for(j=0;j<N;j++){
 		C[k]= matrisa[i][j]-matrisb[i][j];
 		k++;
		}
 	}
 }
 
  /* C = A - B */
 void Multiply(double *A, double *B, double *C, int N){
  int i,j,k=0;
  double D[9];
  double** matrisa;
  matrisa= matrisyap(A,matrisa,N);
  double** matrisb;
  matrisb= matrisyap(B,matrisb,N);
   double** matrisd;
  matrisd= matrisyap(D,matrisd,N);
  for(i=0; i<N; i++){
      for(j=0; j<N; j++){            
          for(k=0; k<N; k++){
              matrisd[i][j] += matrisa[i][k] * matrisb[k][j];
  	      }
 	  }
   }
   k=0;
   for(i=0;i<N;i++){
 		for(j=0;j<N;j++){
 		  C[k]= matrisd[i][j];
 	 	  k++;
		}
	}
}
 
  /* C = A' */ 
void Transpose(double *A, double *C, int N){
	 int i,j,k=0;
	 double** matrisa;
	 matrisa= matrisyap(A,matrisa,N);
  for(i=0;i<N;i++){
  	for(j=0;j<N;j++){
  		C[k]=matrisa[j][i];
  		k++;
	  }
  }
  
  
 }
 
  /* det(A) */
 double Determinant(double *A, int N){   
  int sutun1,sutun2,sutun3;
  double determinant;
  double** matrisa;
  matrisa= matrisyap(A,matrisa,N);
  	if(N==2)
    {
      determinant=(matrisa[0][0]*matrisa[1][1]-matrisa[0][1]*matrisa[1][0]);
      return determinant;
	 }
    if(N==3){
		 sutun1=matrisa[0][0] * ((matrisa[1][1] * matrisa[2][2])  - (matrisa[1][2] * matrisa[2][1]));
 		 sutun2=matrisa[0][1] * ((matrisa[1][0] * matrisa[2][2])  - (matrisa[1][2] * matrisa[2][0]));
 		 sutun3=matrisa[0][2] * ((matrisa[1][0] * matrisa[2][1])  - (matrisa[1][1] * matrisa[2][0]));
 		 determinant=(+sutun1)+ (-sutun2)+ (+sutun3);
  }
  
  return determinant;
}
  
double Inverse(double* A, double* C, int N) {
    int i;
    double determinant;
    double** matrisa;
    matrisa = matrisyap(A, matrisa, N);
    determinant = Determinant(A, 3);
    if (determinant ==0) return -1;
    double tersdeterminant = 1 / determinant;
    C[0] = (matrisa[1][1] * matrisa[2][2] - matrisa[2][1] * matrisa[1][2]) * tersdeterminant;
    C[1] = -(matrisa[0][1] * matrisa[2][2] - matrisa[0][2] * matrisa[2][1]) * tersdeterminant;
    C[2] = (matrisa[0][1] * matrisa[1][2] - matrisa[0][2] * matrisa[1][1]) * tersdeterminant;
    C[3] = -(matrisa[1][0] * matrisa[2][2] - matrisa[1][2] * matrisa[2][0]) * tersdeterminant;
    C[4] = (matrisa[0][0] * matrisa[2][2] - matrisa[0][2] * matrisa[2][0]) * tersdeterminant;
    C[5] = -(matrisa[0][0] * matrisa[1][2] - matrisa[1][0] * matrisa[0][2]) * tersdeterminant;
    C[6] = (matrisa[1][0] * matrisa[2][1] - matrisa[2][0] * matrisa[1][1]) * tersdeterminant;
    C[7] = -(matrisa[0][0] * matrisa[2][1] - matrisa[2][0] * matrisa[0][1]) * tersdeterminant;
    C[8] = (matrisa[0][0] * matrisa[1][1] - matrisa[1][0] * matrisa[0][1]) * tersdeterminant;



    return 0;


}

Suradaki (double**). malloc zaten her pointer’la uyumlu olan void * turunu donduruyor. Bu turu baska herhangi bir ture cast etmek stdlib’in include edilmedigi gibi hatali durumlari maskelemekten baska bir ise yaramiyor.

strdup yerine strncpy kullanmak demek. malloc’u fonksiyon degil cagiran yer yapiyor, fonksiyon gelen pointer’in icini dolduruyor.

Programın akışını anladım hocam, elinize sağlık.

Yok, orada “fonksiyondan” kastım malloc barındıran fonksiyondu, yani matrisyap.

Yani, bu yazdığınız 6 fonksiyonun hepsinde, return etmeden önce, matrisyap fonksiyonuyla elde ettiğiniz double**'ları freelemelisiniz. Çünkü artık onlarla işiniz kalmıyor, hesaplamak istediğiniz şeyi (e.g. transpose, determinant) hesaplamış oluyorsunuz.

Mesela

void Subtract(double *A, double *B, double *C, int N){
    int i, j, k = 0;
    double** matrisa;
    matrisa = matrisyap(A, matrisa, N);

    double** matrisb;
    matrisb = matrisyap(B, matrisb, N);

    for(i = 0; i < N; ++i){
        for(j = 0; j < N; ++j){
            C[k]= matrisa[i][j] - matrisb[i][j];
            ++k;
        }
    }
    // Bu noktada "matrisyap"ın malloc'layarak döndürdüğü pointer'larla
    // işimiz bitti, gerekli hesabı yaptık. matrisa ve matrisb'yi free'liyoruz:
    for (i = 0; i < n; ++i) {
        free(matris_a[i]);
        free(matris_b[i]);
    }
    free(matris_a);
    free(matris_b);
}

Bu arada signature’daki tutarsızlıkla (daha doğrusu fazlalıkla) kast etmeye çalıştığım şey şuydu aslında:

double** matrisb;
matrisb = matrisyap(B, matrisb, N);

Burada matrisyap’ı çağırmadan önce matrisb’yi deklare ediyoruz, sonra matrisyap’a argüman olarak geçiriyoruz. matrisyap zaten onun atamasını gerekli şekilde yapıyor, ama bir de ayriyeten return edip tekrar eşitliyoruz; buna gerek yok demek istemiştim. Yani, ya

double** matrisb;
matrisyap(B, matrisb, N);

şeklinde olur, matrisyap da void olur. Veya,

double** matrisb = matrisyap(B, N);

şeklinde olur; argüman olarak paslamayız, döneni karşılarız. Sizin tercihinize kalmış tabii.

*: Bu arada double** free’leme işlemi altı fonksiyonda da gerekli olduğundan, bu işi yapan küçük bir fonksiyon yazmak isteyebilirsiniz, free_matris gibi.

Dün gece bu free_matris fonksiyonunu oluşturdum her fonksiyonda da kullandım ardından ödevi sisteme upload ettim bile hocam. 3 gündür yardım ediyorsunuz teşekkür ederim.