1.2.4 Arrays

Arrays create single or multidimensional matrices. They are defined by appending an integer encapsulated in brackets at the end of a variable name. Each additional set of brackets defines an additional dimension to the array. When addressing an index in the array, indexing begins at 0 and ends at 1 less than the defined array. If no initial value is given to the array size, then the size is determined by the initializers. When defining a multidimensional array, nested curly braces can be used to specify which dimension of the array to initialize. The outermost nest of curly braces defines the leftmost dimension, and works from left to right.

Examples:

int x[5];
Defines 5 integers starting at x[0], and ending at x[4]. Their values are undefined.

char str[16]=”Blueberry”;
Creates a string. The value at str[8] is the character “y”. The value at str[9] is the null character. The values from str[10] to str[15] are undefined.

char s[]=”abc”;
Dimensions the array to 4 (just long enough to hold the string plus a null character), and stores the string in the array.

int y[3]={4};
Sets the value of y[0] to 4 and y[1] and y[2] to 0.

int joe[4][5]={
 {1,2,3,4,5},
 {6,7,8,9,10},
 {11,12,13,14,15}
};

The first row initializes joe[0], the second row joe[1] and so forth. joe[3] is initialized to 5 zeros.

The same effect is achieved by:
int joe[4][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};


1.2.4 Arrays

Arrays create single or multidimensional matrices. They are defined by appending an integer encapsulated in brackets at the end of a variable name. Each additional set of brackets defines an additional dimension to the array. When addressing an index in the array, indexing begins at 0 and ends at 1 less than the defined array. If no initial value is given to the array size, then the size is determined by the initializers. When defining a multidimensional array, nested curly braces can be used to specify which dimension of the array to initialize. The outermost nest of curly braces defines the leftmost dimension, and works from left to right.

Examples:

int x[5];
Defines 5 integers starting at x[0], and ending at x[4]. Their values are undefined.

char str[16]=”Blueberry”;
Creates a string. The value at str[8] is the character “y”. The value at str[9] is the null character. The values from str[10] to str[15] are undefined.

char s[]=”abc”;
Dimensions the array to 4 (just long enough to hold the string plus a null character), and stores the string in the array.

int y[3]={4};
Sets the value of y[0] to 4 and y[1] and y[2] to 0.

int joe[4][5]={
 {1,2,3,4,5},
 {6,7,8,9,10},
 {11,12,13,14,15}
};

The first row initializes joe[0], the second row joe[1] and so forth. joe[3] is initialized to 5 zeros.

The same effect is achieved by:
int joe[4][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

Veri Yapısı Nedir
Bir konuyla ilgili, mantıksal ilişki içindeki verilerin bellekte saklanmasına yönelik
düzenlemelere veri yapısı denir. Veri yapıları bellekte belirli bir düzen içinde tutulmuş
verilere ulaşılabilmesine, bu veriler üzerinde bazı işlemlerin etkin bir biçimde yapılmasına
olanak sağlar.

Dizi Nedir
Bellekte bitişik bir biçimde bulunan, aynı türden nesnelerin oluşturduğu veri yapısına dizi
(array) denir. Dizi veri yapısının en önemli özelliği, mantıksal bir ilişki içindeki aynı türden
verilerin bellekte bitişik (contigous) olarak tutulmasıdır. Bunun da uygulamalarda
sağladığı fayda şudur: Dizinin bir elemanına, elemanın konum bilgisiyle değişmez bir
zamanda ulaşılabilir. Yani dizinin eleman sayısı ne olursa olsun, konumu bilinen bir
elemana ulaşım zamanı aynıdır. Bu da bazı uygulamaların etkin bir şekilde
gerçekleştirilmesini kolaylaştırır.

C Dilinde Diziler
C dilinde dizi (array), aynı türden bir ya da daha fazla nesnenin bellekte dizi veri yapısı
biçiminde tutulmasını sağlayan araçtır.
C’de bir dizinin tanımlanmasıyla birden fazla sayıda nesne tek bir deyimle tanımlanabilir.
10 elemana sahip bir dizi tanımlamak yerine, şüphesiz isimleri farklı 10 ayrı nesne de
tanımlanabilir. Ama 10 ayrı nesne tanımlandığında bu nesnelerin bellekte bitişik olarak
yerleşmeleri güvence altına alınmış bir özellik değildir. Oysa dizi tanımlamasında, dizinin
elemanı olan bütün nesnelerin bellekte bitişik olarak yer almaları güvence altına alınmış
bir özelliktir. Dizi de bir veri türü olduğuna göre, dizilerin de kullanılmalarından önce
tanımlanmaları gerekir.

Dizilerin Tanımlanması
Dizi tanımlamalarının genel biçimi:

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

Yukarıdaki genel biçimde köşeli ayraç, eleman sayısının seçimlik olduğunu değil, eleman
sayısı bilgisinin köşeli ayraç içine yazılması gerektiğini gösteriyor.

tür : Dizi elemanlarının türünü gösteren anahtar sözcüktür.
dizi ismi : İsimlendirme 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];
int ave[10];
char path[80];

Yukarıdaki tanımlamalarda
a, 20 elemanlı, her bir elemanı double türden olan bir dizidir.
ave, 10 elemanlı, her bir elemanı int türden olan bir dizidir.
path, 10 elemanlı, her bir elemanı char türden olan bir dizidir.

Tanımlamada yer alan, eleman sayısı belirten ifadenin bir tamsayı türünden değişmez
ifadesi olması zorunludur. Bir başka deyişle derleyici bu ifadenin değerini derleme
zamanında elde edebilmelidir:

int x = 100;
 int a[x]; /* Geçersiz */
 int b[5.]; /* Geçersiz */
 int c[10 * 20];
 int d[sizeof(int) * 100];

Yukarıdaki deyimlerden a ve b dizilerinin tanımlamaları geçersizdir. a dizisinin tanımında
boyut belirten ifade olarak değişmez ifadesi olmayan bir ifade kullanılıyor. b dizisinin
tanımında ise boyut belirten ifade bir gerçek sayı türündendir. c dizisinin tanımında ise bir
hata söz konusu değildir. 10 * 20 bir değişmez ifadesidir. d dizisinin tanımı da bir hata
oluşturmaz çünkü sizeof işlecinin ürettiği değer derleme zamanında elde edilir.

Dizi bildirimlerinde eleman sayısını belirten ifade yerine sıklıkla simgesel değişmezler
kullanılır:

#define ARRAY_SIZE 100

int a[ARRAY_SIZE];

Program içinde dizi boyutu yerine hep ARRAY_SIZE simgesel değişmezi kullanılabilir.
Böylece programda daha sonra dizi boyutuna ilişkin bir değişiklik yapılmak istendiğinde,
yalnızca simgesel değişmezin değerinin değiştirilmesi yeterli olur.
Diğer değişken bildirimlerinde olduğu gibi, virgül ayracıyla ayrılarak, birden fazla dizi, tür
belirten sözcüklerin bir kez kullanılmasıyla tanımlanabilir:

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

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

Diziler ve diğer nesneler türleri aynı olmak kaydıyla tek bir tanımlama deyimiyle
tanımlanabilir:

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 köşeli ayraç işleciyle []
ulaşılabilir. Köşeli ayraç işleci bir gösterici işlecidir. Bu işleç “Göstericiler” konusunda
ayrıntılı bir şekilde ele alınacak.
Köşeli ayraç işlecinin terimi dizi ismidir. Aslında bu bir adres bilgisidir, çünkü bir dizi ismi
işleme sokulduğunda, işlem öncesi derleyici tarafından otomatik olarak dizinin ilk
elemanının adresine dönüştürülür. Köşeli ayraç içinde dizinin kaçıncı indisli elemanına
ulaşılacağını gösteren bir tamsayı ifadesi olmalıdır.
C dilinde bir dizinin ilk elemanı, dizinin sıfır indisli elemandır.

T bir tür bilgisi olmak üzere

T a[SIZE];

gibi bir dizinin ilk elemanı a[0] son elemanı ise a[SIZE – 1]’dir. Örnekler:

dizi[20] /* a dizisinin 20 indisli yani 21. elemanı olan nesne */
ave[0] /* ave dizisinin 0 indisli yani birinci elemanı olan nesne */
total[j] /* total dizisinin j indisli elemanı olan nesne*/

Görüldüğü gibi “bir dizinin n. elemanı” ve “bir dizinin n indisli elemanı” terimleri dizinin
farklı elemanlarını belirtir. Bir dizinin n indisli elemanı o dizinin n + 1 . elemanıdır.

Bir dizi tanımlaması ile karşılaşan derleyici, tanımlanan dizi için bellekte yer ayırır.
Ayrılacak yer şüphesiz

dizinin eleman sayısı * bir elemanın bellekte kapladığı yer

kadar byte olur. Örneğin:

int a[5];

gibi bir dizi tanımlaması yapıldığını düşünelim. Windows işletim sisteminde çalışılıyorsa
derleyici a dizisi için bellekte 4 * 5 = 20 byte yer ayırır.

Dizi indis ifadelerinde ++ ya da — işleçleri sık kullanılır:

int a[20];
int k = 10;
int i = 5;

a[k++] = 100;

deyimiyle dizinin 10 indisli elemanına yani dizinin 11. elemanına 100 değeri atanıyor.
Daha sonra k değişkeninin değeri 1 artırılarak 11 yapılıyor.

a[–i] = 200;

deyimiyle dizinin 4 indisli elemanına yani dizinin 5. elemanına 200 değeri atanıyor. Daha
sonra i değişkeninin değeri 1 azaltılarak 4 yapılıyor.

Köşeli ayraç işlecinin kullanılmasıyla artık dizinin herhangi bir elemanı diğer değişkenler
gibi kullanılabilir. Aşağıdaki örnekleri inceleyin:

a[0] = 1;

a dizisinin ilk elemanına 1 değeri atanıyor.

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

b dizisinin 6. elemanının değeri ekrana yazdırılıyor:

++c[3];

c dizisinin 4. elemanının değeri 1 artırılıyor:

d[2] = e[4];

d dizisinin 3. elemanına e dizisinin 5. elemanı atanıyor:

Diziler üzerinde işlem yapmak için sıklıkla döngü deyimleri kullanılır. Bir döngü deyimi
yardımıyla bir dizinin tüm elemanlarına ulaşmak, çok karşılaşılan bir durumdur.

Aşağıda SIZE elemanlı a isimli bir dizi için for ve while döngü deyimlerinin kullanıldığı bazı
kalıplar gösteriliyor:

a dizisinin bütün elemanlarına 0 değeri atanıyor:

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

Aynı iş bir şüphesiz bir while döngü deyimiyle de yapılabilirdi:

i = 0;
while (i < SIZE)
a[i++] = 0;

Aşağıda a dizisinin elemanlarına standart scanf işleviyle standart giriş biriminden değer
alınıyor:

for (i = 0; i < SIZE; i++)
scanf(“%d”, &a[i]);

ya da

i = 0;
while (i < SIZE)
scanf(“%d”, &a[i++]);

Aşağıda a dizisinin elemanlarının toplamı hesaplanıyor:

for (total = 0, i = 0; i < SIZE; i++)
total += a[i];

ya da

total = 0;
i = 0;

while (i < SIZE)
total += a[i++];

Dizilerin Taşırılması
Bir dizi tanımlamasını gören derleyici dizi için bellekte dizinin tüm elemanlarının sığacağı
büyüklükte bir alan ayırır:

double a[10];

Gibi bir tanımlama yapıldığında, çalışılan sistemde double türünün bellekte 8 byte yer
kapladığı var sayılırsa, dizi için bellekte bitişik (contiguous) toplam 80 byte’lık bir yer
ayrılır.
Dizinin son elemanı a[9] olur. Çok sık yapılan bir hata, dizinin son elemanına ulaşmak
amacıyla yanlışlıkla bellekte derleyici tarafından ayrılmamış bir yere değer atamak, yani
diziyi taşırmaktır:

a[10] = 5.;

deyimiyle bellekte ne amaçla kullanıldığı bilinmeyen 8 byte’ lık bir alana, yani güvenli
olmayan bir bellek bölgesine değer aktarma girişiminde bulunulur. Dizi taşmaları derleme
zamanında kontrol edilmez. Böyle hatalar programın çalışma zamanı ile ilgilidir.

Dizilere İlkdeğer Verilmesi
Değişken tanımlamalarında tanımlanan bir değişkenin “ilkdeğer verme sözdizimi” diye
isimlendirilen bir kural ile belirli bir değerle başlatılması sağlanabiliyordu.
Tanımlanan dizilere de ilkdeğer verilebilir:

double sample[5] = {1.3, 2.5, 3.5, 5.8, 6.0};
char str[4] = {‘d’, ‘i’, ‘z’, ‘i’};
unsigned a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

Dizilere yukarıdaki gibi ilkdeğer verildiğinde, verilen değerler dizinin ilk elemanından
başlayarak dizi elemanlarına sırayla atanmış olur.
Dizilerin tüm elemanlarına ilkdeğer verme zorunluluğu yoktur. Dizinin eleman sayısından
daha az sayıda elemana ilkdeğer verilmesi durumunda kalan elemanlara 0 değeri atanmış
olur. Bu kural hem yerel hem de global diziler için geçerlidir.
Bu durumda bir dizinin bütün elemanlarına 0 değeri verilmek isteniyorsa bunun en kısa
yolu aşağıdaki gibidir:

int a[20] = {0};

Yalnızca dizinin ilk elemanına 0 ilkdeğeri veriliyor. Bu durumda derleyici dizinin kalan
elemanlarına otomatik olarak 0 değeri yerleştirecek kodu üretir.

Dizi elemanlarına ilkdeğer verilmesinde kullanılan ifadeler, değişmez ifadeleri (constant
expression) olmalıdır.

int a[10] = {b, b + 1, b + 2}; /* Geçersiz */

gibi bir ilkdeğer verme işlemi geçersizdir.

Bir diziye ilkdeğer verme işleminde, dizi eleman sayısından daha fazla sayıda ilkdeğer
vermek geçersizdir:

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

Yukarıdaki örnekte b dizisi 5 elemanlı olmasına karşın, ilkdeğer verme deyiminde 6 değer
kullanılıyor. Bu durum derleme zamanında hata oluşturur.

İlkdeğer verme işleminde dizi boyutu belirtilmeyebilir. Bu durumda derleyici dizi
uzunluğunu, verilen ilkdeğerleri sayarak kendi hesaplar. Dizinin o boyutta açıldığını kabul
eder. Örneğin:

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

Derleyici yukarıdaki deyimi gördüğünde a dizisinin 5 elemanlı olduğunu kabul eder. Bu
durumda yukarıdaki gibi bir bildirimle aşağıdaki gibi bir bildirim eşdeğerdir:

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

Başka örnekler :

char name[] = {‘B’ ‘E ‘, ‘R’, ‘N’, ‘A’, ‘\0’};
unsigned short count[ ] = {1, 4, 5, 7, 8, 9, 12, 15, 13, 21};

Derleyici name dizisinin boyutunu 6, count dizisinin boyutunu ise 10 olarak varsayar.
Diziye ilkdeğer verme listesi bir virgül atomuyla sonlandırılabilir:

int a[] = { 1, 4, 5, 7, 8, 9, 12, 15, 13,
2, 8, 9, 8, 9, 4, 15, 18, 25,
};

Yerel ve Global Diziler
Bir dizi de diğer nesneler gibi yerel ya da global olabilir. Yerel diziler blokların içinde
tanımlanan dizilerdir. Global diziler ise global isim alanında, yani tüm blokların dışında
tanımlanır. Global bir dizinin tüm elemanları, global nesnelerin özelliklerine sahip olur.

Yani dizi global ise, dizi elemanı olan nesneler dosya bilinirlik alanına (file scope) ve statik
ömre (static storage duration) sahip olurlar. Global bir dizi söz konusu olduğunda eğer
dizi elemanlarına değer verilmemişse, dizi elemanları 0 değeriyle başlatılır. Ama yerel
diziler söz konusu olduğunda, dizi elemanı olan nesneler blok bilinirlik alanına (block
scope) ömür açısından ise otomatik ömür karakterine (automatic storage class) sahip
olur. Değer atanmamış dizi elemanları içinde çöp değerler (garbage values) bulunur.
Aşağıdaki programı yazarak derleyin:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10
 int g[SIZE];</p>
<p style="text-align: justify;">int main()
 {
 int y[SIZE];
 int i;</p>
<p style="text-align: justify;">for (i = 0; i < SIZE; ++i)
 printf("g[%d] = %d\n", i, g [i]);</p>
<p style="text-align: justify;">for (i = 0; i < SIZE; ++i)
 printf("y[%d] = %d\n", i, y [i]);</p>
<p style="text-align: justify;">return 0;
 }

Dizilerin Birbirine Atanması
Dizilerin elemanları nesnedir. Ancak bir dizinin tamamı bir nesne olarak işlenemez:

int a[SIZE], b[SIZE];

gibi bir tanımlamadan sonra, a dizisi elemanlarına b dizisinin elemanları kopyalanmak
amacıyla, aşağıdaki gibi bir deyimin yazılması sözdizim hatasıdır.

a = b; /* Geçersiz */

Yukarıdaki gibi bir atama derleme zamanı hatasına neden olur. Çünkü dizilerin isimleri
olan a ve b nesne göstermez. Dizinin bellekte kapladığı toplam alan doğrudan tek bir
nesne olarak işlenemez. Yani dizinin elemanları birer nesnedir ama dizinin tamamı bir
nesne değildir. C’de dizi isimleri dizilerin bellekte yerleştirildikleri bloğun başlangıcını
gösteren, dizinin türü ile aynı türden adres değerleridir. Dolayısıyla değiştirilebilir sol taraf
değeri (modifiable L value) değillerdir.
İki dizi birbirine ancak bir döngü deyimi ile kopyalanabilir:

for (i = 0; i < SIZE; ++i)
a[i] = b[i];

Yukarıdaki döngü deyimiyle b dizisinin her bir elemanının değeri a dizisinin eş indisli
elemanına atanıyor. Dizilerin kopyalanması için başka bir yöntem de bir standart C işlevi
olan memcpy işlevini kullanmaktır. Bu işlev “göstericiler” konusunda ele alınacak.

Dizilerin Kullanımına İlişkin Örnekler
Aynı türden nesneler bir dizi altında tanımlanırlarsa, bir döngü deyimi yardımıyla dizi
elemanlarının tamamını işleme sokan kodlar kolay bir biçimde yazılabilir. Aşağıdaki örneği
dikkatle inceleyin:

[/cpp]#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define SIZE 10

int main()
{
int a[SIZE];
int toplam = 0;
int k;

srand(time(0));
for (k = 0; k < SIZE; ++k) {
a[k] = rand() % 100;
printf(“%d “, a[k]);
}
for (k = 0; k < SIZE; ++k)
toplam += a[k];
printf(“\na elemanlari toplami = %d\n”, toplam);

return 0;
}[/cpp]

main işlevinde yer alan ilk for döngü deyimiyle a dizisinin elemanlarına standart rand
işlevi çağrılarıyla 0 – 99 aralığında rastgele değerler atanıyor. Yine aynı döngü içinde
dizinin her bir elemanının değeri ekrana yazdırılıyor. Bunu izleyen ikinci for deyimiyle a
dizisinin her bir elemanının değeri sırasıyla toplam isimli değişkene katılıyor.
Aşağıdaki programda ise int türden bir dizinin en küçük değere sahip olan elamanının
değeri bulunuyor:

[/cpp]#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define SIZE 10

int main()
{
int a[SIZE];
int toplam = 0;
int k, min;

srand(time(0));
for (k = 0; k < SIZE; ++k) {
a[k] = rand() % 100;
printf(“%d “, a[k]);
}
min = a[0];
for (k = 1; k < SIZE; ++k)
if (min > a[k])
min = a[k];
printf(“\nen kucuk eleman = %d\n”, min);

return 0;
}[/cpp]

Algoritmayı biliyorsunuz. min isimli değişken, dizinin en küçük elemanının değerini
tutması için tanımlanıyor. Önce dizinin ilk elemanının dizinin en küçük elemanı olduğu var
sayılıyor. Daha sonra bir for döngü deyimiyle dizinin 1 indisli elemanından başlanarak

dizinin diğer elemanlarının değerlerinin min değişkeninin değerinden daha küçük olup
olmadığı sınanıyor. Eğer dizinin herhangi bir elemanın değeri min değişkeninin
değerinden daha küçük ise min değişkeninin değeri değiştiriliyor ve yeni bulunan
elemanın değeri min değişkenine atanıyor. Döngü çıkışında artık min değişkeni, dizinin en
küçük elemanının değerini tutar, değil mi?

Aşağıdaki programda ise int türden bir dizinin tek ve çift sayı olan elemanlarının aritmetik
ortalamaları ayrı ayrı hesaplanıyor:

[/cpp]#include <stdio.h>

#define SIZE 10

int main()
{
int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
int sum_of_odds = 0;
int sum_of_even = 0;
int no_of_odds = 0;
int k;

for (k = 0; k < SIZE; ++k)
if (a[k] % 2) {
sum_of_odds += a[k];
no_of_odds++;
}
else
sum_of_even += a[k];
if (no_of_odds)
printf(“Teklerin ortalamasi = %lf\n”,(double)sum_of_odds
/no_of_odds);
else
printf(“Dizide tek sayi yok!\n”);

if (SIZE – no_of_odds)
printf(“Ciftlerin ortalamasi = %lf\n”,(double)sum_of_even /(SIZE –
no_of_odds));
else
printf(“Dizide cift sayi yok!\n”);

return 0;
}[/cpp]

Aşağıdaki programda bir dizi içinde arama yapılıyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
 int k;
 int searched_val;</p>
<p style="text-align: justify;">printf("aranacak degeri girin : ");
 scanf("%d", &searched_val);
 for (k = 0; k < SIZE; ++k)
 if (a[k] == searched_val)
 break;</p>
<p style="text-align: justify;">if (k < SIZE)
 printf("a[%d] = %d\n", k, a[k]);
 else
 printf("aranan deger dizide yok!\n");</p>
<p style="text-align: justify;">return 0;
 }

searched_val isimli değişken, dizide aranacak değeri tutmak için tanımlanıyor. Bu
değişkenin değeri standart scanf işleviyle klavyeden alınıyor. Daha sonra oluşturulan bir
for döngüsüyle, dizinin her bir elemanının aranan değere eşitliği döngü gövdesinde yer
alan bir if deyimiyle sınanıyor. Eğer dizinin herhangi bir elemanı aranan değere eşit ise
break deyimi ile döngüden çıkılıyor. Döngü çıkışında eğer döngü değişkeni olan k, SIZE
değerinden küçük ise aranan değer bulunmuş yani döngüden break deyimi ile çıkılmıştır.
Döngüden break deyimi ile çıkılmamışsa k değişkenin değeri SIZE değerine eşit olur,
değil mi?
Dizinin elemanları dizinin içinde sırasız yer alıyorsa, bir değerin dizide bulunmadığı
sonucunu çıkarmak için dizinin tüm elemanlarına bakılmalıdır.
Ancak dizi sıralı ise binary search ismi verilen bir algoritmanın kullanılması arama
işleminin çok daha verimli yapılmasını sağlar:

#include <stdio.h>
 #include <stdlib.h>
 #include <time.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE];
 int k, mid, searched_val;
 int val = 1;
 int low = 0;
 int high = 1;</p>
<p style="text-align: justify;">srand(time(0));</p>
<p style="text-align: justify;">for (k = 0; k < SIZE; ++k) {
 a[k] = val;
 val += rand() % 10;
 printf("%d ", a[k]);
 }
 printf("\naranacak degeri girin : ");
 scanf("%d", &searched_val);
 while (low <= high) {
 mid = (low + high) / 2;
 if (a[mid] == searched_val)
 break;
 if (a[mid] > searched_val)
 high = mid - 1;
 else
 low = mid + 1;
 }
 if (low > high)
 printf("%d degeri dizide bulunamadi!\n", searched_val);
 else
 printf("a[%d] = %d\n", mid, searched_val);</p>
<p style="text-align: justify;">return 0;
 }

Yukarıdaki main işlevinde sıralı bir dizinin içinde arama yapmak amacıyla binary search isimli algoritma kullanılıyor. Dizi sıralanmış olduğuna göre, dizinin ortadaki elemanına bakılmasıyla, dizideki elemanların yarısı artık sorgulama dışı bırakılır, değil mi? 

low değişkeni arama yapılacak dizi parçasının en düşük indisini, high değişkeni ise en
büyük indisini tutuyor. Daha sonra low değeri, high değerinden küçük ya da eşit olduğu
sürece dönen bir while döngüsü oluşturulduğunu görüyorsunuz. mid değişkeni arama
yapılacak dizi parçasının ortadaki elemanının indisini tutuyor. Dizinin mid indisli
elemanının aranan değer olup olmadığına bakılıyor. Aranan değer bulunamamışsa iki
olasılık vardır: mid indisli dizi elemanı aranan değerden büyük ise high değişkeninin
değeri mid – 1 yapılıyor. Böylece arama yapılacak dizi boyutu yarıya düşürülüyor. mid
indisli dizi elemanı aranan değerden küçük ise low değişkeninin değeri mid + 1 yapılıyor.
Böylece yine arama yapılacak dizi boyutu yarıya düşürülüyor.
while döngüsü çıkışında eğer low değeri high değerinden büyükse aranan değer
bulunamamış demektir. Aksi halde dizinin mid indisli elemanı aranan değerdir.

Dizilerin Sıralanması
Dizinin elemanlarını küçükten büyüğe ya da büyükten küçüğe sıralamak için farklı
algoritmalar kullanılabilir. Aşağıda, algısal karmaşıklığı çok yüksek olmayan “kabarcık
sıralaması” (bubble sort) isimli algoritma ile bir dizi sıralanıyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
 int i, k, temp;</p>
<p style="text-align: justify;">for (i = 0; i < SIZE - 1; ++i)
 for (k = 0; k < SIZE -1 - i; ++k)
 if (a[k] > a[k + 1]) {
 temp = a[k];
 a[k] = a[k + 1];
 a[k + 1] = temp;
 }
 for (k = 0; k < SIZE; ++k)
 printf("%d ", a[k]);</p>
<p style="text-align: justify;">return 0;
 }

Aynı algoritma bir do while döngüsü kullanılarak da kodlanabilirdi:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10
 #define UNSORTED 0
 #define SORTED 1</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {12, 25, -34, 45, -23, 29, 12, 90, 1, 20};
 int i, k, temp, flag;</p>
<p style="text-align: justify;">do {
 flag = SORTED;
 for (k = 0; k < SIZE - 1; ++k)
 if (a[k] > a[k + 1]) {</p>
<p style="text-align: justify;">temp = a[k];</p>
<p style="text-align: justify;"><em id="__mceDel"> a[k] = a[k + 1];
 a[k + 1] = temp;
 flag = UNSORTED;
 }
 } while (flag == UNSORTED);</em></p>
<p style="text-align: justify;">for (i = 0; i < SIZE; ++i)
 printf("a[%d] = %d\n", i, a[i]);</p>
<p style="text-align: justify;">return 0;
 }

Aşağıdaki programda bir dizinin elemanları küçükten büyüğe “araya sokma” (insertion
sort) algoritmasıyla sıraya diziliyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
 int i, k, temp;</p>
<p style="text-align: justify;">for (i = 1; i < SIZE; ++i) {
 temp = a[i];
 for (k = i; k > 0 && a[k - 1] > temp; --k)
 a[k] = a[k - 1];
 a[k] = temp;
 }</p>
<p style="text-align: justify;">for (i = 0; i < SIZE; ++i)
 printf("%d ", a[i]);</p>
<p style="text-align: justify;">return 0;
 }

Sıralama yönünü küçükten büyüğe yapmak yerine büyükten küçüğe yapmak için içteki
döngüyü aşağıdaki gibi değiştirmek yeterli olur.

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

Aşağıdaki programda ise diziyi küçükten büyüğe sıralamak için “seçme sıralaması”
(selection sort) algoritması kullanılıyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
 int i, k, min, index;</p>
<p style="text-align: justify;">for (k = 0; k < SIZE; ++k) {
 min = a[k];
 index = k;
 for (i = k + 1; i < SIZE; ++i)
 if (a[i] < min) {</p>
<p style="text-align: justify;">min = a[i];
 index = i;
 }
 a[index] = a[k];
 a[k] = min;
 }</p>
<p style="text-align: justify;">for (k = 0; k < SIZE; ++k)
 printf("%d ", a[k]);</p>
<p style="text-align: justify;">return 0;
 }

Aşağıdaki programda dizinin değeri tek olan elemanları küçükten büyüğe olacak şekilde
dizinin başına, dizinin çift olan elemanları ise küçükten büyüğe dizinin sonuna
yerleştiriliyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
 int i, k, temp;</p>
<p style="text-align: justify;">for (i = 0; i < SIZE - 1; ++i)
 for (k = 0; k < SIZE - 1 - i; ++k)
 if (a[k] % 2 == a[k + 1] % 2 && a[k] > a[k + 1] ||
 a[k] % 2 == 0 && a[k + 1] % 2 != 0) {
 temp = a[k];
 a[k] = a[k + 1];
 a[k + 1] = temp;
 }
 for (k = 0; k < SIZE; ++k)
 printf("%d ", a[k]);</p>
<p style="text-align: justify;">return 0;
 }

Amacı gerçekleştirmek için yine “kabarcık sıralaması” algoritmasının kullanıldığını, ancak
takas yapmak için sınanan koşul ifadesinin değiştirildiğini fark ettiniz mi?

Aşağıdaki programda bir dizi ters çevriliyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {2, 3, 1, 7, 9, 12, 4, 8, 19, 10};
 int k;</p>
<p style="text-align: justify;">for (k = 0; k < SIZE / 2; ++k) {
 int temp = a[k];
 a[k] = a[SIZE - 1 - k];
 a[SIZE - 1 - k] = temp;
 }</p>
<p style="text-align: justify;">for (k = 0; k < SIZE; ++k)</p>
<p style="text-align: justify;">printf("%d ", a[k]);</p>
<p style="text-align: justify;">return 0;
 }

Dizinin ters çevrilmesi için dizi boyutunun yarısı kadar dönen bir döngü içinde, dizinin
baştan n. elemanı ile sondan n. elemanı takas ediliyor.

Aşağıda tanımlanan urand isimli işlev her çağrıldığında 0 – MAX değerleri arasında farklı
bir rastgele sayı üretiyor. İşlevin MAX adet tamsayıyı ürettikten sonra çağrıldığında hata
durumunu bildirmek için -1 değerine geri dönüyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define MAX 100</p>
<p style="text-align: justify;">int flags[MAX] = {0};</p>
<p style="text-align: justify;">int urand(void)
 {
 int k, val;</p>
<p style="text-align: justify;">for (k = 0; k < MAX; ++k)
 if (flags[k] == 0)
 break;
 if (k == MAX)
 return -1;</p>
<p style="text-align: justify;">while (flags[val = rand() % MAX])
 ;
 ++flags[val];</p>
<p style="text-align: justify;">return val;
 }</p>
<p style="text-align: justify;">int main()
 {
 int k;</p>
<p style="text-align: justify;">srand(time(0));</p>
<p style="text-align: justify;">for (k = 0; k < MAX; ++k)
 printf("%d ", urand());</p>
<p style="text-align: justify;">printf("\n\n%d\n", urand());</p>
<p style="text-align: justify;">return 0;
 }

İşlev, bir tamsayının daha önce üretilip üretilmediğini anlayabilmek için flags isimli bir
global bayrak dizisini kullanıyor. flags dizisinin bir elemanının değeri 0 ise o indise karşılık
gelen değerin işlev tarafından henüz üretilmediği anlaşılıyor. Dizi elemanının değeri eğer
1 ise, o değerin daha önce üretildiği anlaşılıyor.

while (flags[val = rand() % MAX])
;

döngüsünden flags dizisinin val değişkenine atanan rastgele indisli bir elemanının değeri
sıfır olduğunda çıkılır, değil mi?

Aşağıdaki program, rastgele üretilen bir sayısal loto kuponunu ekrana yazıyor:

#include <stdio.h>
 #include <stdlib.h>
 #include <time.h></p>
<p style="text-align: justify;">#define KOLON_SAYISI 8</p>
<p style="text-align: justify;">void kolon_yaz()
 {
 int numaralar[50] = {0};
 int k, no;</p>
<p style="text-align: justify;">for (k = 0; k < 6; ++k) {
 while (numaralar[no = rand() % 49 + 1])
 ;
 numaralar[no]++;
 }
 for (k = 1; k < 50; ++k)
 if (numaralar[k])
 printf("%2d ", k);
 }</p>
<p style="text-align: justify;">int main()
 {
 int k;</p>
<p style="text-align: justify;">srand(time(0));</p>
<p style="text-align: justify;">for (k = 0; k < KOLON_SAYISI; ++k) {
 printf("kolon %2d : ", k + 1);
 kolon_yaz();
 printf("\n");
 }
 return 0;
 }

kolon_yaz isimli işlev, tek bir kolonu ekrana yazdırıyor. İşlevde numaralar isimli yerel
dizinin, yine bir bayrak dizisi olarak kullanıldığını görüyorsunuz. Dizinin herhangi bir
indisli elemanının değerinin 0 olması, o indis değerinin daha önce üretilmeyen bir sayı
olduğunu gösteriyor. for döngüsü içinde yer alan while döngüsü, daha önce üretilmeyen
bir sayı bulununcaya kadar dönüyor. Böylece 6 kez dönen for döngüsüyle 6 farklı sayı
üretilmiş oluyor.
Aşağıdaki programda bir dizinin en büyük ikinci elemanının değeri bulunuyor:

#include <stdio.h>
 #define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {12, 34, 3, 56, 2, 23, 7, 18, 91, 4};
 int k;
 int max1 = a[0];
 int max2 = a[1];</p>
<p style="text-align: justify;">if (a[1] > a[0]) {
 max1 = a[1];
 max2 = a[0];
 }</p>
<p style="text-align: justify;">for (k = 2; k < SIZE; ++k)
 if (a[k] > max1) {
 max2 = max1;
 max1 = a[k];
 }
 else if (a[k] > max2)
 max2 = a[k];</p>
<p style="text-align: justify;">printf("en buyuk ikinci deger = %d\n", max2);</p>
<p style="text-align: justify;">return 0;
 }

Aşağıdaki programda yalnızca bir dizinin içinde tek (unique) olan elemanların değerleri
ekrana yazdırılıyor.

#include <stdio.h>
 #include <stdlib.h>
 #include <time.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE];
 int i, k;
 int counter;</p>
<p style="text-align: justify;">srand(time(0));</p>
<p style="text-align: justify;">for (k = 0; k < SIZE; ++k) {
 a[k] = rand() % 30;
 printf("%d ", a[k]);
 }</p>
<p style="text-align: justify;">printf("\n*******************************************************\n");</p>
<p style="text-align: justify;">for (i = 0; i < SIZE; ++i) {
 counter = 0;
 for (k = 0; k < SIZE; ++k)
 if (a[k] == a[i])
 if (++counter == 2)
 break;
 if (counter == 1)
 printf("%d ", a[i]);
 }
 printf("\n");</p>
<p style="text-align: justify;">return 0;
 }

Aşağıdaki program SIZE elemanlı bir dizinin tüm elemanlarına 0 – MAX aralığında
birbirinden farklı rastgele değerler yerleştiriyor:

#include <stdio.h>
 #include <stdlib.h>
 #include <time.h></p>
<p style="text-align: justify;">#define SIZE 50
 #define MAX 100</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE];
 int k;</p>
<p style="text-align: justify;">srand(time(0));</p>
<p style="text-align: justify;">for (k = 0; k < SIZE; ++k) {
 int val;
 while (1) {
 int i;
 val = rand() % MAX;
 for (i = 0; i < k; ++i)
 if (val == a[i])
 break;
 if (i == k)
 break;
 }
 a[k] = val;
 }
 /* dizi yazdırılıyor */
 for (k = 0; k < SIZE; ++k)
 printf("%d ", a[k]);
 printf("\n");</p>
<p style="text-align: justify;">return 0;
 }

Aşağıdaki programda sıralı iki dizi, bir sıralı dizi biçiminde birleştiriliyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 10</p>
<p style="text-align: justify;">int main()
 {
 int a[SIZE] = {2, 3, 6, 7, 8, 9, 13, 45, 78, 79};
 int b[SIZE] = {1, 2, 4, 5, 7, 9, 10, 18, 33, 47};
 int c[SIZE + SIZE];
 int k;
 int index1 = 0, index2 = 0;</p>
<p style="text-align: justify;">for (k = 0; k < SIZE + SIZE; ++k)
 if (index1 == SIZE)
 c[k] = b[index2++];
 else if (index2 == SIZE)
 c[k] = a[index1++];
 else {
 if (a[index1] < b[index2])
 c[k] = a[index1++];
 else
 c[k] = b[index2++];
 }</p>
<p style="text-align: justify;">for (k = 0; k < SIZE + SIZE; ++k)
 printf("%d ", c[k]);</p>
<p style="text-align: justify;">return 0;
 }

char Türden Diziler ve Yazılar
Karakter dizileri, char türden dizilerdir. Karakter dizilerinin, bazı ek özellikleri dışında,
diğer dizi türlerinden bir farkı yoktur. char türden diziler, daha çok, içlerinde yazı tutmak
için tanımlanır.

char str[100];

Yukarıdaki tanımlamada str dizisi, bütün elemanları char türden olan 100 elemanlı bir
dizidir. char türden bir dizi içinde bir yazı tutmak, dizinin her bir elemanına sırayla yazının
bir karakterinin sıra numarasını atamak anlamına gelir. Bu arada char türden bir dizinin
içinde bir yazı tutmanın zorunlu olmadığını, böyle bir dizi pekala küçük tamsayıları tutmak
amacıyla da kullanılabilir.

Yukarıda tanımlanan dizi içinde “Ali” yazısı tutulmak istensin:

str[0] = ‘A’;
str[1] = ‘l’;
str[2] = ‘i’;

Dizi 100 karakterlik olmasına karşın dizi içinde 100 karakterden daha kısa olan yazılar da
tutulabilir. Peki dizi içinde saklanan yazıya nasıl erişilebilir? Yazının uzunluk bilgisi
bilinmiyor. Örneğin yazı ekrana yazdırılmak istendiğinde, int türden diziler için daha önce
yazılan aşağıdaki gibi bir döngü deyiminin kullanıldığını düşünelim:

for (k = 0; k < 100; ++k)
putchar(s[k]);

Böyle bir döngü ile yalnızca Ali yazısı ekrana yazdırılmaz, dizinin diğer 97 elemanının da
görüntüleri, yani çöp değerler ekrana yazdırılır, değil mi?

C dilinde karakterler üzerinde işlemlerin hızlı ve etkin bir biçimde yapılabilmesi için
“sonlandırıcı karakter” (null character) kavramından faydalanılı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. Sonlandırıcı karakter ‘0’ karakteri ile karıştırılmamalıdır.

‘0’ karakterinin ASCII karakter setindeki kod numarası 48’dir. Dolayısıyla tamsayı
olarak değeri 48’dir. Oysa ‘\0’ karakterinin ASCII sıra numarası 0’dır. Dolayısıyla
tamsayı olarak değeri 0’dır. Aşağıdaki programı derleyerek çalıştırın:

#include <stdio.h></p>
<p style="text-align: justify;">int main()
 {
 printf("%d\n", '0');
 printf("%d\n", '\0');</p>
<p style="text-align: justify;">return 0;
 }

Yukarıdaki ilk printf işlevinin çağrılmasıyla ekrana 48 değeri yazdırılırken, ikinci printf
işlevinin çağrılmasıyla ekrana 0 değeri yazdırılır.

char Türden Dizilere İlkdeğer Verilmesi
char türden dizilere ilkdeğer verme işlemi (initializing) aşağıdaki biçimlerde yapılabilir:
Diğer türden dizilerde olduğu gibi virgüllerle ayrılan ilkdeğerler, küme ayracı içinde yer
alır:

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

Diğer dizilerde olduğu gibi dizi eleman sayısından daha fazla sayıda elemana ilkdeğer
vermek geçersizdir.

char name[5] = {‘N’, ‘e’, ‘c’, ‘a’, ‘t’, ‘i’}; /* Geçersiz */

Dizi eleman sayısı kadar elemana ya da dizi eleman sayısından daha az sayıda elemana
ilkdeğer verilebilir. Daha az sayıda elemana ilkdeğer verilmesi durumunda ilkdeğer
verilmemiş elemanlar, diğer dizilerde olduğu gibi, 0 değeriyle başlatılır. 0 değerinin
sonlandırıcı karakter olduğunu biliyorsunuz:

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

Dizi elemanlarına ilkdeğer verilirken dizi boyutu belirtilmeyebilir. Bu durumda derleyici
dizi boyutunu verilen ilkdeğerleri sayarak saptar. Derleyici 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ı
varsayar.
char türden dizilerin tanımlanmasında dizinin boyut değeri yazılmadan, dizinin
elemanlarına virgüllerle ayrılmış değerlerle ilkdeğer verilmesi durumunda, derleyici
sonlandırıcı karakteri dizinin sonuna otomatik olarak yerleştirmez. Bu durumda yazının
sonunda bulunması gereken sonlandırıcı karakter ilkdeğer olarak listede bulunmak
zorundadır:

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

Aynı durum dizinin boyutu ile verilen ilkdeğerlerin sayısını aynı olduğunda da geçerlidir:

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

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

char name[] = “Ali”;

Bu biçimin diğerinden farkı, derleyicinin sonuna otomatik olarak sonlandırıcı karakteri
yerleştirmesidir.

A      name[0]
l       name[1]
i       name[2]
‘\0’  name[3]

Yukarıdaki örnekte derleyici, name dizisini 4 elemanlı olarak açılmış varsayar. Dizinin
eleman sayısından daha fazla sayıda elemana ilkdeğer vermek geçersizdir.

char city[5] = “İstanbul”; /* Geçersiz */

Bu durumun bir istisnası vardır. Eğer dizinin eleman sayısı kadar elemana çift tırnak
içinde ilkdeğer verilirse bu durum geçerlidir. Derleyici bu durumda sonlandırıcı karakteri
dizinin sonuna yerleştirmez.
[Bu durum C dili standartlarına yöneltilen eleştirilerden biridir. C++ dilinde bu durum sözdizim hatasıdır.]

char name[3] = “Ali”; /* C’de geçerli, C++’da geçersiz */

A      name[0]
l       name[1]
i       name[2]
???  Buraya ‘\0’ yerleştirilmiyor

‘\0’ karakteri, karakter dizileri ü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 gerekir. Ama char türden diziler söz
konusu olduğunda artık dizi uzunluğunu bilmek gerekmez, çünkü yazının sonunda ‘\0’
karakter bulunacağından, kontrol ifadeleriyle bu durum sınanarak yazının sonuna gelinip
gelinmediği anlaşılabilir. Ancak ‘\0’ karakterin, karakter dizilerinde yazıların son elemanı
olarak kullanılmasının bir zararı da diziye fazladan bir karakter, yani ‘\0’ karakteri
eklemek zorunluluğudur. Bu nedenle SIZE elemanlı bir dizide en fazla SIZE – 1
uzunluğunda bir yazı saklanabilir.
C dilinde bir yazıyı klavyeden alan ya da bir yazıyı ekrana yazan standart işlevler bulunur.

gets işlevi
Daha önce ele alınan getchar, getch ve getche işlevleri klavyeden tek bir karakter
alıyorlardı. gets, klavyeden karakter dizisi almakta kullanılan standart bir C işlevidir.
Kullanıcı, klavyeden karakterleri girdikten sonra enter tuşuna basmalıdır. İşlev, 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 belirtir. gets işlevinin de parametresi
aslında char türden bir adrestir. Ancak göstericilerle ilgili temel kavramlar henüz
anlatılmadığı için şimdilik gets işlevini yalnızca işinize yarayacak kadar öğreneceksiniz.
Örneğin :

char s[20];
gets(s);

ile klavyeden enter tuşuna basılana kadar girilmiş olan tüm karakterler, name dizisi içine
sırayla yerleştirilir. Klavyeden “Necati” yazısının girildiğini varsayalım:
gets işlevi, klavyeden girilen karakterleri diziye yerleştirdikten sonra dizinin sonuna
sonlandırıcı karakteri yerleştirir.

N        s[0]
e         s[1]
c         s[2]
a        s[3]
t        s[4]
i        s[5]
‘\0’   s[6]

gets işlevi, dizi için hiçbir şekilde dizinin taşmasına yönelik bir kontrol yapmaz. gets işlevi
ile dizi eleman sayısından daha fazla karakter girilirse, dizi taşacağı için beklenmeyen
sonuçlarla karşılaşılabilir. Bu tür durumları göstericiler konusunda “gösterici hataları”
başlığı altında ayrıntılı olarak inceleyeceğiz.
gets işlevi ‘\0’ karakterini dizinin sonuna eklediği için, SIZE boyutunda bir dizi için gets
işleviyle alınacak karakter sayısı en fazla SIZE – 1 olmalıdır. Çünkü sonlandırıcı karakter
de diğer karakterler gibi bellekte bir yer kaplar. Örnek :

char isim[6];
gets(isim);

ile klavyeden Necati isminin girildiğini düşünelim:

isim dizisinin tanımlanmasıyla derleyici bu dizi için bellekte 6 byte yer ayırır (isim[0]
…isim[5]).

N        s[0]
e         s[1]
c         s[2]
a        s[3]
t        s[4]
i        s[5]
‘\0’   s[6]

gets işlevi bu durumda ‘\0’ karakterini, derleyicinin dizi için ayırmadığı bir bellek
hücresine yazar. Bu tür durumlara “dizinin bir taşırılması hatası” (off bye one) denir.
Taşma durumuyla ilgili olarak ortaya çıkacak hatalar, derleme zamanına değil çalışma
zamanına (run time) ilişkindir.
Aşağıdaki programı inceleyin:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 char str[SIZE];
 int ch;
 int index = 0;</p>
<p style="text-align: justify;">printf("bir yazı girin: ");
 printf("\n\n");</p>
<p style="text-align: justify;">while ((ch = getchar()) != '\n')
 str[index++] = ch;
 str[index] = '\0';</p>
<p style="text-align: justify;">return 0;
 }

Yukarıdaki main işlevinde klavyeden alınan bir yazı str dizisi içinde saklanıyor. Klavyeden
‘\n’ karakteri alınana kadar, girilen tüm karakterler str dizisinin elemanlarına sırayla
atanıyor. Klavyeden ‘\n’ karakteri alındığında, diziye yazılan son karakterden sonra,
dizideki yazının sonunu işaretlemesi amacıyla ‘\0’ karakter yazılıyor.

Klavyeden alınan bir yazı, char türden bir dizinin içine standart scanf işleviyle de
yerleştirilebilir. Bu amaçla %s format karakterleri kullanılır. Ancak bu durumda klavyeden

girilen karakterlerin hepsi diziye yerleştirilmez. Klavyeden alınan ilk boşluk karakteri ile
diziye yerleştirme işlemi sona erer. Aşağıdaki programı inceleyin:

#include <stdio.h></p>
<p style="text-align: justify;">int main()
 {
 char name[20];
 char fname[30];
 int no;</p>
<p style="text-align: justify;">printf("isim soyisim ve numara girin : ");
 scanf("%s%s%d", name, fname, &no);
 /***/
 return 0;
 }

Programın çalışma zamanında scanf işlevi çağrıldığında aşağıdaki girişin yapıldığını
düşünelim. (‘_’ karakteri boşluk karakterini gösteriyor):

__Necati___Ergin___564

Bu durumda Necati yazısı name dizisine, Ergin yazısı fname dizisine, 564 tamsayı değeri
ise no isimli değişkene yerleştirilir.

puts işlevi
puts, standart bir C işlevidir. Bu işlev, bir karakter dizisinde tutulan yazıyı ekrana
yazdırmak için kullanılır. Yazıyı saklayan karakter dizisinin ismini (dizi ismi derleyici
tarafından otomatik olarak dizinin başlangıç adresine dönüştürülmektedir) parametre
olarak alır. puts işlevi, karakter dizisini ekrana yazdıktan sonra imleci sonraki satırın
başına geçirir:

#include <stdio.h></p>
<p style="text-align: justify;">int main()
 {
 char name[20];</p>
<p style="text-align: justify;">printf("bir isim girin : ");
 gets(name);
 puts(name);</p>
<p style="text-align: justify;">return 0;
 }

Yukarıdaki örnekte gets işlevi ile klavyeden alınan yazı, puts işlevi ile ekrana yazdırılıyor.

Karakter dizileri içinde tutulan yazıları ekrana yazdırmak için, standart printf işlevi de
kullanılabilir. Bu durumda formatlama karakterleri olarak %s kullanılarak dizinin ismi
(dizinin başlangıç adresi) ile eşlenir.

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

ile

puts(name);

aynı işi yapar. Ancak printf işlevi, dizi içinde tutulan yazıyı ekrana yazdırdıktan sonra
imleci alt satıra taşımaz.

puts(name);

deyimi yerine aşağıdaki kod parçası da yazılabilirdi:

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

puts işlevi ve %s format karakteriyle kullanıldığında printf işlevi, sonlandırıcı karakter
görene kadar bütün karakterleri ekrana yazar. Bu durumda, yazının sonundaki
sonlandırıcı karakter herhangi bir şekilde ezilirse her iki işlev de ilk sonlandırıcı karakteri
görene kadar yazma işlemini sürdürür. Aşağıdaki programı inceleyin:

#include <stdio.h></p>
<p style="text-align: justify;">int main()
 {
 char city[] = "Ankara";</p>
<p style="text-align: justify;">city[6] = '!';
 puts(city);</p>
<p style="text-align: justify;">return 0;
 }

city[6] = ‘!’;

atamasıyla Ankara yazısının sonundaki sonlandırıcı karakter ezilerek üzerine ! karakteri
yazılıyor. Daha sonra çağrılan puts işlevi ekrana

Ankara!

yazısını yazdıktan sonra ilk sonlandırıcı karakteri görene kadar ekrana yazmayı sürdürür.
Göstericiler konusunda bu durumun bir gösterici hatası oluşturduğunu göreceksiniz. puts
ve printf işlevleri, karakter dizilerini yazarken yalnızca sonlandırıcı karakteri dikkate alır.
Bu işlevler karakter dizilerinin uzunluklarıyla ilgilenmez.

Karakter Dizileriyle İlgili Bazı Küçük Uygulamalar
Aşağıdaki programda bir karakter dizisi içinde tutulan yazının uzunluğu bulunuyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 char str[SIZE];
 int k;
 int len = 0;</p>
<p style="text-align: justify;">printf ("bir yazi girin : ");
 gets(str);
 printf("yazi = (%s)\n", str);
 for (k = 0; str[k] != '\0'; ++k)
 len++;
 printf("(%s) yazisinin uzunlugu = %d\n", str, len);</p>
<p style="text-align: justify;">return 0;
 }

Programda yer alan

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

döngü deyiminin yürütülmesinden sonra, döngü değişkeni olan k’nın değeri de yazının
uznluğu olur, değil mi?

Aşağıdaki programda char türden bir dizi içine alınan yazı, ekrana tersten yazdırılıyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 char s[SIZE];
 int k;</p>
<p style="text-align: justify;">printf("bir yazı girin :");
 gets(s);
 for (k = 0; s[k] != '\0'; ++k)
 ;</p>
<p style="text-align: justify;">for (--k; k >= 0; --k)
 putchar(s[k]);</p>
<p style="text-align: justify;">return 0;
 }

Aşağıdaki programda önce bir karakter dizisine bir yazı alınıyor. Daha sonra yazının
küçük harf karakterleri büyük harfe, büyük harf karakterleri küçük harfe dönüştürülüyor:

#include <stdio.h>
 #include <ctype.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 char str[SIZE];
 int k;</p>
<p style="text-align: justify;">printf ("bir yazi girin : ");
 gets(str);
 printf("yazi = (%s)\n", str);</p>
<p style="text-align: justify;">for (k = 0; str[k] != '\0'; ++k)
 str[k] = isupper(str[k]) ? tolower(str[k]) : toupper(str[k]);</p>
<p style="text-align: justify;">printf("donustulmus yazi = (%s)\n", str);</p>
<p style="text-align: justify;">return 0;
 }

Aşağıdaki programda bir karakter dizisine klavyeden alınan yazı ters çevriliyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 char str[SIZE];
 int k, temp, len;</p>
<p style="text-align: justify;">printf ("bir yazi girin : ");
 gets(str);
 for (len = 0; str[len] != '\0'; ++len)
 ;</p>
<p style="text-align: justify;">for (k = 0; k < len / 2; ++k) {
 temp = str[k];
 str[k] = str[len - 1 - k];
 str[len - 1 - k] = temp;
 }
 printf("ters cevrilmis yazi = (%s)\n", str);
 return 0;
 }

Yukarıdaki kodda kullanılan algoritmayı inceleyin. Birinci for döngüsü ile yazının uzunluğu
bulunuyor. Daha sonra yazının uzunluğunun yarısı kadar dönen bir for döngü deyimi
oluşturuluyor. Döngünün her turunda yazının baştan n. karakteri ile sondan n. karakteri
yer değiştiriliyor. Yazı uzunluğu tek sayı ise, yazının ortasındaki karakter yerinde kalır.
Yazının sonundaki sonlandırıcı karakter

str[len]

olduğuna göre, yazının son karakteri

str[len – 1]

karakteridir, değil mi?
Aşağıdaki programda ise klavyeden girilen bir yazının içinde bulunan tüm İngilizce harfler
sayılıyor ve kaç tane oldukları ekrana yazdırılıyor:

#include <stdio.h>
 #include <ctype.h></p>
<p style="text-align: justify;">#define SIZE 500</p>
<p style="text-align: justify;">int main()
 {
 char str[SIZE];
 int letter_counter[26] = {0};
 int k;</p>
<p style="text-align: justify;">printf("bir yazi girin : ");
 gets(str);
 for (k = 0; str[k] != '\0'; ++k)
 if (isalpha(str[k]))
 letter_counter[toupper(str[k]) - 'A']++;
 for (k = 0; k < 26; ++k)
 if (letter_counter[k])
 printf("%3d tane %c\n", letter_counter[k], 'A' + k);
 return 0;</p>
<p style="text-align: justify;">}

main işlevi içinde kullanılan letter_counter isimli dizi, bir sayaç dizisi olarak kullanılıyor.
Dizinin 1. elemanı ‘A’, ‘a’ karakterlerinin, dizinin 2. elemanı ‘B’, ‘b’ karakterlerinin,
dizinin sonuncu elemanı ‘Z’, ‘z’ karakterlerinin sayacı olarak görev yapıyor. Bu yerel
dizi, ilkdeğer verme deyimiyle sıfırlanıyor. İlk for döngü deyimiyle, yazının tüm
karakterleri dolaşılıyor, yazının herhangi bir karakteri eğer bir harf karakteri ise, büyük
harfe dönüştürülerek bu karakterden ‘A’ değeri çıkarılıyor. Elde edilen değerin
letter_counter dizisine indis yapıldığını ve letter_counter dizisinin bu indisli elemanının
değerinin 1 artırıldığını görüyorsunuz.
İkinci for döngü deyimiyle ise bu kez sayaç dizisinin, değeri 0 olmayan elemanlarının
değerleri ekrana yazdırılıyor.
Aşağıdaki programda ise bir diziye alınan bir yazı içinden rakam karakterleri siliniyor.
Kodu inceleyin:

#include <stdio.h>
 #include <ctype.h></p>
<p style="text-align: justify;">#define SIZE 500</p>
<p style="text-align: justify;">int main()
 {
 char str[SIZE];
 int k;
 int index = 0;</p>
<p style="text-align: justify;">printf("bir yazi girin : ");
 gets(str);</p>
<p style="text-align: justify;">printf("yazi = (%s)\n", str);</p>
<p style="text-align: justify;">for (k = 0; str[k] != '\0'; ++k)
 if (!isdigit[k])
 str[index++] = str[k];
 str[index] = '\0';
 printf("yazi = (%s)\n", str);</p>
<p style="text-align: justify;">return 0;
 }

Yazıdan rakam karakterlerini silmek için yazı, bulunduğu yere yeniden kopyalanıyor.
Ancak kopyalama yapılırken, rakam karakterleri kopyalanmıyor. index isimli değişken,
dizinin neresine yazılacağını gösteriyor. Eğer bir karakter rakam karakteri değilse, bu
karakter dizinin index indisli elemanına atanıyor, sonra index değişkeninin değeri 1
artırılıyor. Ancak yazının tamamını dolaşan for döngüsünden çıktıktan sonra, silme
işleminden sonra oluşan yazının sonuna, sonlandırıcı karakter ekleniyor.

Aşağıdaki programda bir yazının toplam sözcük sayısı bulunuyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 200
 #define OUTWORD 0
 #define INWORD 1</p>
<p style="text-align: justify;">int is_sep(int ch);</p>
<p style="text-align: justify;">int main()</p>
<p style="text-align: justify;">{
 char str[SIZE];
 int word_counter = 0;
 int k;
 int word_flag = OUTWORD;</p>
<p style="text-align: justify;">printf("bir yazi girin : ");
 gets(str);</p>
<p style="text-align: justify;">for (k = 0; str[k] != '\0'; ++k)
 if (is_sep(str[k]))
 word_flag = OUTWORD;
 else if (word_flag == OUTWORD) {
 word_flag = INWORD;
 word_counter++;
 }</p>
<p style="text-align: justify;">printf("toplam %d sozcuk var!\n", word_counter);</p>
<p style="text-align: justify;">return 0;
 }</p>
<p style="text-align: justify;">int is_sep(int ch)
 {
 char seps[] = " \t.,;:?!";
 int k;</p>
<p style="text-align: justify;">for (k = 0; seps[k] != '\0'; ++k)
 if (ch == seps[k])
 return 1;
 return 0;
 }

is_sep işlevi, sıra numarasını aldığı bir karakterin, sözcükleri birbirinden ayıran ayraç
karakterlerinden biri olup olmadığını sınıyor.
main işlevi içinde tanımlanan word_flag isimli bayrak değişkeni, bir sözcüğün içinde mi
dışında mı olunduğunu gösteriyor. Bu değişkene ilkdeğer olarak, kelimenin dışında (OUT)
değerinin verildiğini görüyorsunuz.
Bir for döngü deyimiyle yazının her bir karakterinin ayraç karakteri olup olmadığı
sınanıyor. Eğer ayraç karakteri ise word_flag değişkenine OUT değeri atanıyor. Eğer
karakter ayraç karakteri değilse ve aynı zamanda bayrağın değeri OUT ise, bayrağa IN
değeri atanıyor ve sözcük sayısını tutan sayacın değeri 1 artırılıyor.

Aşağıdaki programda, bir yazının içinde ardışık olarak yer alan eş karakterlerin sayısı bire
indiriliyor:

#include <stdio.h></p>
<p style="text-align: justify;">#define SIZE 100</p>
<p style="text-align: justify;">int main()
 {
 char str[SIZE];
 int index = 0;
 int k;</p>
<p style="text-align: justify;">printf("bir yazi girin : ");
 gets(str);</p>
<p style="text-align: justify;">for (k = 0; str[k] != '\0'; ++k)</p>
<p style="text-align: justify;">if (str[k] != str[k + 1])
 str[++index] = str[k + 1];
 printf("yazi = (%s)\n", str);</p>
<p style="text-align: justify;">return 0;
 }