Categories: C

C Programlama Dersi – 6

Selam,

Uzun bir aradan sonra eğitimime kaldığım yerden devam ediyorum. Artık daha kısa ve öz olarak devam etmeye çalışacağım. Bunun için c4learn.com üzerindeki dersleri anladığım kadar Türkçeleştirip, biraz düzenleyerek aktarmaya çalışacağım. c4learn üzerindeki konu anlatımları kısa, öz ve gayet anlaşılır çünkü.

Lafı uzatmadan hemen bugünkü konumu açıklıyorum:

  • Diziler
    • Tek boyutlu diziler
    • Çok boyutlu diziler

Dizi Nedir?

Aynı tipten verileri tutan bir koleksiyon olarak düşünebiliriz.

Değişkenler sayesinde verileri tutabiliyorum lakin bir değişkende  bir veri tutabilirim. Çok sayıda veri tutmam gerektiğinde tek tek değişken mi tanımlamam gerekecek? Mesela 100 öğrenci için sıra numarası tanımlamamız gerektiğini varsayalım. Bunun için siraNo1, siraNo2, siraNo3siraNo100 şeklinde 100 tane değişken tanımlayabiliriz. Ama bu hem zaman hem performans kaybı olur. Yani hiç ekonomik değil ve “amele!” diye yükselen çığlıklar duyabilirsiniz.

Bunun yerine bir dizi tanımlayarak, bellekten kendimize 100 blokluk “contiguous memory”  olarak bir yer tahsis ederiz ve bu 100 numaraya tek bir değişken adıyla ulaşabiliriz.

Contiguous Memory Nedir?

Nam-ı diğer olarak continuous memory (ardışık hafıza) olarakta biliniyormuş. Özet geçmek gerekirse, bir işlem için bellekten 1000-1200 arası adresleri kendimiz için ayırttığımızı düşünelim. Bu durumda 200 blok bizim için ardışık olarak ayrılmış olacak. Tıpkı az sonra yapacağımız dizi tanımlama ya da alloc() / malloc() fonksiyonları kullanmak gibi.

Tek Boyutlu Diziler

Dizi Tanımlama

//<veriTipi> <diziAdi> [diziBoyutu];
int siraNo[100];

Yukarıda siraNo isimli int tipinde 100 boyutlu bir dizi tanımladık. Yani bellekte bizim için yan yana dizilmiş 100 tane bloğun ya da bellek hücresinin rezerve edildiğini söylebiliriz.

Dizi Elemanlarına Veri Atama

Dizimiz hazır olduğuna göre öğrenci numaralarını girmeye başlayabiliriz. Yanlış önce bilmemiz gereken bir ufak nokta var.

Resimde, dizimize 5 adet öğrenci numarası girilmiş. Ve dikkat ederseniz ilk elemanın konumu yani indisi 0. C dilinde dizilerin indisleri 0 dan başlayarak ilerler. Yani 100 elemanlı bir dizinin ilk elemanı 0. indistedir. 100. eleman ise 99. indistedir. E o zaman 41. eleman da 40. indistedir.

İlk elemanın 0.indisten başladığını öğrendiğimize göre dizimize nasıl veri gireceğimizi görelim:

siraNo[0] = 4;
siraNo[1] = 5;
siraNo[2] = 33;
siraNo[3] = 13;
siraNo[4] = 1;

4, 5, 33, 13, 1 bizim verilerimiz yani öğrencilerin sıra numarası. 0,1,2,3,4 ise dizinin indisi yani elemanların dizideki konumu.

Bu ayrıca şu demektir: indis numaralarıyla dizi elemanlarımıza rahatlıkla ulaşabiliriz.

100 elemanlı bir dizi tanımladım ama 5 eleman girip bırakırsam geriye kalan 95 blok içinde ne saklayacak? Tabii ki ben ne istersem onu saklamayacak. Ne saklayacağı ise tamamen sizin kısmetinize kalmış. Daha önce o hücrede saklanan bir başka değeri ya da saçma bir sayı da görebilirsiniz.

Dizilere Başlangıç Değeri Atama

Az önce siraNo dizisini tanımlayıp daha sonra elemanları girdim. Bunun yerine diziyi tanımlarken de elemanlarını belirtebilirim:

int siraNo[7] = {10, 71, 5, 54, 14, 53, 13};

Ya da dolaylı yoldan da dizi uzunluğunu belirtebilirdim:

int siraNo[] = {10, 71, 5, 54, 14, 53, 13};

Yukarıda dizi elemanlarını belirtmedim ama derleyici kodlar derlenmeye başladığı zaman dizideki elemanları benim için sayıyor ve buna göre dizi uzunluğunu belirliyor. Bu türden başlangıç atamalarına “Compile Time Initialization” yani “derleme zamanı atama” deniliyor. “derleme zamanı atama” kısmı ne kadar doğru bilmiyorum çünkü “Initialization” için tam olarak Türkçe karşılık bulamadım. Initialization Türkçe’ye “başlangıç, başlama” olarak çevriliyor ama yazılım için “ilk değer ataması” olarak çevirebiliriz sanırım.

int siraNo[12] = {0};

Bir önceki başlıkta bahsettiğim, dizi uzunluğu kadar veri girmezsek rastgele verilerin elemanlara atanmasını istemiyorsak, yukarıdaki şekildeki gibi bir atama yapabiliriz. Bu şekilde dizinin tüm elemanları 0 olarak belirlenecektir.

Dizileri Yazdırma

Dizideki elemanlara indis numarasıyla ulaştığımıza göre indis numarasına göre dizideki elemanları yazdırabilirim.

int siraNo[] = {10, 71, 5, 54, 14, 53, 13};
    
    printf("%dn", siraNo[0]);
    printf("%dn", siraNo[3]);
    printf("%dn", siraNo[6]);
    printf("%dn", siraNo[50]); //dizide olmayan indis

Çıktı:

10
54
13
-2144480248

Şimdi basit bir örnek ile buraya kadar olan kısımları pekiştirelim. Amacımız kullanıcıdan 5 tane tam sayı almak ve bunların toplamını ve ortalamasını hesaplamak.

int sayilar[5];
    int sayac, toplam = 0;
    float ortalama = 0;
    puts("5 adet tam sayı giriniz:");
    
    for(sayac=0; sayac<5; sayac++) {
        printf("%d.sayi: ", sayac+1);
        scanf("%d", &sayilar[sayac]);
        toplam += sayilar[sayac];
    }
    ortalama = (float)toplam/5;
    printf("Toplam: %d ve ortalama: %.2f", toplam, ortalama);

 Çok Boyutlu Diziler

Bildiğimiz matrisler bunlar. Tek boyutlu diziyi tek satırlık bir tablo gibi düşünebiliriz. Çok boyutlu diziler ise birden fazla satır ve sütundan meydana gelirler. Genellikle 2 boyutlu diziler kullanılır. Oyun yapımlarında ise 3 boyutlu diziler kullanılabilir. x, y, z koordinatlarını tutmak için mesela.

Şimdilik 2 boyutlu dizilerle yetinmeye bakıyorum. Öncelikle 2 boyutlu dizi nasıl tanımlanırmış görelim:

//<veriTipi> <diziAdi> [satir][sütun]
int sayilar[3][2];

Yukarıda 3 satır ve 2 sütundan oluşan bir matris yani 2 boyutlu dizi tanımlamış olduk. Daha net olması için şu şekilde de tanımlayabilirim:

int sayilar[3][2] = {
                 { 1 , 4 },   
                 { 5 , 2 },  
                 { 6 , 5 }   
                };

Doğal olarak tek boyutlu dizide geçerli olan kurallar çift boyutlu diziler için de geçerli. Satır ve sütun indislerinin 0 dan başlaması gibi.

Çift Boyutlu Dizilerin Yazdırılması

int a[3][3] = { 1,2,3,
                5,6,7,
                8,9,0 };
    
    int satirSayac, sutunSayac;
    for(satirSayac = 0; satirSayac<3; satirSayac++) {
        for(sutunSayac =0; sutunSayac<3; sutunSayac++) {
            printf("%d ", a[satirSayac][sutunSayac]);
        }
        printf("n");
    }

Yukarıda çift boyutlu dizi tanımlamanın farklı bir şeklini de görmüş olduk. Şimdi gelelim kodumuzun ne yaptığına. İlk for döngümüz dizimizdeki yani a matrisindeki satır sayısı kadar çalışacak. İçteki for döngüsü ise bulunduğu satırdaki sütunları yazdıracak.

  1. satirSayac = 0 olarak döngümüz başladı.
  2. içteki for döngüsüne geçtik ve sutunSayac = 0 olarak döngümüz başladı.
  3. printf() ile a[0][0] indisini yazdırıyoruz ve sonuna bir boşluk bırakıyoruz. Yani 1.satır 1.sütun => “1 “
  4. sutunSayac = 1 oldu ve içteki for döngüsüne devam ediyoruz.
  5. tekrar printf() ile bu sefer a[0][1] indisini yazdırıyoruz. Yani 1.satır 2.sütun => “2 “
  6. sutunSayac = 2 oldu ve içteki for döngüsü son kez çalışıyor.
  7. a[0][2] değerini ekrana yazdırıyoruz ve içteki for döngüsünden çıkıyoruz. => “3 “
  8. İçteki for döngüsünden çıktıktan sonra 10. satırdaki printf() ile bir satır aşağıya geçiyoruz.
  9. satirSayac = 1 olarak tekrar başlıyor ve aynı adımları tekrar uyguluyor.

Dizilerin Bellekteki Adresini Göstermek

Yazının başında bir dizi oluştuğunda ramde bizim için belirli bir bloğun tahsis edildiğini öğrenmiştim. Şimdi bunu canlı olarak görelim.

int tekBoyutluDizi[5] = {11, 22, 33, 44, 55};
    int i,j;
    for(i=0; i <5; i++) {
        printf("a[%d]: %d ve bellekteki adresi: %u n", i, tekBoyutluDizi[i], &tekBoyutluDizi[i]);
    }
    
    int matris[3][4] = {
                            {11, 22, 33, 44},
                            {55, 66, 77, 88},
                            {99, 14, 53, 13}  
                        };
    
    printf("n Çift Boyutlu Dizi nn");
    for(i=0; i<3; i++) {
        for(j=0; j<4; j++) {
            printf("[%d][%d]: %d <%u> ", i, j, matris[i][j], &matris[i][j]);
        }
        printf("n");
    }

Diziler hakkında daha çok yol katmem gerek. Sadece ufak bir giriş yapmış oldum. Kalan kısmını başka bir derse bırakıyorum.

Özet

  • Diziler aynı tipten bir çok veriyi tutar ve tek bir deişken adıyla tüm verilere ulaşabilirim.
  • Bir dizi tanımlandığı zaman bellekte sıralı olarak yer tahsis edilir.
  • veriTipi diziAdi[diziBoyutu] şeklinde dizi tanımlanır
  • Elemanları başlangıçta atayabilirim (compile time initialization) ya da program akışında da (run time init.) girebilirim. Değer ataması olmayan indisler rastgele verilerle doldurulur.
  • Dizi indisleri 0 dan başlar.
  • İndisler ile dizideki elemanlara ulaşabilirim.
  • Çift boyutlu diziler (matrisler) için tanımlama veriTipi diziAdi[satir][sütun] şeklinde.

Çalışma Soruları

Senaryo1: 10 boyutlu integer tipinde bir dizi tanımlayıp içini rastgele verilerle dolduralım ve daha sonra kullanıcıdan bir değer girmesini isteyelim. Girilen değerin dizi de olup olmadığını bulalım.

Senaryo2: int tipindeki diziyi 1-100 arası sayılarla doldurup, tek sayıları ve çift sayıları yazdıralım. Daha sonra tek ve çift sayıların ortalamasını bulalım.

Eğitimim için kullandığım örnekleri bu adresteki github reposunda saklıyorum. Ders başlığıyla eşit olan klasörde kaynak kodları bulabilirsiniz.

Senaryo1

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


int main(int argc, char** argv) {

    int array[10];
    int i, number;
    
    //generate random values and assing to array
    for(i=0; i<10; i++) {
        array[i] = (i+2)*3;
    }
    
    //print array
    for(i=0; i<10; i++) {
        printf("%d ", array[i]);
    }
    
    puts("nPlease, enter a number: ");
    scanf("%d", &number);
    
    //check the array
    for(i=0; i<10; i++) {
        if(number == array[i]) {
            printf("Here your number in array[%d]: %d", i, array[i]);
            return;
        }
    }
    printf("There is no your number.");
    return (EXIT_SUCCESS);
}

 Senaryo 2

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


int main(int argc, char** argv) {

    int numbers[100];
    int i, evens=0, odds=0;
    int totalOdd = 0, totalEven = 0;
    //assing the numbers
    for(i=0; i<100; i++) {
        numbers[i] = i+1;
    }
    //print odd numbers and even numbers, also calculate total  each one of them
    for(i=0; i<100; i++) {
        if( (numbers[i] % 2) == 0) {
            printf("Even: %dn", numbers[i]);
            totalEven += numbers[i];
            evens++;
        }
        else {
            printf("Odd: %dn", numbers[i]);
            totalOdd += numbers[i];
            odds++;
        }
    }
    //print averages
    printf("Average of even numbers: %dn", (totalEven / evens) );
    printf("Average of odd numbers: %dn", (totalOdd / odds) );
    
    return (EXIT_SUCCESS);
}

Eğer yanlış ya da düzeltilmesi gereken bir nokta farkettiyseniz, lütfen bana bildirin.

Share
Published by
yusufkaracin

Recent Posts

Celery Checklist [Python]

Celery ile alakalı "best practice"leri ve faydalı araçları bir araya getiren güzel bir checklist'e denk…

5 yıl ago

JavaScript Dizileri için 13 İpucu

Diziler en temel ve sık kullandığımız araçlardan... Kod yazarken işimizi kolaylaştıracak, daha temiz kod yazmamızı…

5 yıl ago

List & Tuple Mini Test (Python)

listve tuple bilginizi test etmek ister misiniz? realpython.com da keşfettiğim ve Türkçe'ye çevirdiğim mini teste…

5 yıl ago

Bilmeniz Gereken 11 Python Mülakat Sorusu

Rehberlik sağlaması ve bilgi tazelemesi açısından faydalı olduğunu düşündüğüm bir Toptal blog paylaşımınıTürkçe'ye çevirdim.Devamını okuyunBilmeniz…

5 yıl ago

Angular Componentlere Konsol Üzerinden Hızlı Erişim

Angular componentlerine console üzerinden hızlıca erişmek için kullanılan bir teknik. Unutmamak için kendime not düşüyorum.Devamını…

5 yıl ago

Birkaç Güzel JavaScript Sorusu İster Miydiniz?

Geçtiğimiz günlerde keşfettiğim ve oldukça da hoşuma giden repoyu paylaşmak istiyorum: lydiahallie/javascript-questions Genel olarak temel…

5 yıl ago