C de diziler (arrays) nedir

0
4116

 C de diziler (arrays) nedir

Bellekte ardışıl bir biçimde bulunan ve aynı türden nesnelerin oluşturduğu veri yapısına  dizi denir.

Dizilerin kullanılmasını gerektiren iki önemli özellikleri vardır :

 

  1. Bellekte ardışıl  (contigous) olarak bulunmaları
  2. elemanların aynı türden nesne olmalarıdır.

 

Diziler bileşik nesnelerdir. Yani bir dizinin tanımlanmasıyla birden fazla sayıda nesne birlikte tanımlanabilir. (bileşik sözcüğü ingilizce aggregate sözcüğünün karşılığı olarak kullanılmıştır.)

Örneğin 10 elemanlık bir dizi tanımlamak yerine, şüphesiz farklı isimde 10 ayrı nesne de tanımlanabilir. Ama 10 ayrı nesne tanımlandığında bu nesnelerin bellekte ardışıl (contigous) olarak yerleşmeleri garanti altına alınmış bir özellik değildir. Oysa dizi tanımlamasında, dizinin elemanı olan bütün nesnelerin bellekte ardışıl (contigous) olarak yer almaları garanti altına alınmış bir özelliktir.

 

Diziler aslında bellekte ardışıl olarak yer alan n adet aynı türden nesnenin oluşturduğu veri yapıları olduğuna göre dizi elemanı olan nesnelerin de kullanılmasından önce tanımlanmaları gerekecektir.

 

 

Dizi tanımlamaları aşağıdaki gibi yapılır :

<tür> <dizi_ismi> [<eleman sayısı>];

 

Yukaridaki gösterimde köşeli parantez eleman sayısının seçimlik oldugunu degil, eleman sayısı bilgisinin köşeli parantez içine yazılması gerektiğini göstermektedir.

 

tür                  :  dizi elemanlarının türünü gösteren anahtar sözcüktür.

dizi ismi     :  isimlendirme kurallarına uygun olarak verilecek herhangi bir isimdir.

eleman sayısı  : dizinin kaç elemana sahip olduğunu gösterir.

 

örnek dizi bildirimleri:

 

double a[20];                                       /* a, 20 elemanlı ve elemanları double türden olan bir dizidir*/

float ave[10];                                       /* ave 10 elemanlı ve her elemanı float türden olan bir dizidir. */

unsigned long total[100];           /* total 100 elemanlı ve her elemanı unsigned long türden olan bir dizidir */

char path[80];                           /* path 80 elemanlı ve her elemanı char türden olan bir dizidir. */

 

bildirim ifadesinde yer alan eleman sayısının mutlaka tamsayı türlerinden birinden sabit ifadesi olması zorunludur. (sabit ifadesi – constant expression tanımını hatırlayalım)

 

int dizi[x];                     /* x dizisinin bildirimi derleme zamanında hata olusturur .*/

int dizi[5.];                    /* gerçek sayı türünden sabit ifadesi olduğu için derleme zamanında hata olusturur .*/

 

int sample[10 * 20]        /* sample dizisinin bildirimi geçerlidir. Eleman sayısını gösteren ifade sabit ifadesidir.

 

Dizi bildirimlerinde eleman sayısı yerine sıklıkla sembolik sabitler kullanılır:

 

#define             MAXSIZE         100

 

int dizi[MAXSIZE];                    /* geçerli bir bildirimdir */

 

diğer değişken bildirimlerinde olduğu gibi, virgül ayıracıyla ayrılarak, birden fazla dizi tek bir tür belirten anahtar sözcükle tanımlanabilir.

 

int x[100], y[50], z[10];

 

x, y ve z  elemanları int türden olan dizilerdir.

 

Dizi tanımlamaları diğer değişken tanımlamaları ile kombine edilebilir :

 

int a[10], b, c;

 

a int türden 10 elemanlı bir dizi, b ve c int türden nesnelerdir.

 

Dizi elemanlarının her biri ayrı birer nesnedir. Dizi elemanlarına index operatörüyle [] ulaşılabilir. Index operatörü bir gösterici operatörüdür. Göstericiler konusunda ayrıntılı bir şekilde ele alınacaktır.

 

index operatörünün operandı dizi ismidir. (aslında bu bir adres bilgisidir, çünkü dizi isimleri adres beilgisi belirtirler.) Köşeli parantez içinde dizinin kaçıncı indisli elemanına ulaşacağımızı  gösteren bir tamsayı ifadesi olmalıdır.

C dilinde dizilerin ilk elemanı sıfırıncı indisli elemandır.

 

a[n] gibi bir dizinin ilk elemanı a[0] son elemanı ise a[n – 1] dur.

 

Örnekler :

 

dizi[20]             /* a dizisinin 20. indisli yani 21. sıradaki elemanı. */

ave[0]               /* ave dizisinin 0. indisli yani birinci sıradaki elemanı */

total[j]              /* total dizisinin j indisli elemanı */

 

Bir dizi tanımlaması ile karşılaşan derleyici, tanımlanan dizi için bellekte yer tahsis edecektir..Ayrılacak yer şüphesiz dizinin eleman sayısı * bir elemanın bellekte kapladığı yer kadar byte olacaktır. Örneğin :

 

int a[5];

 

gibi bir dizi tanımlaması yapıldığını düşünelim. DOS işletim sisteminde çalışıyorsak, derleyici a dizisi için bellekte 2 * 5 = 10 byte yer ayıracaktır. Bellekte bu dizinin yerleşimi aşağıdaki gibi olacaktır :

 

—————————— a[0]
—————————— a[1]
—————————— a[2]
—————————— a[3]
—————————— a[4]
——————————

 

 

dizi kullanımının getirdiği en büyük avantaj  indisleme yardımıyla döngü deyimleriyle tüm dizi elemanlarını kolay bir şekilde işleme sokabilmektir.

 

dizi indis ifadelerinde ++ ya da – operatörlerinin kullanıldığı sık görülür.

 

int a[20];

int k = 10;

int i =5;

 

a[k++] = 100;    /* a dizisinin 10 indisli elemanına yani 11. elemanına 100 değeri atanıyor. */

a[–i] = 200;       /* a dizisinin 4 indisli elemanına yani 5. elemanına 200 değeri atanıyor. */

 

index operatörünün kullanılmasıyla artık dizinin herhangi bir elemanı diğer değişkenler gibi kullanılabilir. Örnekler :

 

a[0] = 1;                                                                                  /* a dizisinin ilk elemanına 0 değeri atanıyor. */

printf(“%d\n”, sample[5]);                                             /* sample dizisinin 6. elemanı yazdırılıyor. */

++val[3];                                                                                 /* val dizisinin 4. elemanı 1 artırılıyor. */

val[2] = sample[2];                                /* val dizisinin 3. elemanına sample dizisinin 3. elemanı atanıyor. */

 

diziler üzerinde işlem yapmak için sıklıkla for ve while döngüleri kullanılır. Aşağıda SIZE elemanlı ve sample isimli bir dizi için for ve while döngülerinin kullanıldığı bazı kalıplar gösterilmektedir:

 

for (i = 0; i < SIZE; ++i)

sample[i] = 0;

 

i = 0;

while (i < SIZE) {

sample[i] = 0;

++i;

}                                                                                             /* sample dizisinin bütün elemanları sıfırlanıyor */

 

 

for (i = 0; i < SIZE; i++) {

scanf(“%d”, &sample[i]);

++i;

}

 

 

i = 0;

while (i < SIZE) {

scanf(“%d”, &sample[i]);

++i;

}                  /* sample dizisinin elemanlarına scanf fonksiyonuyla klavyeden değer aliniyor.*/

 

 

for (i = 0; i < SIZE; i++)

total += sample[i];

 

 

i = 0;

while (i < SIZE) {

total += sample[i];

++i;

}                                                          /* sample dizisinin elemanları toplaniyor. */

 

Bir dizi tanımlaması yapıldığı zaman derleyici tanımlaması yapılmış dizi için bellekte toplam dizi uzunluğu kadar yer ayırır. Örneğin :

 

double a[10];

 

gibi bir tanımlama yapıldığında dizi için bellekte ardışıl (contigious) toplam 80 byte’lık bir yer ayırılacaktır.

 

Dizinin son elemanı a[9] olacaktır. Çok sık yapılan bir hata, dizinin son elemanı diye bellekte derleyici tarafından tahsis edilmemiş bir yere değer atamaktır.

 

a[10] = 5.;

 

deyimiyle bellekte rasgele 8 byte’lık bir alana (güvenli olmayan) bir yere 5. değeri yazılmaktadır.

 

Dizilere ilk değer verilmesi (array initialization)

 

Dizilere ilk değer verme işleminin genel şekli aşağıdaki gibidir :

 

<tür> <dizi ismi>[[uzunluk]] = {d1, d2, d3……..};

 

Örnekler :

 

double sample[5] = {1.3, 2.5, 3.5, 5.8, 6.0};

char str[4] = {‘d’, ‘i’, ‘z’, ‘i’};

unsigned[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

 

Dizilere yukarıdaki gibi ilk değer verildiğinde, verilen değerler dizinin ilk elemanından başlayarak dizi elemanlarına sırayla atanmış olur.

 

Dizilerin tüm elemanlarına ilk değer verme zorunluluğu yoktur. Dizinin eleman sayısından daha az sayıda elemana ilk değer verilmesi durumunda kalan elemanlara otomatik olarak 0 değeri atanmış olur.

Bu durumda bütün dizi elemanlarına 0 değeri atanmak isteniyorsa bunun en kısa yolu :

 

int a[20] = {0};

 

yalnızca dizinin ilk elemanına 0 değeri vermektir. Bu durumda derleyici dizinin kalan elemanlarına otomatik olarak 0 değeri atayacaktır.

 

Dizi elemanlarına ilk değer verilmesinde kullanılan ifadeler, sabit ifadeleri olmalıdır.

 

int a[10] = {b, b + 1, b + 2};

 

gibi bir ilk değer verme işlemi derleme zamanı hatası oluşturur.

 

Bir diziye ilk değer verme işleminde dizi eleman sayısından daha fazla sayıda ilk değer vermek derleme zamanında hata oluşumuna neden olur :

 

int b[5] = {1, 2, 3, 4, 5, 6};   /* error */

 

yukarıdaki örnekte b dizisi 5 elemanlı olmasına karşın, ilk değer verme ifadesinde 6 değer kullanılmıştır.

 

dizi elemanlarına ilk değer verme işleminde dizi uzunluğu belirtilmeyebilir, bu durumda derleyici dizi uzunluğunu verilen ilk değerleri sayarak kendi hesaplar ve dizinin o uzunlukta açıldığını kabul eder. Örneğin :

 

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

 

derleyici yukarıdaki ifadeyi gördüğünde sample dizisinin 5 elemanlı olduğunu kabul edecektir. Bu durumda yukarıdaki gibi bir bildirimle  aşağıdaki gibi bir bildirim eşdeğer olacaktır:

 

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

 

başka örnekler :

 

char name[ ] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’ ‘ ‘, ‘E’, ‘r’, ‘g’, ‘i’, ‘n’, ‘\0’};

unsigned short count[ ] = {1, 4, 5, 7, 8, 9, 12, 15, 13, 21};

 

derleyici name dizisinin uzunluğunu 13, count dizisinin uzunluğunu ise 10 olarak varsayacaktır.

 

yerel ve global diziler

 

Bir dizi de, diğer nesneler gibi yerel ya da global olabilir. Yerel diziler blokların içlerinde tanımlanan dizilerdir. Global diziler ise tüm blokların dışında tanımlanırlar. Global bir dizi söz konusu olduğunda eğer dizi elemanlarına değer verilmemişse, dizi elemanları 0 değeriyle başlatılacaktır. Ama yerel diziler söz konusu olduğunda, değer atanmamış dizi elemanları içinde rasgele değerler (garbage values) bulunacaktır. Aşağıdaki örneği yazarak derleyicinizde yazarak deneyiniz :

 

#include <stdio.h>

 

int global[10];

 

main()

{

int yerel[10], i;

for (i = 0; i < 10; ++i)

printf(“global[%d] = %d\n”, i, global[i]);

for (i = 0; i < 10; ++i)

printf(“global[%d] = %d\n”, i, global[i]);

}

 

dizilerin birbirine atanması

 

int a[SIZE], b[SIZE];

 

tanımlamasından sonra, a dizisi elemanlarına b dizisinin elemanları kopyalanmak istenirse

 

a = b;               /*   hata   */

 

yukarıdaki gibi bir atama derleme zamanı hatası verecektir. Çünkü a ve b dizi isimleridir. C dilinde dizi isimleri nesne göstermezler. Dizi isimleri dizilerin bellekte yerleştirildikleri alanın başlangıcını gösteren ve dizinin türü ile aynı türden adres değerleridir. (Dolayısıyla sabit değerlerdir.)

 

Dizileri ancak bir döngü kullanarak kopyalayabiliriz :

 

for (i = 0; i < SIZE; ++i)

a[i] = b[i];

 

dizilerin kopyalanması için başka bir yöntem de bir standart C fonksiyonu olan memcpy (memory copy) fonksiyonunu kullanmaktır.

 

dizilerle ilgili uygulama örnekleri:

 

Dizilerin kullanılmasındaki temel neden aynı türden verilerin bir dizi altında tanımlanmasıyla, döngüler yardımıyla dizi elemanlarının çok kolay bir şekilde işleme tutulabilmesidir. Aşağıdaki örneklerde bu temalar işlenmiştir :

 

Uygulama 1 : Bir dizi elemanlarının toplamının bulunması

 

#include <stdio.h>

#include <conio.h>

 

#define SIZE                10

 

main()

{

int dizi[SIZE] = {12, 25, -34, 45, 67, 89, 24, -2, -15, 40};

int toplam = 0;

int k;

 

clrscr();

for (k = 0; k < SIZE; ++k)

toplam += dizi[k];

printf(“dizi elemanları toplamı = %d\n”, toplam);

 

return 0;

}

 

Uygulama 2 : bir dizi içindeki en küçük sayıyı bulan program :

 

#include <stdio.h>

#include <conio.h>

 

#define SIZE     10

 

main()

{

int dizi[SIZE] = {12, 25, -34, 45, 67, 89, 24, -2, -15, 40};

int min, k;

 

clrscr();

min = dizi[0];

for (k = 1; k < SIZE; ++k)

if (min > dizi[k])

min = dizi[k];

printf(“en küçük eleman = %d\n”, min);

 

return 0;

}

 

eğer en küçük elemanın kendisiyle birlikte, dizinin kaçıncı elemanı olduğu da bulunmak istenseydi .

 

int indis;

for (k = 1; k < SIZE; ++k)

if (min > dizi[k]) {

min = dizi[k];

indis = k;   /* en küçük eleman yenilendikçe indisi başka bir değişkende saklanıyor. */

}

 

Uygulama 3. bir diziye klavyeden değer alarak daha sonra dizi elemanlarını ekrana yazdıran program :

 

#include <stdio.h>

#include <conio.h>

 

#define SIZE                10

 

main()

{

int dizi[SIZE];

int k;

 

clrscr();

for (k = 0; k < SIZE; ++k)

scanf(“%d”, &dizi[k]);

for (k = 0; k < SIZE; ++k)

printf(“dizi[%d] = %d\n”, k, dizi[k]);

return 0;

}

 

Uygulama 4 : Bir dizi içerisindeki elemanları küçükten büyüge doğru bubble sort algoritmasıyla sıraya dizen program:

 

#include <stdio.h>

#include <conio.h>

 

#define SIZE     10

 

main()

{

int dizi[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};

int i, k, temp;

 

clrscr();

for (i = 0; i < SIZE – 1; ++k)

for (k = 0; k < SIZE – 1; ++k)

if (dizi[k] > dizi[k + 1]) {

temp = dizi[k];

dizi[k] = dizi[k + 1];

dizi[k + 1] = temp;

}

for (i = 0; i < SIZE; ++i)

printf(“dizi[%d] = %d\n”, k, dizi[k]);

return 0;

}

 

Bu algoritmanın performansı basit bir düzenleme ile artırılabilir. Dıştaki döngünün her dönüşünde en büyük sayı en sona gidecektir. Bu durumda içteki döngünün her defasında SIZE – 1 kez dönmesine gerek yoktur. İçteki döngü SIZE – 1 – i kez dönebilir.

for (i = 0; k < SIZE – 1; ++k)

for (k = 0; k < SIZE – 1; ++k)

 

Bubble sort algoritmasını sıraya dizme işlemi tamamlandığında dıştaki döngüyü sonlandıracak biçimde düzenleyebiliriz :

 

#include <stdio.h>

#include <conio.h>

 

#define SIZE                10

#define UNSORTED     0

#define SORTED                       1

 

main()

{

int dizi[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};

int i, k, temp, flag;

for (i = 0; i < SIZE – 1; ++k) {

flag = SORTED;

for (k = 0; k < SIZE – 1; ++k)

if (dizi[k] > dizi[k + 1]) {

temp = dizi[k];

dizi[k] = dizi[k + 1];

dizi[k + 1] = temp;

flag = UNSORTED;

}

if (flag == SORTED)

break;

}

for (i = 0; i < SIZE; ++i)

printf(“dizi[%d] = %d\n”, i, dizi[i]);

return 0;

}

 

bu yeni düzenleme diğerine göre daha iyi de olsa performans açısından çok ciddi bir farklılığı yoktur.

 

Uygulama 5: Bir dizi içerisindeki elemanları küçükten büyüge insertion sort algoritmasıyla sıraya dizen program:

 

#include <stdio.h>

#include <conio.h>

 

#define SIZE     10

 

main()

{

int dizi[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};

int i, j, temp;

 

clrscr();

for (i = 1; i < SIZE; ++i) {

temp = dizi[i];

for (j = i; j > 0 && dizi[j – 1] > temp; –j)

dizi[j] = dizi[j – 1];

dizi[j] = temp;

}

for (i = 0; i < SIZE; ++i)

printf(“dizi[%d] = %d\n”, i, dizi[i]);

return 0;

}

 

sıralama yönünü küçükten büyüğe yapmak yerine büyükten küçüğe yapmak için içerideki döngüyü

 

for (j = i; j > 0 && dizi[j – 1] < temp; –j)

 

şeklinde değiştirmek yeterli olacaktır.

 

 

 

 

 

 

Uygulama 6 : Bir dizi içerisindeki elemanları küçükten büyüge selection sort algoritmasıyla sıraya dizen program:

 

#include  <stdio.h>

 

#define     SIZE     10

 

int a[SIZE] = { 12, 23, 45, 78, -23, ,56, 78, 3, 9, -4};

 

void main()

{

int k, l, max, indis;

 

for (k = 0; k < SIZE; ++k) {

max = a[k];

indis = k;

for (l = k + 1; l < SIZE; ++l)

if (a[l] > max) {

max = a[l];

indis = l;

}

a[indis] = a[k];

a[k] = max;

}

for (k = 0; k < SIZE; ++k)

printf(“%d\n”, a[k]);

}

 

 

karakter dizileri

 

Karakter dizileri char türden dizilerdir. Karakter dizilerinin bazı ilave özellikler dışında diğer dizi türlerinden bir farkı yoktur. char türden diziler daha çok içlerinde yazı tutmak için tanımlanırlar.

 

char s[100];

 

yukarıdaki tanımlamada s dizisi bütün elemanları char türden olan 100 elemanlı bir dizidir.

 

Karakter dizileri en sık kullanılan dizilerdir. C dilinde yazı ve mesaj gibi bilgiler karakter dizileri içinde saklanırlar. Karakterler üzerinde işlemlerin hızlı ve etkin bir biçimde yapılabilmesi için “sonlandırıcı karakter” (NULL KARAKTER) kavramından faydalanılmaktadır.

Sonlandırıcı karakter ASCII tablosunun (ya da sistemde kullanılan karakter setinin) sıfır numaralı (‘\x0’ ya da ‘\0’) karakteridir. Dolayısıyla sayısal değer olarak 0 sayısına eşittir. Görüntüsü yoktur. Bu karakter DOS ve UNIX sistemlerinde sonlandırıcı karakter olarak kullanılmaktadır. stdio.h içerisinde NULL sembolik sabiti 0 olarak tanımlandığı için sonlandırıcı karaktere NULL karakter de denir. NULL karakter ‘0’ karakteri ile karıştırılmamalıdır.

 

‘0’         karakterinin ASCII sıra numarası 48’dir. Dolayısıyla tamsayı değeri olarak 48 değerine sahiptir.

‘\0”       karakterinin ASCII sıra numarası 0’dır. Dolayısıyla tamsayı değeri olarak 0 değerine sahiptir.

 

printf(“%d\n”, ‘0’);

printf(“%d\n”, ‘\0’);

 

yukarıdaki ilk printf fonksiyonunun çağırılmasıyla ekrana 48 değeri yazdırılırken, ikinci printf fonksiyonunun çağırılmasıyla ekrana 0 değeri yazdırılmaktadır.

 

 char türden dizilere ilk değer verilmesi

 

char türden dizilere ilk değer verme işlemi (initializing) aşağıdaki biçimlerde yapılabilir .

 

  1. Diğer türden dizilerde olduğu gibi virgüllerle ayrılan ilk değerler küme parantezi içinde yer alır :

 

char name[12] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’, ‘ ‘, ‘E’, ‘r’, ‘g’, ‘i’,’n’};

 

Diğer dizilerde olduğu gibi dizi eleman sayısından daha fazla sayıda elemana ilk değer vermek derleme zamanında hata oluşumuna neden olur.

 

char name[5] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’, ‘ ‘, ‘E’, ‘r’, ‘g’, ‘i’,’n’};                                   /* error */

 

Dizi eleman sayısı kadar elemana ya da dizi eleman sayısından daha az sayıda elemana ilk değer verilebilir. Daha az sayıda elemana ilk değer verilmesi durumunda ilk değer verilmemiş elemanlar diğer dizilerde olduğu gibi 0 değeriyle başlatılacaklardır. 0 değerinin NULL karakter olduğunu hatırlayalım :

 

char name [10] = {‘A’, ‘l’, ‘i’};

 

‘A’

name[0]

‘l’

name[1]

‘i’

name[2]

‘\0’

name[3]

‘\0’

name[4]

‘\0’

name[5]

‘\0’

name[6]

‘\0’

name[7]

‘\0’

name[8]

‘\0’

name[9]

 

Dizi elemanlarına ilk değer verilirken dizi boyutu belirtilmeyebilir. Bu durumda derleyici dizi boyutunu verilen ilk değerleri sayarak saptar ve diziyi bu boyutta açılmış varsayar.

 

char name[ ] = {‘A’, ‘l’, ‘i’};

 

yukarıdaki tanımlama deyimiyle derleyici name dizisinin 3 elemanlı olarak açıldığını varsayacaktır.

 

Boyut bilgisi vermeden, char türden dizilere tek tek ilk değer verilmesi durumunda, ve boyut bilgisi verilerek dizinin toplam eleman sayısı kadar elemana tek tek ilk değer verilmesi durumunda, derleyici NULL karakteri dizinin sonuna otomatik olarak yerleştirmeyecektir. Bu durumda eğer sonlandırıcı karakter özelliğinden faydalanılmak isteniyorsa, NULL karakter de verilen diğer ilk değerler gibi programcı tarafından verilmelidir. Örnek :

 

char name[ ] = {‘A’, ‘l’, ‘i’, ‘\0’};

char isim[7] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’, ‘\0’};

 

Bu şekilde ilk değer vermek zahmetli olduğundan, ilk değer vermede ikinci bir biçim oluşturulmuştur. Karakter dizilerine ilk değerler çift tırnak içinde de verilebilir :

 

char name[ ] = “Ali”;

 

bu biçimin diğerinden farkı derleyicinin sonuna otomatik olarak NULL karakteri yerleştirmesidir.

 

‘A’

name[0]

‘l’

name[1]

‘i’

name[2]

‘\0’

name[3]

 

yukarıdaki örnekte derleyici diziyi 4 elemanlı olarak açılmış varsayacaktır. Dizi eleman sayısından daaha fazla sayıda elemana ilk değer vermeye çalışmak bu biçimin kullanılması durumunda da derleme zamanında hata oluşumuna neden olacaktır.

 

char city[5] = “İstanbul”;                        /* error */

 

Bu durumun bir istisnası vardır. Eger tam olarak dizi eleman sayısı kadar dizi elemanına çift tırnak içinde ilk değer verilirse bu durum ERROR oluşturmaz. Derleyici bu durumda NULL karakteri dizinin sonuna yerleştirmez. Bu durum C dili standartlarına yöneltilen eleştirilerden biridir. C++ dilinde bu durum da error oluşturmaktadır:

 

char name[3] =”Ali”;                  /* error değil */

 

‘A’

name[0]

‘l’

name[1]

‘i’

name[2]

buraya bu durumda null karakter yerleştirilmiyor.

 

 

NULL karakter karakterler üzerinde yapılan işlemleri hızlandırmak için kullanılır. Örneğin int türden bir dizi kullanıldığında dizi elemanları üzerinde döngüleri kullanarak işlem yaparken dizi uzunluğunun mutlaka bilinmesi gerekmektedir. Ama char türden diziler söz konusu olduğunda artık dizi uzunluğunu bilmemiz gerekmez, çünkü yazının sonunda NULL karakter bulunacağından, kontrol ifadelerinde bu durum test edilerek yazının sonuna gelinip gelinmediği anlaşılır. Ancak NULL karakterin , karakter dizilerinde yazıların son elemanı olarak kullanılmasının dezavantajı da diziye fazladan bir karakter yani NULL karakteri eklemek zorunluluğudur. Bu nedenle SIZE elemanlı bir diziye en fazla SIZE – 1 tane karakter girilmelidir.

 

 

klavyeden karakter dizisi alan ve ekrana karakter dizisi yazan standart C fonksiyonları

 

Daha önce gördüğümüz getchar, getch, ve getche fonksiyonları klavyeden tek bir karakter alıyorlardı. Yine putchar fonksiyonu ise tek bir karakteri ekrana yazıyordu. C dilinde birden fazla karakteri (bir stringi) klavyeden alan ya da birden fazla karakteri ekraana yazan standart fonksiyonlar bulunmaktadır. :

 

gets fonksiyonu

 

gets fonksiyonu klavyeden karakter dizisi almakta kullanılan standart bir C fonksiyonudur. Kullanıcı karakterleri girdikten sonra enter tuşuna basmalıdır. Klavyeden girilecek karakterlerin yerleştirileceği dizinin ismini parametre olarak alır. daha önce de belirtildiği gibi dizi isimleri aslında bir adres bilgisi belirtmektedir. gets fonksiyonunun da parametresi aslında char türden bir adrestir. Ancak göstericilerle ilgili temel kavramları henüz öğrenmediğimiz için şimdilik gets fonksiyonunun char türden bir dizi içine klavyeden girilen karakterleri yerleştirdiğini kabul edeceğiz. Örneğin :

 

char name[20];

 

gets(name);

 

ile klavyeden enter tuşuna basılana kadar girilmiş olan tüm karakterler name dizisi içine sırayla yerleştirilirler. Klavyeden Necati yazısının girildiğini kabul edelim.

 

‘N’

name[0]

‘e’

name[1]

‘c’

name[2]

‘a’

name[3]

‘t’

name[4]

‘i’

name[5]

‘\0’

name[6]

 

gets fonksiyonu klavyeden girilen karakterleri diziye yerleştirdikten sonra dizinin sonuna NULL karakter (sonlandırıcı karakter) diye isimlendirilen 0 numaralı ASCII karakterini (ya da kullanılan karakter setinin 0 numaralı karakterini) koyar.

 

gets fonksiyonu dizi için hiç bir şekilde sınır kontrolu yapmaz. gets fonksiyonu ile dizi eleman sayısından fazla karakter girilirse, d,z, taşacağı için beklenmeyen sonuçlarla karşılaşılabilir. Bu tür durumlar göstericiler konusunda (gösterici hataları) detaylı olarak incelenecektir.

gets fonksiyonu ‘\0’ karakterini dizinin sonuna eklediği için SIZE uzunluğunda bir dizi için gets fonksiyonuyla alınacak karakter sayısı en fazla SIZE – 1 olmalıdır. Çünkü sonlandırıcı karakterde diğer karakterler gibi bellekte bir yer kaplamaktadır. Örnek :

 

char isim[12];

 

gets(isim);

 

ile klavyeden Necati Ergin isminin girildiğini düşünelim.

 

‘N’

isim[0]

‘e’

isim[1]

‘c’

isim[2]

‘a’

isim[3]

‘t’

isim[4]

‘i’

isim[5]

‘ ‘

isim[6]

‘E’

isim[7]

‘r’

isim[8]

‘g’

isim[9]

‘i’

isim[10]

‘n’

isim[11]

‘\0’

taşma

 

isim dizisinin tanımlanmasıyla derleyici bu dizi için bellekte 12 byte yer ayıracaktır. isim[0] …isim[11]

gets fonksiyonu bu durumda ‘\0’ karakterini derleyicinin dizi için tahsis etmediği bir bellek hücresine yazacaktır. Bu tür durumlara dizinin taşırılması (off bye one) denmektedir.

taşma durumuyla ilgili olarak ortaya çıkacak hatalar derleme zamanına değil çalışma zamanına (run time) ilişkindir.

 

puts fonksiyonu

 

puts fonksiyonu bir karakter dizisinin içeriğini ekrana yazdırmak için kullanılır. İçeriği yazdırılacak olan karakter dizisinin ismini parametre olarak alır. puts fonksiyonu karakter dizisini ekrana yazdıktan sonra imleci sonraki satırın başına geçirir.

 

char name[20];

 

gets(name);

puts(name);

 

yukarıdaki örnekte gets fonksiyonu ile klavyeden alınan karakter dizisi puts fonksiyonu ile ekrana yazdırılmaktadır.

 

karakter dizilerini ekrana yazdırmak için printf fonksiyonu da kullanılabilir.

 

printf(“%s\n”, name);

 

ile

 

puts(name);

 

aynı işi yapmaktadır. Ancak printf fonksiyonu dizi içeriğini ekrana yazdırdıktan sonra imleci alt satıra taşımaz.

 

puts(name);

 

deyimi yerine aşağıdaki kod parçasını da yazabilirdik.

 

for (i = 0; name[i] != ‘\0’; ++i)

putchar(s[i]);

putchar(‘\n’);

 

puts fonksiyonu ve %s format karakteriyle kullanıldığında printf fonksiyonu, sonlandırıcı karakter görene kadar bütün karakterleri ekrana yazar. Bu durumda, herhangi bir şekilde NULL karakter ezilirse her iki fonksiyon da ilk sonlandırıcı karakteri görene kadar yazma işlemine devam edecektir.

 

Örneğin :

 

char city[ ] = “Ankara”;

 

city[6] = ‘!’;

 

deyimi ile sonlandırıcı karakter ortadan kaldırılırsa (ezilirse) :

 

puts(name);

 

şeklinde puts fonksiyonu çağırıldığında ekrana Ankara!yazıldıktan sonra tesadüfen ilk NULL karakter görülene kadar ekrana yazmaya devam edilir. puts ve printf fonksiyonları karakter dizilerini yazarken yalnızca NULL karakteri dikkate alırlar. karakter dizilerinin uzunluklarıyla ilgilenmezler.

 

sizeof operatörünün dizilerle kullanılması

 

sizeof operatörü operand olarak bir dizi ismi aldığında byte olarak o dizinin toplam uzunluğunu değer olarak üretir.

 

double sample[10];

 

sizeof(sample)

 

ifadesi 80 değerini üretecektir.

 

sizeof operatörü operand olarak dizinin bir elemanını aldığında ürettiği değer, dizi hangi türden ise o türün kullanılan sistemdeki byte olarak uzunluğu olacaktır. yani yukarıdaki örnekte

 

sizeof(sample[0])                      ifadesi, 8 değerini üretecektir.

 

sizeof operatörünü bir dizinin uzunluk bilgisi gerektiği yerde de kullanabiliriz :

 

sizeof(sample) / sizeof(sample[0])

 

ifadesi dizi uzunluğunu verecektir. Örnek :

 

for (i = 0; i < sizeof(a) / sizeof(a[0]); ++i)

a[i] = 0;

 

 

karakter dizileriyle ilgili bazı küçük uygulama örnekleri

 

Uygulama 7: Karakter dizisi içerisindeki yazının uzunluğunu bulan program:

 

#include <stdio.h>

 

main()

{

int k = 0,

char s[50];

 

gets(s);

while (s[k] != ‘\0’)

++k;

printf(“uzunluk = %d\n”, k);

}

 

yukarıda while döngüsü yerine for döngüsü kullanılabilirdi :

 

for (k = 0; s[k] != ‘\0’; ++k)

;

 

 

Uygulama 8: karakter dizisini tersten yazdıran program :

 

#include <stdio.h>

 

#define    SIZE    100

 

main()

{

char s[SIZE];
int k;

 

printf(“bir yazı giriniz :”);

gets(s);

for (k = 0; s[k + 1] != ‘\0’; ++k)

++k;

for (; k >= 0; –k)

putchar(s[k]);

return 0;

}

 

 

Uygulama 9: Karakter dizisindeki, büyük harfleri küçük harfe küçük harfleri büyük harfe çeviren bir program :

 

#include <stdio.h>

#include <ctype.h>

 

#define             SIZE                100

 

main()

{

char s[SIZE];

int k;

 

printf (“bir yazı giriniz : “);

gets(s);

for (k = 0; s[k] != ‘\0’; ++k)

s[k] = isupper(s[k]) ? toupper(s[k]) : tolower(s[k]);

printf(“dönüştürülmüş yazı \n”);

puts(s);

return 0;

}

 

Uygulama 10 : Karakter dizisini tersyüz eden program :

 

#include <stdio.h>

 

main()

{

char s[50];

int n, j, temp,

 

gets(s);

for (n = 0; s[n] != ‘\0’; ++n)

;

for (j = 0; j < n / 2; ++j) {

temp = s[n – j – 1];

s[n – j – 1] = s[j];

s[j] = temp;

}

puts(s);

}

 

Uygulama 11 : bir karakter dizisi içindeki harfleri küçükten büyüğe doğru sıralayan bir program

 

#include <stdio.h>

 

#define             SIRALI               1

#define             SIRASIZ                       0

 

main()

{

char s[100];

int flag, k, temp;

 

clrscr();

printf(“bir yazı giriniz :”);

gets(s);

do {

flag = SIRALI;

for (k = 0; s[k + 1] != ‘\0’; ++k)

if (s[k] > s[k + 1]) {

temp = s[k];

s[k] = s[k + 1];

s[k + 1] = temp;

flag = SIRASIZ;

}

} while (flag == SIRASIZ);

printf(“sıralanmış yazı :\n”);

puts(s);

getch();

}

 

1. 10 elemanlı int türünden bir dizi ıçerisindeki en çok yinelenen sayıyı bulunuz. (En çok yinelenen sayı birden fazla ise dizi içerisinde ilk görüleni bulacaktır.). Denemeyi diziye ilkdeğer vererek yapınız.

 

 

2.  SIZE elemanlı bir int diziyi ilkdeğer vererek tanımlayınız. Bu dizinin elemanlarını değil de elemanlarının indislerini sıraya dizerek başka bir dizi içerisine yerleştiriniz. (Bu algoritmaya indis sort denir. SIZE sembolik sabitine istediğiniz değeri verebilirsiniz.)

 

Test programı aşağıdaki gibi olabilir:

 

#define SIZE                5

 

void main(void)

{

int a[SIZE] = {7, 9, 3, 51, 8};

int b[SIZE];

int i;

 

/* …. */

for (i = 0; i < SIZE; ++i)                        /* 3, 1, 4,  0, 2 */

printf(“%d\n”, b[i]);

for (i = 0; i < SIZE; ++i)                        /* 51, 9, 8, 7, 3 */

printf(“%d\n”, a[b[i]]);

}