Forum: Diğer Konular RSS
C kodlama standardı
Sayfa:  önceki  1  2  3  sonraki 
Avatar
Salih Dinçer #16
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj ID 7499
erdem:
#include <stdio.h>
 
int main()
{
    int dizimiz [4][5] = { {0, 1, 2, 3, 4},
                           {5, 6, 7, 8, 9},
                           {0, 1, 2, 3, 4},
                           {5, 6, 7, 8, 9} };
 
    int (* dizi) [5] = dizimiz;
 
    int satir, sutun;
    for (satir = 0; satir < 4; ++satir) {
        for (sutun = 0; sutun < 5; ++sutun) {
            printf("%d", * (* (dizi + satir) + sutun));
        }
        printf("\n");
    }
}

Peki benek sayısı artmaya başlayınca da mı ayırarak kullanalım. Örneğin
    int ( * dizi) [5] = dizimiz;
ya da
            printf("%d", * ( * (dizi + satir) + sutun));
bu şekilde. Dikkat ederseniz burada boşlukları bir arttırdım. Sonra (* dizi) ile [5], dizimizdeki [4] ve [5] gibi bitişik mi olsun.

Ne yapmak istediğini anlamak için kodu, şu şekilde D'ye çevirdim:
void main() {
    int[][] dizimiz = [ [0, 1, 2, 3, 4],
                        [5, 6, 7, 8, 9],
                        [0, 1, 2, 3, 4],
                        [5, 6, 7, 8, 9] ];
 
    int[]*[] dizi  = [ &dizimiz[0],
                       &dizimiz[1],
                       &dizimiz[2],
                       &dizimiz[3] ];
 
    for(int satir = 0; satir < 4; ++satir) {
        for(int sutun = 0; sutun < 5; ++sutun) {
            printf("%d", *(dizi[satir].ptr + sutun));
        }
        printf("\n");
    }
}
Elbette bunu dilimlerle de yapabilirdik ama madem işaretçi aritmetiği yapacağız öyleyse başka şey karıştırmamalıydık...:)

Verilerinin tanımlandığı ve döngünün kurulduğu üst bölümü yok farz edip asıl satıra odaklanırsak birebir D karşılığı şu olsa gerek:

            printf("%d", *(dizi[satir].ptr + sutun));

Elbette dizi[satir] şeklinde kullanmış olmam da bir fark ama burada .ptr sayesinde bir yıldızdan kurtulmuş olmamız önemli bir fark. Peki aritmetik yapmayıp biraz cimnastik yaparsak başka farklı ne yapabiliriz? Önce .ptr'yi kaldıralım:

            printf("%d", (*dizi[satir])[sutun]);

Şimdi de yıldızı kaldırıp .ptr'yi koyalım:

            printf("%d", dizi[satir].ptr[sutun]);

Hoş değil mi...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #17
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
erdem:
Sonra (* dizi) ile [5], dizimizdeki [4] ve [5] gibi bitişik mi olsun.
Soruyu ihmal etmişim, kusura bakma...

Bence parantez olmasın çünkü o kafa karıştırıyor. Şöyle bana daha güzel görünüyor:
    int* dizi[4]; // veya int *dizi[4]; ve hatta int * dizi[4]; 
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #18
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Benim alıştıklarım da şöyle:

    int dizimiz[4][5] = /* ... */;
 
    int (*dizi)[5] = dizimiz;
 
    printf("%d", *(*(dizi + satir) + sutun));

Ali
Avatar
Salih Dinçer #19
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Çok ilginç sonuçlar elde ettim!

Erdem, aslında diziyi temsil eden bir işaretçi tanımlamak istemiş ki o yüzden boyutunu 4 değil 5 yapmış! Ben ise her satırı işaret eden 4 işaretçi tanımlamıştım. Bu durumda D'de şöyle yapmalıydık:
int * dizi = dizimiz[3].ptr;
Peki neden 3?

Cevabı çok ilginç, biraz da D'deki bellek yerleşimi ve işaretçi aritmetiği ile ilgili. Eğer yukarıdaki gibi dizinin son satırını işaret ederseniz döngü içinde odaklandığımız satırın şu şekilde olması gerekiyor:
printf("%d, ", *( dizi + sutun + satir * 8 ) );
Çünkü veriler belleğe ters işleniyor. Sanırım Ali hocam, D.ershane'deki bir dersde, D'de değişkenlerin aşağıdan yukarıya doğru tanımlandığını o yüzden main() dışındaki işlevlerin herhangi bir yerde (yani C'deki gibi değil!) olabileceğini yazmıştı. İşte bu yüzden yukarıdaki satırın çıktısı ne yazık (belki de bir gün işimize de yarar?) ki ters olmakta:
5, 6, 7, 8, 9,
0, 1, 2, 3, 4,
1, 3, 5, 7, 9,
0, 1, 2, 3, 4,

Not: 2. satırı "1, 3, 5, 7, 9," ile değiştirmiştim...

Peki, şimdi işaret eden değişkenimiz (dizi), dizimiz'in başını (dizimiz[0].ptr) gösterirse n'olur? İşte o zaman işler karışıyor ve çıkarma işlemi yapmamız gerekiyor. Çıktının istediğimiz şekilde düz olması için satır şu:
printf("%d, ", *( dizi + sutun - satir * 8 ) );
Şimdi soruyorum...

Peki neden 8?

Tamam, bu bir bayt'ın içerdiği 8 bit demek olabilir. Belki derleyicinin 32 bit olmasından da kaynaklanabilir. Ama dikkat 32 bit'de size_t.sizeof = 4'dür. Bu 2x demek ama hala 8'in nereden geldiğini anlamış değilim...:)

acehreli:
Benim alıştıklarım da şöyle:
    :    :    :
    int (*dizi)[5] = dizimiz;
    :    :    :
Hocam, neden parantez kullanıyorsunuz?
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #20
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
Bu durumda D'de şöyle yapmalıydık:
int * dizi = dizimiz[3].ptr;
Peki neden 3?

dizi, dizimiz[3] diliminin ilk elemanını gösteriyor. Ondan başka bir şey değil. O göstergeyi ancak dizimiz[3]'ün elemanları üzerinde gezinmek için kullanabilirsin. Aritmetik işlemler o göstergeyi o elemanların dışında bir yeri gösterecek biçimde değiştiremezler. Yoksa C ve C++'ta da olduğu gibi, tanımsız davranıştır.

O yüzden buradaki sonuçlara bakarak bir anlam çıkartamayız.

Cevabı çok ilginç, biraz da D'deki bellek yerleşimi ve işaretçi aritmetiği ile ilgili.

Daha doğrusu, D runtime'ın bu sürümündeki çalışması ile ilgili. Hatta dilimleri uzunlukları değiştiğinde arka planda işleyen pool allocator'ın davranışına göre bile farklı olabilir.

Çünkü veriler belleğe ters işleniyor. Sanırım Ali hocam, D.ershane'deki bir dersde, D'de değişkenlerin aşağıdan yukarıya doğru tanımlandığını o yüzden main() dışındaki işlevlerin herhangi bir yerde (yani C'deki gibi değil!) olabileceğini yazmıştı.

Sanki yerel değişkelerin program yığıtındaki yerleşimleriyle ilgili gibia ama  kulağa hiç doğru gelmiyor. Tam yerini bulabilirsen düzeltmek isterim.

    :    :    :
    int (*dizi)[5] = dizimiz;
    :    :    :
Hocam, neden parantez kullanıyorsunuz?

Parantez olmadığı zaman "int göstergesi dizisi" olur; o dizide beş eleman varmış. Parantez olursa "beş adet int dizisinin göstergesi" olur.

Ali
Avatar
Salih Dinçer #21
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Hmm anladım, peki o satırın eşdeğeri şu olabilir mi? Çünkü aynı sonucu veriyor...
"C KODU":
int * dizi[4];
 
      dizi[0] = dizimiz[0];
      dizi[1] = dizimiz[1];
      dizi[2] = dizimiz[2];
      dizi[3] = dizimiz[3];
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #22
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Şimdi C kodu üzerinde konuşuyoruz, değil mi?

    int dizimiz [4][5] = { {0, 1, 2, 3, 4},
                           {5, 6, 7, 8, 9},
                           {0, 1, 2, 3, 4},
                           {5, 6, 7, 8, 9} };
 
    int (* dizi) [5] = dizimiz;
 
// ...
 
        * (* (dizi + satir) + sutun)

dizimiz'in türü: Her birisi 5 int'lik 4 diziden oluşan dizi.

dizi'nin türü: 5 int'lik dizi göstergesi.

dizi+satir: dizi'nin satir kadar sonrasındaki dizi. Örneğin dizi+1 {5, 6, 7, 8, 9} dizisini gösterir.

*(dizi+satir): dizi+satir göstergesinin gösterdiği dizi. Örneğin {5, 6, 7, 8, 9} dizisinin kendisi.

*(dizi+satir)+sutun: Derleyici düşünür: Bir diziye bir tamsayı ekleniyor. Garip. Anlaşılan diziyi bir gösterge gibi kullanmak istiyorlar. O zaman şu kuralı uygulayayım: Dizinin kendisi yerine, ilk elemanı gösteren gösterge olarak davranayım. Örneğin sutun==2 olduğunda *(dizi+satir)+sutun, 7 değerli int'i gösteren bir göstergedir.

*(*(dizi+satir)+sutun): Yukarıdaki göstergenin gösterdiği int. Yani örneğin 7 değerli eleman.

Senin son gösterdiğin kod da aynı sonucu verir ama bir farkla: Yukarıda derleyicinin garip bularak yardımcı olduğu kural sen diziyi ilklerken uygulanır:

Salih Dinçer:
Hmm anladım, peki o satırın eşdeğeri şu olabilir mi? Çünkü aynı sonucu veriyor...
"C KODU":
int * dizi[4];
 
      dizi[0] = dizimiz[0];
      dizi[1] = dizimiz[1];
      dizi[2] = dizimiz[2];
      dizi[3] = dizimiz[3];

dizi[0] bir int göstergesi. Ona dizimiz[0] diye bir dizi eşitlemeye çalışıyoruz. Türleri aynı değil. O zaman derleyici "diziyi ilk elemanını gösteren gösterge" olarak kullanıyor ve dizi[0]'a dizimiz[0]'ın ilk elemanının adresini atıyor. Yukarıdaki incelemeyi onun için de yapabiliriz:

dizi+satir: dizi bir dizi olduğu halde ona bir gösterge gibi davranılıyor. O zaman dizi, ilk elemanının adresi yerine geçecek. İlk elemanı bir int* olduğuna göre ilk elemanının adresi int**'dir. Örneğin dizi+1 {5, 6, 7, 8, 9} dizisinin ilk elemanını gösteren göstergedir. (Hocam bunlar çok karışık konular. :))

*(dizi+satir): dizi+satir göstergesinin göstergesinin gösterdiğidir. Yani {5, 6, 7, 8, 9} dizisinin ilk elemanı gösterilmektedir.

*(dizi+satir)+sutun: {5, 6, 7, 8, 9} dizisinin sutun'uncu elemanı gösterilmektedir.

*(*(dizi+satir)+sutun): Yukarıdaki göstergenin gösterdiği int'tir. Yani 7.

Umarım doğrudur. Bunları biraz olsun printf ile yazdırmaya çalışarak anlayabiliyoruz:

            printf("%d", dizi);

Hata mesajı bize dizi'nin türünü söylüyor:

error: format ‘%d’ expects type ‘int’, but argument 2 has type ‘int **’

Ali
erdem (Moderatör) #23
Üye Tem 2009 tarihinden beri · 978 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #19
Aslında buradaki çift benekli göstergelerin dizilerle nasıl kullanılacağını daha önce Ali bey Yahoo Cdili grubunda anlatmıştı. Ben de ordan öğrendim.

http://tech.groups.yahoo.com/group/cdili/message/1647

Hatta  "Aslında insan bunun nedenini tam anlamadan da hayatını sürdürebilir" yazmış :)

Salih Dinçer:
Hocam, neden parantez kullanıyorsunuz?

Parantez kullanmazsak int göstergelerden oluşan bir dizi olmuş oluyor.

    int * dizi[8]// 8 tane int göstergesinden oluşan bir dizi
    int (*dizi)[8]; // 8 tane tamsayıdan oluşan bir dizi için gösterge 

Bu konuda Ali bey de zaten açıklama yazmış. Ama linux altında cdecl aracını da kullanabilirsin.

$ cdecl
Type `help' or `?' for help
cdecl> explain int* dizi[8]
declare dizi as array 8 of pointer to int
cdecl> explain int (*dizi)[8]
declare dizi as pointer to array 8 of int

Bunu yapabilmemizin nedeni sayilar[2] aslında *(sayilar + 2) demek.

#include <stdio.h>
 
int main()
{
    int sayilar[5] = {10, 20, 30, 40, 50};
    int * ptr;
    ptr = sayilar;
 
    printf("%d", sayilar[2]);
    printf("%d", ptr[2]); // göstergeyi dizi gibi kullanıyorum
 
    printf("%d", *(sayilar + 2));
    printf("%d", *(ptr + 2)); // sayilar[2] demekle aynı şey
}
Bu mesaj erdem tarafından değiştirildi; zaman: 2012-08-28, 11:30.
Avatar
Salih Dinçer #24
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #22
acehreli:
Şimdi C kodu üzerinde konuşuyoruz, değil mi?
Eğer bu iletime cevap yazıyorsan orada .ptr'li örnekler verdiğim için D kodu.

Bu arada analizler için teşekkürler, tek tek deneyerek inceleyeceğim...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #25
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #23
erdem:
Bu konuda Ali bey de zaten açıklama yazmış. Ama linux altında cdecl aracını da kullanabilirsin.
Teşekkürler, bundan haberim yoktu ve görünüşe göre bilgisayarımda da yokmuş! N'aptım yükledim tabi...:)
İndirilmesi gereken dosya boyutu 26,6 kB
Bu işlemden sonra 106 kB ek disk alanı kullanılacak.
Alınıyor:1 http://es.archive.trisquel.info/trisquel/ dagda/main cdecl i386 2.5-11 [26,6 kB]
0sn'de 26,6 kB alındı (59,4 kB/s)
Önceden seçilmeyen cdecl paketi seçiliyor.
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #26
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #24
Salih Dinçer:
acehreli:
Şimdi C kodu üzerinde konuşuyoruz, değil mi?

Hayır, "C KODU" başlıklı kod için sormuştum ama zaten C demişsin. :)

Bu arada analizler için teşekkürler, tek tek deneyerek inceleyeceğim...

Umarım doğrudur. :)

Ali
Avatar
Salih Dinçer #27
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Evraka!

8 sayısının (sanırım) sebebini geçmişteki bir tartışmada buldum:

acehreli on 2012-03-15, 13:21:
Salih Dinçer:
Sizeof'u kullanma sebebim ise veri türünün daha büyük değişkenlerde olması durumunda

Dilimin eleman türünden bahsediyorsun o zaman. Ama veri.sizeof dediğin zaman dilim denen referans nesnesinin büyüklüğünü alıyorsun. O her zaman için bir gösterge ve bir uzunluk üyesinden oluşur. Yani her dilim 32 bitlik sistemlerde 8 bayt, 64 bitlik sistemlerde de 16 bayt olur.
Bu arada, şu aşağıda paylaştığım D denemesinden anladığım kadarıyla da dizideki veriler, belleğe kod içinde yazdığımız sırada değil tersi şeklinde yerleştiriliyor. Ayrıca her satır arasında 16 bayt fark var. Bunun 4'ü verinin kendisi olmalı çünkü her veri 32 bitlik int değeri ve zaten bunu sütunlar arasındaki farktan (4 bayt) anlıyoruz. Tabi arta kalan boşluğu (8 + 4 bayt) bakkal hesabıyla çözemediğimi itiraf etmeliyim...:)
import std.stdio;
 
void main(){
  int[][] dizi = [ [-1, -3, -5, -7, -9], // Negatif tek sayılar kümesinin başı
                   [ 13579], // Pozitif tek sayılar kümesinin başı
                   [ 02468]  // Pozitif çift sayılar kümesinin başı
                 ];
 
  int sınır = dizi[0].length;
  int sonSatır = dizi.length - 1;
  int sonSınır = sonSatır * 8 + sınır;
 
  for(int adres = 0; adres < sonSınır; adres++)
  {
    if(adres < sınır)
    {
      //writef("%d\t", *(dizi[sonSatır].ptr + adres) );/*
      writef("%X\t", (dizi[sonSatır].ptr + adres) );//*/
    }
    else
    {
      adres += 2;
      sınır += 8;
      writeln;
    }
  }
  writeln;
}
Hadi, 8 bayt aradaki 'referans nesnesi'nin büyüklüğü; peki geriye kalan 4 bayt ne ola ki?

Dip Not: Belki de bu kodun aynısını C'de denemeli. Orada da benzer bir boşluk var mı? Ama şimdi çıkmalıyım...

Teşekkürler...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #28
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
C kodunu da denedim ve D'nin bakış açısı çok çok farklı olduğunu gördüm. Çünkü C'de alıştığımız sırada ve peş peşe veriler belleğe yerleşiyor. İşte bu yüzden tek döngü ile bir çift boyutlu diziye işaretçi aritmetiği ile erişilebilirmiş:
#include <stdio.h>
 
int main() {
    int dizimiz [3][5] = { {-1, -3, -5, -7, -9 }, // Negatif tek sayılar kümesinin başı
                           { 13579 }, // Pozitif tek sayılar kümesinin başı
                           { 02468 }  // Pozitif çift sayılar kümesinin başı
                         };
    int i;
    for(i = 0; i < sizeof(dizimiz) / sizeof(int); i++) {
        printf("%d\t", *(&dizimiz[0][0] + i));
        if((i+1) % 5 == 0) printf("\n"); // Her 5 elamandan sonra satır başı yap
    }
 
    return 0;
}
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #29
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
C'de dizi diye ayrıca bir tür olmadığı için öyle oluyor. D'de C dizilerine en yakın olan şey statik dizilerdir (uzunluğu derleme zamanında bilinen).

Burada bir şey daha anlıyoruz: D'de dizi içine dizi yerleştirdiğimizi sanıyoruz ama aslında içtekiler dilim. Dilimlerin de dizi kavramıyla tek yakınlıkları, D çalışma ortamının (D runtime) bizim için yönettiği elemanlara erişim sağlamak.

Salih, gördüğün 16 bayt herhalde hizalama (alignment) ile ilgilidir. Şurada "Türlerin .alignof niteliği" başlığında var:

  http://ddili.org/ders/d/bellek_yonetimi.html

Belki 64 veya 32 bit derleme arasında fark görebilirsin.

Ali
acehreli (Moderatör) #30
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Şimdi biraz daha düşündüm: Benim sistemimde 16 bayt tutmasının nedeni, dilimlerin iki üyesinin de 8 bayt olmasından geliyor: size_t türünde uzunluk ve eleman göstergesi.

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Sayfa:  önceki  1  2  3  sonraki 
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-18, 07:51:04 (UTC -08:00)