Bir Kanalı Sabit Multi Dimensional Array C++

Ben Kenobi

Müdavim
Müdavim
Katılım
6 Kasım 2011
Mesajlar
7,338
Reaksiyon puanı
3,156
Puanları
1,358
Bana bir kanalı sabit multi dimensional array mantığını özet geçecek biri var mı ?

Kod:
double(*Değişken)[4] = new double[BaşkaBirDeğişken][4];

misal böyle bir değişken için
Kod:
delete Değişken;
Kod:
delete *Değişken;
kodları arasında ne fark var, sanırım ikincisi doğru olan.

ya da
Kod:
double(*BambaşkaBirDeğişken)[4] = new double[BaşkaBirDeğişken][4];
yaptıktan sonra
Kod:
BambaşkaBirDeğişken= Değişken;
dersek ne olur ?

Son bir soru, yine bir öncekiyle bağlantılı olarak
Kod:
for (int i = 0; i < 3; ++i)
    *BambaşkaBirDeğişken[i] = *Değişken[i];
Şimdi ne olur ?

Bu sorularımdan pointer mantığını tam oturtamadığımı çıkartabilirsiniz, evet doğru çıkarım yaptınız, aslında tek kanalda sıkıntım yok, ama multi kanal ve bir tanesi fixed olan multi kanal olunca tam kavrayamıyorum, anlatacak var mı ?. :D
 

arsenik

Müdavim
Müdavim
Katılım
8 Ağustos 2009
Mesajlar
11,355
Reaksiyon puanı
242
Puanları
243
Ben c++ bilmiyorum ama pointer kavramını c üzerinden öğrenmeye çalışmıştım okuduğum kitapta.

Bir dizinin adı başına * alıp pointer'a dönerse o aynı zamanda dizinin ilk elemanının bellekteki adresine eşittir.

Kod:
double *p;
double balance[10];

p = balance;

Şöyle bir şeyde mesela balance dizisinin ilk elemanının bellekteki adresi p değişkenine atanmıştır.

C++ Pointer to an Array

Kod:
double(*a)[4]

Üstteki gibi bir tanımlama yanlış bilmiyorsam 4 double tipli değişkenin bellek adresini saklayan bir dizi. İçerisinde başka bir dizi bellek adresini tutuyor.

How to interpret complex C/C++ declarations - CodeProject

Ne sormak istediğini açıkçası tam anlamadım. Doğrusu pointerlar hakkında çok iyi bilgim de yok.

Bunları anlamanın en iyi yolu örnekler üstünde çalışmaktır bence.

Altta bir örnek hazırladım. C de çalışıyor.


Kod:
#include <stdio.h>

int main () {

   int  var = 20;   /* ****** variable declaration */
   int  *ip;        /* pointer variable declaration */
 
   int *ip4[4];
 
 
 
   ip = &var;  /* store address of var in pointer variable*/

   printf("Address of var variable: %x\n", &var  );

   /* address stored in pointer variable */
   printf("Address stored in ip variable: %x\n", ip );

   /* access the value using the pointer */
   printf("Value of *ip variable: %d\n", *ip );
 
 
   int a[3][4] = {
   {0, 1, 2, 3} ,   /*  initializers for row indexed by 0 */
   {4, 5, 6, 7} ,   /*  initializers for row indexed by 1 */
   {8, 9, 10, 11}   /*  initializers for row indexed by 2 */ };
 
   int(*ip44)[4] = a;
 
 
 
   for(int i=0;i<3;i++)
   {
       for(int j =0;j<4;j++)
       {
           printf("i [%d],  j %d - *(ip44[i]+j) degeri %d - *ip44[i] %d\n ", i,j,*(ip44[i]+j),ip44[i]);
       }
   }
 
 
 
 


 
 
 
 
 
 
 
 
   return 0;
}




Çıktı

Kod:
Address of var variable: bf9e7a6c
Address stored in ip variable: bf9e7a6c
Value of *ip variable: 20
i [0],  j 0 - *ip44 degeri 0
 i [0],  j 1 - *ip44 degeri 1
 i [0],  j 2 - *ip44 degeri 2
 i [0],  j 3 - *ip44 degeri 3
 i [1],  j 0 - *ip44 degeri 4
 i [1],  j 1 - *ip44 degeri 5
 i [1],  j 2 - *ip44 degeri 6
 i [1],  j 3 - *ip44 degeri 7
 i [2],  j 0 - *ip44 degeri 8
 i [2],  j 1 - *ip44 degeri 9
 i [2],  j 2 - *ip44 degeri 10
 i [2],  j 3 - *ip44 degeri 11


Üstteki örneğe göre şekilli bir şeyler yapıp bize de açıklayabilirsin. :D

* ları kaldır ekle & ekle çıkar vs.

Şu bellek adreslerini de yazdırsam daha iyiydi onu da sen yazdır j arttığında bellek adresi ne kadar artıyor onu da görelim ki daha iyi netleşsin olaylar.

Mesela neden j kadarlık artışta karşılık gelen bellek adresi de j kadarlık artış ile yine uygun verinin adresini alıyor öğrenelim.
 
Son düzenleme:

errno

Doçent
Katılım
17 Temmuz 2016
Mesajlar
694
Reaksiyon puanı
567
Puanları
93
Merhaba,

new : programcı kontrolünde olmak kaydı ile Heap alanında tahsis yapar.
delete : Heap alanında tahsis edilen alanın serbest bırakılmasını sağlar.

Note : int ve float gibi veri tipleri tarafından kullanılan bellek sisteme otomatik olarak geri verilmektedir. Evet bu gibi bir yazım şekline rastlarsanız
şaşırmayınız. İlk olarak Appendix'lerde veya C/C++ standartları kılavuzlarında belirtilip belirtilmediğini lütfen kontrol ediniz.

int* p1 = new int[100];
delete[] p1;
delete p1;

Her iki delete operatörü ile yapılan işlemde geçerlidir ve sisteme ayırdığınız alanı geri vermektedir.

Aşağıda gibi bir yazım doğrudur.
double(*degisken)[4] = new double[baskabirdegisken][4];

Silme işlemi için aşağıdaki delete operatörü ile yapılan işlemlerde geçerlidir.

int const baskabirdegisken = 4;
double(*degisken)[4] = new double[baskabirdegisken][4];
delete degisken;
delete[] degisken;

Breakpoint kullanarak dizinin içerisindeki bilgileri kontrol edip teyit edebilirsiniz. Delete işlemlerinden sonrada dizinin içerisine baktığınızda tahsis edilen bellek alanlarının serbest bırakıldığını da göreceksinizdir.

Ancak aşağıdaki bir yazım şekli sizin sadece göstericinizin gösterdiği alanı boşaltma işlemini yapar. Daha doğrusu rastgele boş bellek alanları atayacaktır. Ama siz buna rağmen göstercinizin gösterdiği alan içerisindeki bilgileri okuyabilirsiniz. Derleyiciniz sizin yerinize otomatik olarak değerler atayacaktır. Bu değerlerin gelme sebebi ise göstericinizi sildiniz ama ona bir ilk değer vermediniz. Dolayısıyla gösterici, istemediğimiz bir yerleri işaret edecektir.

delete *degisken;

Eğer free operatörünü kullanırsanız ise; (ki bu ayrıca bir C konusudur) bir pointeri silemezsiniz. Pointer'in gösteridği bellek alanını, yani daha önce allocate edilen (malloc, calloc ve realloc fonksiyonları ile tahsis edilen) yeri/yerleri serbest bırakmış olursunuz, ya da boş bellek ayırmış olursunuz demek daha doğru olur. (Örnek olarak : NULL ya da 0 (sıfır) atayabilirsiniz.)

Diğer bir yandan göstericilerle ilgili ilginç bulacağınız bir bilgi ise; Buffer kullanılarak ayrılan bellek bölgesi statik olduğundan bunu silmek için delete operatörü kullanılmaz. (konumuz dışı ancak kısa bilgi)

Örnek :
const int buf[512];
char buffer[buf];
double *p1;
p1 = new (buffer) double[3];
...

Diğer bir sorunuza gelince; aşağıdaki yazım size aynı dizi sonuçlarını verecektir. Yani Değişken değerinde ne varsa BambaşkaBirDeğişken
de aynı değerleri alacaktır.

BambaşkaBirDeğişken= Değişken;

Aşağıdaki döngü ise gösterdiğiniz yerdeki aynı tipten olan değişkene, yine gösterdiğiniz aynı tipteki dizinin elemanının atamasını yapar.

for (int i = 0; i < 3; ++i)
*BambaşkaBirDeğişken = *Değişken;

Yani Değişken[0] içindeki elemanı alır BambaşkaBirDeğişken[0] içindeki yere atamasını yapar. (Satır atamalarını yapar, sütun değil)


Eğer aşağıdaki işlemi yapmış olsaydınız; Değişkenden BambaşkaBirDeğişke'ne sütunla birlikte ekleme işlemini yapabilirdiniz.

for (int i = 0; i < 4; i++)
{
for (int k = 0; k < 4; k++){
bambaskabirdegisken[k] = degisken[k];
printf("%f ", bambaskabirdegisken[k]);
}
}


C dilinden bahsetmişken örnek olarak biraz bahsedelim. Göstericileri bildiğinizi sayıyorum ve Göstericileri gösteren göstericilere
örnek vermek istiyorum.

char **ptr;

- ptr bir göstericiyi gösteren göstericidir.
- ptr'nin gösterdiği yerde bulunan nesne yani p*, karakter türünden bir göstericidir.
- **ptr karakter türünden bir nesnedir.

ptr'ye güvenli/geçerli bir adres ataması için :
p=(char **) malloc(sizeof(char *));

Fonksiyon gösteren göstericiler :
<geri dönüş değerinin türü>(* gösterici ismi)([parametre türleri]);

long (*p1) (void);
p1 göstericisinin içerisine geri dönüş değeri long ve parametresi void olan bir fonksiyon adresi konur.

long (*p2) (int,int);
p2 göstericisinin içerisine geri dönüş değeri long ve parametreleri int tiplerinde iki adet parametre ile bir fonksiyon adresi konur.

Ornek :
void func(void)
{printf("Selam");}

void (*p) (void);
p=func;

NOT : Eğer yanlışlık varsa lütfen bilgilendiriniz.

Saygılarımla.

--- Gönderi Güncellendi ---
Merhaba,

aşağıdai kodlar doğrudur. Düzenleme yapmama rağmen editör kayıt yapmıyor.

for (int i = 0; i < 4; i++)
{
for (int k = 0; k < 4; k++){
bambaskabirdegisken[k] = degisken[k];
printf("%f ", bambaskabirdegisken[k]);
}
}

Hatta yine yapmıyor.. Neyse k'nın sol tarafında köşeli parantez ile i'de olması gerekiyor. Editörü doğru kullanamıyorum sanırım.
 
Son düzenleme:

Ben Kenobi

Müdavim
Müdavim
Katılım
6 Kasım 2011
Mesajlar
7,338
Reaksiyon puanı
3,156
Puanları
1,358
@arsenik teşekkürler.
sorunuzu cevaplayayım, bellekteki artış miktarı compiler tarafından pointer'a ait tipin bellekte kapladığı miktar ile çarpılarak hesaplanır.
yani misal j 1 iken 2 olduğunda compiler bu artan değeri yani 2 - 1 değerini int(*ip44)[4] belirtildiği üzere int tipinin bellek büyüklüğü olan 32 bit yani 4 byte ile çarparak bellek adresini hesaplar.


@errno teşekkürler.
heap ve stack kavramlarını biliyorum.
bellekte yer ayırma ve silme kavramlarını da biliyorum.
ancak dinamik olarak ayrılmış multi dimension veya tek kanalı sabit multi dimension tipleri nasıl silebiliriz, bilmiyorum.

double(*Değişken)[4] = new double[BaşkaBirDeğişken][4];
şeklinde ayırdığım kod için
delete Değişken;
yazdığımda ReSharper uyarı vermekte.
delete *Değişken;
yazdığımda ReSharper uyarı vermiyor.

free, malloc gibi kavramlar C'nin konusu, onlarla şu an için işim yok.
statik ayrılan arraylerin silinmesine gerek yoktur, bunu da biliyorum, sadece new sözcüğü ile oluşturulanlarda silinme gerekir, bunu da biliyorum.
ama misal dinamik ayrılmış veya tek kanalı statik multi dimension arrayler nasıl silinir bilmiyorum.
ayrıca şöyle birşey mümkün mü onu da bilmiyorum.
double[4](*Değişken) = new double[4][BaşkaBirDeğişken];
eğer mümkünse yani ilk kanal statik ikincisi dinamikse nasıl silinir, onu da bilmiyorum.

bazı şeyleri daha iyi anlamama yardımcı oldunuz, tekrar teşekkürler.
 

errno

Doçent
Katılım
17 Temmuz 2016
Mesajlar
694
Reaksiyon puanı
567
Puanları
93
Merhaba,

Yukarıdaki kodlar Windows 10 Pro, Visual Studio 2013 Pro ile test edilmiştir. Ancak ReSharper ile nasıl bir sonuç vereceğini bilemiyorum.

Ben Kenobi yukarıdaki yazımda "sizinde bildiğiniz gibi" diyerek başlayacaktım ancak saatin verdiği dalgınlığıma verin lütfen. Daha önce ReSharper hiç kullanmadım. Ancak derleyici ayarlarından olma ihtimali var mı onu bilmiyorum. Bazı derleyicileri sanırım optimize etmeniz gerekiyor olabilir bazı kullanımlar için.

Saygılarımla.
 

Ben Kenobi

Müdavim
Müdavim
Katılım
6 Kasım 2011
Mesajlar
7,338
Reaksiyon puanı
3,156
Puanları
1,358
Merhaba,

Yukarıdaki kodlar Windows 10 Pro, Visual Studio 2013 Pro ile test edilmiştir. Ancak ReSharper ile nasıl bir sonuç vereceğini bilemiyorum.

Ben Kenobi yukarıdaki yazımda "sizinde bildiğiniz gibi" diyerek başlayacaktım ancak saatin verdiği dalgınlığıma verin lütfen. Daha önce ReSharper hiç kullanmadım. Ancak derleyici ayarlarından olma ihtimali var mı onu bilmiyorum. Bazı derleyicileri sanırım optimize etmeniz gerekiyor olabilir bazı kullanımlar için.

Saygılarımla.

Bu arada bilmediklerimi öğrendim sanırım, sizinle paylaşayım.
Dinamik ve statik kanalları olan multi arraylerde dinamikler başa, statikler sona gelmeliymiş.
Yani böyle birşey mümkün değil.
double[4](*Değişken) = new double[4][BaşkaBirDeğişken];
Ama tam tersi mümkün.
double(*Değişken)[4] = new double[BaşkaBirDeğişken][4];

C'de nasıl bilmiyorum ama C++'da new kelimesi kullanılırken [] kullanıldıysa silerken
delete[] Değişken
kullanılmadıysa
delete Değişken
demek gerekiyormuş.
delete[] Değişken yaptıktan sonra ReSharper uyarı vermedi.
Sizin de belirttiğiniz gibi delete *değişken ifadesi yanlış.

Zaten ikisi de dinamik olan multi arrayler üretilirken de silinirken de for döngüsü kullanılıyor.

Bunları dün araştırma ile bulamadım ancak bugün buldum, sihirli kelime fixed yani Google'da "C++ multi dimensional array one dimension fixed" şeklinde aratırsanız uygun sonuçlar çıkabiliyor.

Herşey daha iyi oturdu yerli yerine, tekrar teşekkürler.
 
Üst