28.02.2015 Views

Ders 1: Giriş

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Ders</strong> 1: <strong>Giriş</strong><br />

• <strong>Giriş</strong><br />

• 1.1 Tarihçe<br />

• 1.2 Neden C?<br />

• 1.3 İlk C Programı<br />

• 1.4 Başlık Dosyaları<br />

• 1.5 Kaynak Kodunun Derlenmesi<br />

• 1.6 C Kodlarının Temel Özellikleri<br />

• 1.7 Kod Yazımı için Bazı Tavsiyeler<br />

<strong>Giriş</strong><br />

Bu ilk derste, bir C programın nasıl derlenip çalıştırılacağı ve Internet'te bulabileceğiz<br />

derleyicilerden bahsedilecektir. En basit C programının derleyip çalıştırdıktan sonra, geriye<br />

kalan sadece C Programlama Dili'nin kurallarını, yapısını ve deyimlerini öğrenmekten<br />

ibarettir.<br />

1.1 Tarihçe<br />

C Programlama Dili genel amaçlı orta seviyeli ve yapısal bir programlama dilidir. 1972<br />

yılında Dennis Ritchie tarafından Bell Telefon Labaraturvarında Unix işletim sistemi ile<br />

kullanılmak için tasarlanmıştır. C, özellikle sistem programlamada sembolik makine dili<br />

(Asembler) ile tercih edilmektedir. İşletim sistemleri, derleyiciler ve debug gibi aşağı seviyeli<br />

sistem programlarının yazılımında yoğun olarak C programlama dili kullanılır.<br />

C'nin yayılması ve gelişmesi, büyük bir bölümü C dili ile yazılan UNIX işletim sisteminin<br />

popüler olmasıyla başlamıştır. C Programlama Dili, hemen her alanda kullanılmaktadır.<br />

Günümüzde nesneye yönelik programlama dilleri (C++, Java) ve script dilleri (JavaScript,<br />

JavaApplet, PHP) gibi programlama dilleri C Programlama Dili'nden esinlenmiştir.<br />

C taşınabilir (portable) bir dildir. Yani herhangi bir C programı hiçbir değişikliğe uğramadan,<br />

veya çok az bir değişimle, başka bir derleyicide ve/veya işletim sisteminde derlenebilir.<br />

Örneğin, Windows işletim sistemlerinde yazılan bir C kodu, Linux, UNIX veya VAX gibi<br />

işletim sistemlerinde de derlenebilir. Taşınabilirlik, herkesin kabul ettiği bir standart ile<br />

gerçekleştirilebilir. Bugün, C Programla Dili için American National Standards Institute<br />

(ANSI) kurumunun Mart 2000'de belirlediği C99: ISO/IEC 9899:1999 standartı Standart C<br />

olarak kabul edilmiştir.<br />

Burada verilen C notarında, ağırlıklı olarak ANSI C veya diğer adıyla Standart C konu<br />

edilmiştir.<br />

1.2 Neden C?


C Programlama Dili'ni popüler kılan önemli nedenler aşağıda listelenmiştir:<br />

• C, güçlü ve esnek bir dildir. C ile işletim sistemi veya derleyici yazabilir, kelime<br />

işlemciler oluşturabilir veya grafik çizebilirsiniz.<br />

• C, iyi bir yazılım geliştirme ortamına sahiptir.<br />

• C, özel komut ve veri tipi tanımlamasına izin verir.<br />

• C, taşınabilir bir dildir.<br />

• C, gelişimini tamamlamış ve standardı oluşmuş bir dildir.<br />

• C, yapısal bir dildir. C kodları fonksiyon olarak adlandıralan alt programlardan<br />

oluşmuştur.<br />

• C++, Java, JavaScript, JavaApplet, PHP, C#, ... gibi diller C dilinden esinlenmiştir.<br />

1.3 İlk C Programı<br />

Program 1.1 de verilen C programı derlendikten sonra, ekrana 'Merhaba Dünya!' yazısını<br />

basan yalın bir C programıdır. Satır başlarına yerleştirilen 1:, 2: 3: ... rakamlarının<br />

yazılmasına gerek yoktur. Bu rakamlar sadece daha sonra program ile ilgili açıklama<br />

yapılırken, ilgili satırda bulunan kodlar izah edilirken kullanılacaktır. Bu programın<br />

bilgisayarda ilk.c adı ile kaydedilmiştir.<br />

Program 1.1: Derlendikten sonra ekrana 'Merhaba Dünya!' yazar<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

/* ilk.c: ilk C programi */<br />

#include <br />

main()<br />

{<br />

printf("Merhaba Dünya!\n");<br />

}<br />

/* ... */<br />

Programda, 1. satırda /* ... */ sembolleri görülmektedir. Bu ifadeler arasında<br />

yazılan herhangi bir metin, işlem vb. satırlar, derleyici tarafından işlenmez<br />

(değerlendirilmez). Yani /* */ ifadeleri açıklama operatörüdür.<br />

NOT<br />

Açıklama operatörü olarak C++ tarzı iki-bölü (//) de<br />

kullanılmaktadır. Günümüzde birçok C derleyicisi //<br />

operatörünü desteklemektedir. Bu operatörü kullanmadan<br />

önce derleyicinizin bu operatörü desteklediğinden emin<br />

olun.<br />

/*<br />

Bu satırlar derleyici tarafından<br />

değerlendirilmez. Ayrıca programın<br />

tarzı<br />

çalışma hızını da değiştirmez.<br />

*/<br />

C<br />

// Bu satırlar derleyici tarafından<br />

// değerlendirilmez. Ayrıca programın C++<br />

tarzı<br />

// çalışma hızını da değiştirmez.


#include <br />

2. satırdaki #include deyimi, programda eklenecek olan başlık dosyanını işaret eder.<br />

Bu örnekte verilen başlık dosyası (header file) stdio.h dir. #include <br />

ifadesi stdio.h dosyasının derleme işlemine dahil edileceğini anlatır[1]-[2].<br />

main()<br />

4. satırdaki main() özel bir fonksiyondur. Ana program bu dosyada saklanıyor<br />

anlamındadır. Programın yürütülmesine bu fonksiyondan başlanır. Dolayısıyla her C<br />

programında bir tane main() adlı fonksiyon olmalıdır.<br />

printf()<br />

6. satırdaki printf() standart kütüphane bulunan ekrana formatlı bilgi yazdırma<br />

fonksiyondur. stdio.h dosyası bu fonksiyonu kullanmak için program başına ilave<br />

edilmiştir. Aşağıda printf() fonksiyonunun basit kullanımı gösterilmiştir.<br />

Örnek kullanım şekli<br />

Ekranda yazılacak ifade<br />

printf("Element: Aluminyum");<br />

Element: Aluminyum<br />

printf("Atom numarası = %d",13); Atom numarası = 13<br />

printf("Yoğunluk = %f g/cm3",2.7);<br />

printf("Erime noktası = %f<br />

derece",660.32);<br />

1.4 Başlık Dosyaları<br />

Yoğunluk = 2.7 g/cm3<br />

Erime noktası = 660.32<br />

derece<br />

C dilinde bir program yazılırken, başlık dosyası (header file) olarak adlandırılan bir takım<br />

dosyalar #include önişlemcisi kullanılarak program içine dahil edilir. C kütüphanesinde<br />

bulunan birçok fonksiyon, başlık dosyaları içindeki bazı bildirimleri kullanır. Bu tür<br />

dosyaların uzantısı .h dir. ANSI C'deki standart başlık dosyaları şunlardır:<br />

assert.h locale.h stddef.h<br />

ctype.h math.h stdio.h<br />

errno.h setjmp.h stdlib.h<br />

float.h signal.h string.h<br />

limits.h stdarg.h time.h<br />

Bir çok C derleyicisinde yukarıdakilere ek olarak tanımlanmış başlık dosyaları da vardır.<br />

Bunlar derleyicinin yardım kısmından veya derleyicinin kullanım kılavuzundan öğrenilebilir.<br />

ilk.c programında kullanılan başlık dosyası stdio.h, #include ifadesi ile<br />

derleme işlemine dahil edilmiştir. stdio.h standard giriş/çıkış (STandarD-Input-Output)<br />

kütüphane fonksiyonları için bazı bildirimleri barındıran bir dosyasıdır. Programda kullanılan<br />

printf() fonksiyonunu kullanmadan önce bu başlık dosyası programın başına mutlaka ilave<br />

edilmelidir. Aksi halde derleme esnasında<br />

undefined reference to _printf<br />

şeklinde bir hata mesajı ile karşılaşılır.<br />

1.5 Kaynak Kodunun Derlenmesi<br />

C programları veya kaynak kodları (source code) uzantısı .c olan dosyalarda saklanır.<br />

Kaynak kod, bir C derleyicisi (C compiler) ile nesne koduna (object code) daha sonra uygun


ir bağlayıcı (linker) programı ile işletim sistemininde çalıştırılabilen (executable) bir koda<br />

dönüştürülür. Bazı işletim sistemleri ile kullanılan C Derleyicileri ve bu derleyicilerde ilk.c<br />

programının komut satırında nasıl derleneceği Tablo 1.1'de verilmiştir. Eğer ismi geçen<br />

derleyicinin bir editörü varsa ilk.c bu editör de derlenebilir.<br />

Tablo 1.1: İşletim sistemleri, bazı derleyiciler ve derleme komutları<br />

İşletim Sistemi Derleyici Derleme Çalıştırma<br />

Microsoft C cl ilk.c ilk.exe<br />

Borland Turbo C Web tcc ilk.c ilk.exe<br />

MS-DOS / Borland C bcc ilk.c ilk.exe<br />

Windows Zortec C ztc ilk.c ilk.exe<br />

GCC (GNU Compiler Collection) gcc ilk.c -o<br />

ilk.exe<br />

Windows için Web ilk.exe<br />

GCC (GNU Compiler Collection) gcc ilk.c -o<br />

UNIX / Linux<br />

Web<br />

ilk ilk<br />

./ilk veya nice<br />

Bunların dışında, komut satırını kullanmadan, kodlarınızı Windows ortamında çalışan GCC<br />

tabanlı DevC++ veya Salford Plato3 derleyicileri ile derlemek mümkün. Bu tip derleyicilerde<br />

hata ayıklama işlemini kolaylaştırmak için kodlar farlı renkte gösterilir. Fakat program<br />

çıktıları için kullanılan ekran klasik DOS ekranıdır. Şekil 1.1 ve 1.2"de bu programların ekran<br />

görüntüleri verilmiştir.<br />

Şekil 1.1: DevC++ derleyicine ait editör. Derleme ve çalıştırma işlemleri araç çubuğu<br />

üzerindeki butonlarla yapılır.


Şekil 1.2: Silverfrost Salford (Plato3) derleyicine ait editör. Derleme, bağlama ve çalıştırma<br />

işlemleri araç çubuğu üzerindeki butonlarla yapılır.<br />

<strong>Ders</strong>lerimizde kullanılan kaynak kodları, Turbo C ve GCC derleyicileri ile komutsatırında<br />

derlenmiştir. Turbo C derleyicisi isteğe bağlı editörden veya komut satırından derlenebilir.<br />

Editörü başlatmak için C:\TC> dizini altındaki TC.EXE dosyasının çalıştırılması yeterlidir.<br />

Şekil 1.3'de Turbo C editör ortamı gösterilmiştir.


Şekil 1.3: Turbo C derleyicisine ait editör. Derleme için F9, Derleme bağlama ve çalıştırma<br />

işlemleri için CTRL+F9 tuş kombinasyonu kullanılabilir..<br />

ilk.c nin Borland Turbo C ve GCC Programları ile derlenmesi ve çalıştırılması:<br />

DERLEME ve ÇALIŞTIRMA<br />

MS DOS (Turbo C)<br />

C:\TC> tcc ilk.c<br />

C:\TC> ilk.exe<br />

Linux (GCC)<br />

$ gcc ilk.c -o ilk<br />

$ ./ilk<br />

ilk.c nin çıktısı:<br />

ÇIKTI<br />

Merhaba Dünya!<br />

1.6 C Kodlarının Temel Özellikleri<br />

Bir C programı aşağıda verilen özellikleri mutlaka taşımalıdır.<br />

• Yazılımda kullanılacak olan her fonksiyon için ilgili başlık dosyası programın başına<br />

ileve edilmedlidir.<br />

• Her C programı main() fonksiyonunu içermelidir.<br />

• Program içinde kullanılacak olan değişkenler ve sabitler mutlaka tanımlanmalıdır.<br />

• Satırın sonuna ; işareti konmalıdır.<br />

• Her bloğun ve fonksiyonun başlangıcı ve bitişi sırasıyla { ve } sembolleridir.


• C dilinde yazılan kodlarda küçük-büyük harf ayrımı vardır (case sensitive).<br />

Örneğin A ile a derleyici tarafından farklı değerlendirilir.<br />

• Açıklama operatörü /* */ sembolleridir.<br />

1.7 Kod Yazımı için Bazı Tavsiyeler<br />

• Program açıklamaları ve döküman hazırlama program yazıldıkça yapın! Bu<br />

unutulmaması gereken çok önemli husustur.<br />

• Değişken, sabit ve fonksiyon adları anlamlı kelimelerden seçilip yeterince uzun<br />

olmalıdır. Eğer bu isimler bir kaç kelimeden oluşacak ise, kelimeler alt çizgi ( _ ) ile<br />

ayrılmalıdır veya her kelime büyük harfle başlamalıdır. Örneğin:<br />

•<br />

• int son_alinan_bit;<br />

• void KesmeSayisi();<br />

• float OrtalamaDeger = 12.7786;<br />

• Sabitlerin bütün harflerini büyük harfle yazın. Örneğin:<br />

•<br />

• #define PI 3.14;<br />

• const int STATUS=0x0379;<br />

• Her alt yapıya girerken birkaç boşluk veya TAB tuşunu kullanın. Bu okunabilirliği<br />

arttıracaktır. Örneğin:<br />

•<br />

• k = 0;<br />

• for(i=0; i


• <strong>Giriş</strong><br />

• 2.1 Veri Tipleri<br />

• 2.2 Değişkenler<br />

• 2.3 Sabitler<br />

• 2.4 Rakamsal Bilgiler<br />

• 2.5 Değişken Bildirim Yerleri ve Türleri<br />

• 2.6 Tip Dönüşümleri<br />

<strong>Giriş</strong><br />

Orta ve yüksek seviyeli dillerin hemen hemen hepsinde veri tipi ve değişken kavramı<br />

bulunmaktadır. Bu kısımda C programlama dilindeki temel veri tipleri, tanımlayıcılar,<br />

değişkenler ve sabitler konu edilecektir.<br />

2.1 Veri Tipleri<br />

Veri tipi (data type) program içinde kullanılacak değişken, sabit, fonksiyon isimleri gibi<br />

tanımlayıcıların tipini, yani bellekte ayrılacak bölgenin büyüklüğünü, belirlemek için<br />

kullanılır. Bir programcı, bir programlama dilinde ilk olarak öğrenmesi gereken, o dile ait veri<br />

tipleridir. Çünkü bu, programcının kullanacağı değişkenlerin ve sabitlerin sınırlarını belirler.<br />

C programlama dilinde dört tane temel veri tipi bulunmaktadır. Bunlar:<br />

char<br />

int<br />

float<br />

double<br />

Fakat bazı özel niteleyiciler vardır ki bunlar yukarıdaki temel tiplerin önüne gelerek onların<br />

türevlerini oluşturur. Bunlar:<br />

short<br />

long<br />

unsigned<br />

Bu niteleyiciler sayesinde değişkenin bellekte kaplayacağı alan isteğe göre değiştirilebilir.<br />

Kısa (short), uzun (long), ve normal (int) tamsayı arasında yalnızca uzunluk farkı vardır.<br />

Eğer normal tamsayı 32 bit (4 bayt) ise uzun tamsayı 64 bit (8 bayt) uzunluğunda ve kısa<br />

tamsayı 16 biti (2 bayt) geçmeyecek uzunluktadır. İşaretsiz (unsigned) ön eki kullanıldığı<br />

taktirde, veri tipi ile saklanacak değerin sıfır ve sıfırdan büyük olması sağlanır. İşaretli ve<br />

işaretsiz verilerin bellekteki uzunlukları aynıdır. Fakat, işaretsiz tipindeki verilerin üst limiti,<br />

işaretlinin iki katıdır.<br />

NOT<br />

Kısa ve uzun tamsayı tutacak tanımlayıcılar için int<br />

anahtar kelimesinin yazılmasına gerek yoktur.<br />

short s; /* short int s; anlamında */<br />

long k; /* long int k; anlamında */


Bir C programı içerisinde, veri tiplerinin bellekte kapladığı alan sizeof operatörü ile<br />

öğrenilebilir. İlgi cekici olan, bu alanların derleyiciye ve işletim sistemine bağlı olarak<br />

değişiklik göstermesidir. Program 2.1'de, sizeof operatörü kullanılarak, veri tiplerinin bellek<br />

uzunlularının nasıl ekrana yazdırılacağı gösterilmiştir. Programın çıktısı, farklı derleyiciler ve<br />

işletim sisteminde denendiğinde bu durum daha iyi anlaşılır. Lütfen inceleyin.<br />

Program 2.1: Değişken tipleri ve türevlerinin bellekte kapladıkları alanlar<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

ÇIKTI<br />

/* 02prg01.c : sizeof operatörünün kullanımı */<br />

#include <br />

main()<br />

{<br />

printf( "char<br />

sizeof(char));<br />

printf( "short<br />

sizeof(short));<br />

printf( "int<br />

sizeof(int));<br />

printf( "long<br />

sizeof(long));<br />

: %d bayt\n",<br />

: %d bayt\n",<br />

: %d bayt\n",<br />

: %d bayt\n",<br />

printf( "unsigned char : %d bayt\n",<br />

sizeof(unsigned char));<br />

printf( "unsigned short : %d bayt\n",<br />

sizeof(unsigned short));<br />

printf( "unsigned int<br />

sizeof(unsigned int));<br />

printf( "unsigned long<br />

sizeof(unsigned long));<br />

printf( "float<br />

sizeof(float));<br />

printf( "double<br />

sizeof(double));<br />

printf( "long double<br />

sizeof(long double));<br />

}<br />

: %d bayt\n",<br />

: %d bayt\n",<br />

: %d bayt\n",<br />

: %d bayt\n",<br />

: %d bayt\n",<br />

Windows (32 bit) Turbo C Windows (32 bit) Salford<br />

Linux (32 bit) GCC<br />

Linux (64<br />

bit) GCC


char : 1<br />

bayt<br />

short : 2<br />

bayt<br />

int : 2<br />

bayt<br />

long : 4<br />

bayt<br />

unsigned char : 1<br />

bayt<br />

unsigned short : 2<br />

bayt<br />

unsigned int : 2<br />

bayt<br />

unsigned long : 4<br />

bayt<br />

float : 4<br />

bayt<br />

double : 8<br />

bayt<br />

long double : 10<br />

bayt<br />

char : 1<br />

bayt<br />

short : 2<br />

bayt<br />

int : 4<br />

bayt<br />

long : 4<br />

bayt<br />

unsigned char : 1<br />

bayt<br />

unsigned short : 2<br />

bayt<br />

unsigned int : 4<br />

bayt<br />

unsigned long : 4<br />

bayt<br />

float : 4<br />

bayt<br />

double : 8<br />

bayt<br />

long double : 10<br />

bayt<br />

char : 1<br />

bayt<br />

short : 2<br />

bayt<br />

int : 4<br />

bayt<br />

long : 4<br />

bayt<br />

unsigned char : 1<br />

bayt<br />

unsigned short : 2<br />

bayt<br />

unsigned int : 4<br />

bayt<br />

unsigned long : 4<br />

bayt<br />

float : 4<br />

bayt<br />

double : 8<br />

bayt<br />

long double : 12<br />

bayt<br />

char<br />

: 1 bayt<br />

short<br />

: 2 bayt<br />

int<br />

: 4 bayt<br />

long<br />

: 8 bayt<br />

unsigned<br />

char :<br />

1 bayt<br />

unsigned<br />

short :<br />

2 bayt<br />

unsigned<br />

int :<br />

4 bayt<br />

unsigned<br />

long :<br />

8 bayt<br />

float<br />

: 4 bayt<br />

double<br />

: 8 bayt<br />

long<br />

double<br />

: 16<br />

bayt<br />

int veritipi ve türevleri ile hesaplanabilecek en küçük ve en büyük tamsayılar için aşağıdaki<br />

formül kullanılabilir:<br />

Alt sınır = -2 8*sizeof(tip)<br />

Üst sınır = 2 8*sizeof(tip) -1<br />

Örneğin 4 baytlık bir int tipi için:<br />

Alt sınır = -2 8*sizeof(int) = -2 32 = -2147483648<br />

Üst sınır = 2 8*sizeof(int) -1 = 2 32 -1 = 2147483647<br />

Tablo 2.1'de bütün tipler, bellekte kapladıkları alanlar ve hesaplanabilcek (bellekte doğru<br />

olarak saklanabilecek) en büyük ve en küçük sayılar listelenmiştir.<br />

Tablo 2.1: Değişken tipleri ve bellekte kapladıkları alanlar<br />

Veri Tipi Açıklama<br />

Bellekte<br />

işgal ettiği<br />

Alt sınır<br />

boyut<br />

Üst sınır<br />

(bayt)<br />

char Tek bir -128 127<br />

karakter veya<br />

unsigned<br />

1<br />

küçük<br />

char<br />

tamsayı için<br />

0 255<br />

short int Kısa tamsayı<br />

-32,768 32,767<br />

unsigned<br />

2<br />

için<br />

short int<br />

0 65,535


-2,147,483,648 2,147,483,647<br />

int<br />

Tamsayı için 4<br />

0 4,294,967,295<br />

int<br />

unsigned<br />

-<br />

long int Uzun<br />

tamsayı için 8 9,223,372,036,854,775,808 9,223,372,036,854,775,807<br />

unsigned<br />

long int<br />

0 18,446,744,073,709,551,615<br />

Tek duyarlı<br />

gerçel sayı<br />

float<br />

4<br />

için (7<br />

-3.4e +/- 38 +3.4e +/- 38<br />

basamak)<br />

Çift duyarlı<br />

gerçel sayı<br />

double<br />

8<br />

için (15<br />

-1.7e +/- 308 +1.7e +/- 308<br />

basamak)<br />

2.2 Değişkenler<br />

Değişkenler bilgisayarın geçici belleğinde bilginin saklandığı gözlere verilen sembolik<br />

adlardır. Bir C programında, bir değişken tanımlandığında bu değişken için bellekte bir yer<br />

ayrılır. Her değişkenin tuttuğu değerin nasıl bir veri olduğunu gösteren (önceki bölümde<br />

anlatılan) bir veri tipi vardır [1], [3].<br />

C programlama dilinde, değişkenler ve sabitler programın başında bulunmalıdır. Bazı<br />

uygulamalarda değişkenin bir başlangıç değerinin olması istenir. Böyle durumlarda değişken<br />

bildirilirken başlangıç değeri verilebilir. Örneğin:<br />

char isim='X', z; /* değer atamak zorunlu değil */<br />

int sayi=0, n;<br />

float toplam=0.0, sonuc=22.14;<br />

Değişken isimleri verirken bazı kurallara uymak zorunludur. Bunlar:<br />

• Değişken adları en fazla 32 karakterden oluşabilir. 32 karakterden uzun değişken<br />

adları ilk 32 karakteri değerlendirilir. Geriye kalan karakterler işleme tabi tutulmaz.<br />

• Değişken adları ingiliz alfabesinde bulunan karakterler (A-Z) veya (a-z) yada rakamlar<br />

(0-9) ile yazılmalıdır. Türkçe karakterler, özel karakter veya boşluk karakteri<br />

kullanılamaz.<br />

• Değişken adları herhangi bir rakam ile başlayamaz. Ilk karakter bir harf olamalıdır.<br />

Sonrakiler rakamlardan oluşabilir.<br />

• Aşağıda verilen kelimeler ANSI C 'nin anahtar kelimeleridir (key words) ve değişken<br />

ismi olarak kullanılamaz.<br />

•<br />

• auto double int struct<br />

• break else long switch<br />

• case enum register typedef<br />

• char extern return union


• const float short unsigned<br />

• continue for signed void<br />

• default goto sizeof volatile<br />

• do if static while<br />

Bu kurallara göre aşağadaki değişken (sabit, fonksiyon) adlarının geçerliliğini inceleyiniz.<br />

Değişken/Sabit/Fonksiyon/Yapı Adı Geçerlilik Açıklama<br />

asal geçerli -<br />

Momentum geçerli -<br />

ivme geçerli -<br />

olasilik geçerli -<br />

IsikHizi geçerli -<br />

isik_hizi geçerli Alt çizgi karakteri '_' kullanılabilir<br />

isik hizi geçersiz Boşluk karakteri kullanılamaz<br />

ışık_hızı geçersiz Türkçe karakter kullanılamaz<br />

1Bit geçersiz rakam ile başlanamaz<br />

typedef geçersiz Anahtar kelimelerden birisi kullanılamaz<br />

2.3 Sabitler<br />

Sabit bildirimi, başlangıç değeri verilen değişken bildirimi gibi yapılır. Ancak, veri tipinin<br />

önüne const anahtar sözcüğü konmalıdır. Örneğin:<br />

const float PI = 3.142857;<br />

const double NOT= 12345.8596235489;<br />

const int EOF= -1;<br />

const char[] = "devam etmek için bir tuşa basın...";<br />

gibi sabit bildirimleri geçerli olup bunların içerikleri program boyunca değiştirilemez.<br />

Yalnızca kullanılabilir. Genellikle, sabit olarak bildirilen değişken isimleri büyük harflerle,<br />

diğer değişken isimlerinin ise küçük harflerle yazılması (gösterilmesi) C programcıları<br />

tarafından geleneksel hale gelmiştir.<br />

Birçok C programında sabitler #define önişlemci komutu ile de tanımlandığını görebilirsiniz.<br />

Bu komutla sabit bildirimi, bir program parçasına ve makro fonksiyon tanımlaması<br />

yapılabilir. Bir program geliştirilirken simgesel sabitlerin kullanılması programın<br />

okunurluğunu arttırır ve bazen gerekli de olabilir. Aşağıda verilen simgesel sabit bildirimleri<br />

geçerlidir.<br />

#define MAX 100<br />

#define DATA 0x0378<br />

#define YARICAP 14.22


2.4 Rakamsal Bilgiler<br />

C programlama dili içinde tanımlanabilecek sabit rakamlar rakamsal bilgi (literal) olarak<br />

adlandırılır. Her veri tipi kendi rakamsal bilgisine sahiptir. Bu bilgiler, kaynak kod içerisinde,<br />

özel değerleri ifade eder. Örneğin aşağıdaki atama işleminde 25 ve 17.2 sayıları gibi:<br />

i = 25; /* 25, int tipinde bir rakamsal bilgidir */<br />

r = 17.2; /* 17.2, double tipinde bir rakamsal bilgidir */<br />

C dilinde bütün tamsayı sabitler varsayılan (default) olarak int tipinde, gerçel sayı sabitler<br />

varsayılan olarak double tipindedir. Ancak sabitleri gösteren rakamların sonuna eklenecek U<br />

(veya u), L (veya l) ve F (veya f) harfleri ile bu durum değiştirilebilir. Bu yüzden, aşağıdaki<br />

atamalar aynı anlamda değildir.<br />

i = 25; /* int rakam */<br />

i = 25U; /* unsigned int rakam */<br />

i = 25L; /* long int rakam */<br />

i = 25UL; /* unsigned long rakam */<br />

i = 25L; /* long int rakam */<br />

r = 17.2; /* double rakam */<br />

r = 17.2L; /* long double rakam */<br />

r = 17.2F; /* float rakam */<br />

Tamsayı (int) rakamsal bilgiler, 8 (oktal) ve 16 (hexadesimal) sayı tabanında da<br />

gösterilebilir. Bunun için sabit rakamın başına, 8 tabanı için 0 (sıfır) ve 16 tabanını için 0x<br />

sembolleri eklenir. 16'lık sistemdeki hafler büyük (A, B, C, D, E ve F) veya küçük (a, b, c ,d,<br />

e ve f) olabilir. Buna gösterime göre, aşağıdaki atmalar aynı anlamadadır:<br />

i = 75; /* i = 75, 10 tabanında */<br />

i = 0113; /* i = 75, 8 tabanında */<br />

i = 0x4b; /* i = 75, 16 tabanında */<br />

i = 0x4B; /* i = 75, 16 tabanında */<br />

Gerçel sayılar ondalıklı veya üstel olmak üzere iki biçimde gösterilebilir. Örneğin 123.456<br />

sayısının aynı anlama gelen dört farklı gösterimi aşağıda verilmiştir. Üstel gösterimde,<br />

1.23456e+2 veya 1.23456E+2 sayısı matematikteki 1.23456 x 10 2 gösterimi ile eşdeğerdir.<br />

x = 123.456; /* ondalıklı gösterimi */<br />

x = 123.456e+0; /* üstel gösterim */<br />

x = 1.23456e+2; /* üstel gösterim */<br />

x = 1234.56E-1; /* üstel gösterim */<br />

Karakter sabitler, bir harf için tek tırnak, birden çok karakter için çift tırnak içinde belirtilirler.<br />

'A' /* bir karakter */<br />

"Merhaba Dunya" /* bir karakter kümesi */<br />

Program 2.1'de, program içinde tanımlanan değişken sabitlerin ekrana nasıl yazdırılacağı<br />

gösterilmiştir.<br />

Program 2.2: Değişkenlerin ve sabitlerin ekrana yazdırılması<br />

01: /* 02prg02.c : Değişkenler ve sabitlerin ekrana


02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

ÇIKTI<br />

yazdırılması */<br />

#include <br />

#define PI 3.141593<br />

int main()<br />

{<br />

const int MAX = 100;<br />

char c = 'a';<br />

char *s = "Bu bir sicim";<br />

int i = 22;<br />

float f = 33.3;<br />

double d = 44.4;<br />

printf("PI = %lf\n",PI);<br />

printf("MAX= %d\n", MAX);<br />

printf("c = %c\n", c);<br />

printf("s = %s\n", s);<br />

printf("i = %d\n", i);<br />

printf("f = %f\n", f);<br />

printf("d = %lf\n",d);<br />

return 0;<br />

}<br />

PI = 3.141593<br />

MAX= 100<br />

c = a<br />

s = Bu bir sicim<br />

i = 22<br />

f = 33.299999<br />

d = 44.400000<br />

2.5 Değişken Bildirim Yerleri ve Türleri<br />

Yerel (local) Bildirim<br />

Yerel değişkenler kullanıldığı fonksiyon içerisinde bildirilir. Yalnızca bildirildiği fonksiyon<br />

içerisinde tanınır ve kullanılabilir.<br />

int topla(int a,int b)<br />

{<br />

/* yerel (local) değişken c nin bildirimi */<br />

int c;<br />

c = a + b;<br />

return c;<br />

}<br />

Genel (general) Bildirim


Genel değişkenler bütün fonksiyonların dışında bildirilir. Bir değişken program boyunca<br />

sürekli olarak kullanılıyorsa genel olarak bildirilmelidir.<br />

#include <br />

void karesi();<br />

/* m ve n global tip değişkendir.<br />

Bu iki değişken tüm program boyunca kullanılmaktadır. */<br />

int m,n;<br />

main()<br />

{<br />

m=7;<br />

karesi();<br />

printf("%d nin karesi %d dir",m,n);<br />

}<br />

void karesi(){<br />

n = m*m;<br />

}<br />

2.6 Tip Dönüşümleri<br />

Bir formül içerisinde bir çok değişken veya sabit olabilir. Bu değişken ve sabitler birbirinden<br />

farklı tipte olursa, hesap sonucunun hangi tipte olacağı önemlidir. Bir bağıntıda, içeriği<br />

dönüşüme uğrayan değişkenler eski içeriklerini korurlar. Dönüştürme işlemi için geçiçi bellek<br />

alanı kullanılır; dönüştürülen değer kullanıldıktan sonra o alan serbest bırakılır.<br />

char kr;<br />

int tam;<br />

long int ltam;<br />

unsigned int utam;<br />

short int stam;<br />

float f;<br />

double d;<br />

bildirimlerine göre:<br />

Bağıntı Sonuç Tipi<br />

------- ----------<br />

kr+5 int<br />

kr+5.0 double<br />

d+tam double<br />

f+d-2 double<br />

utam-tam unsigned<br />

ltam*tam long<br />

tam/2 int<br />

tam/2.0 double<br />

NOT<br />

Tamsayılar arası bölme kesme hatalarına (truncation error)<br />

neden<br />

olur.<br />

Bunun anlamı iki tamsayının oranı yine bir tamsayıdır.


örneğin: 4/2=2; ama 3/2=1 (1.5 değil).<br />

Bir değişkenin sabit değerin veya bağıntının önüne tür veya takı (cast) yazılarak sonucun<br />

hangi tip çıkması istendiği söylenebilir. Genel yazım biçimi:<br />

(tür tipi) bağıntı;<br />

Örneğin:<br />

int x=9;<br />

float a,b,c;<br />

double d;<br />

...<br />

a = x/4;<br />

b = x/4.0;<br />

c = (float) x/4;<br />

işleminin sonucunda a değişkenine 2.0, b ve c değişkenlerine 2.25 değeri aktarılır. Yani 9/4<br />

ile 9/4.0 farklı anlamdadır.<br />

<strong>Ders</strong> 3: Operatörler<br />

• <strong>Giriş</strong><br />

• 3.1 Aritmetik Operatörler<br />

• 3.2 Atama Operatörleri<br />

• 3.3 sizeof Operatörü<br />

<strong>Giriş</strong><br />

Operatörler, değişkenler veya sabitler üzerinde matematiksel ve karşılaştırma işlemlerini<br />

yapan simgelerdir. Yani bir operatör bir veya daha fazla nesne (değişken) üzerinde işlem<br />

yapan sembollerdir. Bu kısımdam aritmetik operatörler, atama operatörleri ve sizeof<br />

operatörü anlatıcaktır. Karşılaştırma Operatörleri, Mantıksal Operatörler ve Bit Düzeyinde<br />

işlem yapan operatörler daha sonraki bölümlerde incelenektir.<br />

3.1 Aritmetik Operatörler<br />

Değişken veya sabitler üzerinde temel aritmetik işlemleri gerçekleyen operatörlerdir. Bunlar<br />

Tablo 3.1'de listelenmiştir.<br />

Tablo 3.1: Aritmetik Operatörler<br />

Operatör Açıklama Örnek Anlamı<br />

+ toplama x + y x ve y nin toplamı<br />

- çıkarma x - y x ve y nin farkı<br />

* carpma x * y x ve y nin çarpımı<br />

/ bölme x / y x ve y nin oranı


% artık bölme x % y x / y den kalan sayı<br />

3.2 Atama Operatörleri<br />

Bu operatörler bir değişkene, bir sabit vaya bir aritmetik ifade atamak (eşitlemek) için<br />

kullanılır.<br />

Birleşik atama: bazı ifadelerde işlem operatörü ile atama operatörü birlikte kullanılarak,<br />

ifadeler daha kısa yazılabilir. Eğer ifade<br />

değişken = değişken [operatör] aritmetik ifade;<br />

şeklinde ise, daha kısa bir biçimde<br />

değişken [operatör]= aritmetik ifade;<br />

olarak yazılabilir. Bu operatörler Tablo 3.2'de listelenmiştir.<br />

Tablo 3.2: Atama Operatörleri<br />

Operatör Açıklama Örnek Anlamı<br />

= atama x = 7; x = 7;<br />

+= ekleyerek atama x += 3 x = x + 3<br />

-= eksilterek atama x -= 5 x = x - 5<br />

*= çarparak atama x *= 4 x = x * 4<br />

/= bölerek atama x /= 2 x = x / 2<br />

%= bölüp, kalanını atama x %= 9 x = x % 9<br />

++ bir arttırma x++ veya ++x x = x + 1<br />

-- bir azaltma x-- veya --x x = x - 1<br />

Bu tanımlamalara göre, aşağıdaki atamaları inceleyiniz:<br />

/* bir arttırma işlemleri */<br />

i++;<br />

++i;<br />

i += 1;<br />

i = i + 1;<br />

/* karmaşık atamalar */<br />

f *= i; // f = f * i; anlamında<br />

f *= i+1; // f = f * (i+1); anlamında<br />

z /= 1 + x; // z = z / (1+x); anlamında<br />

Bir arttırma veya eksiltme operatörlerini kullanırken dikkatli olunmalıdır. Çünkü aşağıdaki<br />

türden atamalar bazen karışıklığa neden olur.<br />

a = 5; // a = 5<br />

b = a++; // a = 6 ve b = 5<br />

c = ++a; // a = 7 ve c = 7


Program 3.1: Aritmetik ve atama operatörlerinin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

ÇIKTI<br />

/* 03prg01.c: Aritmetik ve atama operatorlerinin<br />

kullanimi */<br />

#include <br />

main()<br />

{<br />

int x, y; /* yerel degikenlerin bildirimi<br />

*/<br />

x = 1; /* x in baslangic degeri */<br />

y = 3; /* y nin baslangic degeri */<br />

printf(" x = %d ve y = %d, olarak<br />

veriliyor.\n", x, y);<br />

x = x + y;<br />

printf("x


09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

ÇIKTI<br />

int i; /* bir tamsayı */<br />

int dizi[5]; /* 5 elemanlı bir<br />

tamsayı dizi */<br />

double d; /* bir gercel sayı */<br />

double mizan[6]; /* 6 elemanlı bir<br />

gercel dizi */<br />

char c; /* tek bir karakter */<br />

char str[] = "masa"; /* bir karakter<br />

topluluğu */<br />

printf("sizeof(int) = %d\n",sizeof(int));<br />

printf("sizeof(i) = %d\n",sizeof(i));<br />

printf("sizeof(dizi) =<br />

%d\n\n",sizeof(dizi));<br />

printf("sizeof(double)=<br />

%d\n",sizeof(double));<br />

printf("sizeof(d) = %d\n",sizeof(d));<br />

printf("sizeof(mizan) =<br />

%d\n\n",sizeof(mizan));<br />

printf("sizeof(char) = %d\n",sizeof(char));<br />

printf("sizeof(c) = %d\n",sizeof(c));<br />

printf("sizeof(str) = %d\n",sizeof(str));<br />

return 0;<br />

}<br />

sizeof(int) = 4<br />

sizeof(i) = 4<br />

sizeof(dizi) = 20<br />

sizeof(double)= 8<br />

sizeof(d) = 8<br />

sizeof(mizan) = 48<br />

sizeof(char) = 1<br />

sizeof(c) = 1<br />

sizeof(str) = 5<br />

Programda sizeof(int) değeri ile sizeof(i) değerinin aynı olduğu görülür. dizinin<br />

boyutu 5 olduğu için, sizeof(dizi) = sizeof(int)*5 = 20 şeklinde hesaplanmaktadır.<br />

Diğerleri için benzer durum söz konusu. Ancak, str 4 elemanlı bir dizi olduğu halde<br />

sizeof(str) = 5 dir. Neden? Bunu ilerideki bölümlerde öğreneceğiz.<br />

<strong>Ders</strong> 4: Temel <strong>Giriş</strong>/Çıkış Fonksiyonları<br />

• <strong>Giriş</strong><br />

• 4.1 printf() Fonksiyonu


• 4.2 scanf() Fonksiyonu<br />

• 4.3 puts() Fonksiyonu<br />

• 4.4 gets() Fonksiyonu<br />

• 4.5 getchar() Fonksiyonu<br />

• 4.6 Formatlı Çıktı<br />

<strong>Giriş</strong><br />

Temel giriş/çıkış fonksiyonları, bütün programla dillerinde mevcuttur. Bu tür fonksiyonlar,<br />

kullanıcıya ekrana veya yazıcıya bilgi yazdırmasına, ve bilgisayara klavyeden veri girişi<br />

yapmasına izin verir. Temel giriş/çıkış fonksiyonları kullanılırken stdio.h başlık dosyası<br />

programın başına eklenmelidir. Bu kısımda, en çok kullanılan giriş/çıkış fonksiyonları<br />

anlatılacaktır.<br />

4.1 printf() Fonksiyonu<br />

Standart C kütüphanesinde bulunan printf() fonksiyonu, değişkenlerin tuttuğu değerleri,<br />

onların adreslerini veya bir mesajı ekrana belli bir düzenle (format) standart çıkışa (stdout),<br />

yani ekrana, yazdırmak için kullanılan fonksiyondur. Daha önce yazılan örnek programlarda<br />

printf() fonksiyonundan yararlanmıştık. Şimdi bu fonksiyonun nasıl kullanıldığına bakalım.<br />

Genel yazım biçimi:<br />

int printf(const char *format, ...);<br />

Basit olarak ekrana Hata oluştu!.. şeklinde bir mesaj yazırma işlemi:<br />

printf("Hata Oluştu!..");<br />

şeklindedir. Çoğu zaman ekrana, programda kullanılan bir değişkenin değeri yazdırılmak<br />

istenebilir. Örneğin ekrana bir tamsayı değişkeninin içeriğini basırımak için, printf()<br />

....<br />

int x = 12;<br />

printf("x in değeri %d dir", x);<br />

....<br />

gibi kullanılır. Bu program parçasının ekran çıktısı şöyle olacaktır:<br />

x in değeri 12 dir<br />

Bu örnekte printf fonksiyonuna iki parametre aktarılmıştır. Birincisi ekranda gösterilecek ve<br />

çift tırnaklar arasına yazılan ifadeler, ikincisi ise ekranda sayısal değeri gösterilmek istenen<br />

değişken (x).<br />

*format üç kısımdan oluşmaktadır:<br />

I. Düz metin (literal string): yazdırılmak istenen ileti.


II.<br />

Örneğin: printf("Ben gelmedim kavga için..."); gibi.<br />

Konrol karakterleri (escape squence): değişkenlerin ve sabitlerin nasıl yazılacağını<br />

belirtmek veya imlecin alt satıra geçirilmesi gibi bazı işlemlerin gerçekleştirilmesi için<br />

kullanılır. Bu karakterler Tablo 4.1'de listelenmiştir.<br />

Örneğin: printf("\tDostun evi gönlüdür...\n"); gibi.<br />

Tablo 4.1: Kontrol karakterleri<br />

Karakter Anlamı<br />

\a Ses üretir (alert)<br />

\b imleci bir sola kaydır (backspace)<br />

\f Sayfa atla. Bir sonraki sayfanın başına geç (formfeed)<br />

\n Bir alt satıra geç (newline)<br />

\r Satır başı yap (carriage return)<br />

\t Yatay TAB (horizontal TAB)<br />

\v Dikey TAB (vertical TAB)<br />

\" Çift tırnak karakterini ekrana yaz<br />

\' Tek tırnak karakterini ekrana yaz<br />

\\ \ karakterini ekrana yaz<br />

%% % karakterini ekrana yaz<br />

III.<br />

Tip belirleyici (conversion specifier): % işareti ile başlar ve bir veya iki karakterden<br />

oluşur (%d gibi). Ekrana yazdırılmak istenen değişkenin tipi, % işaretinden sonra<br />

belirtilir (Bkz. Tablo 4.2) Örneğin: printf("x in değeri %d dir"); gibi.<br />

Tablo 4.2: Tip karakterleri<br />

Tip Karakteri Anlamı Yazdırılacak veri tipi<br />

%c tek bir karakter char<br />

%s karakter dizisi (string) char<br />

%d işaretli ondalık tamsayı int, short<br />

%ld uzun işaretli ondalık tamsayı long<br />

%u işaretsiz ondalık tamsayı unsigned int, unsigned short<br />

%lu işaretsiz uzun tamsayı unsigned long<br />

%f Gerçel sayı float<br />

%lf Çift duayarlı gerçel sayı double<br />

Tip karakterlerini kullanarak, birden çok veri tipi yazdırılabilir. Örneğin:<br />

...<br />

int not= 12;<br />

float pi = 3.14;<br />

char kr = 'A';<br />

gibi.<br />

printf(" not = %d , pi = %f ve kr = %c dir", not, pi, kr);<br />

...<br />

printf() fonksiyonu esnektir. Parametreler herhangi bir C deyimi olabilir. Örneğin x ve y


nin toplamı şöyle yazılabilir:<br />

printf("%d", x+y);<br />

printf fonksiyonu kullanımı Program 4.1'de verilmiştir.<br />

Program 4.1: printf() fonksiyonunun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

/* 04prg01.c<br />

Sayısal değerleri ekrana yazdırmak için<br />

printf fonksiyonunun kullanımı */<br />

#include <br />

main()<br />

{<br />

int a = 2, b = 10, c = 50;<br />

float f = 1.05, g = 25.5, h = -0.1, yuzde;<br />

printf("3 tamsayi : %d %d %d\n", a, b,<br />

c);<br />

printf("3 tamsayi [TAB] : %d \t%d \t%d\n",<br />

a, b, c);<br />

printf("\n");<br />

printf("3 reel sayi (yanyana) : %f %f %f\n",<br />

f, g, h);<br />

printf("3 reel sayi (altalta) :<br />

\n%f\n%f\n%f\n\n", f, g, h);<br />

yuzde = 220 * 25/100.0;<br />

printf("220 nin %%25 i %f dir\n", yuzde);<br />

printf("%f/%f isleminin sonucu = %f\n", g,<br />

f, g / f);<br />

printf("\nprogram sonunda beep sesi<br />

cikar...\a");<br />

}<br />

return 0;<br />

ÇIKTI<br />

3 tamsayi : 2 10 50<br />

3 tamsayi [TAB] : 2 10 50<br />

3 reel sayi (yanyana) : 1.050000 25.500000 -0.100000<br />

3 reel sayi (altalta) :<br />

1.050000<br />

25.500000<br />

-0.100000<br />

220 nin %25 i 55.000000 dir<br />

25.500000/1.050000 isleminin sonucu = 24.285715<br />

program sonunda beep sesi cikar...


printf fonksiyonunun geri dönüş değeri int tipindedir. Bu geri dönüş değeri çıktının kaç<br />

karakter olduğunu gösterir. Yani, printf fonksiyonu, *format ile tanımlanmış karakter<br />

topluluğunun kaç bayt olduğu hesaplar[6]. Program 4.2, printf'in bu yönünüde ortaya<br />

çıkaran bir programdır.<br />

Program 4.2: printf() fonksiyonunun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

/* 04prg02.c<br />

printf fonksiyonunun geri dönüş değerini<br />

gösterir */<br />

#include <br />

int main()<br />

{<br />

int karSay;<br />

int sayi = 1234;<br />

karSay = printf("Ugurlu sayim = %d\n",sayi);<br />

printf("Ust satirda karakter sayisi: %d<br />

dir\n", karSay);<br />

}<br />

ÇIKTI<br />

return 0;<br />

Ugurlu sayim = 1234<br />

Ust satirda karakter sayisi: 20 dir<br />

11. satırdaki işlemle, hem ekrana Ugurlu sayim = 1234 iletisi bastırılmakta, hem de karSay<br />

değişkenine bu iletinin uzunluğu atanmaktadır. Ekrana basılan karakterlerin sayısı (\n<br />

karakteri dahil) 20 dir.<br />

4.2 scanf() Fonksiyonu<br />

Birçok programda ekrana verilerin bastırılmasının yanısıra klavyeden veri okunması<br />

gerekebilir. scanf() fonksiyonu klavyeden veri okumak için kullanılan fonksiyondur.<br />

printf() gibi scanf() fonksiyonuda Tablo 4.1 ve Tablo 4.2'de verilen karakterleri kullanır.<br />

Örneğin klaveden bir x tamsayısı okumak için:<br />

scanf("%d",&x);<br />

satırını yazmak yeterli olacaktır. Burada & işareti adres operatörü olarak adlandırılır ve Böüm<br />

11'de ayıntılı olarak açıklanacaktır. Klavyeden iki farklı sayı okunmak istendiğnde scanf()<br />

fonksiyonu şöyle kullanılabilir:<br />

scanf("%d %f",&x,&y);


veriler klavyeden<br />

16 1.56<br />

yada<br />

16 1.56<br />

veya<br />

16<br />

1.56<br />

şekilinde girilebilir. Program 4.3'de scanf() fonsiyonunun kullanımı gösterilmiştir.<br />

Program 4.3: scanf() fonksiyonun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

ÇIKTI<br />

/* 04prg03.c<br />

scanf() fonksiyonu ile int ve float<br />

tipindeki verilerin okunması */<br />

#include <br />

main()<br />

{<br />

int t;<br />

float g;<br />

printf("Bir gercel sayi girin: ");<br />

scanf("%f",&g);<br />

printf("Bir tamsayi girin : ");<br />

scanf("%d",&t);<br />

printf("\n");<br />

printf("\t %f * %f = %f\n",g,g,g*g);<br />

printf("\t %d * %d = %d\n",t,t,t*t);<br />

return 0;<br />

}<br />

Bir gercel sayi girin: 1.34<br />

Bir tamsayi girin : 12<br />

1.340000 * 1.340000 = 1.795600<br />

12 * 12 = 144<br />

4.3 puts() Fonksiyonu<br />

Ekrana yazdırılacak ifade bir karakter topluluğu ise, printf()'e alternatif olarak puts()<br />

fonksiyonu kullanılabilir. Ancak puts(), ekrana bu karakter topluluğu yazdıktan sonra,<br />

imleci alt satıra geçirir. Buna göre:<br />

printf("Sevgi varlığın mayasıdır.\n");<br />

ile<br />

puts("Sevgi varlığın mayasıdır.");<br />

kullanımları eşdeğerdir.


puts() fonksiyonu Tablo 4.1 de verilen kontrol karakterleri ile kullanılabilir.<br />

puts("Bu birinci satır...\nBu ikinci satır.");<br />

Bu birinci satır...<br />

Bu ikinci satır.<br />

4.4 gets() Fonksiyonu<br />

Klavyeden bir karakter topluluğu okumak için kullanılır. Okuma işlemi yeni satır<br />

karakteriyle(\n) karşılasılıncaya kadar sürer. puts() - gets() arsındaki ilişki, printf() -<br />

scanf() arasındaki gibidir. Yani,<br />

ile<br />

scanf("%s",str);<br />

gets(str);<br />

aynı anlamdadır. puts() - gets() fonksiyonlarının kullanımı daha sonra ayrıntılı<br />

işlenecektir.<br />

4.5 getchar() Fonksiyonu<br />

Bu fonksiyon ile standart girişten bir karakter okunur. Programı istenen bir yerde dudurup, bir<br />

karakater girinceye kadar bekletir. Örneğin:<br />

...<br />

for(i=0; i


Stringlerde %s yerine %ws<br />

biçimindeki kullanım ile sağlanır. Burada w yazılacak olan sayının alan genişliği olarak<br />

adlandırılır. Gerçel bir değişken ekrana yazılacaksa, değişkenin virgülden sonra kaç<br />

basamağının yazdırılacağı k sayısı ile belirlenir. Ancak w > k + 2 olmalıdır.<br />

int i=583,j=1453;<br />

printf("%d %d\n",i,j); /* serbest biçim */<br />

printf("%5d %8d\n",i,j); /* formatlı */<br />

program parçasının ekran çıktısı şöyledir:<br />

ÇIKTI<br />

583 1453<br />

583 1453<br />

Birinci satır serbest formatta ikinci satır ise formatlı yazılmıştır. i değişkeninin tuttuğu 583<br />

sayısı %5d formatıyla yazdırılınca, bu sayı için 5 alan genişliği tanımlanır arakasından sağdan<br />

başlayarak sayı bu alana yazılır. Benzer olarak j değişkeni, 8 alan genişlikli bir bölgeye<br />

yazılır.<br />

Gerçel sayılarda iş biraz daha karışık. Örneğin:<br />

int x=123.456;<br />

printf("%f\n",x); /* serbest biçim */<br />

printf("%8.2f\n",x); /* formatlı */<br />

program parçası çalıştırıldığında aşağıdaki sonuç gözlenir:<br />

ÇIKTI<br />

123.456001<br />

123.46<br />

Birinci satır serbest formatta ikinci satır ise formatlı yazılmıştır. İkinci satırda x değişkeni için<br />

ayrılan alan genişliği 8 ve noktadan sonra 2 basamağa kadar hassasiyet önemsenmiştir. Dikkat<br />

edilirse noktadan sonra sayı uygun bir şekilde yuvarlanmış ve sayı sağa dayalı olarak<br />

yazılmıştır.<br />

Son olarak formatlı çıktı ile ilgili bir örnek Program 4.4'de verilmiştir. İnceleyiniz.<br />

Program 4.4: printf() in formatlı kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

/* 04prg04.c: Formatlı çıktı */<br />

#include <br />

main()<br />

{<br />

float x = 7324.25, y = 244.531;<br />

int i = 1299;<br />

char *c = "Merhaba C";


10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

}<br />

printf("%10d\n" ,i);<br />

printf("%10s\n" ,c);<br />

printf("%10.5f\n",x);<br />

printf("%10.1f\n",y);<br />

return 0;<br />

ÇIKTI<br />

1299<br />

Merhaba C<br />

7324.25000<br />

244.5<br />

<strong>Ders</strong> 5: Temel Kütüphane Fonksiyonları<br />

• <strong>Giriş</strong><br />

• 5.1 Matematiksel Fonksiyonlar (math.h)<br />

• 5.2 Standart Kütüphane Fonksiyonları (stdlib.h)<br />

• 5.3 Karakter Üzerinde İşlem Yapan Fonksiyonlar (ctype.h)<br />

<strong>Giriş</strong><br />

Bu kısımda, C Programlama Dili'nde sık kullanılan ve diğer bölümlerde yararlanacağımız<br />

kütüphane fonksiyonlarının bazıları işlenecektir. Kütüphane fonksiyonu C dilinde önceden<br />

tanımlanmış hazır fonksiyonlarıdır. C dilinde birçok iş bu fonksiyonlarla yapılmaktadır.<br />

Her kütüphane fonksiyonu bir başlık dosyasında tanımlanmıştır. Bu yüzden bir kütüphane<br />

fonksiyonunu kullanmadan önce, onun hangi başlık dosyası ile kullanılması gerektiğini<br />

bilmelisiniz.<br />

5.1 Matematiksel Fonksiyonlar (math.h)<br />

Matematiksel fonksiyonların hemen hemen hepsi double veri tipindedir. Bu fonksiyonlardan<br />

biri program içinde kullanılacaksa math.h başlık dosyası program içine eklenmelidir. En çok<br />

kullanılan matematiksel fonksiyonlar Tablo 5.1'de listelenmiştir.<br />

Tablo 5.1: math.h kütüphanesinde tanımlı bazı fonksiyonlar


Fonksiyon Bildirimi Açıklama Örnek Sonuç<br />

int abs(int x); x tamsayısının mutlak değerini hesaplar abs(-4) 4<br />

x gerçel sayısının mutlak değerini<br />

double fabs(double x); fabs(-4.0) 4.000000<br />

hesaplar<br />

double floor(double x'e (x'den büyük) en yakın tamsayıyı<br />

abs(-2.7)<br />

x);<br />

3.000000<br />

gönderir<br />

x'e (x'den küçük) en yakın tamsayıyı<br />

double ceil(double x); abs(5.6)<br />

gönderir<br />

5.000000<br />

double sqrt(double x); pozitif x sayısının karekökünü hesaplar sqrt(4.0) 2.000000<br />

double pow(double x,<br />

double y);<br />

x y pow(2.,<br />

değerini hesaplar<br />

3.)<br />

8.000000<br />

pozitif x sayısının doğal logaritmasını<br />

double log(double x);<br />

log(4.0)<br />

hesaplar, ln(x)<br />

1.386294<br />

double log10(double pozitif x sayısının 10 tabanındaki<br />

log10(4.0)<br />

x);<br />

0.602060<br />

logaritmasını hesaplar<br />

radyan cinsinden girilien x sayısının sinüs<br />

double sin(double x);<br />

sin(3.14) 0.001593<br />

değerini hesaplar<br />

radyan cinsinden girilien x sayısının<br />

-<br />

double cos(double x);<br />

cos(3.14)<br />

kosinüs değerini hesaplar<br />

0.999999<br />

radyan cinsinden girilien x sayısının<br />

-<br />

double tan(double x);<br />

tan(3.14)<br />

tanjant değerini hesaplar<br />

0.001593<br />

sinüs değeri x olan açıyı gönderir. Açı -<br />

double asin(double x); asin(0.5) 0.523599<br />

pi/2 ile pi/2 arasındadır.<br />

cosinüs değeri x olan açıyı gönderir. Açı<br />

double acos(double x); acos(0.5) 1.047198<br />

-pi/2 ile pi/2 arasındadır.<br />

tanjant değeri x olan açıyı gönderir. Açı -<br />

double atan(double x); atan(0.5) 0.463648<br />

pi/2 ile pi/2 arasındadır.<br />

NOT<br />

Bir programda math.h kütüphanesi kullanılacakca, GCC<br />

derleyicisi -lm seçeneği ile birlikte kullanılmalıdır.<br />

Örneğin test.c içinde math.h'i kullanıyorsa derleme:<br />

gcc -lm test.c -o test<br />

şeklinde yapılmalıdır. Aksi halde bir hata mesajı ile<br />

karşılaşılır.<br />

Trigonometrik (sin, cos, tan) fonksiyonlar kendisine parametre olarak gelen değeri radyan<br />

olarak kabul eder ve sonucu hesaplar. Eğer açılar derece cinsinden hesaplanması gerekiyorsa<br />

şu dönüşüm kullanılanılabilir:<br />

radyan = (3.141593/180.0) * derece;<br />

Program 5.1: sin(), cos(), and tan() fonksiyonlarının kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

/* 05prg01.c<br />

30 dercelik açının sinüs, kosinüs, tanjant ve<br />

kotanjant değerleri */<br />

#include


06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

ÇIKTI<br />

#include <br />

#define PI 3.141593<br />

int main()<br />

{<br />

double aci = 30.0;<br />

aci *= PI/180.0; /* radyana çevir */<br />

puts("30 derecenin");<br />

printf("sinusu : %lf\n", sin(aci));<br />

printf("kosinusu : %lf\n", cos(aci));<br />

printf("tanjanti : %lf\n", tan(aci));<br />

printf("kotanjanti: %lf\n", 1.0/tan(aci));<br />

return 0;<br />

}<br />

30 derecenin<br />

sinusu : 0.500000<br />

kosinusu : 0.866025<br />

tanjanti : 0.577350<br />

kotanjanti: 1.732051<br />

5.2 Standart Kütüphane Fonksiyonları (stdlib.h)<br />

Standart kütüphanede, programı sonlandıran, dinamik bellek yönetiminde kullanılan veya<br />

rastgele sayı üretme vb. işlevleri yerine getiren bir çok fonksiyon mevcuttur. Bu kısımda,<br />

bunlardan bir kaçı Tablo 5.2'de listelenmiştir.<br />

Tablo 5.2: stdlib.h kütüphanesinde tanımlı bazı fonksiyonlar<br />

Fonksiyon<br />

Bildirimi<br />

int atoi(const<br />

char *s);<br />

long atol(const<br />

char *s);<br />

double atof(const<br />

char *s);<br />

void<br />

durum);<br />

exit(int<br />

int rand(void);<br />

max(a,b)<br />

Açıklama Örnek Sonuç<br />

Bir karakter topluluğunu tamsayıya<br />

atoi("-12345")<br />

çevirir<br />

-12345<br />

Bir karakter topluluğunu uzun<br />

tamsayıya çevirir<br />

Bir karakter topluluğunu gercel<br />

atof("-123.546")<br />

sayıya çevirir<br />

-123.456<br />

Programı sonlandırarak kontrolü<br />

exit(1)<br />

işletim sistemine geri verir.<br />

-<br />

0 ile RAND_MAX arasında rastgele<br />

sayı<br />

üretir.<br />

rand() 50485132<br />

RAND_MAX, stdlib.h içinde<br />

atol("1234567890") 1234567890<br />

tanımlanmış bir sembolik sabittir<br />

stdlib.h'de tanımlanmış iki<br />

sayıdan en büyüğünü bulan makro max(5, 9) 9


min(a,b)<br />

fonksiyon<br />

stdlib.h'de tanımlanmış iki<br />

sayıdan en küçüğünü bulan makro<br />

fonksiyon<br />

min(5, 9) 5<br />

Program 5.2: rand() fonksiyonu kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

ÇIKTI<br />

/* 05prg02.c<br />

0-100 arasında 10 tane rasgele sayı üretir */<br />

#include <br />

#include <br />

int main()<br />

{<br />

int i, ri;<br />

for(i=1; i


isdigit(c) c bir rakam ise 0 dan farklı, değilse 0 gönderir isdigit('4') 2<br />

islower(c) c a-z arasında ise 0 dan farklı, değilse 0 gönderir islower('P') 0<br />

isupper(c) c A-Z arasında ise 0 dan farklı, değilse 0 gönderir islower('P') 4<br />

c sayısı ile verilen ASCII koda sahip karakteri elde<br />

toascii(c)<br />

toascii(65) A<br />

eden makro<br />

tolower(c) c karakterini küçük harfe çevirir tolower('D') d<br />

toupper(c) c karakterini büyük harfe çevirir toupper('b') B<br />

Program 5.3: ctype.h kütüphansinde bulunan bazı makroların kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

ÇIKTI<br />

/* 05prg03.c<br />

ASCII kodları 32-127 arasında olan<br />

karakterler üzerinde<br />

ctype.h kütüphanesinde tanımlı bazı<br />

makroların kullanımı */<br />

#include <br />

#include <br />

int main(void)<br />

{<br />

int i;<br />

char c;<br />

for(i=32; i


55 7 7 1<br />

56 8 8 1<br />

57 9 9 1<br />

58 : : 0<br />

59 ; ; 0<br />

60 < < 0<br />

61 = = 0<br />

62 > > 0<br />

63 ? ? 0<br />

64 @ @ 0<br />

65 A a 0<br />

66 B b 0<br />

67 C c 0<br />

68 D d 0<br />

69 E e 0<br />

70 F f 0<br />

71 G g 0<br />

72 H h 0<br />

73 I i 0<br />

74 J j 0<br />

75 K k 0<br />

76 L l 0<br />

77 M m 0<br />

78 N n 0<br />

79 O o 0<br />

80 P p 0<br />

81 Q q 0<br />

82 R r 0<br />

83 S s 0<br />

84 T t 0<br />

85 U u 0<br />

86 V v 0<br />

87 W w 0<br />

88 X x 0<br />

89 Y y 0<br />

90 Z z 0<br />

91 [ [ 0<br />

92 \ \ 0<br />

93 ] ] 0<br />

94 ^ ^ 0<br />

95 _ _ 0<br />

96 ` ` 0<br />

97 a a 0<br />

98 b b 0<br />

99 c c 0<br />

100 d d 0<br />

101 e e 0<br />

102 f f 0<br />

103 g g 0<br />

104 h h 0<br />

105 i i 0<br />

106 j j 0<br />

107 k k 0<br />

108 l l 0<br />

109 m m 0<br />

110 n n 0<br />

111 o o 0<br />

112 p p 0<br />

113 q q 0<br />

114 r r 0<br />

115 s s 0<br />

116 t t 0<br />

117 u u 0<br />

118 v v 0<br />

119 w w 0<br />

120 x x 0<br />

121 y y 0<br />

122 z z 0<br />

123 { { 0


124 | | 0<br />

125 } } 0<br />

126 ~ ~ 0<br />

<strong>Ders</strong> 6: Karşılaştırma Deyimleri<br />

• <strong>Giriş</strong><br />

• 6.1 Karşılaştırma Operatörleri ve Mantıksal Operatörler<br />

• 6.2 if, if-else Yapısı<br />

• 6.3 switch - case Yapısı<br />

• 6.4 ? Karşılaştırma Operatörü<br />

<strong>Giriş</strong><br />

Program içerisinde bazen iki veya daha fazla değerin karşılaştırılması gerekebilir. Bunun için,<br />

bütün programlama dillerinde karşılaştırma deyimleri mevcuttur. C dili, if, switch ve ?<br />

olmak üzere üç tip karşılaştırma işlemi yapmaya izin verir. Ancak ? bir operatördür. if<br />

karşılaştırma deyimi ile, diğer programlama dilinde olduğu gibi if-else yapısı da kurulabilir.<br />

switch deyimi, bir değişkenin içeriğine göre program akışını yönlendirir.<br />

6.1 Karşılaştırma Operatörleri ve Mantıksal Operatörler<br />

Tablo 6.1'de listelenen Karşılaştırma Operatörleri, sayısal değerleri veya karakterleri<br />

mukayese etmek için kullanılır.<br />

Tablo 6.1: Karşılaştırma Operatörleri<br />

Operatör Açıklama Örnek Anlamı<br />

> büyüktür x > y x, y den büyük mü?<br />

< küçüktür x < y x, y den küçük mü?<br />

== eşittir x == y x, y ye eşit mi?<br />

>= büyük-eşittir x >= y x, y den büyük yada eşit mi?<br />


C dilinde, bir mantıksal işlemin sonucu tamsayı 0 (sıfır) veya başka bir değer olur. 0 olumsuz<br />

0'dan farklı değerler olumlu olarak yorumlanır. Buna göre, aşağıdaki program parçasının<br />

...<br />

int x = 1, y = 2, s, u, z;<br />

s = 2 > 1;<br />

u = x > 3;<br />

z = x 0;<br />

printf("%d\t%d\t%d", s, u, z);<br />

...<br />

çıktısı:<br />

1 0 1<br />

şeklinde olur. Bunun nedeni:<br />

• 2 her zaman 1 den büyük olduğu için s değişkenine 1,<br />

• x = 1 < 3 olduğu için x değişkenine 0,<br />

• z = x 0; eşitliğin sağtarafının sonucu olumlu olduğu için z değişkenine<br />

1 atanır.<br />

6.2 if, if-else Yapısı<br />

Bu deyimler, koşullu işlem yapan deyimlerdir. if ve else tek bir karşılaştırma deyimi olup<br />

else kullanımı isteğe bağlıdır. Eğer bu koşul olumlu ise if den sonraki bölüm yürütülür ve<br />

else den sonraki bölüm atlanır. Koşul olumsuz ise if den sonraki küme atlanır ve eğer varsa,<br />

else den sonraki kümedeki işlemler gerçekleştirilir.<br />

if deyiminin yapının genel biçimi şöyledir:<br />

if(koşul)<br />

{<br />

...<br />

deyimler; (küme)<br />

...<br />

}<br />

if deyimi kullanılırken kümenin başlangıcı ve bitişini gösteren, küme parantezleri<br />

kullanılmasında kullanıcıya bir esneklik sunulmuştur. Eğer if deyiminden sonra icra edilecek<br />

deyimler tek satırdan oluşuyorsa, bu işaretlerin kullanılması zorunlu değildir. Yani, if<br />

deyimden sonra { ve } işaretleri kullanılmamışsa, bu deyimi takip eden sadece ilk satır işleme<br />

konur. Bu durum, else if, else deyimlerinde ve daha sonra işlenecek for ve while gibi<br />

döngü deyimlerinde de geçerlidir.<br />

Buna göre aşağıdaki kullanım<br />

ile<br />

if(x == y){<br />

puts("x ve y esit");<br />

}<br />

if(x == y)<br />

puts("x ve y esit");


eşdeğerdir.<br />

if deyiminin else ile birlikte kullanımı şu şekildedir:<br />

if(koşul){<br />

...<br />

deyimler; (küme1)<br />

...<br />

}<br />

else{<br />

...<br />

deyimler; (küme2)<br />

...<br />

}<br />

Bu yapının kullanılmasına dair bir örnek Program 6.1'de gösterilmiştir. Program, klavyeden<br />

girilen bir tamsayının çift olup olmadığını sınar. Bilindiği gibi, çift sayılar, 2 ile kalansız<br />

bölünebilen sayılardır.<br />

Program 6.1: if-else deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

/* 06prg01.c<br />

Klavyeden girilen bir sayının çift olup<br />

olmadığını sınar. */<br />

#include <br />

int main()<br />

{<br />

int sayi;<br />

}<br />

ÇIKTI<br />

printf("Bir sayi girin: ");<br />

scanf("%d",&sayi);<br />

if (sayi % 2 == 0)<br />

printf("sayi cifttir.\n");<br />

else<br />

printf("sayi tektir.\n");<br />

return 0;<br />

Bir sayi girin: 3<br />

sayi tektir.<br />

Mantıksal Operatörler kullanarak birden çok karşılaştırma birleştirilebilir. Buna iyi bir örnek<br />

Program 6.2'de gösterilmiştir. Program, bir yılın artık yıl olup olmadığını sınar. Bir yıl içinde,<br />

Şubat ayı 29 gün olursa o yıl artık yıl olarak adlandırılır. Artık yıl peryodik olarak 4 yılda bir<br />

gelir. Genel kanı "bir yıl 4 ile tam bölünebirse o yıl artık yıldır" şeklindedir. Fakat 1996 artık<br />

yıl iken 1800 artık yıl değildir. Genel sorgulama söyle olmalıdır: Eğer bir yıl


• 4 ile tam bölünüyorsa VE 100'e tam bölünmüyorsa VEYA<br />

• 400 'e tam bölünüryorsa<br />

o yıl artık yıldır.<br />

Program 6.2: if-else deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

/* 06prg02.c: Bir yılın artık yil olup<br />

olmadığını sınar. */<br />

#include <br />

void main()<br />

{<br />

int yil;<br />

printf("Bir yil girin: ");<br />

scanf("%d",&yil);<br />

if( yil % 4 == 0 && yil % 100 != 0 || yil %<br />

400 == 0 )<br />

printf("%d artik yil\n",yil);<br />

}<br />

ÇIKTI<br />

else<br />

printf("%d artik yil degil\n",yil);<br />

Bir yil girin: 1996<br />

1996 artik yil<br />

Eğer program içinde kullanılacak koşulların sayısı ikiden çok ise aşağıdaki yapı kullanılır:<br />

if(koşul_1)<br />

{<br />

...<br />

deyimler; (küme_1)<br />

...<br />

}<br />

else if(koşul_2)<br />

{<br />

...<br />

deyimler; (küme_2)<br />

...<br />

}<br />

.<br />

.<br />

.<br />

else if(koşul_n-1)<br />

{<br />

...<br />

deyimler; (küme_n-1)<br />

...<br />

}<br />

else


{<br />

}<br />

...<br />

deyimler; (küme_n)<br />

...<br />

Program 6.3, ax 2 + bx + c = 0 formundaki ikinci dereceden bir polinomun köklerini<br />

hesaplamaktadır. Programda delta değerinin sıfırdan küçük olması durumda köklerin<br />

karmaşık sayıya dönüşeceğide göz önüne alınmıştır. Bu program if, else if ve else yapısı<br />

göstermek için klasik bir örnektir.<br />

Program 6.3: if, else if, else yapısı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

/* 06prg03.c:<br />

ax*x + bx + c = 0 denkleminin (karmaşık<br />

sayılı kökler dahil) çözümü */<br />

#include <br />

#include <br />

int main()<br />

{<br />

float a, b, c, delta, x1, x2, x, kok_delta;<br />

printf("a, b, c degerlerini girin:\n");<br />

scanf("%f %f %f",&a,&b,&c);<br />

delta = b*b - 4.0*a*c;<br />

if( delta > 0.0 ){<br />

x1 = ( -b + sqrt(delta) )/( 2.0*a );<br />

x2 = ( -b - sqrt(delta) )/( 2.0*a );<br />

printf("\nReel kokler:");<br />

printf("\nx1 = %f",x1);<br />

printf("\nx2 = %f",x2);<br />

}<br />

else if( delta < 0.0 ){<br />

kok_delta = ( sqrt(-delta) ) / (2.0*a);<br />

x = -0.5*b/a;<br />

printf("\nKarmasik kokler:");<br />

printf("\nx1 = %f + (%f)i", x,<br />

kok_delta);<br />

printf("\nx2 = %f - (%f)i", x,<br />

kok_delta);<br />

}<br />

else{<br />

x = -0.5*b/a;<br />

}<br />

printf("\nKokler eşit:");<br />

printf("\nx1 = x2 = %f",x);<br />

}<br />

return 0;<br />

ÇIKTI


a, b, c degerlerini girin:<br />

2 4 -8<br />

Reel kokler:<br />

x1 = 1.236068<br />

x2 = -3.236068<br />

ÇIKTI<br />

a, b, c degerlerini girin:<br />

1 1 1<br />

Karmasik kokler:<br />

x1 = -0.500000 + (0.866025)i<br />

x2 = -0.500000 - (0.866025)i<br />

6.3 switch - case Yapısı<br />

Bu deyim bir değişkenin içeriğine bakarak, programın akışını bir çok seçenekten birine<br />

yönlendirir. case (durum) deyiminden sonra değişkenin durumu belirlenir ve takip eden gelen<br />

satırlar (deyimler) işleme konur. Bütün durumların aksi söz konu olduğunda<br />

gerçekleştirilmesi istenen deyimler default deyiminden sonraki kısımda bildirilir. Genel<br />

yazım biçimi:<br />

switch(değişken)<br />

{<br />

case sabit1:<br />

...<br />

deyimler;<br />

...<br />

case sabit2:<br />

...<br />

deyimler;<br />

...<br />

.<br />

.<br />

.<br />

case sabitn:<br />

...<br />

deyimler;<br />

...<br />

default:<br />

...<br />

hata deyimleri veya varsayılan deyimler;<br />

...<br />

}<br />

Program Program 6.4'te switch deyiminin basit bir kullanımı gösterilmiştir.<br />

Program 6.4: switch-case yapısının kullanımı<br />

01:<br />

02:<br />

03:<br />

/* 06prg04.c: switch - case yapısının kullanımı<br />

*/


04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

ÇIKTI<br />

#include <br />

int main(void)<br />

{<br />

char kr;<br />

printf("Lutfen bir karakter girin\n");<br />

kr = getchar(); /* tek bir karakterin<br />

okunması */<br />

switch (kr)<br />

{<br />

case 'a':<br />

printf("a harfine bastiniz\n");<br />

case 'b':<br />

printf("b harfine bastiniz\n");<br />

default:<br />

printf("a veya b ye basmadiniz\n");<br />

}<br />

return 0;<br />

}<br />

Lutfen bir karakter girin<br />

a<br />

a harfine bastiniz<br />

b harfine bastiniz<br />

a veya b ye basmadiniz<br />

ÇIKTI<br />

Lutfen bir karakter girin<br />

b<br />

b harfine bastiniz<br />

a veya b ye basmadiniz<br />

ÇIKTI<br />

Lutfen bir karakter girin<br />

k<br />

a veya b ye basmadiniz<br />

ÇIKTI<br />

Lütfen bir karakter girin<br />

c<br />

a veya b ye basmadiniz<br />

Programda, klavyeden okunan tek bir karakter değişkenin içeriğine bakılıp uygun dallanmalar<br />

yaptırılmıştır. 11. satırda değişken getchar() fonksiyonu ile okutulmuştur. Eğer 'a' veya<br />

'b' karakterlerinden biri girilirse, ekrana bu harflerin girildiğine dair mesaj yazılacak, aksi


takdirde bu karakterin dışında bir karakterin giriş olarak kullanıldığı gösteren bir mesaj<br />

yazılacaktır. Örneğin 'c' karakteri klavyeden girilmiş ise a veya b ye basmadiniz gibi.<br />

Fakat 'a' karakterleri girildiğinde ekrana her üç durumda yazdırılmaktadır. Bunun sebebi,<br />

case 'a': durumunda sırasıyla 16, 18 ve 20. satırların işleme konmasıdır. Bunu engellemek<br />

için 16. satırdan sonra programın başka bir yere yönlendirilmesi gerekir. Bu yönlendirme<br />

break deyimi ile yapılır. Derleyici bu deyim ile karşılaştığında, bulunduğu yapının içinden<br />

koşulsuz olarak ayrılır ve takip eden işleme başlar.<br />

Program 6.4'te case 'a': durumu için 16, 18 ve 20. satırlar da işleme konumuştu. Eğer<br />

klavyeden 'a' karakterini girip ekrana sadece a harfine bastiniz iletisi yazdırılmak<br />

isteniyorsa, 20. satıra break deyimi ilave edilmelidir. break deyiminin kullanımı Program<br />

6.5'te gösterilmiştir.<br />

Program 6.5: switch-case yapısı ve break kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

ÇIKTI<br />

/* 06prg05.c: switch - case yapısı ve break<br />

kullanımı */<br />

#include <br />

int main(void)<br />

{<br />

char kr;<br />

printf("Lutfen bir karakter girin\n");<br />

kr = getchar(); /* tek bir karakterin<br />

okunması */<br />

return 0;<br />

}<br />

switch (kr)<br />

{<br />

case 'a':<br />

printf("a harfine bastiniz\n");<br />

break;<br />

case 'b':<br />

printf("b harfine bastiniz\n");<br />

break;<br />

default:<br />

printf("a veya b ye basmadiniz\n");<br />

break;<br />

}<br />

Lutfen bir karakter girin<br />

a<br />

a harfine bastiniz<br />

ÇIKTI<br />

Lutfen bir karakter girin<br />

k


a veya b ye basmadiniz<br />

Program 6.6 switch-case yapısın farklı bir kullanımı ile ilgili bir örnektir. Programda, önce<br />

iki sayı isteniyor ardından yapılan seçimle bu sayıların toplamı, farkı, çarpımı veya oranı<br />

ekrana yazdırılıyor.<br />

Program 6.6: switch-case yapısı ve break kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

/* 06prg06.c: switch-case yapısı */<br />

#include <br />

#include <br />

int main(void)<br />

{<br />

int secim;<br />

float x,y, sonuc;<br />

}<br />

ÇIKTI<br />

printf("Iki sayi girin: ");<br />

scanf("%f %f",&x,&y);<br />

puts("*** Menu ***");<br />

puts("[1] Toplama");<br />

puts("[2] Cikarma");<br />

puts("[3] Carpma");<br />

puts("[4] Bolme");<br />

printf("Seciminiz: ");<br />

scanf("%d",&secim);<br />

switch( secim )<br />

{<br />

case 1:<br />

sonuc = x + y;<br />

printf("Toplam = %f\n",sonuc);<br />

break;<br />

case 2:<br />

sonuc = x-y;<br />

printf("Fark = %f\n",sonuc);<br />

break;<br />

case 3:<br />

sonuc = x * y;<br />

printf("Carpim = %f\n",sonuc);<br />

break;<br />

case 4:<br />

sonuc = x/y;<br />

printf("Oran = %f\n",sonuc);<br />

break;<br />

default:<br />

puts("Yanlis secim !\a");<br />

}<br />

return 0;<br />

Iki sayi girin: 3 8


*** Menu ***<br />

[1] Toplama<br />

[2] Cikarma<br />

[3] Carpma<br />

[4] Bolme<br />

Seciminiz: 1<br />

Toplam = 11.000000<br />

ÇIKTI<br />

Iki sayi girin: 3 8<br />

*** Menu ***<br />

[1] Toplama<br />

[2] Cikarma<br />

[3] Carpma<br />

[4] Bolme<br />

Seciminiz: 7<br />

Yanlis secim !<br />

switch-case yapısı if-else yapısının bir alternatifidir. Yani, Program 6.6'daki switchcase<br />

kısmı, if-else yapısı ile de aşağıdaki gibi yazılabilirdi. İnceleyiniz.<br />

switch( secim )<br />

{<br />

case 1:<br />

sonuc = x + y;<br />

printf("Toplam =<br />

%f\n",sonuc);<br />

break;<br />

case 2:<br />

sonuc = x-y;<br />

printf("Fark =<br />

%f\n",sonuc);<br />

break;<br />

case 3:<br />

sonuc = x * y;<br />

printf("Carpim =<br />

%f\n",sonuc);<br />

break;<br />

case 4:<br />

sonuc = x/y;<br />

printf("Oran =<br />

%f\n",sonuc);<br />

break;<br />

!\a");<br />

}<br />

default:<br />

puts("Yanlis<br />

secim<br />

if(secim == 1){<br />

sonuc = x + y;<br />

printf("Toplam =<br />

%f\n",sonuc);<br />

}<br />

else if(secim == 2){<br />

sonuc = x-y;<br />

printf("Fark =<br />

%f\n",sonuc);<br />

}<br />

else if(secim == 3 ){<br />

sonuc = x * y;<br />

printf("Carpim =<br />

%f\n",sonuc);<br />

}<br />

else if(secim == 4){<br />

sonuc = x/y;<br />

printf("Oran =<br />

%f\n",sonuc);<br />

}<br />

else{<br />

!\a");<br />

}<br />

puts("Yanlis<br />

secim<br />

6.4 ? Karşılaştırma Operatörü<br />

Bu operatör, if-else karşılaştırma deyiminin yaptığı işi sınırlı olarak yapan bir operatördür.<br />

Genel yazım biçimi:<br />

(koşul) ? deyim1 : deyim2;


İlk önce koşul sınanır. Eğer koşul olumluysa deyim1 aksi takdirde deyim2 değerlendirilir.<br />

deyim1 ve deyim2 de atama işlemi yapılamaz. Ancak koşul deyiminde atama işlemi<br />

yapılabilir. deyim1 ve deyim2 yerine fonksiyon da kullanılabilir. Aşağıda bu deyimin<br />

kullanımına ait örnekler verilmiştir.<br />

x = ( a > b ) ? a : b;<br />

Yukarıdaki ifadede koşul a'nın b'den büyük olmasıdır. Eğer olumluysa x adlı değişkene a,<br />

değilse b değeri atanır. Bu şekilde kullanım if-else yapısı ile kurulmak istenirse:<br />

if( a > b ) x = a;<br />

else x = b;<br />

şeklinde olacaktır. Program 6.7 ? karşılaştırma operatörünün basit bir kullanımını<br />

göstermektedir.<br />

Program 6.7: ? ve if kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

ÇIKTI<br />

/* 06prg07.c: ? ve if-else yapısının kullanımı<br />

*/<br />

#include <br />

int main(void)<br />

{<br />

float x, y, z;<br />

printf("x : "); scanf("%f",&x);<br />

printf("y : "); scanf("%f",&y);<br />

if(y)<br />

/* y, 0'dan<br />

farklı mı? */<br />

z = ( y > x ) ? x/y : x*y; /* y>x ise z<br />

= x/y, değilse z = x*y */<br />

else<br />

z = 0.0;<br />

printf("z = %f\n",z);<br />

return 0;<br />

}<br />

x : 3<br />

y : 5<br />

z = 0.600000<br />

ÇIKTI<br />

x : 11<br />

y : 0<br />

z = 0.000000


12. satırdaki if deyimindeki koşul biraz farklıdır. Genel olarak koşul bu şekilde bildirilirse,<br />

koşulun 0 dan farklı olup olmadığı sınanır. Yani:<br />

if(y)<br />

ile<br />

if( y != 0 )<br />

aynı anlamdadır.<br />

Bu kullanım çok yagındır. Eğer y, 0 dan farklı ise koşul olumlu olarak değerlendirilecektir.<br />

13. satırda ? ile bir sınama yapılmaktadır. Eğer y, x den büyük ise z değişkenine x/y, aksi<br />

takdirde x*y değeri atanmaktadır. Eğer y = 0 ise z değişkenine 0 değeri atanmaktadır.<br />

<strong>Ders</strong> 7: Döngüler<br />

• <strong>Giriş</strong><br />

• 7.1 while Döngüsü<br />

• 7.2 do ... while Döngüsü<br />

• 7.3 for Döngüsü<br />

• 7.4 İç içe Geçmiş Döngüler<br />

• 7.5 Sonsuz Döngü<br />

• 7.6 break Deyimi<br />

• 7.7 continue Deyimi<br />

<strong>Giriş</strong><br />

Döngü (loop) deyimleri, bir kümenin belli bir koşul altında tekrar edilmesi için kullanılır. C<br />

programlama dilinde, while, do...while ve for olmak üzere üç tip döngü deyimi vardır.<br />

Diğer programlama dillerinde olduğu gibi, bu deyimlerle istenildiği kadar iç-içe döngü yapısı<br />

kullanılabilir.<br />

7.1 while Döngüsü<br />

Tekrarlama deyimidir. Bir küme ya da deyim while kullanılarak bir çok kez yinelenebilir.<br />

Yinelenmesi için koşul sınaması döngüye girilmeden yapılır. Koşul olumlu olduğu sürece<br />

çevrim yinelenir. Bu deyimin kullanımı Program 7.1 de gösterilmiştir. Genel yazım biçimi:<br />

while(koşul)<br />

{<br />

...<br />

döngüdeki deyimler; [küme]<br />

...<br />

}


Program 7.1: while döngüsü<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

ÇIKTI<br />

/* 07prg01.c: while döngüsü */<br />

#include <br />

main()<br />

{<br />

int x=0;<br />

while(x


03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

ÇIKTI<br />

#include <br />

main()<br />

{<br />

int sayi;<br />

do<br />

{<br />

printf("Bir sayi girin : ");<br />

scanf("%d",&sayi);<br />

printf("iki kati : %d\n",2*sayi);<br />

}while( sayi>0 ); /* koşul */<br />

puts("Döngü sona erdi.");<br />

return 0;<br />

}<br />

Bir sayi girin : 1<br />

iki kati : 2<br />

Bir sayi girin : 3<br />

iki kati : 6<br />

Bir sayi girin : 4<br />

iki kati : 8<br />

Bir sayi girin : -3<br />

iki kati : -6<br />

Cevrim sona erdi.<br />

15. satırdaki koşul olumlu olduğu sürece (sayi>0 olduğu sürece), klavyeden yeni bir değer<br />

12. satırda okunur. Aksi takdirde (sayi


02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

*/<br />

ÇIKTI<br />

#include <br />

int main()<br />

{<br />

long i, n, faktor;<br />

printf("Faktoriyeli hesaplanacak sayi girin :<br />

");<br />

scanf("%ld",&n);<br />

faktor=1;<br />

for(i=1; i


01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

ÇIKTI<br />

/* 07prg04.c: Sayı sistemi<br />

%d : desimal 10 tabanındaki sayı<br />

%o : oktal 8 tabanındaki sayı<br />

%x : hexadesimal 16 tabanındaki sayı (küçük<br />

harf)<br />

%X : hexadesimal 16 tabanındaki sayı (büyük<br />

harf) */<br />

#include <br />

int main()<br />

{<br />

int i;<br />

for (i=0; i


05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

ÇIKTI<br />

= 3^3 + 7^3 + 1^3.<br />

Bu program İç-içe geçmiş 3 döngü ile bütün<br />

Aramstrong sayıları bulur. */<br />

#include <br />

int main()<br />

{<br />

int a,b,c, kup, sayi, k=1;<br />

for(a=1; a


for döngüsünde, başlangıç, koşul ve artım parametrelerinden herhangi birini kullanmak<br />

isteğe bağlıdır. Her hangi biri verilmediğinde döngünün nasıl davranacağı iyi<br />

yorumlanmalıdır. Örneğin for döngüsünün hiçbir parametresi verilmezse, döngü sonsuz<br />

çevrime girer. Yani:<br />

gibi.<br />

for(;;)<br />

printf("Sonsuz döngü içindeyim...\n");<br />

7.6 break Deyimi<br />

Bir C programında, bir işlem gerçekleştirilirken, işlemin sona erdirilmesi bu deyim ile yapılır.<br />

Örneğin, döngü deyimleri içindekiler yürütülürken, çevrimin, koşuldan bağımsız kesin olarak<br />

sonlanması gerektiğinde bu deyim kullanılır. Mesela:<br />

...<br />

do{<br />

scanf("%d",&x);<br />

}while(1);<br />

...<br />

if(x==0) break;<br />

printf("%f",1.0/x);<br />

Yukarıdaki program parçasında, do ... while döngüsündeki koşul daima olumludur. Bu<br />

durumda döngü sonsuzdur. Fakat döngü içinde if deyimindeki koşul gerçekleşirse, döngü<br />

koşuluna bakılmaksızın terkedilir. Bu işlemi sağlayan break deyimidir.<br />

Program 7.6 klavyeden girilen sayı pozitif olduğu sürece sayının faktoriyelini hesaplar. Sayı<br />

negatif olduğunda döngü break ile sonlandırılır. Inceleyiniz.<br />

Program 7.6: break deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

/* 07prg06.c: n>=0 olduğu sürece n! değerini<br />

hesaplar */<br />

#include <br />

int main()<br />

{<br />

long int i,n,faktor;<br />

while(1) /* sonsuz döngü */<br />

{<br />

printf("Faktoriyeli hesaplanacak sayi<br />

girin : ");<br />

scanf("%ld",&n);<br />

if(n


20:<br />

21:<br />

22:<br />

23:<br />

ÇIKTI<br />

}<br />

return 0;<br />

}<br />

printf("%ld! = %ld\n",n,faktor);<br />

Faktoriyeli hesaplanacak sayi girin : 2<br />

2! = 2<br />

Faktoriyeli hesaplanacak sayi girin : 3<br />

3! = 6<br />

Faktoriyeli hesaplanacak sayi girin : 5<br />

5! = 120<br />

Faktoriyeli hesaplanacak sayi girin : 9<br />

9! = 362880<br />

Faktoriyeli hesaplanacak sayi girin : 0<br />

0! = 1<br />

Faktoriyeli hesaplanacak sayi girin : -4<br />

7.7 continue Deyimi<br />

Bir döngü içerisinde continue deyimi ile karşılaşılırsa, ondan sonra gelen deyimler atlanır ve<br />

döngü bir sonraki çevrime girer. Örneğin:<br />

...<br />

for(x=-50;i


06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

ÇIKTI<br />

#include <br />

int main()<br />

{<br />

int x,y,k=1;<br />

for (x=-3;x


<strong>Giriş</strong><br />

C Programlama Dili fonksiyon olarak adlandırılan alt programların birleştirilmesi kavramına<br />

dayanır. Bir C programı bir yada daha çok fonksiyonun bir araya gelmesi ile oluşur. Bu<br />

özellik bütün Yapısal Diller'in (C, Fortran, Pascal, ...) temelini oluşturur. Yapısal Diller'e<br />

hakim olmak için fonksiyon oluşturmayı ve kullanmayı iyi öğrenmek gerekir.<br />

Bu bölümde, C Programlama Dili'ndeki fonksiyon kavramı, sonraki bölümde (Bölüm 9) esnek<br />

argümanlı fonksiyonlar ve main() fonksiyonu irdelenecektir.<br />

8.1 Fonksiyon Kavramı<br />

Fonksiyon, belirli sayıda verileri kullanarak bunları işleyen ve bir sonuç üreten komut<br />

grubudur. Her fonksiyonun bir adı ve fonksiyona gelen değerleri gösteren argumanları<br />

(bağımsız değişkenleri) vardır. Genel olarak bir fonksiyon Şekil 8.1'deki gibi bir kutu ile<br />

temsil edilir:<br />

Şekil 8.1:Bir fonksiyonun kutu gösterimi<br />

Fonksiyonların girdilerine parametreler yada argumanlar denir. Bir fonksiyon bu<br />

parametreleri alıp bir işleme tabi tutar ve bir değer hesaplar. Bu değer, çıktı veya geri dönüş<br />

değeri (return value) olarak adlandırılır. Unutmayın ki, bir fonksiyonun kaç girişi olursa olsun<br />

sadece bir çıkışı vardır.<br />

C Programlama Dili, kullanıcısına bu türden fonksiyon yazmasına izin verir. C dilinde<br />

hazırlanan bir fonksiyonun genel yapısı şöyledir:<br />

FonksiyonTipi FonksiyonAdı(argüman listesi)<br />

argumanların tip bildirimleri<br />

{<br />

Yerel değişkenlerin bildirimi<br />

...<br />

fonksiyon içindeki deyimler veya diğer fonksiyonlar<br />

...<br />

return geri dönüş değeri;<br />

}<br />

Örneğin iki sayının toplamının hesaplayacak bir fonksiyon şöyle tanımlanabilir:


* klasik biçim */<br />

int topla(x,y)<br />

int x,y<br />

{<br />

int sonuc;<br />

sonuc = x + y;<br />

return sonuc;<br />

}<br />

veya<br />

/* modern biçim */<br />

int topla(int x,int y)<br />

{<br />

int sonuc;<br />

sonuc = x + y;<br />

return sonuc;<br />

}<br />

veya<br />

/* modern biçim */<br />

int topla(int x,int y)<br />

{<br />

return (x+y);<br />

}<br />

Bu örnekte, fonksiyonun kimlik kartı! ve kutu gösterimi şöyledir:<br />

• Fonksiyon tipi: int<br />

• Fonksiyon adı : topla<br />

• parametreler : x ve y<br />

• geri dönüş değeri: x+y<br />

Her üç program parçasında da return (geri dönüş) deyimi kullanılmaktadır. Bu deyim C<br />

programlama dilinin anahtar sözcüklerinden biridir ve fonksiyon içerisinde sonucu, kendisini<br />

çağıran yere göndemek için kullanılır. Yani topla fonksiyonu herhangi bir programın<br />

içerisinde kullanıldığında, fonksiyonun üreteceği sonuç return deyiminden sonra belirtilen<br />

değişken veya işlem olacaktır. Örneğin fonksiyon:<br />

...<br />

int t;<br />

...<br />

t = topla(9,6);<br />

...<br />

şeklinde kullanılırsa, t değişkenine 9+6=15 değeri atanır. topla() fonksiyonunun kullanımı<br />

Program 8.1'in üzerinde açıklanmıştır.<br />

8.2 Fonksiyon Bildirimi<br />

Bir fonksiyonun bildirimi iki türlü yapılır:<br />

1. Ana programdan önce:<br />

2. ...


3. int topla(int x,int y) /* fonksiyon */<br />

4. {<br />

5. ...<br />

6. }<br />

7. ...<br />

8. main()<br />

9. {<br />

10. ...<br />

11. }<br />

12. Ana programdan sonra: Bu durumda fonksiyon örneği (function prototype) ana<br />

programdan önce bildirilmelidir.<br />

13. ...<br />

14. int topla(int x, int y); /* fonksiyon örneği */<br />

15. ...<br />

16. main()<br />

17. {<br />

18. ...<br />

19. }<br />

20. ...<br />

21. int topla(int x, int y) /* fonksiyon */<br />

22. {<br />

23. ...<br />

24. }<br />

Bir C programı içinde, yazmış olduğunuz fonksiyonlar genellikle bu iki tipte kullanılır. İkinci<br />

kullanımda fonksiyon prototipi mutlaka bildirilmelidir. Aksi halde bir hata mesajı ile<br />

karşılaşılır. Fonksiyon prototipinde arguman isimlerinin yazılması zorunlu değildir. Sadece<br />

arguman tiplerini belirtmek de yeterlidir. Yukarıdaki topla fonksiyona ait prototip:<br />

int topla(int x, int y);<br />

şekinde yazılabileği gibi<br />

int topla(int, int);<br />

şeklinde de yazılabilir.<br />

Buraya kadar anlatılanlar Program 8.1 üzeride özetlenmiştir.<br />

Program 8.1: topla fonksiyonunun ana programda kullanılması<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

/* 08prg01.c: iki sayıyı toplar ve sonucu<br />

ekranda gösterir */<br />

#include <br />

int topla(int, int); /*** fonksiyon prototipi<br />

***/<br />

int main()<br />

{<br />

int toplam,a,b;<br />

printf("Iki sayi girin : ");<br />

scanf("%d %d",&a,&b);<br />

/* fonksiyon çağırılıp, a ve b değerleri<br />

parametre olarak aktarılıyor.<br />

topla(a,b) = a + b değeri toplam<br />

değişkenine atanması */<br />

toplam = topla(a,b);


21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

printf("%d ve %d nin toplami %d dir.\n",<br />

a,b,toplam);<br />

}<br />

ÇIKTI<br />

return 0;<br />

/*** fonksiyon tanımlanması ***/<br />

/* Bu fonksiyon iki tamsayıyı toplar */<br />

int topla( int x, int y )<br />

{<br />

int sonuc;<br />

sonuc = x + y;<br />

return sonuc;<br />

}<br />

Iki sayi girin : 5 12<br />

5 ve 12 nin toplami 17 dir.<br />

Programda, klavyeden okunan a ve b değişkenleri fonksiyonuna parametre olarak<br />

aktarılmıştır. Bu değişkenlerin isimleri ile topla fonksiyonunda kullanılan değişkenlerin (x<br />

ve y) isimleri aynı olması zorunlu değildir. Burara a ve b değişkenleri sırasıyla x ve y<br />

değişkenleri yerine konmuştur. 16. satırda toplam adlı tamsayı değişkenine topla<br />

fonksiyonunun dönüş değeri (a + b değeri) atanmıştır.<br />

Belki karmaşık gelmiş olabilir. Fakat Program 8.1 daha kısa şöyle yazılabilirdi:<br />

Program 8.1b: topla fonksiyonunun ana programda kullanılması<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

/* 08prg01b.c: iki sayıyı toplar ve sonucu<br />

ekranda gösterir */<br />

#include <br />

int topla( int x, int y ){<br />

return (x+y);<br />

}<br />

int main(void)<br />

{<br />

int toplam,a,b;<br />

printf("Iki sayi girin : ");<br />

scanf("%d %d",&a,&b);<br />

toplam = topla(a,b);<br />

printf("%d ve %d nin toplami %d dir.\n",<br />

a,b,toplam);<br />

return 0;<br />

}


8.3 Geri Dönüş Değerleri<br />

return anahtar sözcüğünün iki önemli işlevi vardır:<br />

1. fonksiyonun geri dönüş değerini oluşturur<br />

2. fonksiyonu sonlandırır<br />

Bu deyiminden sonra bir değişken, işlem, sabit veya başka bir fonksiyon yazılabilir. Örneğin:<br />

return (a+b/c); /* parantez kullanmak zorunlu değil */<br />

return 10; /* değişken kullanmak mecbur değil */<br />

return topla(a,b)/2.0; /* önce topla fonksiyonu çalışır */<br />

Bir fonksiyonda birden çok geri dönüş değeri kullanılabilir. Fakat, ilk karşılaşılan return<br />

deyiminden sonra fonksiyon sonlananır ve çağrılan yere bu değer gönderilir. Örneğin<br />

aşağıdaki harf fonksiyonunda beş tane return deyimi kullanılmıştır.<br />

char harf(int not)<br />

{<br />

if( not>=0 && not=50 && not=70 && not=80 && not=90 ) return 'A';<br />

}<br />

Bu fonksiyon kendisine parametre olarak gelen 0-100 arasındaki bir notun harf karşılığını<br />

gönderir. Aslında geri gönderilen değer bir tanedir. Eğer bu fonksiyon aşağıdaki gibi<br />

çağrılırsa:<br />

char harfim;<br />

...<br />

harfim = harf(78);<br />

...<br />

harfim değişkenine 'C' değeri (karakteri) atanır.<br />

Program 8.2'de bildirilen artik_yil fonksiyonu, kendisine parametre olarak gelen bir<br />

tamsayıyı yıl bilgisi olarak kabul eder. Eğer yıl artık yıl ise 1 aksi halde 0 gönderir.<br />

Programda iki tane return deyimi kullanıldığına dikkat ediniz. Artık yıl tanımı Bölüm 6'da<br />

verilmişti.<br />

Program 8.2: iki return deyimi kullanan bir fonksiyon<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

/* 08prg02.c: Bir fonksiyonda iki return deyimi<br />

*/<br />

#include <br />

int artik_yil(int); /* fonksiyon prototipi */


08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

void main()<br />

{<br />

int yil;<br />

}<br />

ÇIKTI<br />

printf("Bir yil girin: ");<br />

scanf("%d",&yil);<br />

if( artik_yil(yil) )<br />

printf("%d artik yil\n",yil);<br />

else<br />

printf("%d artik yil degil\n",yil);<br />

/* yil artıl yıl ise 1 aksi halde 0 gönderir */<br />

int artik_yil(int yil)<br />

{<br />

if( yil % 4 == 0 &&<br />

yil % 100 != 0 ||<br />

yil % 400 == 0 ) return 1;<br />

else return 0;<br />

}<br />

Bir yil girin: 1996<br />

1996 artik yil<br />

8.4 void Fonksiyonlar<br />

Bir fonksiyonun her zaman geri dönüş değerinin olması gerekmez. Bu durumda return<br />

deyimi kullanılmayabilir. Eğer bu anahtar kelime yoksa, fonksiyon ana bloğu bitince<br />

kendiliğinden sonlanır. Böyle fonksiyonların tipi void (boş, hükümsüz) olarak belirtilmelidir.<br />

Bu tip fonksiyonlar başka bir yerde kullanılırken, herhangi bir değişkene atanması söz konusu<br />

değildir, çünkü geri dönüş değeri yoktur. Ancak, void fonksiyonlara parametre aktarımı<br />

yapmak mümkündür.<br />

Program 8.3'de void fonksiyona örnek olarak bankamatik fonksiyonu ve kullanımı<br />

gösterilmiştir. Bu fonksiyon kendisine parametre olarak gelen YTL cinsinden para miktarını<br />

20, 10 ve 5 YTL'lik birimler halinde hesaplar. Girilen miktar 5 YTL'nin bir katı değilse,<br />

ekrana uygun bir mesaj gönderir. bankamatik fonksiyonu bir dizi hesap yapmasına rağmen<br />

geriye hiç bir değer göndermez.<br />

Program 8.3: void tipinde bir fonksiyon kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

/* 08prg03.c: Basit bankamatik simulasyonu.<br />

İstenen para miktarını 20, 10 ve 5'lik<br />

birimlere böler<br />

ve sonucu ekrana gösterir. */<br />

#include <br />

void bankamatik(int para)<br />

{


10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

int a,yirmilik,onluk,beslik;<br />

a = para;<br />

if(a%5==0)<br />

{<br />

yirmilik = a/20;<br />

a -= yirmilik*20;<br />

onluk = a/10;<br />

a -= onluk*10;<br />

beslik = a/5;<br />

a -= beslik*5;<br />

printf("\nYirmilik = %d",yirmilik);<br />

printf("\nOnluk = %d",onluk);<br />

printf("\nBeslik = %d\n",beslik);<br />

}<br />

else<br />

printf("Girilen miktar 5 YTL ve katlari<br />

olmali!\a\n");<br />

}<br />

/* return deyimi yok !*/<br />

int main()<br />

{<br />

int miktar;<br />

printf("Cekilecek para miktari (YTL) = ");<br />

scanf("%d",&miktar);<br />

bankamatik(miktar);<br />

değişkene atanmamış ! */<br />

/* fonksiyon bir<br />

}<br />

retrun 0;<br />

ÇIKTI<br />

Cekilecek para miktari = 135<br />

Yirmilik = 6<br />

Onluk = 1<br />

Beslik = 1<br />

ÇIKTI<br />

Cekilecek para miktari = 456<br />

Girilen miktar 5 YTL ve katlari olmali!<br />

void anahtar sözcüğü C'ye sonradan dahil edilmiştir. Standart C'de (ANSI C) bu deyimin<br />

kullanılması zorunlu değildir. Ancak bu deyim okunabilirliği arttırmaktadır. Örneğin:<br />

void bankamatik(int para) bankamatik(int para)<br />

{ {


... ...<br />

} }<br />

şeklindeki kullanımlar geçerli ve aynı anlamdadır.<br />

Başka bir void fonksiyon örneği Program 8.4'de verilmiştir. Programdaki kutu_ciz<br />

fonksiyonu, iki for döngüsü kullanarak 'X' karakterlerinden oluşan basit bir kutu çizimi<br />

yapar. Programda de sadece 18. satır defalarca işleme konur. Program çalıştırıldığında<br />

8*35=280 adet 'X' karakteri ekrana bastırılır. İnceleyiniz.<br />

Program 8.4: basit kutu çizen fonksiyon<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

/* 08prg04.c: Basit bir kutu çizen fonksiyon */<br />

#include <br />

void kutu_ciz( int satir, int sutun )<br />

{<br />

int sut;<br />

for ( ; satir > 0; satir--)<br />

{<br />

for (sut = sutun; sut > 0; sut--)<br />

printf("X");<br />

}<br />

ÇIKTI<br />

}<br />

int main(){<br />

printf("\n");<br />

kutu_ciz(8,35);<br />

return 0;<br />

}<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />

8.5 Fonksiyon Parametreleri<br />

Fonksiyon parametreleri (argümanları) klasik ve modern olmak üzere iki türlü tanımanabilir.<br />

Örneğin aşağıdaki fonksiyon kendisine parametre olarak gelen tamsayının faktoriyelini<br />

gönderir. Bu fonksiyonun parametresi (n):<br />

int faktoriyel(n) /* kalsik biçim */<br />

int n<br />

{


int i=1, f=1;<br />

while(i


Şekil 8.2: Ana programdan alt programların (fonksiyonların) çağırılması.<br />

Fonksiyonu çağırmak için, fonksiyonun adını yazmak yeterlidir.<br />

Fonksiyonların sadece ana program tarafından çağrılması zorunlu değildir. Bir fonksiyon<br />

başka bir fonksiyon tarafından da çağrılabilir. Bu tür kullanıma dair bir örnek Program 8.5'de<br />

verilmiştir. yilin_gunu fonksiyonu, verilen bir tarihin yılın kaçıncı günü olduğunu hesaplar<br />

ve çağrıldığı yere gönderir. İnceleyiniz.<br />

Program 8.5: bir fonksiyonun başka bir fonksiyon tarafından çağrılması<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

/* 08prg05.c: Verilen bir tarihin yılın kaçıncı<br />

günü olduğunu hesaplar. */<br />

#include <br />

int yilin_gunu(int, int, int);<br />

int artik_yil(int);<br />

int main(void)<br />

{<br />

int gun = 1; /* tarih: 01 Ağustos 2003 */<br />

int ay = 8;<br />

int yil = 2003;<br />

printf("%02d %02d %d yilinin\n",gun,ay,yil );<br />

printf("%d. gunudur\n",yilin_gunu(gun,ay,yil)<br />

);<br />

}<br />

return 0;<br />

/* yil artıl yıl ise 1 aksi halde 0 gönderir */<br />

int artik_yil(int yil)<br />

{<br />

if( yil%4==0 && yil%100!=0 || yil%400==0 )<br />

return 1;<br />

else return 0;<br />

}


29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

/* yılın kaçıncı günü olduğunu hesaplar ve o<br />

günü gönderirir */<br />

int yilin_gunu(int gun, int ay, int yil)<br />

{<br />

int ygun = gun;<br />

switch(ay-1)<br />

{<br />

case 12: ygun += 31;<br />

case 11: ygun += 30;<br />

case 10: ygun += 31;<br />

case 9: ygun += 30;<br />

case 8: ygun += 31;<br />

case 7: ygun += 31;<br />

case 6: ygun += 30;<br />

case 5: ygun += 31;<br />

case 4: ygun += 30;<br />

case 3: ygun += 31;<br />

case 2: ygun += 28 + artik_yil(yil); /*<br />

28+1 veya 28+0 */<br />

case 1: ygun += 31;<br />

}<br />

}<br />

return ygun;<br />

ÇIKTI<br />

01 08 2003 yilinin<br />

213. gunudur<br />

8.7 Makro Fonksiyon Tanımlaması<br />

Başlık dosyalarında, bol miktarda makro fonksiyon uygulamalarına rastlanır. Makro<br />

tanımlaması #define önişlemci komutu kullanılarak yapılır. Örneğin aşağıdaki makro<br />

fonksiyonlar geçerlidir.<br />

#define kare(x) (x)*(x)<br />

#define delta(a,b,c) ((b)*(b)-4*(a)(c))<br />

#define yaz() puts("Devam etmek için bir tuşa basın...")<br />

Bu şekilde tanımlanan fonksiyonların kullanımı diğerleri gibidir. Yalnızca programın başında<br />

tanımlanır. Ancak, bu tanımlamalarla fonksiyon bellekte bir yer işgal etmez. Basit bir makro<br />

fonksiyon uygulaması Program 8.6'da gösterilmiştir. buyuk(a,b) makrosu a>b ise a değerini<br />

aksi halde b değerini gönderir.<br />

Program 8.6: Makro fonksiyon uygulaması<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

/* 08prg06.c: makro fonksiyon uygulaması */<br />

#include <br />

#define buyuk(a,b) ( (a>b) ? a:b)


06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

ÇIKTI<br />

int main()<br />

{<br />

int x,y,eb;<br />

printf("iki sayı girin: ");<br />

scanf("%d,%d",&x,&y);<br />

eb = buyuk(x,y);<br />

printf("buyuk olan %d\n",eb);<br />

return 0;<br />

}<br />

iki sayı girin: 8,6<br />

buyuk olan 8<br />

<strong>Ders</strong> 9: Fonksiyonlar II (Alt programlar)<br />

• <strong>Giriş</strong><br />

• 9.1 Esnek Argümanlı Fonksiyonlar<br />

• 9.2 main Fonksiyonu<br />

• 9.3 main Fonksiyonuna Parametre Aktarımı<br />

• 9.4 Komut Satırı Örnekleri<br />

<strong>Giriş</strong><br />

Bu kısımda, esnek argümanlı fonksiyonlar, main() fonksiyonu ve komut satırından main()<br />

fonksiyonuna parametre aktarımı incelenektir.<br />

9.1 Esnek Argümanlı Fonksiyonlar<br />

Aşağıdaki gibi üçüncü dereceden bir polinom düşünelim:<br />

P(x) = a + bx + cx 2 + dx 3<br />

burada a, b, c, d katsayıları gerçel sayı sabitleridir. Bu polinomu temsil eden en basit<br />

fonksiyon şöyle tanımlanabilir.<br />

double p(double x, double a, double b, double c, double d)<br />

{<br />

double p = a + b*x + c*x*x + d*x*x*x;


}<br />

return p;<br />

Buna göre, x = 1.7 için, P(x) = 1 - 2x değerini hesaplamak için bu fonksiyon aşağıdaki gibi<br />

çağırılmalıdır:<br />

sonuc = p(1.7, 1.0, -2.0, 0.0, 0.0);<br />

Burada, kullanılmayan katsayılar için 0.0 değeri mutlaka fonksiyona geçirilmelidir.<br />

Kullanılmayan argumanlar geçirilmeden de fonksiyonu çağırmak mümkündür. C++, Fortran<br />

90 gibi dillerde olduğu gibi, C Programlama Dili, kullanıcılarına argümanları esnek olarak<br />

geçirme imkanı verir. Bunun anlamı, belli kurallar sağlandığında, p() fonksiyonu aşağıdaki<br />

gibi çağrılabilmesidir:<br />

/* x n a b */<br />

sonuc = p(1.7, 2, 1.0, -2.0);<br />

Esnek argümanlar için iki temel kural vardır:<br />

• Esnek argümanlar kullanımı isteğe bağlıdır.<br />

• Esnek argümanları oluşturan küme ardışık olarak listeye eklenmelidir.<br />

Bu türden argümanlar, aşağıdaki gibi, fonksiyonun parametre listesi kısmında ... ile<br />

belirtilir.<br />

double p(double x, int n, ...)<br />

{<br />

}<br />

Esnek Argumanlı Fonksiyon tanımlaması yapabilmek için stdarg.h kütüphanesinde üç tane<br />

makro fonksiyon tanımlanmıştır. Bu fonksiyonlar Tablo 9.1'de listelenmiştir.<br />

Tablo 9.1: stdarg.h'te tanımlı tip ve makro fonksiyonlar<br />

Tip / Fonksiyon Açıklama<br />

va_list ardışık esnek argümalar için tip belirleyici<br />

va_start(ap,<br />

n)<br />

va_arg(ap,<br />

tip)<br />

va_end(ap)<br />

va_list tipinde bildirilmiş ap göstericisi için bellekten n elemanlı yer<br />

ayırır.<br />

Veri tipi tip ile belirlenmiş küme elemanlarına eriştirir.<br />

va_list tipinde bildirilmiş ap göstericisi için bellekten bölgeyi boşaltır.<br />

Bu kurallar ışığında, p() fonksiyonunun genel kullanımı Program 9.1'de gösterilmiştir. p(),<br />

kendisine parametre olarak gelen x, n ve a i katsayılarına göre<br />

P(x,n) = a 0 + a 1 x + a 2 x 2 + ... + a n x n<br />

polinomu hesaplar. a i (i = 0, 1, 2, ..., n) katsayları esnek argüman olarak bildirilmiştir.<br />

Program 9.1: Sonu -1 ile biten kümeyi ekrana yazar<br />

01:<br />

02:<br />

03:<br />

04:<br />

/* 09prg01.c: Polinom hesabı */<br />

#include <br />

#include


05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

50:<br />

51:<br />

52:<br />

53:<br />

54:<br />

55:<br />

56:<br />

57:<br />

58:<br />

59:<br />

60:<br />

61:<br />

62:<br />

#include <br />

/* fonksiyon örneği */<br />

double p(double, int, ...);<br />

int main(void){<br />

double x = 1.7;<br />

printf("x = %lf icin:\n",x);<br />

printf("p(x, 1, 1.0) = %lf\n",<br />

p(x, 1, 1.0));<br />

printf("p(x, 2, 1.0, -2.0) = %lf\n",<br />

p(x, 2, 1.0, -2.0));<br />

printf("p(x, 3, 1.0, -2.0, 0.2) = %lf\n",<br />

p(x, 3, 1.0, -2.0, 0.2));<br />

printf("p(x, 4, 1.0, -2.0, 0.2, 1.1) =<br />

%lf\n",<br />

p(x, 4, 1.0, -2.0, 0.2, 1.1));<br />

printf("p(x, 5, 1.0, -2.0, 0.2, 1.1, -0.6) =<br />

%lf\n",<br />

p(x, 5, 1.0, -2.0, 0.2, 1.1, -0.6));<br />

}<br />

return 0;<br />

/* Verilen x, n ve ai katsayıları için,<br />

P(x,n) = a0 + a1*x + a2*x^2 + ... + an*x^n<br />

polinomu hesaplar.<br />

a0, a1, ..., an katsayları esnek arguman<br />

olarak bildirilmiştir. */<br />

double p(double x, int n, ...)<br />

{<br />

double a, t = 0.0;<br />

int i;<br />

/* arguman göstericisi; ag va_list tipinde */<br />

va_list ag;<br />

/* ag için bellekten n adet hücre ayır */<br />

va_start(ag, n);<br />

for(i=0; i


}<br />

ÇIKTI<br />

x = 1.700000 icin:<br />

p(x, 1, 1.0) = 1.000000<br />

p(x, 2, 1.0, -2.0) = -2.400000<br />

p(x, 3, 1.0, -2.0, 0.2) = -1.822000<br />

p(x, 4, 1.0, -2.0, 0.2, 1.1) = 3.582300<br />

p(x, 5, 1.0, -2.0, 0.2, 1.1, -0.6) = -1.428960<br />

Program 9.2'de, argümanları esnek olarak bildirilmiş topla(int n, ...) fonksiyonu, n tane<br />

tamsayının sayının toplamını hesaplar.<br />

Program 9.2: n tane sayının toplamını hesaplar<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

/* 09prg02.c<br />

n tane sayının toplamının hesaplanması */<br />

#include <br />

#include <br />

int topla(int, ...);<br />

int main(void)<br />

{<br />

printf("topla(2, 11,22)<br />

topla(2, 11,22));<br />

printf("topla(3, 11,22,33)<br />

topla(3, 11,22,33));<br />

printf("topla(4, 11,22,33,44)<br />

topla(4, 11,22,33,44));<br />

= %d\n",<br />

= %d\n",<br />

= %d\n",<br />

printf("topla(5, 11,22,33,44,55) = %d\n",<br />

topla(5, 11,22,33,44,55));<br />

printf("topla(6, 11,22,33,44,55,66) = %d\n",<br />

topla(6, 11,22,33,44,66,66));<br />

return 0;<br />

}<br />

/* Esnek argumanla tanımlanmış n tane tamsayının<br />

sayının<br />

toplamını gönderir */<br />

int topla(int n, ...)<br />

{<br />

va_list ap;<br />

int i, top = 0;<br />

va_start(ap, n);<br />

for (i=1; i


ÇIKTI<br />

topla(2, 11,22) = 33<br />

topla(3, 11,22,33) = 66<br />

topla(3, 11,22,33,44) = 110<br />

topla(5, 11,22,33,44,55) = 165<br />

topla(6, 11,22,33,44,55,66) = 242<br />

Argüman sayısı bilidirilmeden de bir küme üzerinde işlem yapılabilir. Ancak bu durumda<br />

kümenin boyutu başka bir yöntemle hesaplanmalıdır. Program 9.3'de, argümanları esnek<br />

olarak bildirilmiş argyaz(int arg, ...) fonksiyonu, son elemanı -1 olan bir kümenin<br />

elemanlarını ekrana yazar. Kümenin sonu (yani boyutu) -1 ile belirlenmiş olur.<br />

Program 9.3: Sonu -1 ile biten kümeyi ekrana yazar<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

/* 09prg03.c: Esnek argumanların yazdırılması<br />

*/<br />

#include <br />

#include <br />

/* herbiri int tipinde ve sonu -1 ile biten<br />

kümeyi ekrana yazar */<br />

void argyaz(int arg, ...)<br />

{<br />

va_list ap;<br />

int i;<br />

}<br />

va_start(ap, arg);<br />

for (i = arg; i != -1; i = va_arg(ap, int))<br />

printf("%d ", i);<br />

va_end(ap);<br />

putchar('\n');<br />

int main(void)<br />

{<br />

argyaz(5, 2, 14, 84, 97, 15, 24, 48, -1);<br />

argyaz(84, 51, -1);<br />

argyaz(-1);<br />

argyaz(1, -1);<br />

}<br />

ÇIKTI<br />

return 0;<br />

5 2 14 84 97 15 24 48<br />

84 51<br />

1


9.2 main Fonksiyonu<br />

Ana program anlamına gelen main de bir fonksiyondur. C programlarının başlangıcı ve sonu<br />

bu fonksiyonla belirlenir. Buna göre, bir C (veya C++) programı sadece bir tane main<br />

içerebilir.<br />

main fonksiyonu da geri dönüş değeri kullanabilir. main fonksiyonunun geri dönüş değerinin<br />

görevi, programın çalışması bittikten sonra sonucu işletim sistemine göndermektir. Program<br />

içinde return deyimi ile iletilen değer 0 olduğunda, bu işletim sistemi tarafından "program<br />

başarılı olarak sonlandı" olarak değerlendir. Başka bir deyişle,<br />

return 0;<br />

program, kullanıcının talebi doğrultusunda (olumlu anlamda) "yapması gereken işi yaptı"<br />

mesajını işletim sistemine bildirilir. 0'dan farklı herhangi bir değer ise programın sorunlu<br />

sonlandığı anlamına gelecektir. Bu yüzden bütün C programlarımızın sonuna return 0; ilave<br />

ediyoruz.<br />

Bazı programcılar main fonksiyonunun başına şey yazmaz.<br />

main()<br />

{<br />

...<br />

return 0;<br />

}<br />

Bu durumda geri dönüş değeri tamsayı (int) kabul edilir. Bu şekilde kullanımda, yeni tip<br />

derleyiciler uyarı (warning) mesajı verebilirler. Bu yüzden, aşağıdaki kullanımı tavsiye<br />

ediyoruz.<br />

int main()<br />

{<br />

...<br />

return 0;<br />

}<br />

Eğer ana programdan bir değer döndürülmeyecekse, main fonksiyonunun önüne aşağıdaki<br />

gibi void deyimi eklelenmelidir. Ancak bu bazı derleyiciler tarafından hata olarak<br />

yorumlanır. Bu nedenle, aşağıdaki kullanımlar pek tavsiye edilmez.<br />

yada<br />

void main()<br />

{<br />

...<br />

}<br />

void main(void)<br />

{<br />

...<br />

}


9.3 main() Fonksiyonuna Parametre Aktarımı<br />

NOT<br />

Bu ve sonraki kısımda (9.3) anlatılanlar Bölüm 10, 11 ve 16<br />

okunduktan sonra daha iyi anlaşılacaktır. Ancak, konu<br />

akışını bozmamak için, bu konunun buraya konması uygun<br />

bulunmuştur.<br />

Ana programa parametre aktarımı, derlenmiş (çalıştırılabilir) bir program komut satırından<br />

(işletim sistemi ortamından) çalıştırılacağı zaman yapılır. Parametre aktarımı, programın adı<br />

yazılıp bir boşluk bırakıldıktan hemen sonra yapılır. Parametreler, komut satırından sayısal<br />

olarak girilse bile program içinde karakter topluluğu (string) olarak gelir. Bu durumda, bu<br />

ifadeleri sayısal değerlere çeviren (atoi(), atol(), atof() gibi) fonksiyonlar kullanılır.<br />

Genel kullanım biçimi:<br />

...<br />

int main(arguman_sayısı, arguman_vektörü)<br />

int arguman_sayısı;<br />

char *arguman_vektörü[];<br />

{<br />

.<br />

.<br />

.<br />

if(arguman_sayısı < ...){<br />

printf("Eksik parametre !\n");<br />

exit(1);<br />

}<br />

if(arguman_sayısı > ...){<br />

printf("Cok fazla parametre !\n");<br />

exit(1);<br />

}<br />

.<br />

... arguman_vektörü[0] ... /* 1. eleman program adı */<br />

... arguman_vektörü[1] ... /* 2. eleman 1. parametre */<br />

... arguman_vektörü[2] ... /* 3. eleman 2. parametre */<br />

.<br />

}<br />

Program 9.1, komut satırından girilen iki sayının toplamını hesaplar.<br />

Program 9.1: Komut satırından girilen iki sayının toplamını hesaplar<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

/* topla.c<br />

Komut satırından girilen iki sayının<br />

toplamını hesaplar.<br />

Kullanımı: topla sayı1 sayı2 */<br />

#include <br />

#include <br />

int main(int argsay, char *argvek[]){<br />

int toplam;<br />

if(argsay < 3){<br />

printf("Eksik parametre !\n");


15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

}<br />

}<br />

exit(1);<br />

if(argsay > 3){<br />

printf("Cok fazla parametre !\n");<br />

exit(1);<br />

}<br />

toplam = atoi(argvek[1]) + atoi(argvek[2]);<br />

printf("Toplamlari %d\n",toplam);<br />

return 0;<br />

Program 9.1, topla.c derlendikten sonra üretilen Windows ortamında üretilen topla.exe ve<br />

Linux ortamında üretilen topla dosyasının çalıştırılması şöyledir:<br />

• Turbo C 2.0 Derlecisi kullanılarak (topla.c programı C:\TC adlı dizinin altına<br />

kaydedildiği<br />

varsayılmıştır)


• Dev-C++ Derlecisi kullanılarak (topla.c programı C:\Users\bingul\Desktop<br />

adlı dizinin altına kaydedildiği varsayılmıştır)<br />

• Linux gcc derleyicisi kullanılarak (topla.c programı /home/bingul/ adlı dizinin<br />

altına kaydedildiği varsayılmıştır)<br />

Komut satırında yazılan dosya adı dahil toplam parametre sayısı 3 tür. Bunlar:<br />

topla 4 9<br />

| | |<br />

V V V<br />

argvek[0] argvek[1] argvek[2]<br />

şeklindedir.<br />

Program 9.1, komut satırından girilen iki sayının toplamını hesaplar. Bu programın daha<br />

gelişmiş hali Program 9.2'de verilmiştir. Program 9.2 çalıştırıldığında, komut satırından<br />

girilen iki sayı ve bir operatör bekler. Girilen operatöre göre beş aritmetik işlemden birinini<br />

yapıp sonucu ekranda gösterir. İnceleyiniz.


Program 9.2: Komut satırından girilen iki sayı ve bir operatör bilgisine göre 5 işlemden<br />

birini hesaplar<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

/* hesap.c: Komut satırından girilen iki sayı<br />

üzerinde 5 işlem yapar.<br />

*/<br />

Kullanımı: hesap <br />

#include <br />

#include <br />

int main(int args, char **argv)<br />

{<br />

int s1, s2;<br />

float sonuc;<br />

char op;<br />

if(args != 4){<br />

printf("Eksik veya fazla parametre !\n");<br />

printf("Kullanimi: hesap <br />

\n");<br />

return 1;<br />

}<br />

s1 = atoi(argv[1]); /* 1. parametre:<br />

sayi1 */<br />

op = argv[2][0]; /* 2. parametrenin<br />

ilk karakteri: operator */<br />

s2 = atoi(argv[3]); /* 3. parametre:<br />

sayi2 */<br />

switch(op)<br />

{<br />

case '+':<br />

sonuc = s1 + s2; break;<br />

case '-':<br />

sonuc = s1 - s2; break;<br />

case '*':<br />

sonuc = s1 * s2; break;<br />

case '/':<br />

sonuc = (float) s1 / s2; break;<br />

case '%':<br />

sonuc = s1 % s2; break;<br />

default:<br />

sonuc = 0.0;<br />

printf("Yanlis operator %c\n",op);<br />

printf("Operatorler: +, -, *, / veya<br />

%%\n");<br />

}<br />

printf("sonuc = %f\n",sonuc);<br />

return 0;<br />

}<br />

Program hesap.c adlı dosyada saklandığı varsayılırsa, programın Linux ortamındaki çıktısı<br />

şöyle olacaktır:


9.4 Komut Satırı Örnekleri<br />

Aşağıda verilen iki program, Linux işletim sistemindeki cp ve wc komutlarının basit kaynak<br />

kodlarıdır:<br />

• cp (copy) komutu, bir text dosyasının kopyasını oluşturur.<br />

Kullanımı: cp kaynak_dosya hedef_dosya<br />

• wc (word count) komutu, bir dosyanın kaç karakter, kelime satırdan oluştuğunu bulup<br />

ekrana<br />

yazar.<br />

Kullanımı: wc dosya_adı<br />

<strong>Ders</strong> 10: Diziler<br />

• <strong>Giriş</strong><br />

• 10.1 Dizilerin Bildirimi<br />

• 10.2 Dizilere Başlangıç Değeri Verme<br />

• 10.3 Dizileri Yazdırma/Okuma<br />

• 10.4 Sıralama (Sorting)<br />

• 10.5 Karakter Dizileri (Strings)<br />

• 10.6 Çok Boyutlu Diziler<br />

• 10.7 Dizilerin Fonksiyonlarda Kullanılması<br />

<strong>Giriş</strong>


Dizi, aynı tipteki verilere tek bir isimle erişmek için kullanılan bir kümedir. Bu küme<br />

matematikteki küme kavramından biraz farklıdır. Bir dizi bildirildikten sonra, dizinin bütün<br />

elemanları bellekte peşpeşe saklanır [1]. Bu yüzden dizilere tek bir isim altında çok sayıda<br />

değişken içeren bellek bölgesi de denir. Buna göre, bir diziyi dizi yapan iki temel özellik<br />

vardır [2]:<br />

• dizi elemanların bellekte (program çalıştığı sürece) sürekli biçimde bulunması<br />

• dizi elemanların aynı türden değişkenler olması<br />

10.1 Dizilerin Bildirimi<br />

Bir dizi çok sayıda değişken barındırdığından, bunları birbirinden ayırdetmek için indis adı<br />

verilen bir bilgiye ihtiyaç vardır. C Programlama Dili'nde, bir dizi hangi tipte tanımlanmış<br />

olursa olsun başlangıç indisi her zaman 0'dır.<br />

Bir dizinin bildirim işleminin genel biçimi söyledir:<br />

veriTipi dizi_adı[eleman_sayısı];<br />

Örneğin, 5 elemanlı, kütle verilerini bellekte tutmak için, kutle dizisi şöyle tanımlanabilir:<br />

float kutle[5];<br />

Bu dizinin elemanlarına bir değer atama işlemi şöyle yapılabilir:<br />

kutle[0] = 8.471<br />

kutle[1] = 3.683<br />

kutle[2] = 9.107<br />

kutle[3] = 4.739<br />

kutle[4] = 3.918<br />

NOT<br />

1. elemanın indisi 0,<br />

5. elemanın indisinin 4 olduğuna dikkat edin.<br />

Bildirim sırasında dizilerin eleman sayısı tamsayı türünden bir sabit ifadesiyle belirtilmesi<br />

zorunludur. Örneğin:<br />

int n = 100;<br />

int a[n];<br />

şeklindeki tanımlama, dizi uzunluğunun değişken (n) ile belirtilmesi nedeniyle geçersizdir.<br />

Bunun yerine, dizilerin eleman sayısı aşağıdaki gibi sembolik sabitlerle belirtmek<br />

mümkündür.<br />

#define n 100<br />

...<br />

int a[n];<br />

Bir dizinin bellekte kapladığı alanın bayt cinsinden karşılığı sizeof operatörü ile<br />

öğrenilebilir.<br />

int a[5], b, c;<br />

...<br />

b = sizeof(a); /* bellekte kapladığı alan: b = 4*5 =<br />

20 bayt */


*/<br />

c = sizeof(a) / sizeof(int); /* Dizinin boyutu : c = 20/4 = 5<br />

10.2 Dizilere Başlangıç Değeri Verme<br />

Bir diziye başlangıç değerleri aşağıdaki gibi kısa formda atanabilir:<br />

float kutle[5]= { 8.471, 3.683, 9.107, 4.739, 3.918 };<br />

int maliyet[3] = { 25, 72, 94 };<br />

double a[4] = { 10.0, 5.2, 7.5, 0.0};<br />

Küme parantezlerinin sonlandırıcı ; karakteri ile bittiğine dikkat ediniz.<br />

Bir dizinin uzunluğu belirtilmeden de başlangıç değeri atamak mümkündür.<br />

int a[] = { 100, 200, 300, 400 };<br />

float v[] = { 9.8, 11.0, 7.5, 0.0, 12.5};<br />

Derleyici bu şekilde bir atama ile karşılaştığında, küme parantezi içindeki eleman sayısını<br />

hesaplar ve dizinin o uzunlukta açıldığını varsayar. Yukarıdaki örnekte, a dizisinin 4, v<br />

dizisinin 5 elemanlı olduğu varsayılır.<br />

10.3 Dizileri Yazdırma/Okuma<br />

printf ve scanf fonksiyonları bir dizinin okunması ve yazdırılması için de kullanılır.<br />

Örneğin bir A dizisinin aşağıdaki gibi bildirildiğini varsayalım:<br />

int A[10];<br />

Bu dizinin elemanlarını klavyeden okumak için:<br />

for(i=0; i


03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

ÇIKTI<br />

#include <br />

#define N 10<br />

int main()<br />

{<br />

int i;<br />

float x[N], ort, toplam = 0.0;<br />

for(i=0; i


Program 10.2: 10 sayının ortalamasını ve standart sapmasını hesaplar<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

/* 10prg02.c<br />

10 tane sayının aritmetik ortlamasını ve<br />

standart sapmasını hespalar. */<br />

#include <br />

#include <br />

#define N 10<br />

int main(void)<br />

{<br />

int i;<br />

float x[N], toplam = 0.0, ort, std_sap = 0.0;<br />

}<br />

ÇIKTI<br />

/* ortalama hesabı */<br />

for(i=0; i


Bazı uygulamalarda bir grup sayının büyükten küçüğe, veya küçükten büyüğe, doğru<br />

sıralanması gerekebilir. Bu tip sıralama problemleri için çeşitli algoritmalar geliştirilmiştir.<br />

Sıralama mantığını anlamadan önce bir dizinin en büyük (veya en küçük) elemanının nasıl<br />

bulunduğunu inceleyelim. Program 10.3, bir dizinin en büyük elemanını bulup ekrana yazar.<br />

Program 10.3: Bir dizinin en büyük elemanının bulunuşu<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

ÇIKTI<br />

/* 10prg03.c<br />

Bir dizinin en büyük elemanını bulup ekrana<br />

yazar */<br />

#include <br />

int main(void)<br />

{<br />

int a[10] = {100, -250, 400, 125 ,550, 900,<br />

689, 450, 347, 700};<br />

int k, eb;<br />

/* ilk eleman en büyük kabul ediliyor */<br />

eb = a[0];<br />

for(k=1; keb ) eb = a[k];<br />

printf("En buyuk eleman = %d\n",eb);<br />

return 0;<br />

}<br />

En buyuk eleman = 900<br />

En büyük sayıyı bulan bu algoritma oldukça kolaydır. 12. satırda eb = a[0]; ataması ile<br />

dizinin ilk elemanının en büyük olduğu varsayılır. Daha sonra büyüğe rastladıkça (15. satır)<br />

eb = a[k]; ile eb değişmektedir.<br />

Program 10.3 bir dizinin en büyük elemanını bulur. En büyük elemanın kaçıncı indis (eleman)<br />

olduğu sorgulanmak istendiğinde: programdaki koşul yapısını aşağıdaki gibi değiştirmek<br />

yeterlidir. eb değiştikçe, i değişkeni en büyük elemanın indisini tutar.<br />

for(k=0; k eb ){<br />

eb = a[k];<br />

i = k;<br />

}<br />

}<br />

n elemanlı bir dizinin, elemanlarını büyükten küçüğe doğru sıralamak için çok popüler iki<br />

algoritma aşağıda verilmiştir[2].<br />

Seçerek Sıralama (Selection Sort):<br />

En büyük elemanı bul başa koy biçimindeki sıramadır. Algoritmanın uygulaması Program


10.4'de<br />

gösterilmiştir.<br />

Bu algoritmada kullanılan kombinasyon sayısı (algoritmanın karmaşıklığı): n*(n-1)/2 dir.<br />

Program 10.4: Seçerek Sıralama (Selection Sort) Algoritması<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

ÇIKTI<br />

/* 09prg04.c<br />

Seçerek Sıralama (Selection Sort) Algoritması<br />

ile bir<br />

dizinin elemanlarını büyükten küçüğe dogru<br />

sıralar */<br />

#include <br />

#define n 10<br />

int main(void)<br />

{<br />

int a[n] = {100, -250, 400, 125 ,550, 900,<br />

689, 450, 347, 700};<br />

int i, j, k, eb;<br />

/* Dizinin kendisi */<br />

printf("Once : ");<br />

for(k=0;k


Kabarcık Sıralama (Bubble Sort):<br />

Yanyana elemanları karşılaştırarak yer değiştir biçimde sıralamadır. Algoritmanın uygulaması<br />

Program 10.5'de gösterilmiştir.<br />

Bu algoritmanın karmaşıklığı: (n-1) 2 dir.<br />

Program 10.5: Kabarcık Sıralama (Bubble Sort) Algoritması<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

/* 09prg05.c<br />

Kabarcık Sıralama (Bubble Sort) Algoritması<br />

ile bir<br />

dizinin elemanlarını büyükten küçüğe dogru<br />

sıralar */<br />

#include <br />

#define n 10<br />

int main(void)<br />

{<br />

int a[n] = {100, -250, 400, 125 ,550, 900,<br />

689, 450, 347, 700};<br />

int j,k,gecici;<br />

/* Dizinin kendisi */<br />

printf("Once : ");<br />

for(k=0; k


C dilinde, karakter dizileri oldukça sık kullanılır. Sadece karakter dizilerine özel olarak,<br />

karakter dizilerinin sonuna sonlandırcı karakter olarak adlandırılan bir simge eklenir.<br />

Sonlandırcı karakter, işlemlerin hızlı ve etkin bir biçimde yapılabilmesine olanak sağlar[2].<br />

Sonlandırıcı karakter:<br />

• dizinin bittiği yeri gösterir,<br />

• ASCII tablosunun sıfır numaralı ('\0') karakteridir.<br />

Karakter dizilerine iki şekilde başlangıç değeri verilebilir.<br />

char s[7] = {'d','e','n','e','m','e','\0'};<br />

yada<br />

char s[7] = "deneme";<br />

Birinci tanımlamada sonlandırıcı karakter programcı tarafından konmalıdır. Ikinci<br />

tanımlamada ise buna gerek yoktur. Çünkü, sonlandırıcı karakter bu atamayla, derleyici<br />

tarafından eklenir.<br />

NOT<br />

char s[7] = "deneme";<br />

ataması geçeli olmasına rağmen, aşağıdaki atama<br />

geçersizdir:<br />

char<br />

char s = "deneme";<br />

Karakter dizileri gets() fonksiyonu ile klavyeden okunabilir.<br />

char ad[20];<br />

...<br />

gets(ad);<br />

s[7];<br />

Program 10.6'da bir karakter dizisinin uzunluğunun nasıl bulunduğu, Program 10.7'de ise bir<br />

karakter dizisinin tersyüz edilişi gösterilmiştir. İnceleyiniz.<br />

Program 10.6: Bir karakter dizisinin uzunluğunu bulur<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

/* 09prg06.c: Bir karakter dizisinin uzunluğunu<br />

bulur */<br />

#include <br />

int main(void)<br />

{<br />

char s[40];<br />

int k = 0;<br />

/* diziyi oku */<br />

printf("Bir seyler yazin : ");<br />

gets(s);<br />

/* sonlandırıcı karaktere kadar karakterleri<br />

say */<br />

while( s[k]!='\0' )<br />

k++;


20:<br />

21:<br />

ÇIKTI<br />

printf("Dizinin uzunlugu : %d\n",k);<br />

return 0;<br />

}<br />

Birseyler yazin : Gazintep Universitesi<br />

Dizinin uzunlugu : 21<br />

Program 10.7: Bir karakter dizisinin tersini bulur<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

ÇIKTI<br />

/* 09prg07.c: Bir karakter dizisini tersyüz eder<br />

*/<br />

#include <br />

int main(void)<br />

{<br />

char s[40], gecici;<br />

int i, n;<br />

/* diziyi oku */<br />

printf("Bir seyler yazin : ");<br />

gets(s);<br />

/* sonlandırıcı karaktere kadar */<br />

for(n=0; s[n] != '\0'; n++)<br />

;<br />

for(i=0; i


Bir dizi birden çok boyuta sahip olabilir. Örneğin iki boyutlu b dizisi şöyle tanımlanabilir:<br />

float b[9][4];<br />

İki boyutlu diziler matris olarak adlandırılır. ilk boyuta satır, ikinci boyuta sütün denir.<br />

Yukarıda b matrisinin eleman sayısı 9x4=36 dır. Bu durumda, genel olarak bir dizi şöyle<br />

gösterilir:<br />

Tablo 10.1: Dizlerin Bildirimi<br />

Dizi Çeşiti Genel Bildirimi Örnek<br />

Tek boyutlu diziler (Vektörler) tip dizi_adı[eleman_sayısı] int veri[10];<br />

İki boyutlu diziler (Matrisler) tip dizi_adı[satır_sayısı][sutun_sayısı] float mat[5][4<br />

Çok boyutlu diziler tip dizi_adı[boyut_1][boyut_2]...[boyut_n]; double x[2][4]<br />

Çok boyutlu diziler tek boyuta indir generek bellekte tutulurlar. Tek indisli dizilerde olduğu<br />

gibi, çok indisli dizilere de başlangıç değeri vermek mümkün. Örneğin 3 satır ve 4 sütünlu<br />

(3x4=12 elemanlı) bir x matrisinin elemanları şöyle tanımlanabilir:<br />

int x[3][4] = {11,34,42,60, 72,99,10,50, 80,66,21,38};<br />

yada<br />

int x[3][4] = {11,34,42,60, /* 1. satır elemanları */<br />

72,99,10,50, /* 2. satır elemanları */<br />

80,66,21,38}; /* 3. satır elemanları */<br />

Bu matris ekrana matris formunda yazılmak istendiğinde:<br />

for(i=0; i


11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

}<br />

int b[SAT][SUT] = {1, 2, 3, 4, 5, 6};<br />

int c[SAT][SUT];<br />

int i, j;<br />

puts("A Matrisi:");<br />

for(i=0; i


09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

{<br />

ÇIKTI<br />

int a[N][N], b[N][N], c[N][N];<br />

int i,j,k,toplam;<br />

puts("A Matrisini girin:");<br />

for(i=0; i


01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

/* 10prg10.c: bir dizinin yazdırılması */<br />

#include <br />

void dizi_yaz(float x[], int n);<br />

int main(){<br />

float kutle[5]= { 8.471, 3.683, 9.107, 4.739,<br />

3.918 };<br />

}<br />

dizi_yaz(kutle, 5);<br />

return 0;<br />

void dizi_yaz(float x[], int n)<br />

{<br />

int i;<br />

}<br />

ÇIKTI<br />

for(i=0; i


09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

int enBuyuk(int a[], int n)<br />

{<br />

int k, en_buyuk_eleman;<br />

}<br />

ÇIKTI<br />

/* ilk eleman en büyük kabul ediliyor */<br />

en_buyuk_eleman = a[0];<br />

for(k=1; ken_buyuk_eleman )<br />

en_buyuk_eleman = a[k];<br />

return en_buyuk_eleman;<br />

int main()<br />

{<br />

int a[10] = {100, -250, 400, 125 ,550, 900,<br />

689, 450, 347, 700};<br />

int eb;<br />

eb = enBuyuk(a,10);<br />

printf("En buyuk eleman = %d\n",eb);<br />

return 0;<br />

}<br />

En buyuk eleman = 900<br />

Son olarak, bir kare matrisin iz (trace) değerini bulup ekrana yazan bir fonksiyon Program<br />

10.12'de verilmişitir. Bir kare matrisin izi, matrisin asal köşegen üzerinde bulunan<br />

elemanların toplamı olarak tanımlıdır. Bu tanıma göre, aşağıdaki matrisin izi 2 + 8 + 4 = 14<br />

tür..<br />

İz matematiksel olarak şöyle gösterilir:<br />

Program 10.12: Bir matrisin izi<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

/* 10prg12.c<br />

Bir 3x3 bir matrisin izinin fonksiyonla<br />

bulunması */<br />

#include <br />

double iz(double a[][3], int);<br />

int main()


10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

{<br />

double a[3][3], izA;<br />

int i,j;<br />

puts("matrisi girin:");<br />

for(i=0; i


<strong>Giriş</strong><br />

Hemen hemen bütün programlama dillerinin temelinde gösterici (pointer) veri tipi<br />

bulunmaktadır. Bir çok dil gösterici kullanımını kullanıcıya sunmamıştır veya çok sınırlı<br />

olarak sunmuştur. Fakat C Progrmalam Dili'nde göstericiler yoğun olarak kullanılır. Hatta<br />

gösterici kavramı C dilinin bel kemiğidir. Kavranması biraz güç olan göstericiler için -latife<br />

yapılıp- C kullanıcılarını "gösterici kullanabilenler ve kullanmayanlar" olmak üzere iki gruba<br />

ayıranlar da olmuştur. Özetle, bir C programcısı gösterici kavramını anlamadan C diline<br />

hakim olamaz.<br />

Türkçe yazılan C kitaplarda pointer kelimesi yerine aşağıdaki ifadelerden biri karşılaşılabilir:<br />

pointer = işaretçi = gösterici = gösterge<br />

Anlatımda, gösterici terimini kullanacağız.<br />

11.1 Değişken ve Bellek Adresi<br />

Bilgisayarın ana belleği (RAM) sıralı kaydetme gözlerinden oluşmuştur. Her göze bir adres<br />

atanmıştır. Bu adreslerin değerleri 0 ila belleğin sahip olduğu üst değere bağlı olarak<br />

değişebilir. Örneğin 64 MB bir bellek, 64*1024*1024 = 67108864 adet gözden oluşur.<br />

Bir programlama dillinde, belli bir tipte değişken tanımlanıp ve bir değer atandığında, o<br />

değişkene dört temel özellik eşlik eder:<br />

1. değişkenin adı<br />

2. değişkenin tipi<br />

3. değişkenin sahip olduğu değer (içerik)<br />

4. değişkenin bellekteki adresi<br />

Örneğin tam adlı bir tamsayı değişkenini aşağıdaki gibi tanımladığımızı varsayalım:<br />

int tam = 33;<br />

Bu değişken için, int tipinde bellekte (genellikle herbiri 1 bayt olan 4 bayt büyüklüğünde) bir<br />

hücre ayrılır ve o hücreye 33 sayısı ikilik (binary) sayı sitemindeki karşılığı olan 4 baytlık (32<br />

bitlik):<br />

00000000 00000000 00000000 00100001<br />

sayısı elektronik olarak yazılır. tam değişkenine ait dört temel özellik Şekil 11.1'deki gibi<br />

gösterilebilir:


Şekil 11.1: Bir değişkene eşlik eden dört temel özellik<br />

Bellek adresleri genellikle onaltılık (hexadecimal) sayı sisteminde ifade edilir. 0x3fffd14<br />

sayısı onluk (decimal) sayı sisteminde 67108116 sayına karşık gelir. Bunun anlamı, tam<br />

değişkeni, program çalıştığı sürece, bellekte 67108116. - 67108120. numaralı gözler<br />

arasındaki 4 baytlık hücreyi işgal edecek olmasıdır. Şekil 11.1'deki gösterim, basit ama<br />

anlaşılır bir tasvirdir. Gerçekte, int tipindeki tam değişkeninin bellekteki yerleşimi ve içeriği<br />

(değeri) Şekil 11.2'de gösterildiği gibi olacaktır.<br />

Şekil 11.2: tam adlı değişkenin bellekteki gerçek konumu ve ikilik düzendeki içeriği<br />

Değişkenin saklı olduğu adres, & karakteri ile tanımlı adres operatörü ile öğrenilebilir. Bu<br />

operatör bir değişkenin önüne konursa, o değişkenin içeriği ile değil adresi ile ilgileniliyor<br />

anlamına gelir. Aşağıdaki program parçasının:<br />

çıktısı:<br />

int tam = 33;<br />

printf("icerik: %d\n",tam);<br />

printf("adres : %p\n",&tam);<br />

icerik: 33


adres : 3fffd14<br />

şeklindedir. Burada birinci satır tam değişkeninin içeriği, ikinci ise adresidir. Adres<br />

yazdırılırken %p tip belirleyicisinin kullanıldığına dikkat ediniz.<br />

11.2 Gösterici Nedir?<br />

Gösterici, bellek alanındaki bir gözün adresinin saklandığı değişkendir. Göstericilere veriler<br />

(yani değişkenlerin içeriği) değil de, o verilerin bellekte saklı olduğu hücrenin başlangıç<br />

adresleri atanır. Kısaca gösterici adres tutan bir değişkendir.<br />

Bir gösterici, diğer değişkenler gibi, sayısal bir değişkendir. Bu sebeple kullanılmadan önce<br />

program içinde bildirilmelidir. Gösterici tipindeki değişkenler şöyle tanımlanır:<br />

tip_adı *gösterici_adı;<br />

Burada tip_adı herhangi bir C tip adı olabilir. Değişkenin önünedeki * karakteri<br />

yönlendirme (indirection) operatörü olarak adlandırılır ve bu değişkenin veri değil bir adres<br />

bilgisi tutacağını işaret eder. Örneğin:<br />

char *kr; /* tek bir karakter için */<br />

int *x; /* bir tamsayı için */<br />

float *deger, sonuc; /* deger gösterici tipinde, sonuc sıradan<br />

bir gerçel değişkenler */<br />

Yukarıda bildirilen göstericilerden; kr bir karakterin, x bir tamsayının ve deger bir gerçel<br />

sayının bellekte saklı olduğu yerlerin adreslerini tutar.<br />

Bir göstericiye, bir değişkenin adresini atamak için adres operatörünü kullanabiliriz. Örneğin<br />

tamsayı tipindeki tam adlı bir değişken ve ptam bir gösterici olsun. Derleyicide, aşağıdaki gibi<br />

bir atama yapıldığında:<br />

int *ptam, tam = 33;<br />

.<br />

.<br />

.<br />

ptam = &tam;<br />

ptam göstericisinin tam değişkeninin saklandığı adresi tutacaktır. Bu durum Şekil 11.3'deki<br />

gibi tasvir edilir.


Şekil 11.3: Göstericinin bir değişkenin adresini göstermesi<br />

Şekil 11.3'deki gösterimde, ptam göstericisinin içeriği tam değişkeninin içeriği (33) değil<br />

adresidir (0x3fffd14). Ayrıca, ptam değişkeni, bellekte başka bir hücrede saklandığına ve bu<br />

hücrenin int değil int * tipinde bir bölge olduğuna dikkat ediniz. Buraya kadar anlatılanlar,<br />

Program 11.1'de özetlenmiştir.<br />

Program 11.1: Bir değişkenin içeriğini ve adresini ekrana yazdırma<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

/* 10prg01.c: ilk gösterici programı */<br />

#include <br />

int main()<br />

{<br />

int *ptam, tam = 33;<br />

ptam = &tam;<br />

printf("tam: icerik = %d\n", tam);<br />

printf("tam: adres = %p\n",&tam);<br />

printf("tam: adres = %p\n",ptam);<br />

return 0;<br />

}<br />

7. satırda değişkenler bildirilmiştir. 9. satırdaki atama ile tam değişkeninin adresi, ptam<br />

göstericisine atanmıştır. Bu satırdan itibaren ptam, tam değişkeninin gösterir. 11. satıda tam'ın<br />

içeriği (33 sayısı), 12. ve 13. satırda tam'ın adresi, %p tip karakteri ile, ekrana yazdırılmıştır.<br />

Ekran çıktısı incelendiğinde, &tam ve ptam içereriğinin aynı anlamda olduğu görülür.<br />

ÇIKTI<br />

tam: icerik = 33<br />

tam: adres = 0x3fffd14<br />

tam: adres = 0x3fffd14<br />

tam adlı değişkenin içeriğine ptam gösterici üzerinde de erişilebilir. Bunun için program<br />

içinde ptam değişkeninin önüne yönelendirme operatörü (*) koymak yeterlidir. Yani *ptam,<br />

tam değişkeninin adresini değil içeriğini tutar. Buna göre:<br />

*ptam = 44;


komutuyla, ptam'ın adresini tuttuğu hücreye 44 değeri atanır. Bu durum, Program 11.2'de<br />

gösterilmiştir.<br />

Program 11.2: Bir değişkenin içeriğini ve adresini ekrana yazdırma<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

ÇIKTI<br />

/* 10prg02.c: ikinci gösterici programı */<br />

#include <br />

int main()<br />

{<br />

int *ptam, tam = 33;<br />

ptam = &tam; /* ptam -> tam */<br />

printf("&tam = %p\n",&tam);<br />

printf("ptam = %p\n",ptam);<br />

printf("\n");<br />

printf("tam = %d\n",tam);<br />

printf("*ptam = %d\n",*ptam);<br />

printf("\n");<br />

*ptam = 44; /* tam = 44 anlamında */<br />

printf("tam = %d\n",tam);<br />

printf("*ptam = %d\n",*ptam);<br />

return 0;<br />

}<br />

&tam = 0x3fffd14<br />

ptam = 0x3fffd14<br />

tam = 33<br />

*ptam = 33<br />

tam = 44<br />

*ptam = 44<br />

Özetle ptam = &tam atamasıyla:<br />

• *ptam ve tam, tam adlı değişkenin içeriği ile ilgilidir.<br />

• ptam ve &tam, tam adlı değişkenin adresi ile ilgilidir.<br />

• * yönlendirme ve & adres operatörüdür.<br />

11.3 Gösterici Aritmetiği<br />

Göstericiler kullanılırken, bazen göstericinin gösterdiği adres taban alınıp, o adresten önceki<br />

veya sonraki adreslere erişilmesi istenebilir. Bu durum, göstericiler üzerinde, aritmetik<br />

işlemcilerin kullanılmasını gerektirir. Göstericiler üzerinde yalnızca toplama (+), çıkarma (-),<br />

bir arttırma (++) ve bir eksiltme (--) operatörleri işlemleri yapılabilir.


Aşağıdaki gibi üç tane gösterici bildirilmiş olsun:<br />

char *kar;<br />

int *tam;<br />

double *ger;<br />

Bu göstericiler sırasıyla, bir karakter, bir tamsayı ve bir gerçel sayının bellekte saklanacağı<br />

adreslerini tutar. Herhangi bir anda, tuttukları adresler de sırasıyla 10000 (0x2710), 20000<br />

(0x4e20) ve 30000 (0x7530) olsun. Buna göre aşağıdaki atama işelemlerinin sonucu:<br />

kar++;<br />

tam++;<br />

ger++;<br />

sırasyla 10001 (0x2711), 20004 (0x4e24) ve 30008 (0x7538) olur. Bir göstericiye ekleme<br />

yapıldığında, o anda tuttuğu adres ile eklenen sayı doğrudan toplanmaz. Böyle olsaydı, bu<br />

atamaların sonuçları sırasıyla 10001, 20001 ve 30001 olurdu. Gerçekte, göstericiye bir<br />

eklemek, göstericinin gösterdiği yerdeki veriden hemen sonraki verinin adresini<br />

hesaplamaktır.<br />

Genel olarak, bir göstericiye n sayısını eklemek (veya çıkarmak), bekllekte gösterdiği veriden<br />

sonra (veya önce) gelen n. elemanın adresini hesaplamaktır. Buna göre aşağıdaki atamalar<br />

şöyle yorumlanır.<br />

kar++; /* kar = kar + sizeof(char) */<br />

tam = tam + 5; /* tam = tam + 5*sizeof(int) */<br />

ger = ger - 3; /* ger = ger - 3*sizeof(double) */<br />

Program 11.3, bu bölümde anlatlanları özetlemektedir. İnceleyiniz.<br />

Program 11.3: Gösterici aritmetiği<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

/* 10prg03.c: gösterici aritmetiği */<br />

#include <br />

int main()<br />

{<br />

char *pk, k = 'a';<br />

int *pt, t = 22;<br />

double *pg, g = 5.5;<br />

pk = &k;<br />

pt = &t;<br />

pg = &g;<br />

printf("Onceki adresler: pk= %p pt= %p<br />

pg= %p \n", pk, pt, pg);<br />

pk++;<br />

pt--;<br />

pg = pg + 10;<br />

printf("Sonraki adresler: pk= %p pt= %p<br />

pg= %p \n", pk, pt, pg);


ÇIKTI<br />

return 0;<br />

}<br />

Onceki adresler: pk= 0xbfbbe88f pt= 0xbfbbe888<br />

pg= 0xbfbbe880<br />

Sonraki adresler: pk= 0xbfbbe890 pt= 0xbfbbe884<br />

pg= 0xbfbbe8d0<br />

11.4 Gösterici ve Diziler Arasındaki İlişki<br />

C dilinde göstericiler ve diziler arasında yakın bir ilişki vardır. Bir dizinin adı, dizinin ilk<br />

elemanının adresini saklayan bir göstericidir. Bu yüzden, bir dizinin herhangi bir elemanına<br />

gösterici ile de erişilebilir. Örneğin:<br />

int kutle[5], *p, *q;<br />

şeklinde bir bildirim yapılsın. Buna göre aşağıda yapılan atamalar geçerlidir:<br />

atandı */<br />

atandı */<br />

atandı */<br />

p = &kutle[0]; /* birinci elemanın adresi p göstericisne<br />

p = kutle; /* birinci elemanın adresi p göstericisne<br />

q = &kutle[4]; /* son elemanın adresi q göstericisne<br />

İlk iki satırdaki atamalar aynı anlamdadır. Dizi adı bir gösterici olduğu için, doğrudan aynı<br />

tipteki bir göstericiye atanabilir. Ayrıca, i bir tamsayı olmak üzere,<br />

ile<br />

kutle[i];<br />

*(p+i);<br />

aynı anlamdadır. Bunun sebebi, p göstericisi kutle dizisinin başlangıç adresini tutmuş<br />

olmasıdır. p+i işlemi ile i+1. elemanın adresi, ve *(p+i) ile de bu adresteki değer hesaplanır.<br />

NOT<br />

Bir dizinin, i. elemanına erişmek için *(p+i) işlemi<br />

yapılması zorunludur. Yani<br />

*p+i;<br />

/* p nin gösterdiği değere (dizinin ilk<br />

elemanına) i sayısını ekle */<br />

*(p+i); /* p nin gösterdiği adresten i blok<br />

ötedeki sayıyı hesapla */<br />

anlamındadır. Çünkü, * operatörü + operatörüne göre işlem<br />

önceliğine sahiptir.<br />

Program 11.4'de tanımlanan fonksiyon kendine parameter olarak gelen n elemanlı bir dizinin<br />

aritmetik ortlamasını hesaplar.<br />

Program 11.4: Bir dizi ile gösterici arasındaki ilişki


01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

/* 10prg04.c: gösterici dizi ilişkisi */<br />

#include <br />

double ortalama(double dizi[], int n);<br />

int main()<br />

{<br />

double a[5] = {1.1, 2.2, 3.3, 4.4, 5.5};<br />

double o;<br />

o = ortalama(a,5);<br />

printf("Dizinin ortalaması = %lf\n",o);<br />

return 0;<br />

}<br />

double ortalama(double dizi[], int n)<br />

{<br />

double *p, t=0.0;<br />

int i;<br />

}<br />

ÇIKTI<br />

p = dizi; /* veya p = &dizi[0] */<br />

for(i=0; i


C (ve C++) programlama dilinde fonksiyon parametreleri değer geçerek (pass by value) yada<br />

adres geçerek (pass by reference) olarak geçilebilir. Bu şekilde geçirilen parametreler,<br />

fonksiyon içersinde değiştirilse bile, fonksiyon çağılıldıktan sonra bu değişim çağrılan yerdeki<br />

değerini değiştirmez. Fakat, bir parametre adres geçerek aktarılısa, fonksiyon içindeki<br />

değişikler geçilen parametreyi etkiler. Adres geçerek aktarım, gösterici kullanmayı zorunlu<br />

kılar.<br />

Örneğin, Program 11.5'de fonksiyonlara değer ve adres geçerek aktarımın nasıl yapılacağı<br />

gösterilmiştir.<br />

Program 11.5: Bir değişkenin içeriğini ve adresini ekrana yazdırma<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

/* 10prg05.c: Değer geçerek ve adres geçerek<br />

aktarım */<br />

#include <br />

void f1(int ); /* iki fonksiyon */<br />

void f2(int *);<br />

int main()<br />

{<br />

int x = 55;<br />

printf("x in degeri,\n");<br />

printf("Fonksiyonlar cagrilmadan once:<br />

%d\n",x);<br />

/* f1 fonksiyonu çağrılıyor...*/<br />

f1(x);<br />

printf("f1 cagirildiktan sonra :<br />

%d\n",x);<br />

/* f2 fonksiyonu çağrılıyor...*/<br />

f2(&x);<br />

printf("f2 cagirildiktan sonra :<br />

%d\n",x);<br />

return 0;<br />

}<br />

/* Değer geçerek aktarım */<br />

void f1(int n){<br />

n = 66;<br />

printf("f1 fonksiyonu icinde :<br />

%d\n",n);<br />

}<br />

/* Adres geçerek aktarım */<br />

void f2(int *n){<br />

*n = 77;<br />

printf("f2 fonksiyonu icinde :<br />

%d\n",*n);<br />

}


5. ve 6. satırlada kendine geçilen parametrenin değerini alan f1 fonksiyonu ve parametrenin<br />

adresini alan f2 adlı iki fonksiyon örneği belirtilmişdir. 11. satırdaki x değişkeni 16. ve 21.<br />

satırlarda, f1(x) ve f2(&x) fonksiyonlarına, sırasıyla değer ve adres geçerek aktarılmıştır. f1<br />

içinde x (n = 66; işlemi ile) değişime uğramış, fakat çağrılma işleminin sonucunda, x'in<br />

değeri değişmemiştir. Ancak f2 içinde x'in ( *n = 77 işlemi ile) değişimi, çağrıldıktan<br />

sonrada korunmuştur. Yani, adres geçerek yaplıan aktarımda, f2'ye aktarılan değer değil adres<br />

olduğu için, yollanan x parametresi f2 içinde değişikliğe uğrayacak ve bu değişim çağrıldığı<br />

21. satırdan itibaren devam edecektir.<br />

ÇIKTI<br />

x in degeri,<br />

Fonksiyonlar cagrilmadan once: 55<br />

f1 fonksiyonu icinde : 66<br />

f1 cagirildiktan sonra : 55<br />

f2 fonksiyonu icinde : 77<br />

f2 cagirildiktan sonra : 77<br />

Program 11.6'da iki tamsayı değişkeninin nasıl takas (swap) edileceği gösterilmiştir. Bu<br />

işlemi C porgramlama dilinde, eğer değişkenler global olarak bildirilmemişse, gösterici<br />

kullanmadan bu işlemi yapmak imkansızdır.<br />

Program 11.6: İki tamsayının birbiri ile takas edilmesi<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

/* 10prg06.c: iki sayının birbiri ile takas<br />

edilmesi */<br />

#include <br />

void takas(int *, int *);<br />

int main()<br />

{<br />

int a, b;<br />

a=22; b=33;<br />

printf("takas oncesi : a=%d b=%d\n",a,b);<br />

takas(&a, &b);<br />

printf("takas sonrasi: a=%d b=%d\n",a,b);<br />

return 0;<br />

}<br />

void takas(int *x, int *y)<br />

{<br />

int z;<br />

}<br />

z = *x;<br />

*x = *y;<br />

*y = z;


ÇIKTI<br />

takas oncesi : a=22 b=33<br />

takas sonrasi: a=33 b=22<br />

11.6 NULL Gösterici<br />

Bir göstericinin bellekte herhangi bir adresi göstermesi, veya öncden göstermiş olduğu adres<br />

iptal edilmesi istemirse NULL sabiti kullanılır. Bu sabit derleyicide ASCII karakter tablosunun<br />

ilk karakteridir ve '\0' ile sembolize edilir.<br />

int *ptr, a = 12;<br />

.<br />

.<br />

ptr = &a; /* ptr bellekte a değişkenin saklandığı yeri<br />

gösteriyor */<br />

.<br />

.<br />

ptr = NULL; /* ptr bellekte hiç bir hücreyi göstermiyor */<br />

*ptr = 8 /* hata! NULL göstericinin gösterdiği yere bir<br />

değer atanamaz */<br />

11.7 void Tipindeki Göstericiler<br />

void göstericiler herhangi bir veri tipine ait olmayan göstericilerdir. Bu özelliğinden dolayı,<br />

void gösterici genel gösterici (generic pointer) olarak da adlandırılır.<br />

void göstericiler, void anahtar sözcüğü ile bildirilir. Örneğin:<br />

gibi.<br />

void *adr;<br />

void göstericiler yalnızca adres saklamak için kullanılır. Bu yüzden diğer göstericiler<br />

arasında atama işlemlerinde kullanılabilir. Örneğin aşağıdaki atamada derleyici bir uyarı veya<br />

hata mesajı vermez:<br />

void *v;<br />

char *c;<br />

.<br />

.<br />

.<br />

v = c; /* sorun yok !*/<br />

Program 11.7'de void tipindeki bir göstericinin, program içinde, farklı tipteki verileri nasıl<br />

göstereceği ve kullanılacağı örneklenmiştir. İnceleyiniz.<br />

Program 11.7: void gösterici ile farklı tipteki verileri gösterme<br />

01:<br />

02:<br />

/* 10prg07.c: void gosterici (generic pointer)<br />

uygulamasi */


03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

#include <br />

void yaz(void *);<br />

int main()<br />

{<br />

char kar = 'a';<br />

int tam = 66;<br />

double ger = 1.2;<br />

void *veri;<br />

veri = &kar;<br />

printf("veri -> kar: veri %c karakter<br />

degerini gosteriyor\n", *(char *) veri);<br />

veri = &tam;<br />

printf("veri -> tam: simdi veri %d tamsayi<br />

degerini gosteriyor\n", *(int *) veri);<br />

veri = &ger;<br />

printf("veri -> ger: simdi de veri %lf<br />

gercel sayi degerini gosteriyor\n", *(double *)<br />

veri);<br />

}<br />

return 0;<br />

ÇIKTI<br />

veri -> kar: veri a karakter degerini gosteriyor<br />

veri -> tam: simdi veri 66 tamsayi degerini<br />

gosteriyor<br />

veri -> ger: simdi de veri 1.200000 gercel sayi<br />

degerini gosteriyor<br />

Benzer olarak, fonksiyon parameterelerinin kopyalanması sırasında da bu türden atama<br />

işlemleri kullanılabilir. Uygulamada, tipten bağımsız adres işlemlerinin yapıldığı<br />

fonksiyonlarda, parametre değişkeni olarak void göstericiler kullanılır. Örneğin<br />

void free (void *p)<br />

{<br />

.<br />

.<br />

.<br />

}<br />

Parametresi void *p olan free fonksiyonu, herhangi türden gösterici ile çağrılabilir.<br />

<strong>Ders</strong> 12: Katarlar (Stringler)<br />

• <strong>Giriş</strong><br />

• 12.1 Katar Bildirimi


• 12.2 Katarlara Başlangıç Değeri Atama<br />

• 12.3 Katar Üzerinde İşlem Yapan Standart G/Ç Fonksiyonları<br />

• 12.4 Bazı Katar Fonksiyonları<br />

• 12.5 Katarların Fonksiyonlarda Kullanılması<br />

<strong>Giriş</strong><br />

Katarlar anlaşılması en zor konulardan biridir. C programlama dilinde iki tırnak içine alınan<br />

her ifadeye katar denir. Örneğin:<br />

"Izmir"<br />

"sonuc = %d\n"<br />

"Devam etmek icin ENTER tusuna basin."<br />

Türkçe yazılan C kitaplarda, ingilizce string kelimesi yerine aşağıdaki ifadelerden biri<br />

karşılaşılabilir:<br />

katar = karakter topluluğu = karakter dizisi = sözce = sicim<br />

Anlatımda, katar terimini kullanacağız.<br />

12.1 Katar Bildirimi<br />

Katarlar, char tipinde bildirilen karakter dizileridir ve harfler, rakamlar, veya bazı<br />

sembolleriden oluşur. C dilinde katar bildirimi için bir tip deyimi yoktur. Bu yüzden, bir<br />

katara bir dizi veya gösterici gözüyle bakılır. Genel olarak bir katarın bildirimi:<br />

yada<br />

char katar_adı[eleman_sayısı];<br />

char *katar_adı;<br />

şeklinde yapılır. Örneğin bir öğrencinin isim bilgisi ad adlı bir katarla tutulmak istenirse:<br />

yada<br />

char ad[10];<br />

char *ad;<br />

şeklinde programın başında bildirilmelidir.<br />

12.2 Katarlara Başlangıç Değeri Atama<br />

Diğer dizi bildirimlerinde olduğu gibi, karakter dizilerine başlangıç değeri verilebilir. Örneğin<br />

aşağıda verilen iki bildirim aynı anlamdadır:<br />

char s[5]={'I','z','m','i','r','\0'};<br />

char s[5]="Izmir";


Birinci satırdaki bildirimde '\0' (NULL) sonlandırıcı karakter dizisinin sonlandığını gösterir.<br />

Daha önce de bahsedildiği gibi sonlandırıcı karakter, karakter dizileri üzerinde işlemlerin hızlı<br />

ve etkin bir biçimde yapılabilmesine olanak sağlar. İkinci bildirimde buna gerek yoktur.<br />

Eğer bir karakter dizisinin kaç eleman sayısı belirtilmezse, başlangıçta bildirilen karakter<br />

sayısı kaç tane ise dizinin eleman sayısı o kadar olduğu varsayılır.<br />

char s[] = "Ankara"; /* 6 elemanlı */<br />

Eğer bildirim gösterici ile yapılmak isterirse:<br />

yada<br />

Ancak<br />

char *s = "Ankara"; /* 6 elemanlı */<br />

char *s;<br />

s = "Ankara";<br />

char s[6];<br />

s = "Ankara";<br />

şeklindeki bir atama geçersizdir. Çünkü bu şekilde yapılan bildirimde s bir değişken değil<br />

dizidir.<br />

Elemanları katar olan diziler tanımlamak mümkündür. Örneğin en uzunu 7 karakter olan 5<br />

farklı isim bir çatı altında şöyle toplanabilir:<br />

yada<br />

yada<br />

char isim[5][8] = { "Semra", "Mustafa", "Ceyhun", "Asli", "Leyla" };<br />

char isim[][8] = { "Semra", "Mustafa", "Ceyhun", "Asli", "Leyla" };<br />

char *isim[5] = { "Semra", "Mustafa", "Ceyhun", "Asli", "Leyla" };<br />

Görüldüğü gibi, bu tip tanımlamalarda birinci boyut (satır) dizinin eleman sayısını, ikinci<br />

boyut (sütun) her bir elemanın sahip olabileceği maksimum karakter sayısını gösterir.<br />

NOT<br />

Katar ifadelerinde doğrudan çift tırnak " veya ters bölü \<br />

karakterleri kullanılamaz. Bu durumda katar ifadeleri<br />

içerisinde<br />

" yerine \"<br />

\ yerine \\<br />

kullanılmalıdır. Örneğin:<br />

char *mes = "\"ilk.c\" dosyasinin yeri:";<br />

char *yol = "C:\\WINDOWS\\DESKTOP\\C";<br />

...<br />

puts(mes);<br />

puts(yol);<br />

ile ekrana aşağıdaki satırlar bastırlır:<br />

"ilk.c" dosyasinin yeri:<br />

C:\WINDOWS\DESKTOP\C


12.3 Katarlar Üzerinde İşlem Yapan Standart G/Ç<br />

Fonksiyonları<br />

printf() ve scanf() fonksiyonları diğer tiplerde olduğu gibi formatlı okuma/yazma amaçlı<br />

kullanılır. Katar formatı %s dir. Örneğin:<br />

char str[20];<br />

...<br />

scanf("%s",str);<br />

printf("%s\n",str);<br />

satırları ile klavyeden okunan katarın ilk 20 karakteri ekrana yazdırlabilir. Burada printf()<br />

fonksiyonu:<br />

printf(str);<br />

şeklinde de kullanılabir. Bu durumda, katar ekrana yazdırılır fakat imlec (cursor) bir alt satıra<br />

geçmez.<br />

gets() fonksiyonu klavyeden karakter dizisi almakta kullanılan bir C fonksiyonudur. Bu<br />

fonksiyon, klavyeden girilen karakterleri diziye yerleştirdikten sonra dizinin sonuna otomatik<br />

olarak NULL ('\0') karakterini ekler.<br />

char str[20];<br />

...<br />

gets(str);<br />

NOT<br />

gets() fonksiyonunu kullanmak biraz tehlikeli olabilir.<br />

Çünkü, gets() ile okuma yapılırken katarın büyüklüğünü<br />

dikkate alınmaz. Örneğin:<br />

char s[10];<br />

gets(s);<br />

şeklindeki okuma işleminde s en fazla 10 karakter<br />

saklayabilirken, gets() ile 100 karakter girilirse, derleyici<br />

bütün karakterleri saklamaya çalışır. Bu durumda, program<br />

sağlıklı çalışmaz ve hata verir. Bu yüzden bazı derleyiciler,<br />

gets() kullanıldığında aşağıdaki gibi bir uyarı verir.<br />

warning: the `gets' function is dangerous and should<br />

not be used.<br />

Sonuç olarak, scanf() fonksiyonunu kullanmanız tavsiye<br />

edilir.<br />

puts() fonksiyonu bir karakter dizisini ekrana yazdırmak için kullanılır. Bu fonksiyon diziyi<br />

ekrana yazdırdıktan sonra imleci (cursor) bir sonraki satıra geçirir.<br />

char *str = "Hangi cilgin bana zincir vuracakmis sasarim";<br />

...<br />

puts(str);<br />

puts(str) ile printf("%s\n",str) işlevsel olarak birbirine eşdeğerdir.


Buraya kadar anlatılanlar Program 12.1-3 de özetlenmiştir.<br />

Program 12.1: Bir katarın farklı yöntemlerle ekrana yazdırılması<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

ÇIKTI<br />

/* 12prg01.c<br />

Bir katarın farklı yöntemlerle ekrana<br />

yazılması */<br />

#include <br />

int main()<br />

{<br />

char dizi[7] = {'S', 'e', 'l', 'a', 'm',<br />

'!', '\0'};<br />

int i;<br />

/* Herbir karakteri ayrı ayrı alt alta yaz<br />

*/<br />

printf("Dizi elemanlari:\n");<br />

for (i=0; i


02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

ÇIKTI<br />

karakterlerinin sayısı hesaplar */<br />

#include <br />

int main()<br />

{<br />

char str[20];<br />

int i,sayac=0;<br />

printf("Bir string girin: ");<br />

gets(str);<br />

for(i=0; str[i] != '\0'; i++)<br />

if( str[i] == 'm') sayac++;<br />

printf("'m' karakteri sayisi = %d\n",sayac);<br />

return 0;<br />

}<br />

Bir katar girin: marmara<br />

'm' karakteri sayisi = 2<br />

13. satırdaki döngüde, str[i]!='\0', koşulu ile sonlandırıcı karaktere gelinip gelinmedği<br />

sorgulanmaktadır. 14. satırda katar içindeki 'm' karakterine rastlanırsa sayac değeri bir<br />

artmaktadır. Katar sonuna kadar bütün 'm' karakterlerinin toplamı hesaplanıp ekrana<br />

yazdırılmıştır.<br />

Program 12.2'deki döngü şöyle de yazılabilirdi:<br />

...<br />

for(i=0; str[i]; i++)<br />

if(str[i] == 'm') sayac++;<br />

...<br />

Buradaki işlemle str[i], NULL karakterinden farklı olduğu sürece döngü devam ettirilmiştir.<br />

Aşağıdaki program elemanlı katar olan bir karakter dizisini ekrana yazar.<br />

Program 12.3: Bir katarı yazdırma<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

/* 12prg03.c: Bir elemanları katar olan karakter<br />

dizisini yazdırma */<br />

#include <br />

int main()<br />

{<br />

char *gun[7] = { "Pazartesi", "Sali",<br />

"Carsamba",<br />

"Cumartesi", "Pazar" };<br />

int i;<br />

"Persembe",<br />

"Cuma",


14:<br />

15:<br />

16:<br />

ÇIKTI<br />

for(i=0; i


Program 12.4: strcmp fonksiyonunun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

/* 12prg04.c: Basit bir şifre programı.<br />

Kullanıcı en fazla 3 kez yanlış şifre<br />

girebilir. */<br />

#include <br />

#include <br />

int main()<br />

{<br />

char sifre[8];<br />

int sonuc, hak=3;<br />

while( hak-- > 0 )<br />

{<br />

printf("Sifre : ");<br />

gets(sifre);<br />

al */<br />

sonuc = strcmp(sifre,"elma%xj4");<br />

if( sonuc==0 ){<br />

kontrol */<br />

puts("sifre dogru");<br />

break;<br />

}<br />

else<br />

puts("sifre yanlis");<br />

}<br />

/* şifreyi<br />

/* şifre<br />

}<br />

return 0;<br />

ÇIKTI<br />

Sifre : admin<br />

sifre yanlis<br />

Sifre : root<br />

sifre yanlis<br />

Sifre : elma%xj4<br />

sifre dogru<br />

Program 12.5: strcpy fonksiyonunun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

/* 12prg05.c: Bir katarı diğerine kopyalama */<br />

#include <br />

#include <br />

int main()<br />

{<br />

char str1[] = "Deneme";<br />

char str2[15], str3[15];<br />

int i;<br />

/* strcpy kullanarak kopyalama */


13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

ÇIKTI<br />

strcpy(str2, str1);<br />

/* strcpy kullanmadan kopyalama */<br />

for(i=0; str1[i]; i++)<br />

str3[i] = str1[i];<br />

str3[i] = '\0'; /* sonlandırıcı ekle */<br />

/* sonuçlar ekrana */<br />

printf("str1 : %s\n",str1);<br />

printf("str2 : %s\n",str2);<br />

printf("str3 : %s\n",str3);<br />

return 0;<br />

}<br />

str1 : Deneme<br />

str2 : Deneme<br />

str3 : Deneme<br />

Program 12.6: strcat fonksiyonunun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

ÇIKTI<br />

/* 12prg06.c: Bir katarı diğerine ekler */<br />

#include <br />

#include <br />

int main()<br />

{<br />

char mesaj[20] = "Selam "; /* 1. katar */<br />

char isim[10]; /* 2. katar */<br />

printf("Adiniz ? : ");<br />

scanf("%s",isim);<br />

/* ekle */<br />

strcat(mesaj, isim);<br />

printf("%s\n",mesaj);<br />

return 0;<br />

}<br />

Adiniz ? : Mert<br />

Selam Mert<br />

Program 12.7: strlen fonksiyonunun kullanımı<br />

01:<br />

02:<br />

03:<br />

/* 12prg07.c: Bir karakter dizisinin uzunluğunu<br />

bulur */


04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

ÇIKTI<br />

#include <br />

#include <br />

int main()<br />

{<br />

char s[20];<br />

int k = 0;<br />

printf("Bir seyler yazin : ");<br />

scanf("%s",s);<br />

/* sonlandırıcı karaktere kadar */<br />

while( s[k] != '\0' )<br />

k++;<br />

puts("Dizinin uzunlugu");<br />

printf("strlen kullanarak =<br />

%d\n",strlen(s));<br />

printf("strlen kullanmadan = %d\n",k);<br />

return 0;<br />

}<br />

Bir seyler yazin : deneme stringi<br />

Dizinin uzunlugu<br />

strlen kullanarak = 14<br />

strlen kullanmadan = 14<br />

Program 12.8: Isim sırlama<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

/* 12prg08.c<br />

Kabarcık Sıralama (Bubble Sort) Algoritması<br />

ile<br />

isimleri alfabetik sırayla listeler */<br />

#include <br />

#include <br />

#define n 5<br />

int main()<br />

{<br />

char isim[n][8] = { "Semra", "Mustafa",<br />

"Ceyhun", "Asli", "Leyla" };<br />

char gecici[8];<br />

int i,j,k;<br />

puts("Once:\n------");<br />

for(i=0; i


27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

{<br />

}<br />

strcpy(gecici ,isim[j]);<br />

strcpy(isim[j] ,isim[j+1]);<br />

strcpy(isim[j+1],gecici);<br />

puts("\nSonra:\n------");<br />

for(i=0; i


15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

printf("Uzunlugu (struzn) : %d\n",struzn(s));<br />

printf("Uzunlugu (strlen) : %d\n",strlen(s));<br />

return 0;<br />

}<br />

/* bir karakter dizisinin uzunluğunu hesaplar */<br />

int struzn(char *str)<br />

{<br />

int n = 0;<br />

}<br />

ÇIKTI<br />

while(str[n])<br />

n++;<br />

return n;<br />

Bir katar girin: Programlama<br />

Uzunlugu (struzn) : 11<br />

Uzunlugu (strlen) : 11<br />

Program 12.10: strrev dengi bir fonksiyon: strcev<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

/* 12prg10.c: Bir katarın tersini veren bir<br />

fonksiyon */<br />

#include <br />

#include <br />

char *strcev(char *);<br />

int main()<br />

{<br />

char s[50];<br />

printf("Bir katar girin: ");<br />

scanf("%s",s);<br />

printf("Katar, s : %s\n",s);<br />

printf("Tersi, strcev(s) : %s\n",strcev(s));<br />

return 0;<br />

}<br />

/* str katarını ters-yüz eder */<br />

char *strcev(char *str)<br />

{<br />

int i,n;<br />

char gecici;<br />

n = strlen(str);<br />

for(i=0; i


33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

ÇIKTI<br />

}<br />

str[i] = str[n-i-1];<br />

str[n-i-1] = gecici;<br />

return str; /* geri dönüş değeri bir gösterici<br />

*/<br />

}<br />

Bir katar girin: Programlama<br />

Katar, s : Programlama<br />

Tersi, strcev(s) : amalmargorP<br />

<strong>Ders</strong> 13: Dinamik Bellek Yönetimi<br />

• <strong>Giriş</strong><br />

• 13.1 Dinamik Dizi Fonksiyonları<br />

• 13.2 Dinamik Matrisler<br />

<strong>Giriş</strong><br />

Bir C programı içerisinde, dizilerin boyutu ve kaç elemanlı olduğu program başında<br />

belirtilirse, derleyici o dizi için gereken bellek alanını (bölgesini) program sonlanıncaya kadar<br />

saklı tutar ve bu alan başka bir amaç için kullanılamaz [1]. Bu türden diziler statik dizi olarak<br />

isimlendirilir. Statik dizinin boyutu programın çalışması esnasında (run time) değiştirilemez.<br />

Fakat, programın çalışırken bir dizinin boyutu ve eleman sayısı bazı yöntemler kullanılarak<br />

değiştirilebilir. Bu tür dizilere dinamik dizi denir. Dinamik diziler için gereken bellek<br />

bölgesi, derleyici tarafından işletim sisteminden istenir, kullanılır ve daha sonra istenirse bu<br />

bölge boşaltırılır. Bu bölümde, dinamik dizi kavramı ve dinamik bellek yönetimi<br />

anlatılacaktır.<br />

13.1 Dinamik Dizi Fonksiyonları<br />

ANSI C'de, dinamik diziler işaretçi kullanılarak ve standart kütüphanedeki malloc(),<br />

calloc(), realloc() ve free() fonksiyonlarının yardımıyla ile oluşturulur veya boşaltılır.<br />

Bu fonksiyonlar Tablo 13.1 de listelenmiştir.<br />

Tablo 13.1: stdlib.h kütüphanesindeki dinamik bellek fonksiyonları<br />

Dinamik Bellek Fonksiyonu<br />

void *malloc(size_t eleman_sayısı);<br />

Açıklama<br />

Bellekte herbiri size_t tipinde olan<br />

eleman_sayısı kadar yer (bellek bloğu)<br />

ayırır. Bu yer verilmezse geriye NULL gönderir.


void *calloc(size_t eleman_sayısı,<br />

size_t nbayt);<br />

void *realloc(void *ptr, size_t<br />

nbayt);<br />

void free(void *ptr);<br />

Bellekte herbiri nbayt kadar yer işgal edecek<br />

eleman_sayısı kadar boş yer ayırır ve bütün<br />

bitleri sıfırlar. Bu yer ayrılamazsa geriye NULL<br />

gönderir.<br />

ptr işaretçisi ile gösterilen bellek bloğunu,<br />

nbayt kadar büyüterek veya küçülterek<br />

değiştirir. Bu iş gerçekleşmezse geriye NULL<br />

gönderir.<br />

Daha önce ayrılan adresi ptr'de saklanan<br />

bellek alanının boşaltır.<br />

Tamsayı tipinde bir dinamik dizi tanımlanırken aşağıdaki işlem basamakları izlenmelidir:<br />

/* dinamik dizi bildirimi */<br />

int *dizi;<br />

/* eleman saysını belirle */<br />

scanf("%d",&n);<br />

/* n tane bellek bloğu isteniyor */<br />

dizi = (int *) malloc( sizeof(int)*n );<br />

/* Boş yer varmı sorgulanıyor */<br />

if( dizi == NULL )<br />

printf("Yetersiz bellek alanı\n"), exit(1);<br />

...<br />

/* dizi burada kullanılıyor */<br />

...<br />

/* bellek bloğu boşaltılıyor */<br />

free(dizi);<br />

Program 13.1, eleman sayısı klavyeden girilen bir dizinin aritmetik ortalamasını hesaplar.<br />

Eleman sayısı sıfır veya negatif bir değer olduğunda, sonsuz döngüden çıkılır ve program<br />

sonlanır. İnceleyiniz.<br />

Program 13.1: Dinamik dizi ile ortalama hesabı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

/* 13prg01.c: Dinamik dizi ile ortalama hesabı<br />

*/<br />

#include <br />

#include <br />

int main(){<br />

int n,i;<br />

float *x, toplam, ort;<br />

while(1)<br />

{<br />

/* dizinin eleman sayısı okunuyor */<br />

printf("\nEleman sayısını girin: ");<br />

scanf("%d",&n);


18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

);<br />

ÇIKTI<br />

/* eleman sayısı


06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

char *altKatar(char *str, int, int);<br />

int main()<br />

{<br />

int i;<br />

char *s, *parca;<br />

s = "programlama";<br />

for(i=0; s[i]; i++)<br />

{<br />

parca = altKatar(s, 0, i);<br />

puts(parca);<br />

}<br />

return 0;<br />

}<br />

/* str'nin p1. elemanindan p2. elemanina kadar<br />

olan alt katarını gonderir. */<br />

char *altKatar(char *str, int p1, int p2)<br />

{<br />

int i, j=0, n;<br />

static char *alt;<br />

n = p2 - p1;<br />

}<br />

ÇIKTI<br />

/* bellekten yer ayrılıyor... */<br />

alt = (char *) malloc( n*sizeof(char) );<br />

for(i=p1; i


01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

50:<br />

/* 13prg02.c: Dinamik matris tanımlama */<br />

#include <br />

#include <br />

int main()<br />

{<br />

int **matris;<br />

int satir, kolon;<br />

int s, k;<br />

int i;<br />

printf("Matrisin satır sayısı: ");<br />

scanf("%d", &satir);<br />

printf("Matrisin kolon sayısı: ");<br />

scanf("%d", &kolon);<br />

/* dıştaki dizi için bellek alanı isteniyor<br />

*/<br />

matris = (int **) calloc(satir,<br />

sizeof(int));<br />

/* içteki dizi için bellek alanı isteniyor<br />

*/<br />

for(i = 0; i < satir; i++)<br />

matris[i] = (int *) calloc(kolon,<br />

sizeof(int));<br />

/* matrisin elemanları okunuyor */<br />

for(s = 0; s < satir; s++)<br />

for(k = 0; k < kolon; k++) {<br />

printf("Matrisin elemanı girin:<br />

matris[%d][%d] = ", s, k);<br />

scanf("%d", &(matris[s][k]));<br />

}<br />

printf("\nGirilen matris:\n");<br />

for(s = 0; s < satir; s++) {<br />

for(k = 0; k < kolon; k++)<br />

printf("%4d", matris[s][k]);<br />

}<br />

printf("\n");<br />

/* içteki dizi boşaltılıyor */<br />

for(i = 0; i < satir; i++)<br />

free((void *) matris[i]);<br />

/* dıştaki dizi boşaltılıyor */<br />

free((void *) matris);<br />

}<br />

return(0);<br />

ÇIKTI<br />

Matrisin satır sayısı: 2<br />

Matrisin kolon sayısı: 3


Matrisin elemanı girin: matris[0][0] = 1<br />

Matrisin elemanı girin: matris[0][1] = 2<br />

Matrisin elemanı girin: matris[0][2] = 3<br />

Matrisin elemanı girin: matris[1][0] = 5<br />

Matrisin elemanı girin: matris[1][1] = 6<br />

Matrisin elemanı girin: matris[1][2] = 8<br />

Girilen matris:<br />

1 2 3<br />

5 6 8<br />

<strong>Ders</strong> 14: Gösterici Uygulamaları<br />

• <strong>Giriş</strong><br />

• 14.1 Gösterici Uygulamarı<br />

<strong>Giriş</strong><br />

Bu bölümde bazı gösterici uygulamaları gösterilmiştir.<br />

14.1 Gösterici Uygulamarı<br />

i. Rastgele dizi<br />

ii. Bir dizinin elemanlarını küçükten büyüğe doğru sıralama<br />

iii. Bir dizinin kare kökünü hesaplayan fonksiyon<br />

iv. Dinamik matris çarpımı<br />

Program 14.1: Rastgele dizi<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

/* 14prg01.c: Rastgele Dizi */<br />

#include <br />

#include <br />

/* dizinin ilk n elemanına [0,1] arasında<br />

rastgele sayı atar */<br />

void rastgele(double *dizi, int n){<br />

int i;<br />

}<br />

for(i=0; i


21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

}<br />

srand(1234567);<br />

rastgele(x, 5);<br />

puts("Rastgele dizi elemanları:");<br />

for(i=0; i


38:<br />

39:<br />

}<br />

printf("\n");<br />

return 0;<br />

ÇIKTI<br />

Once : 22 44 11 55 33<br />

Sonra: 11 22 33 44 55<br />

Program 14.3: Bir dizinin kare kökünü hesaplayan fonksiyon<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

/* 14prg03.c: Bir dizinin kare kökünü hesaplayan<br />

fonksiyon */<br />

#include <br />

#include <br />

#include <br />

double *kare_kok(double *, int);<br />

int main()<br />

{<br />

double A[5] = {1.0, 2.0, 4.0, 8.0, 16.0};<br />

double *B;<br />

int i;<br />

}<br />

printf("A dizisi: ");<br />

for(i=0; i


45: c[i] = sqrt(dizi[i]);<br />

}<br />

return c;<br />

ÇIKTI<br />

A dizisi: 1.000000 2.000000 4.000000 8.000000<br />

16.000000<br />

B dizisi: 1.000000 1.414214 2.000000 2.828427<br />

4.000000<br />

Program 14.4: Dinamik Matris Çarpımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

/* 14prg04.c: Dinamik Matris Çarpımı<br />

Bu program A(mxn) matrisi ile B(pxq)<br />

matrisini çarpımını hesaplar.<br />

Çarpım matrisi C(mxq), C = AB dir. Çarpımın<br />

sonucu matris_carp()<br />

fonksiyonu ile hesaplanır.<br />

Örnek:<br />

~~~~~~<br />

[ 1 0 2 ] [ 3 1 ] [ 1 0<br />

2 ] [ 3 1 ] [ 5 1 ]<br />

A = [-1 3 1 ] B =[ 2 1 ] ==> C = AB = [-1 3<br />

1 ] [ 2 1 ] = [ 4 2 ]<br />

[ 1 0 ]<br />

[ 1 0 ]<br />

*/<br />

#include <br />

#include <br />

double **matris_carp(double **, int, int,<br />

double **, int, int);<br />

int main()<br />

{<br />

double **A;<br />

double **B;<br />

double **C;<br />

int i, j;<br />

/* A matrisi için bellekten yer ayır */<br />

A = (double **) calloc( 2, sizeof(double));<br />

for(i = 0; i < 2; i++)<br />

A[i] = (double *) calloc(3,<br />

sizeof(double));<br />

/* B matrisi için bellekten yer ayır */<br />

B = (double **) calloc( 3, sizeof(double));<br />

for(i = 0; i < 3; i++)<br />

B[i] = (double *) calloc(2,<br />

sizeof(double));


44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

50:<br />

51:<br />

52:<br />

53:<br />

54:<br />

55:<br />

56:<br />

57:<br />

58:<br />

59:<br />

60:<br />

61:<br />

62:<br />

63:<br />

64:<br />

65:<br />

66:<br />

67:<br />

68:<br />

69:<br />

70:<br />

71:<br />

72:<br />

73:<br />

74:<br />

75:<br />

76:<br />

77:<br />

78:<br />

79:<br />

80:<br />

81:<br />

82:<br />

83:<br />

84:<br />

85:<br />

86:<br />

}<br />

/* A matrisinin elemanları */<br />

A[0][0] = 1.0; A[0][1] = 0.0; A[0][2] = 2.0;<br />

A[1][0] =-1.0; A[1][1] = 3.0; A[1][2] = 1.0;<br />

/* B matrisinin elemanları */<br />

B[0][0] = 3.0; B[0][1] = 1.0;<br />

B[1][0] = 2.0; B[1][1] = 1.0;<br />

B[2][0] = 1.0; B[2][1] = 0.0;<br />

/* C = AB matrisi */<br />

C = matris_carp(A,2,3, B,3,2);<br />

for(i=0; i


<strong>Ders</strong> 15: Yapılar ve Birlikler<br />

• <strong>Giriş</strong><br />

• 15.1 enum Deyimi (Enumeration Constants)<br />

• 15.2 Yapı, struct Deyimi (Structures)<br />

• 15.3 typedef Deyimi<br />

• 15.4 Birlik, union Deyimi<br />

<strong>Giriş</strong><br />

C, kullanıcının kendi veri tipini tanımlamasına müsaade eder. Bu kısımda böyle veritiplerinin<br />

nasıl oluşturulacağı anlatılacaktır.<br />

15.1 enum Deyimi (Enumeration Constants)<br />

Bu tip, değişkenin alabileceği değerlerin belli (sabit) olduğu durumlarda programı daha<br />

okunabilir hale getirmek için kullanılır. Genel yazım biçimi:<br />

enum tip_adı{değer_1, değer_2, ..., değer_n} değişken_adı;<br />

tip_adı programcı tarafından verilen tip ismidir. değişken_adı ise program içinde<br />

kullanılacak olan değişkenin adıdır. Eğer kullanılmazsa program içinde daha sonra enum ile<br />

birlikte kullanılır. Örneğin:<br />

enum bolumler{programcilik, donanim, muhasebe, motor};<br />

tanımı ile derleyici programcilik için 0, donanim için 1, muhasebe için 2 ve motor için 3<br />

değerini kabul ederek atamaları buna göre yapar. Değişken adı bildirilirse daha sonra enum<br />

kullanmaya gerek kalmaz. Örneğin:<br />

enum renkler {kirmizi, mavi, sari} renk;<br />

enum gunler {pazartesi, sali, carsamba, persembe, cuma, cumartesi,<br />

pazar};<br />

gibi yapılan sabit tanımlamaları program içinde kullanılabilir:<br />

enum bolumler bolum;<br />

enum gunler gun;<br />

...<br />

bolum = muhasebe; /* bolum = 2 anlamında */<br />

gun = cuma; /* gun = 4 anlamında */<br />

renk = kirmizi; /* renk = 0 anlamında */<br />

Program 15.1 enum anahtar kelimesinin basit kullanımları gösterilmiştir.<br />

Program 15.1: enum kullanımı


01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

/* 15prg01.c: Klavyeden girilen bir sayının tek<br />

olup olmadığını sınar */<br />

#include <br />

enum BOOLEAN{ FALSE, TRUE }; /* 0, 1 */<br />

int tek(int n){ return (n % 2); }<br />

int main()<br />

{<br />

enum BOOLEAN sonuc;<br />

int x;<br />

}<br />

ÇIKTI<br />

printf("Bir sayi girin: ");<br />

scanf("%d",&x);<br />

sonuc = tek(x); /* tek mi? */<br />

if( sonuc == TRUE )<br />

puts("Girilen sayi tek ");<br />

else<br />

puts("Girilen sayi cift");<br />

return 0;<br />

Bir sayi girin: 5<br />

Girilen sayi tek<br />

enum bloğu içinde tanımlanmış değişkenlerin sahip sabit olacağı değerler Program 15.2<br />

olduğu gibi programcı tarafından belirlenebilir.<br />

Program 15.2: enum kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

/* 15prg02.c: Beş sabit bölüm için enum<br />

kullanımı */<br />

enum bolumler{<br />

programcilik = 1, /* 1 */<br />

donanim, /* 2 */<br />

muhasebe, /* 3 */<br />

motor, /* 4 */<br />

buro /* 5 */<br />

} bolum;<br />

int main()<br />

{<br />

bolum = donanim;<br />

printf("bolum : %d\n",bolum);<br />

bolum += 2; /* bolum = motor */<br />

printf("Yeni bolum : %d\n",bolum);


22: return 0;<br />

}<br />

ÇIKTI<br />

bolum : 2<br />

Yeni bolum : 4<br />

15.2 Yapı, struct Deyimi (Structures)<br />

Aralarında mantıksal bir ilişki bulunan farklı türden bilgiler "yapılar (structures)" içerisinde<br />

mantıksal bir bütün olarak ifade edilebilir. Yapılar diziler gibi bellekte sürekli kalır. Bir yapı<br />

içerisindeki elemanlara üye (member) denir. Üyelerin herbiri farklı veri tipine sahip olabilir.<br />

Bu sayede, kendi tipinizi üretebilirsiniz.<br />

Genel yapı bildirimi:<br />

struct yapı_adı{<br />

tip yapı_değişken_ismi;<br />

tip yapı_değişken_ismi;<br />

...<br />

};<br />

NOT<br />

enum ile sabit bildirimi yapılırken<br />

struct ile değişken bildirimi yapılır.<br />

Bir öğrenciye ait bilgileri bir çatı altında aşağıdaki gibi toplanabilir:<br />

/* kayit veri tipi! */<br />

struct kayit{<br />

/* üyeler */<br />

char ad[10];<br />

long no;<br />

short sinif;<br />

};<br />

Bu tipte bir değişken tanımlama:<br />

struct kayit ogr1, ogr2;<br />

şeklinde olabilir. ogr1 değişkeni ile tanımlanan 1. öğrencinin numarasına bir değer atama<br />

işlemi:<br />

ogr1.no = 2012597;<br />

şeklinde yapılır. Bu deyimin kullanımı Program 15.3, ve 15.4'de gösterilmiştir. Inceleyiniz.<br />

Program 15.3: struct deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

/* 15prg03.c<br />

Bir öğrenciye ait bilgilerin struct deyimi<br />

ile bir çatı altında toplanması */<br />

#include


07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

ÇIKTI<br />

/* kayit yapısı */<br />

struct kayit{<br />

char ad[10];<br />

long no;<br />

int sinif;<br />

};<br />

int main()<br />

{<br />

struct kayit ogr;<br />

tipinde */<br />

/* ogr değişkeni kayit<br />

printf("Ogrenci Nosu : ");<br />

scanf("%ld",&ogr.no);<br />

printf("Ogrenci Adi : "); scanf("%s" ,<br />

ogr.ad);<br />

printf("Ogrenci Sinifi: "); scanf("%d"<br />

,&ogr.sinif);<br />

printf("\n*** Girilen bilgiler ***");<br />

printf("\nNo : %ld",ogr.no);<br />

printf("\nAdi : %s ",ogr.ad);<br />

printf("\nSinifi: %d ",ogr.sinif);<br />

return 0;<br />

}<br />

Ogrenci Nosu : 948589<br />

Ogrenci Adi : Ahmet<br />

Ogrenci Sinifi: 2<br />

*** Girilen bilgiler ***<br />

No : 948589<br />

Adi : Ahmet<br />

Sinifi: 2<br />

Yapılar, diğer değişkenler gibi, fonksiyonlara parametre olarak geçirelilebilir.<br />

Program 15.4: struct deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

/* 15prg04.c<br />

Yapıların bir fonksiyona parametere olarak<br />

aktarılabilmesi */<br />

#include <br />

struct TARIH{<br />

int gun,ay,yil;<br />

};<br />

void goster(struct TARIH x){<br />

printf("Tarih: %02d-%02d-%4d\n", x.gun,<br />

x.ay, x.yil);<br />

}<br />

int main()<br />

{<br />

struct TARIH n; /* n değişkeni TARIH tipinde


19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

*/<br />

n.gun = 1;<br />

n.ay = 8;<br />

n.yil = 2003;<br />

goster(n);<br />

ÇIKTI<br />

return 0;<br />

}<br />

Tarih: 01-08-2003<br />

Yapılarla da, gösterici tanımlamaları yapılabilir. Ancak, bir yapı gösteren göstericinin,<br />

gösterdiği yere yönlendirme operatörü, ->, ile erişilir.<br />

Program 15.5: struct deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

/* 15prg05.c: Bir yapı gösteren gösterici */<br />

#include <br />

struct Meyve{<br />

float agirlik;<br />

float fiyat;<br />

};<br />

int main()<br />

{<br />

struct Meyve *muz, elma;<br />

float muzTutar, elmaTutar;<br />

/* muz Meyve tipinde bir gösterici */<br />

muz->agirlik = 2.50;<br />

muz->fiyat = 3.50;<br />

muzTutar = muz->fiyat * muz->agirlik;<br />

/* elma Meyve tipinde bir değişken */<br />

elma.agirlik = 2.00;<br />

elma.fiyat = 1.75;<br />

elmaTutar = elma.fiyat * elma.agirlik;<br />

printf("Meyve Agırlık Birim Fiyatı<br />

TUTAR (TL)\n");<br />

printf("----- ------- ------------ ---<br />

--------\n");<br />

printf("Muz %7.2f %7.2f<br />

%7.2f\n",<br />

muz->agirlik, muz->fiyat, muzTutar);<br />

printf("Elma %7.2f %7.2f<br />

%7.2f\n",<br />

elma.agirlik, elma.fiyat, elmaTutar);<br />

return 0;<br />

}


ÇIKTI<br />

Meyve Agırlık Birim Fiyatı TUTAR (TL)<br />

----- ------- ------------ -----------<br />

Muz 2.50 3.50 8.75<br />

Elma 2.00 1.75 3.50<br />

15.3 typedef Deyimi<br />

struct ile oluşturulan yapıda typedef deyimi kullanılırsa, bu yapıdan değişken tanımlamak<br />

için tekrar struct deyiminin kullanılmasına gerek kalmaz.<br />

typedef struct kayit{<br />

char ad[10];<br />

long no;<br />

short sinif;<br />

} ogr1,ogr2;<br />

Program 15.4 küçük bir değişiklike Program 15.6'de yeniden yazılmıştır. Inceleyiniz.<br />

Program 15.6: typedef - struct deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

ÇIKTI<br />

/* 15prg06.c<br />

Yapıların bir fonksiyona parametere olarak<br />

aktarılabilmesi.<br />

typedef deyimi kullanıldığında struct<br />

deyimine gerek yoktur */<br />

#include <br />

typedef struct{<br />

int gun,ay,yil;<br />

}TARIH;<br />

void goster(TARIH x){<br />

printf("Tarih: %02d-%02d-%4d\n", x.gun,<br />

x.ay, x.yil);<br />

}<br />

int main(void)<br />

{<br />

TARIH n;<br />

n.gun = 1;<br />

n.ay = 8;<br />

n.yil = 2003;<br />

goster(n);<br />

return 0;<br />

}<br />

Tarih: 01-08-2003


typedef başka kullanımı da vardır. C dilinde program kodları bu deyimle tamamen<br />

türkçeleştirilebilir. Örneğin bu deyim:<br />

typedef int tamsayi;<br />

şeklinde kullanılırsa programda daha sonra int tipinde bir değişken tanımlarken şu biçimde<br />

kullanılmasına izin verilir.<br />

tamsayi x,y; /* int x,y anlaminda */<br />

15.1 Birlik, union Deyimi<br />

Birlikler de yapılar gibi sürekli belleğe yerleşen nesnelerdir. Birlikler yapılara göre seyrek<br />

kullanılır. Bir programda veya fonksiyonda değişkenlerin aynı bellek alanını paylaşması için<br />

ortaklık bildirimi union deyimi ile yapılır. Bu da belleğin daha verimli kullanılmasına imkan<br />

verir. Bu tipte bildirim yapılırken struct yerine union yazılır. Genel yazım biçimi:<br />

union birlik_adı{<br />

tip birlik_değişken_ismi;<br />

tip birlik_değişken_ismi;<br />

...<br />

};<br />

union paylas{<br />

float f;<br />

int i;<br />

char kr;<br />

};<br />

Yukarıdaki bildirim yapıldığında, değişkenler için bellekte bir yer ayrılmaz. Değişken<br />

bildirimi:<br />

union paylas bir,iki;<br />

şeklinde yapılır. Üyelere erişmek aşağıdaki gibi olur:<br />

bir.kr= 'A';<br />

iki.f = 3.14;<br />

bir.i = 2000;<br />

Program 15.7: typedef - deyiminin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

/* 15prg07.c<br />

union x ve y nin aynı bellek alanını işgal<br />

ettiğinin kanıtı */<br />

#include <br />

union paylas{<br />

int x;<br />

int y;<br />

}z;<br />

int main()<br />

{<br />

int *xAdres,*yAdres;


15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

ÇIKTI<br />

z.x = 11;<br />

xAdres = &z.x;<br />

printf("x = %d y = %d\n",z.x, z.y);<br />

z.y = 22;<br />

yAdres = &z.y;<br />

printf("y = %d y = %d\n",z.x, z.y);<br />

printf("xAdres = %p yAdres = %p\n",xAdres,<br />

yAdres);<br />

return 0;<br />

}<br />

x = 11 y = 11<br />

y = 22 y = 22<br />

xAdres = 0x804974c<br />

yAdres = 0x804974c<br />

<strong>Ders</strong> 16: Dosya Yönetimi<br />

• <strong>Giriş</strong><br />

• 16.1 Dosya Açma ve Kapama<br />

• 16.2 Metin ve İkili Dosyalar<br />

• 16.3 Dosya Fonksiyonları<br />

• 16.4 Standart Dosyalar<br />

<strong>Giriş</strong><br />

Birçok programda, bazı verilerin disk üzerinde saklanmasına gerek duyulur. Bütün<br />

programlama dillerinde, sabit disk sürücüsü (Hard Disk Drive, HDD) üzerindeki verileri<br />

okumak veya diske veri yazmak için hazır fonksiyonlar tanımlanmıştır. C programlama<br />

dilinde, disk dosyasına erişim iki yöntemle yapılır. Bunlar üst düzey ve alt düzey olarak<br />

adlandırılır. Üst düzey G/Ç yöntemi ANSI C tarafından desteklenmektedir. Bu kısımda Üst<br />

düzey G/Ç konu edilecektir[1].<br />

16.1 Dosya Açma ve Kapama<br />

Bir dosyaya okuma/yazma yapmak için onun açılması gerekir. Dosya açmak için fopen(),<br />

kapatmak için fclose() fonksiyonu kullanılır. Bu fonksiyonlar stdio.h başlık dosyasında<br />

tanımlanmıştır.<br />

Genel olarak, dosya açma kapama adımları şu şekildedir:<br />

FILE *dosya; /* dosya göstericisi */<br />

dosya = fopen(const char dosya_adı, const char mod);


...<br />

dosya işlemleri<br />

...<br />

fclose(dosya);<br />

Burada FILE, stdio.h içerisinde bildirilmiş bir yapıdır. mod ile açılacak olan dosyanın ne<br />

amaçla açılacağı belirlenir[2].<br />

Tablo 16.1: Dosya açma modları<br />

Açılış Modu İşlem Türü<br />

Salt okunur (read only). Dosyanın açılabilmesi için önceden oluştrulmuş<br />

r<br />

olması gerekir. Bu modda açılmş olan bir dosyaya yazma yapılamaz.<br />

Yalnızca yazma (write only). Dosya diskte kayıtlı olsun veya olamsın dosya<br />

w<br />

yeniden oluşturulur. Bu modda açılmış olan bir dosyadan okuma yapılamaz.<br />

Ekleme (append). Kayıtlı bir dosyanın sonuna veri eklemek için açılır. Bu<br />

a<br />

modda açılmış olan bir dosyadan okuma yapılamaz.<br />

Okuma ve yazma. Bu modda açılmış olan bir dosyanın daha önce varolması<br />

r+<br />

gerekir.<br />

Okuma ve yazma. Bu modda açılmış olan bir dosya var olsun veya olmasın<br />

w+<br />

dosya yeniden oluşturulur.<br />

a+ Okuma ve yazma. Kayıtlı bir dosyanın sonuna veri eklemek için açılır.<br />

deneme.dat adlı bir dosyanın, yazmak için açılıp açılmadığını test etmek için aşağıdaki kod<br />

kullanılır:<br />

FILE *yaz; /* dosya göstericisi */<br />

yaz = fopen("deneme.dat", "w");<br />

if( yaz == NULL ){<br />

puts("dosya acilmiyor...");<br />

exit(1);<br />

}<br />

...<br />

/* açılırsa! dosya işlemleri */<br />

...<br />

fclose(yaz);<br />

NOT<br />

deneme.dat dosyası ile ana program aynı dizin içinde<br />

olmalıdır. Aksi halde, dosyanın tam yolu bildirilmelidir.<br />

Örneğin dosyanın yolu: C:\WINDOWS\DESKTOP\deneme.dat<br />

ise dosya açılırken<br />

yaz = fopen("C:\\WINDOWS\\DESKTOP\\deneme.dat",<br />

"w");<br />

şeklinde açık yol bildirilmelidir. Aynı işlem Linux ortamında


da<br />

geçerlidir.<br />

gibi.<br />

yaz = fopen("/home/bingul/DATA/deneme.dat","w");<br />

16.2 Metin ve İkili Dosyalar<br />

İşletim sistemlerinde genelde iki çeşit dosya kullanımına rastlanmaktadır. Bunlar metin (text)<br />

ve ikili (binary) dosyalar olmak üzere ikiye ayrılır. Dosyanın hangi türden olduğu açılırken<br />

fopen() fonksiyonu ile belirtilebilir.<br />

Açılış modunda metin dosyaları için t, ikili dosyalar için b eklenir. Örneğin "r+t" şeklinde<br />

bir açılış modu var olan bir dosyanın okuma yazma ve metin olarak açılacağı anlamına gelir.<br />

Benzer olarak "wb" açılış modu dosyanın ikili modda oluşturulacağını gösterir. Fakat bu<br />

belirleme yapılmamışsa, varsayılan açılış modu metindir (yani t).<br />

16.3 Dosya Fonksiyonları<br />

Bu kısımda, Tablo 16.2'de verilen dosyalama foksiyonlarının bazılarının kullanımı, örnek<br />

programlar üzerinde anlatılmıştır.<br />

Tablo 16.2: Üst düzey dosyalama fonksiyonları<br />

Fonksiyon<br />

fopen()<br />

fclose()<br />

putc()<br />

getc()<br />

feof()<br />

fprintf()<br />

fscanf()<br />

fputs()<br />

fgets()<br />

fwrite()<br />

fread()<br />

Görevi<br />

Dosya oluşturur, açar<br />

Dosyayı kapatır<br />

Dosyaya bir karakter yazar<br />

Dosyadan bir karakter okur<br />

Dosya sonuna gelindiğini sorgular<br />

Dosyaya formatlı veri yazar<br />

Dosyadan formatlı veri okur<br />

Dosyaya katar yazar<br />

Dosyadan katar okur<br />

Dosyaya dizi yazar<br />

Dosyadan dizi okur<br />

Program 16.1: Bir dosyaya veri yazma<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

/* 16prg01.c:<br />

10 öğrenciye ait bilgileri 'ogrenci.txt'<br />

dosyasına kaydeder. */<br />

#include <br />

#include <br />

int main()<br />

{


10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

ÇIKTI<br />

FILE *dg; /* dosya göstericisi */<br />

const int n = 10; /* öğrenci sayısı */<br />

char ad[10];<br />

int no, Not, i=0;<br />

dg = fopen("ogrenci.txt", "w");<br />

if( dg == NULL )<br />

puts("ogrenci.txt dosyasi acilmadi. !\n"),<br />

exit(1);<br />

puts("10 ogrenciye ait bilgileri girin:");<br />

while( i++


C:\TC> edit ogrenci.txt<br />

$ edit ogrenci.txt<br />

yada<br />

$ pico ogrenci.txt<br />

NOT<br />

ogrenci.txt dosyası daha önce oluşturulmuşsa Program<br />

16.1 önceki verileri silip yerine yeni verileri yazacaktır. Bu<br />

dosyaya yeni bir veri eklemek için fopen() fonksiyonunu 'a'<br />

modu ile kullanılmalıdır.<br />

Bir dosyadan veri okumanın bir çok şekli vardır. Veri okuma işlemine basit bir örnek Program<br />

16.2 de sunulumuştur. Bu program ogrenci.txt dosyasında kayıtlı öğrencilerden, en düşük<br />

notu, en yüksek notu ve sınıf ortalamasını (0'lar hariç) hesaplamaktadır.<br />

Program 16.2: Bir dosyadan veri okuma<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

/* 16prg02.c:<br />

ogrenci.txt dosyasından no, isim ve not<br />

bilgileri okur ve<br />

notlar arasından en büyüğü, en küçüğü ve<br />

sınıf ortlamasını (0'lar hariç) hesaplar. */<br />

#include <br />

#include <br />

int main()<br />

{<br />

FILE *dg; /* dosya işaretçisi */<br />

char Ad[10];<br />

int Not, No, eb, ek, n, top;<br />

float ort;<br />

if( (dg=fopen("ogrenci.txt","r")) == NULL )<br />

puts("Dosya açılmadı !\n"), exit(1);<br />

/* başlangıç değerleri ata */<br />

ek = 1000; /* çok büyük */<br />

eb = -1000; /* çok küçük */<br />

top = 0; /* notların toplamı */<br />

n = 0; /* notu 0'dan farlı<br />

öğrencilerin toplamı */<br />

while( !feof(dg) ) /*<br />

dosyanın sonuna kadar */<br />

{<br />

fscanf(dg,"%d %s %d",&No,Ad,&Not); /*<br />

verileri oku! */<br />

if(Not>eb) eb = Not;<br />

büyük ve en küçük bulunuyor... */<br />

if(Not


44:<br />

45:<br />

ÇIKTI<br />

fclose(dg); /*<br />

dosyayı kapat */<br />

ort = (float) top/n; /*<br />

ortalama (0 lar hariç!) */<br />

printf("En yuksek not = %2d\n",eb); /*<br />

sonuçlar ekrana ... */<br />

printf("En dusuk not = %2d\n",ek);<br />

printf("Ortalama = %4.1f\n",ort);<br />

return 0;<br />

}<br />

En yuksek not = 92<br />

En dusuk not = 0<br />

Ortalama = 69.2<br />

Bir program içinde birden çok dosya açmak mümkündür. Örneğin bir dosyadan okunan<br />

veriler farklı bir formatta başka bir dosyaya yazılması istenebilir.Program 16.3 kelvin.sck<br />

dosyasında bulunan 100 adet kelvin cinsinden sıcaklık bilgilerini derece karşılıklarını<br />

derece.sck dosyasına yazar. Bu iki sıcaklık arasındaki çevrim kuralı: K = 273 + C<br />

şeklindedir.<br />

Program 16.3: Bir dosyada saklı verileri farklı bir biçimde başka bir dosyaya yazma<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

/* 16prg03.c<br />

'kelvin.sck' dosyasında bulunan 100 adet<br />

kelvin cinsinden sıcaklık<br />

bilgilerini derece karşılıklarını<br />

'derece.sck' dosyasına yazar.<br />

Bu iki sıcaklık arasındaki çevrim kuralı: K =<br />

273 + C şeklindedir. */<br />

#include <br />

#include <br />

int main(void)<br />

{<br />

/* dosya göstericileri */<br />

FILE *oku, *yaz;<br />

/* Dosya adları */<br />

char *kaynak_dosya = "kelvin.sck";<br />

char *hedef_dosya = "derece.sck";<br />

float K,D;<br />

int i=0, n=100;<br />

/* Dosylara erişim mümkün mü ? */<br />

if( (oku=fopen(kaynak_dosya, "r")) == NULL )<br />

{<br />

printf("%s dosyası acilmadi.\n",<br />

kaynak_dosya);


30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

exit(1);<br />

}<br />

if( (yaz=fopen(hedef_dosya, "w")) == NULL )<br />

{<br />

printf("%s acilmadi.\n", hedef_dosya);<br />

exit(2);<br />

}<br />

for(i=0; i derece.sck<br />

cevirme islemi tamamlandi.<br />

16.4 Standart Dosyalar<br />

C Programlama Dili'nde bilgisayarın sahip olduğu ekran, klavye ve portlar birer dosya olarak<br />

tanımlanmıştır. Bu dosyalara standart dosyalar denir. Program çalışmaya başladığında beş<br />

adet standart dosya otomatik olarak açılır. C, stdio.h başlık dosyasında tanımlanan bütün bu<br />

standart dosyalara birer sembolik isim vermiştir[3]. Bu isimler Tablo 16.3'de listelenmiştir.<br />

Tablo 16.3: Standart Dosyalar<br />

Dosya adı<br />

stdout<br />

stderr<br />

stdin<br />

stdprn<br />

stdaux<br />

Görevi<br />

Standart çıkış ortamı (ekran)<br />

Standart hata çıkış ortamı (ekran)<br />

Standart giriş ortamı (klavye)<br />

Standart LPT (paralel port)<br />

Standart COM (seri port)<br />

Bu dosyaların sembolik isimleri birer dosya göstericisidir. Bu sebeple FILE yapısal değişkeni<br />

ile kullanılabilen dosya fonksiyonları bu dosyalar için de kullanılabilir. Örneğin, ekrana<br />

(standart çıkışa) bir yazı bastırmak için:


fprintf(stdout,"Merhaba C\n");<br />

Bilgilerin yazıcıya gönderilmesi için yine fprintf fonksiyonu kullanılır. Örneğin:<br />

fprintf(stdprn,"Merhaba C\n");<br />

satırı yazıcıya Merhaba C iletinini gönderir.<br />

Ayrıca, LPT1 veya PRN ismini dosya ismi olarak kullanıp yazıcıya basım yapmak da<br />

mümkündür [4]. Örneğin:<br />

FILE *dg;<br />

...<br />

dg = fopen("LPT1","wt");<br />

fprintf(dg,"Merhaba C\n");<br />

...<br />

flcose(dg);<br />

NOT<br />

Tablo 16.3 de verilen standart dosyalardan stdprn ve<br />

stdaux Turbo C'de tanımlı iken Standart C'de tanımlı<br />

değildir. (bkz: stdio.h)<br />

Program 16.4 Turbo C derleyicisinde derlendiğinde hem ekrana hemde yazıcıya birer mesaj<br />

yazar.<br />

Program 16.4: Standart dosyaların kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

ÇIKTI<br />

/* 16prg04.c<br />

Standart dosyaları kullanarak hem ekrana<br />

hemde<br />

yazıcıya birer mesaj yazar. (sadece Turbo C)<br />

*/<br />

#include <br />

int main()<br />

{<br />

fprintf(stdout,"Bu mesaj *ekrana*<br />

yazilacak ...\n");<br />

fprintf(stdprn,"Bu mesaj *yaziciya*<br />

yazilacak ...\n");<br />

return 0;<br />

}<br />

Bu mesaj *ekrana* yazilacak ...<br />

NOT<br />

Eğer yazıcı bağlı yada açık değilse, işletim sistemi<br />

kullanıcıyı uyaracak ve programın çıktısı şöyle olacaktır:<br />

Bu mesaj *ekrana* yazilacak ...<br />

Yazma hatası yazılan aygıt PRN


Durdur, yeNiden dene, Yoksay, ipTal?d<br />

<strong>Ders</strong> 18: Port Denetimi<br />

• <strong>Giriş</strong><br />

• 18.1 Port Kavramı<br />

• 18.2 Port G/Ç Fonksiyonları<br />

• 18.3 Paralel Port Örnekleri<br />

• 18.4 Seri Port Örnekleri<br />

• 18.5 Linux'de Portlara Erişim<br />

<strong>Giriş</strong><br />

Bu kısımda, ağırlıklı olarak Windows işletim sistemlerinde çalışan (Turbo C, Dev-C++ gibi)<br />

derleyicilerin bünyesinde bulunan port fonksiyonları ve kullanımları anlatılacaktır. Linux<br />

işletim sisteminde benzer uygulamaların nasıl yapılacağı bölüm sonunda verilmiştir.<br />

Bir program içerisinden donanımsal birimlere erişmek veya onları kullanmak için birçok yol<br />

vardır. En basiti, bu gibi birimlere aynı bellek gözüne erişilmiyormuş gibi gösterici kullanarak<br />

erişmektir; ancak bu durum sistem mimarisinden dolayı her zaman mümkün olmayabilir. Bu<br />

durumda, ilgili birimlere erişmek için derleyicilerin sahip olduğu hazır kütüphane<br />

fonksiyonları kullanılır[1].<br />

NOT<br />

• Windows XP ve Vista işletim sistemileri, güvenlik<br />

nedeniyle, C derleyicilerine ait portlara erişim<br />

fonksiyonlarını kullanmaya da izin vermeyebilir.<br />

• Linux işletim sistemi kullanıcıları ana kullanıcı (root)<br />

olmadığı sürece, portlara erişim izni yoktur.<br />

18.1 Port Kavramı<br />

Anakartın üzerinde bir bilgisayarın en önemli bileşenleri (Veriyolları, Portlar, CPU, RAM,<br />

BIOS, ChipSet, ROM, I/O devrelerinin çoğu) bulunur. Anakart, sistemin çalışmasını organize<br />

eder. Bu organizasyon anakart üzerinde bulunan yongalar (entegre devreler) sayesinde<br />

gerçekleşir. Anakart üzerinde bilgisayara veri giriş/çıkış için kullanılan pinlere veya


elektriksel bağlantı noktalarına port denir. Örneğin: Paralel port (LPT), seri port (COM),<br />

AGP portu, PCI portları gibi.<br />

Daha fazla bilgi için burayı tıklayın.<br />

18.2 Port <strong>Giriş</strong>/Çıkış Fonksiyonları<br />

Bir bilgisayarın portlarına erişmek için birçok fonksiyon vardır. Tablo 18.1'de, Turbo C<br />

derleyicisinde bululunan ve bu konu ile ilgili birkaç fonksiyon tanıtılmıştır.<br />

NOT<br />

Turbo C derleyicisinde, port fonksiyonları kullanılabilmesi<br />

için dos.h başlık dosyası programa ilave edilmelidir.<br />

Tablo 18.1: dos.h'te tanımlı bazı port erişim fonksiyonları<br />

Port Fonksiyonu<br />

Açıklama<br />

void outp(int port_adresi,int bayt_degeri); Porta bir baytlık veri yazar<br />

void outport(int port_adresi,int deger);<br />

Porta bir kelime * yazar<br />

void outportb(int port_adresi,unsigned char deger); Porta bir baytlık veri yazar<br />

int inp(int port_adresi);<br />

Porttan bir baytlık veri okur<br />

int inport(int port_adresi);<br />

Porttan bir kelime okur<br />

char inportb(int port_adresi);<br />

Porttan bir baytlık veri okur<br />

(*) kelime (word) : Porta yazılacak veya porttan okunacak, bir tamsayının bellekte<br />

kaplayacağı alanı temsil eder. (Bu alan sizeof() operatörü ile öğrenilebilir)<br />

Port foksiyonlarının kullanımı, örnek programlar üzerinde, bir sonraki bölümlerde<br />

incelenmiştir. Bütün programlar Turbo C derleyicisinde denemiştir. Eger bu derleyiciye sahip<br />

degilseniz, buradan inderbilirsiniz.<br />

18.3 Paralel Port Örnekleri<br />

Bu bölümde, bir önceki kısımda verilen port fonksiyonları ile, bir PC'nin paralel portunun<br />

nasıl denetleneceği 6 tane örnek programda anlatılmıştır.<br />

NOT<br />

Standart bir PC'de LPT nin alt portlarının adresleri,<br />

DATA için 0x378, STATUS için 0x379 ve CONTROL<br />

0x37A dır;<br />

Program 18.1: outp fonksiyonunun kulanımı<br />

01:<br />

02:<br />

/* 18prg01.c: outp örneği */


03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

ÇIKTI<br />

#include <br />

#include <br />

#define DATA 0x0378<br />

int main()<br />

{<br />

int deger = 25;<br />

outp(DATA, deger);<br />

printf("\n%X nolu adrese %d degeri<br />

yazildi.", DATA, deger);<br />

return 0;<br />

}<br />

378 adresine 25 degeri yazildi.<br />

Program 18.1'de 6. satırda tanımlanan porta, 12.satırda 25 değeri yazılmaktadır. Bu değer PC<br />

paralel portunun DATA uçlarına yazılır. Bu sebeple 25 değeri ikili sistemde (binary) ifade<br />

edilip 8 bite bölünür, yani 25 = 00011001 şekinde DATA portuna yazılır. Burada 1 portun<br />

ilgili bacağına +5V DC sinyalini gönderir. 0 olan bağlantı noktalarına ise sinyal gönderilmez.<br />

Bu değerler basit bir voltmetre ile ölçülüp test edilebilir.<br />

Porta yazılmak veya porttan okunmak istenen veriyi ikili (binary) olarak görüntülemek yararlı<br />

olabilir. Program 18.2'de cevir_taban2 fonksiyonu bu amaçla yazılmıştır.<br />

Program 18.2: outportb fonksiyonun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

/* 18prg02.c: outportb fonksiyonu */<br />

#include <br />

#include <br />

#include <br />

#define DATA 0x0378<br />

long cevir_taban2(int);<br />

int main()<br />

{<br />

int deger = 0x19; /* deger = 25 */<br />

outportb(DATA,deger);<br />

printf("\nDATA portuna gonderilen deger %d :<br />

%08ld",deger, cevir_taban2(deger));<br />

return 0;<br />

}


23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

/* Bu fonksiyon 10 tabanındaki bir sayıyı<br />

2 tabınındaki karşılığını hesaplar. */<br />

long cevir_taban2(int x)<br />

{<br />

int i = 0, k;<br />

long bin = 0;<br />

}<br />

ÇIKTI<br />

while( x>0 )<br />

{<br />

if(x%2) k = 1;<br />

else k = 0;<br />

bin += k*pow(10,i++);<br />

x /= 2;<br />

}<br />

return bin;<br />

DATA portuna gonderilen deger 25 : 00011001<br />

9. satırdaki cevir_taban2 fonksiyonu, kendisine parametere olarak gelen bir tamsayıyı iki<br />

tabana çevirir. Ekranda porta yazılan değer ve onun iki tabanındaki karşılığı, uygun bir<br />

formatla, 8 bit halinde gösterilmiştir.<br />

inp() ve inportb() fonksiyonları, PC bağlantı noktalarından sırasıyla bir karakter ve bir<br />

baytlık veri okumak mümkündür. Program 18.3, bu fonksiyonlar ile nasıl veri okunacağına<br />

dair iyi bir fikir verir.<br />

Program 18.3: inp ve inportb fonksiyonlarıyla paralel porta atanan varsayılan değerleri<br />

öğrenme<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

/* 18prg03.c: inp ve inportb fonksiyonlarının<br />

kullanımı */<br />

#include <br />

#include <br />

#define DATA 0x0378<br />

#define STATUS DATA+1<br />

#define CONTROL DATA+2<br />

int main()<br />

{<br />

int veri;<br />

puts("Paralel porta atanan degerler (Hex):");<br />

veri = inp(DATA);<br />

printf( "Data portu : %X\n",veri );<br />

veri = inp(STATUS);<br />

printf( "Status portu : %X\n",veri );


22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

ÇIKTI<br />

veri = inportb(CONTROL);<br />

printf( "Kontrol portu : %X\n",veri );<br />

return 0;<br />

}<br />

Paralel porta atanan degerler (Hex):<br />

Data portu : 4<br />

Status portu : 7F<br />

Kontrol portu : CC<br />

Programın elde ettiği değerler, porta hiç bir müdehale olmadan elde edilmiştir ve her<br />

bilgisayarda başka bir sonuç verebilir. Bu fonksiyonların tek parameteresi olduğuna dikkat<br />

ediniz.<br />

Bir porta herhangi bir veri yazıldıktan sonra, bu veri o portun saklayıcısına (register) yazılır<br />

ve yeni bilgi yazılmadıkça orada kalır. Program 18.4 CONTROL portuna ouportb ile yazılan<br />

bir verinin inportb fonksiyonu ile okunması gösterilmiştir.<br />

Program 18.4: inportb ve outportb fonksiyonlarının kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

ÇIKTI<br />

/* 18prg04.c: inportb ve outportb örneği */<br />

#include <br />

#include <br />

#define PORT 0x037A<br />

int main()<br />

{<br />

int deger;<br />

deger = inportb(PORT); /* varsayılan deger<br />

*/<br />

printf("\nPorta veri yazilmadan onceki deger<br />

: %X",deger);<br />

deger = 0x0A; /* deger = 10 */<br />

outportb(PORT, deger);<br />

deger = inportb(PORT);<br />

printf("\nPorta veri yazdiktan sonraki deger<br />

: %X",deger);<br />

return 0;<br />

}<br />

Porta veri yazilmadan onceki deger : CC


Porta veri yazdiktan sonraki deger : CA<br />

Program 18.4'ün çıktısı incelendiğinde, portta varsayılan değerin CCh, veri yazıldıktan<br />

sonraki değerin CAh olduğu görülmektedir. CONTROL portunun ilk 4-bitine müdehale<br />

edilebildiği halde ikinci 4-biti değiştirilememiş. Neden?<br />

18.4 Seri Port Örnekleri<br />

Bu bölümde, yine Standart C'de olmayan bilgisayarın seri portları üzerinden iletişim konu<br />

edilecektir.<br />

NOT<br />

Standart bir PC'de COM1 için ilk adres 0x3F8, COM2 için<br />

0x2F8 dir;<br />

Standart PC'lerin seri iletişim portlarına erişim UART olarak adlandırılan bir birim üzerinden<br />

gerçekleştirilir. Bu birim anakat üzerindeki bir entegre devredir. Ancak temel olarak bilinmesi<br />

gereken alma saklayıcısına ve gönderme saklayıcısına nasıl erişileceği ve UART'ın<br />

ayarlarının nasıl yapılacağıdır. Program 18.5'de bir dosya içeriğinin karakter karakter seri port<br />

üzerinden karşı tarafa nasıl gönderileceği görülmektedir[1].<br />

Program 18.5: Bir metin dosyasının içeriğini seri porta aktarır.<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

/* 18prg05.c: Bir metin dosyasının içeriğini<br />

seri porta aktarır */<br />

#include <br />

#include <br />

#include <br />

int main()<br />

{<br />

char kr;<br />

FILE *dosya;<br />

/* UART'ın ayarlanması */<br />

outportb(0x3FB,0x80);<br />

outport (0x3F8,0x0C);<br />

outportb(0x3FB,0x1B); /* 9600 bps.dur biti<br />

1.cift eslik, 8 bit veri*/<br />

/* dosya açılıyor */<br />

if ( (dosya=fopen("deneme.txt", "r")) ==<br />

NULL) {<br />

puts ("Hata olustu! Dosya acilmadi.");<br />

exit(1);<br />

}<br />

while( !feof(dosya) )<br />

{<br />

kr=getc(dosya); /*<br />

dosyadan bir karakter oku */<br />

while ( (inportb(0x3FD) & 0x20)==0 ); /*


31:<br />

32:<br />

gönderme saklayicisi sınanıyor */<br />

ouportb(0x3F8,kr); /*<br />

porta gönderiliyor */<br />

}<br />

fclose(dosya); /*<br />

dosya kapatiliyor */<br />

return 0;<br />

}<br />

Bir UART iletişim işine geçmeden önce ayarlanmalıdır; yani, iletişim hızı, hata biti kullanıp<br />

kullanılmayacağı gibi birtakım bilgilerin yerleştirimi yapılmalıdır. UART'ın herhangi bir<br />

andaki durumu, yani veri göndermeye hazır olup olmadığı, yeni veri gelip gelmediği gibi<br />

bilgiler hat durum saklayıcısı üzerindeki bitlere bakılarak anlaşılır. Örneğin, UART'a<br />

gönderilmesi için bir veri yazılmadan önce, göndermek için uygun olup olmadığı<br />

sınanmalıdır. Program 18.6'de seri port üzerinden gelen karakterleri alıp ekrana nasıl yazıldığı<br />

görülmektedir[1].<br />

Program 18.6: Seri port üzerinden gelen karakterleri alıp ekrana yazar.<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

/* 18prg06.c: Seri port üzerinden gelen<br />

karakterleri alıp ekrana yazar */<br />

#include <br />

#include <br />

int main()<br />

{<br />

char kr;<br />

/* UART'ın ayarlanması */<br />

outportb(0x3FB,0x80);<br />

outport (0x3F8,0x0C);<br />

outportb(0x3FB,0x1B); /* 9600 bps.dur biti<br />

1.cift eslik, 8 bit veri*/<br />

while(1)<br />

{<br />

while( (inportb(0x3FD) & 0x01)==0 ); /*<br />

yeni karakter gelene kadar bekle */<br />

kr=inportb(0x3F8); /*<br />

geleni al ve kr'ye yerleştir */<br />

printf("%c", kr);<br />

}<br />

return 0;<br />

}<br />

Soru: Son iki programı öyle değiştirin ki, birinin klavyesinden girilen, diğerinin ekranında<br />

görülsün.<br />

18.5 Linux'de Portlara Erişim


Linux işletim sisteminde portlara erişmek için birkaç yol vardır. Burada, gcc derleyicisinin<br />

içine gömülebilen assemble dili kullanılarak oluşturulan port fonksiyonları gösterilecektir.<br />

Linux'de ana kullanıcı (root) olmadıkça veya ana kullanıcı izin vermedikçe portlara erişmeniz<br />

mümkün değildir. Bu yüzden, önce programın portlara erişim izni verip vermediği<br />

sınanmalıdır. Bunun için, /usr/include/sys/io.h dosyası içinde tanımlı ioperm()<br />

fonksiyonu kullanılabilir.<br />

Program 18.7 de basit bir port erişim programı verilmiştir. Kullanıcıların, programın başına<br />

ilave edebileceği başlık dosyaları için ayrıca bkz. Bölüm 20.<br />

Program 18.7: Linux'de port erişimi<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

/* 18prg07.c<br />

Linux işletim sisteminde portlara erişim */<br />

#include <br />

#include <br />

#include <br />

#include "linuxPort.h"<br />

int main()<br />

{<br />

int deger = 25;<br />

/* porta erişim izni var mı?<br />

sadece root ve onun izin verdiği<br />

kullanıcılar erişebilir ) */<br />

if( port_erisim() ) exit(1);<br />

outportb(DATA, deger);<br />

printf("\n%X nolu adrese %d degeri<br />

yazildi.", DATA, deger);<br />

return 0;<br />

}<br />

17. satırdaki port_erisim() fonksiyonu ioperm() fonksiyonunu çağırıp erişim iznini<br />

denetler. port_erisim(), aşağıda verilen linuxPort.h dosyası içinde tanımlanmıştır.<br />

linuxPort.h bütün Linux tabanlı işletim sistemlerinde bulunan gcc derleyici ile<br />

kullanılabilir.<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

/********************************************************************<br />

*<br />

**<br />

**<br />

** linuxPort.h<br />

**<br />

**<br />

**<br />

** Linux işletim sisteminde kullanılabilecek port fonksiyonları<br />

**<br />

**<br />

**


13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

50:<br />

51:<br />

52:<br />

53:<br />

54:<br />

55:<br />

56:<br />

57:<br />

58:<br />

59:<br />

60:<br />

61:<br />

62:<br />

63:<br />

64:<br />

65:<br />

66:<br />

67:<br />

68:<br />

69:<br />

70:<br />

71:<br />

72:<br />

73:<br />

** Oluşturma tarihi: Haziran 2006<br />

**<br />

** Enson güncelleme: Kasım 2008<br />

**<br />

**<br />

**<br />

*********************************************************************<br />

/<br />

//<br />

// Standart PC için Port adresleri ----------------------------------<br />

--<br />

//<br />

#define DATA 0x378<br />

#define STATUS 0x379<br />

#define CONTROL 0x37A<br />

#define COM1 0x3F8<br />

#define COM2 0x2F8<br />

#define MCR 0x3FC // Modem Control Register (8 bit)<br />

#define MSR 0x3FE // Modem Status Register (8 bit)<br />

#define KEYB1 0x060<br />

#define KEYB2 0x064<br />

//<br />

// port erişim fonksiyonları ----------------------------------------<br />

--<br />

// Bu fonksiyonlar, gcc derleyicisinde dosyasında<br />

mevcuttur<br />

//<br />

void outportb(unsigned short port, unsigned char data)<br />

{<br />

__asm__ __volatile__ ("outb %1, %0"<br />

:<br />

: "dN" (port),<br />

"a" (data));<br />

}<br />

void outport(unsigned short port, unsigned short data)<br />

{<br />

__asm__ __volatile__ ("outw %1, %0"<br />

:<br />

: "dN" (port),<br />

"a" (data));<br />

}<br />

unsigned char inportb(unsigned short port)<br />

{<br />

unsigned char rv;<br />

__asm__ __volatile__ ("inb %1, %0"<br />

: "=a" (rv)<br />

: "dN" (port));<br />

return rv;<br />

}<br />

unsigned short inport(unsigned short port)<br />

{<br />

unsigned short rv;<br />

__asm__ __volatile__ ("inw %1, %0"<br />

: "=a" (rv)


74:<br />

75:<br />

76:<br />

77:<br />

78:<br />

79:<br />

80:<br />

81:<br />

82:<br />

83:<br />

84:<br />

85:<br />

86:<br />

87:<br />

88:<br />

89:<br />

90:<br />

91:<br />

92:<br />

93:<br />

94:<br />

95:<br />

96:<br />

97:<br />

98:<br />

99:<br />

100<br />

:<br />

101<br />

:<br />

102<br />

:<br />

103<br />

:<br />

104<br />

:<br />

105<br />

:<br />

106<br />

:<br />

107<br />

:<br />

108<br />

:<br />

109<br />

:<br />

110<br />

:<br />

111<br />

:<br />

112<br />

:<br />

113<br />

:<br />

114<br />

:<br />

115<br />

:<br />

116<br />

:<br />

117<br />

}<br />

: "dN" (port));<br />

return rv;<br />

//<br />

// erisim izinlerini kontrol et -------------------------------------<br />

//<br />

int port_erisim(void)<br />

{<br />

int i, erisim = 0;<br />

/* paralel porta erisim izni var mi? */<br />

for(i=0; i


:<br />

118<br />

:<br />

}<br />

outportb(COM1 + 3 , 0x03); // 8 bit, parity yok, 1 dur biti<br />

outportb(COM1 + 2 , 0xC0); // FIFO Kontrol saklayıcısı<br />

<strong>Ders</strong> 19: Grafik Kullanımı<br />

• <strong>Giriş</strong><br />

• 19.1 Grafik Ekranına Geçiş<br />

• 19.2 Bazı Grafik Fonksiyonları<br />

• 19.3 Renk Kodları<br />

• 19.4 Örnekler<br />

<strong>Giriş</strong><br />

Bu kısımda sadece Turbo C derleyicisine ait basit grafik uygulamaları kısaca anlatılmıştır.<br />

Örneklerde verilen grafik fonksiyonları ANSI C de bulunmamaktadır. Bu yüzden bir çok C<br />

derleyicisi, kendi bünyesinde farklı grafik fonksiyonlarına sahiptir. Örneğin Linux<br />

ortamındaki grafik kullanmak için g2 kütüphanesi geliştirilmiştir.<br />

19.1 Grafik Ekranına Geçiş<br />

Turbo C'de, Grafik sistemine geçmek için, initgraph() fonksiyonunu kullanılır. Bütün<br />

çizimler sadece DOS ortamında çalışır. Grafik fonksiyonlarının kullanılması için graphics.h<br />

başlık dosyası programın başına ilave edilmelidir. Grafik işlemleri için temel işlemler:<br />

#include <br />

#include <br />

...<br />

int surucu = DETECT, grmod, hata_kodu; /* DETECT grafik<br />

sürücüsünü otomatik seçer */<br />

.<br />

.<br />

.<br />

initgraph(&surucu, &grmod, ""); /* grafik ekranını başlat<br />

*/<br />

hata_kodu = graphresult(); /* hata_kodu al */<br />

if (hata_kodu != grOk) /* hata_kodu 0 dan farklı<br />

ise başlatma */<br />

{<br />

puts("Hata olustu.");<br />

puts("Grafik ekrani baslatilamiyor.");<br />

exit(1);<br />

}


.<br />

. /* grafik işlemleri ... */<br />

.<br />

closegraph(); /* grafik ekranını kapat */<br />

şeklindedir.<br />

NOT<br />

initgraph fonksiyonundaki 3. parametre ("") boş<br />

bırakıldığında kaynak dosyanın C:\TC dizininde olması<br />

zorunludur.<br />

Eğer kaynak dosya başka bir dizinin altında ise o zaman<br />

initgraph(&surucu, &grmod, "C:\\TC");<br />

şeklinde kullanılmalıdır.<br />

Turbo C'de varsayılan grafik modu (640,480) çözünürlüğe ayarlanmıştır. Bu modda, Çizim<br />

ekrenının sol-üst köşesine ait koordinat (0,0) olarak tanımlıdır. Varsayılan moddaki bazı<br />

koordinatlar Şekil 19.1'de gösterilmiştir.<br />

Şekil 19.1: Turbo C varsayılan moddaki koordinatlar<br />

19.2 Bazı Grafik Fonksiyonları<br />

Bu bölümde Turbo C grafik fonksiyonlarının bazıları tanıtılmıştır. Bunların dışında biçok<br />

fonksiyon vardır. Bu fonksiyonlar derleyicinin başvuru kitabından veya derleyicinin yardım<br />

kısmından öğrenilebilir.<br />

Tablo 19.1: graphics.h'te tanımlı bazı grafik fonksiyonları<br />

Fonksiyon<br />

moveto(x,y);<br />

Açıklama<br />

Son noktayı (x,y) noktasına taşır


lineto(x,y);<br />

line(x1,y1,x2,y2);<br />

circle(x,y,r);<br />

arc(x,y,baş_açı,bit_açı,r);<br />

ellipse(x,y,baş_açı,bit_açı,xr,yr);<br />

putpixel(x,y,renk);<br />

rectangle(sol,üst,sağ,alt);<br />

bar(sol,üst,sağ,alt);<br />

bar3d(sol,üst,sağ,alt,derinlik,şapka);<br />

setcolor(renk);<br />

setbkcolor(renk);<br />

outtext(*katar);<br />

outtextxy(x,y,*katar);<br />

settextstyle(font,yön,boyut);<br />

cleardevice();<br />

closegraph();<br />

Son noktadan (x,y) noktasına düz bir<br />

çizgi çizer.<br />

(x1,y1) noktasından (x2,y2) noktasına<br />

düz bir çizgi çizer.<br />

Merkezi (x,y) olmak üzere yarıçapı r<br />

olan bir çember çizer.<br />

Merkezi (x,y) noktasında ve yarıçapı r<br />

olan, baş_açı açısından dan başlayıp<br />

bit_açı açısına kadar bir yay çizer.<br />

Elipsin bir parçası olan yayı, merkezi<br />

(x,y) ve yarıçapları xr, yr olacak biçimde<br />

baş_açı açısındandan başlayarak<br />

bit_açı açısına kadar bir yay çizer.<br />

(x,y) noktasına verilen renkte bir nokta<br />

çizer.<br />

Sol üst köşesi (sol,üst) ve sağ alt köşesi<br />

(sağ,alt) koordinatlarında olacak şekilde<br />

bir dikdörtgen çizer.<br />

İki boyutlu ve taralı bir bar çizer.<br />

Üç boyutlu ön yüzeyi taralı bar çizer.<br />

Şapka 0 ise barın üst kısmı çizilmez.<br />

Çizilen olan şeklin rengini belirler<br />

Arka alanın rengini belirler.<br />

Grafik ekranında katar yazdırır.<br />

Grafik ekranında yazılacak katar'ı, (x,y)<br />

ile belirlenen noktadan başlayarak yazar.<br />

Ekranda yazılacak olan bir katarın<br />

yazıtipini, yönünü ve boyutunu belirler.<br />

yön=0 ise yatay, yön=1 ise dikey yazar.<br />

Ekranı temizler. DOS'taki CLS komutu<br />

gibi.<br />

Grafik ekranını kapatıp normal yazı<br />

ekranına (DOS ekranı) döner.<br />

19.3 Renk Kodları<br />

Grafik ekranında kullanılan renkler 0-15 arasında renk kodları, yada simgesel sabit karşılıkları<br />

ile tanımlıdır. Bu tanımlamaların tamamı graphics.h'de şöyle bildirilmiştir (bkz<br />

graphics.h):<br />

enum COLORS {<br />

BLACK, /* koyu renkler */<br />

BLUE,<br />

GREEN,<br />

CYAN,<br />

RED,


MAGENTA,<br />

BROWN,<br />

LIGHTGRAY,<br />

DARKGRAY,<br />

LIGHTBLUE, /* açık renkler */<br />

LIGHTGREEN,<br />

LIGHTCYAN,<br />

LIGHTRED,<br />

LIGHTMAGENTA,<br />

YELLOW,<br />

WHITE<br />

};<br />

Ayrıca bu kodları liste halinde Tablo 19.2 de bulabilirsiniz.<br />

Tablo 19.2: conio.h ve graphics.h'te tanımlı Standart CGA Video Renk Kodları<br />

Renk (TR) Renk (EN)<br />

Renk<br />

Örneği<br />

Renk Kodu<br />

Siyah BLACK 0<br />

Mavi BLUE 1<br />

Yeşil GREEN 2<br />

? CYAN 3<br />

Kırmızı RED 4<br />

Menekşe MAGENTA 5<br />

Kahverengi BROWN 6<br />

Açık Gri LIGHTGRAY 7<br />

Koyu Gri DARKGRAY 8<br />

Açık Mavi LIGHTBLUE 9<br />

Açık Yeşil LIGHTGREEN 10<br />

Açık ? LIGHTCYAN 11<br />

Açık Kırmızı LIGHTRED 12<br />

Açık Menekşe LIGHTMAGENTA 13<br />

Sarı YELLOW 14<br />

Beyaz WHITE 15<br />

19.4 Örnekler<br />

NOT<br />

Buradaki örnek programlar Turbo C'nin editör ortamında<br />

derlenmiştir.<br />

Program 19.1: Grafik ekranında; bir çizgi, bir çember, bir yay, bir dikdörtgen ve bir elips<br />

çizer<br />

01:<br />

02:<br />

03:<br />

04:<br />

/* 19prg01.c<br />

Çizim ekranında bir çizgi, bir çember,<br />

bir yay, bir dikdörtgen ve bir elips çizer.<br />

*/


05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

#include <br />

#include <br />

int main()<br />

{<br />

int sur = DETECT, gmod;<br />

/* grafik ekranını başlat */<br />

initgraph(&sur,&gmod,"");<br />

line (12, 12, 298, 198);<br />

circle (200, 100, 75);<br />

arc (200, 100, 90, 180, 50);<br />

rectangle (10, 10, 300, 200);<br />

ellipse (320, 240, 0, 180, 50, 70);<br />

return 0;<br />

}<br />

getchar();<br />

closegraph(); /* grafik ekranını kapat */<br />

Program<br />

çıktısı<br />

Program 19.2: outtext, outtextxy, setcolor, settextstyle, setlinestyle fonksiyonları<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

/* 19prg02.c<br />

Bu program ekranda yatay ve dikey iki yazı<br />

yazar ve<br />

farklı kalınlıkta iki çizgi çizer. */<br />

#include <br />

#include <br />

int main()<br />

{<br />

int surucu=DETECT,mod;<br />

initgraph(&surucu,&mod,"C:\\TC");<br />

setcolor(3);<br />

outtext("Merhaba C.");<br />

setcolor(10);<br />

outtextxy(30,40,"Bu yazi YATAY");<br />

setcolor(YELLOW);


22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

return 0;<br />

}<br />

settextstyle(1,1,5);<br />

outtextxy(50,60,"Bu yazi DIKEY");<br />

setcolor(WHITE);<br />

setlinestyle(3,0,1);<br />

line(320,240,500,350);<br />

setcolor(RED);<br />

setlinestyle(1,1,3);<br />

circle(320,240,100);<br />

getchar();<br />

closegraph();<br />

Program<br />

çıktısı<br />

Program 19.3: y=f(x) ile belirlenen bir fonksiyonu çizer<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

/* 19prg03.c<br />

x : [-20, 20] aralığında y= 5 * sin(x)<br />

fonksiyonunun grafiğini çizer. */<br />

#include <br />

#include <br />

#include <br />

int main()<br />

{<br />

int sur = DETECT, grmode;<br />

float x,y,olcek;<br />

int X,Y;<br />

initgraph(&sur, &grmode, "C:\\TC");<br />

setcolor(BLUE);<br />

coordinatları mavi */<br />

line(0,240,640,240);<br />

line(320,0,320,480);<br />

/* x-y<br />

olcek = 15.0; /* Ölçek<br />

değiştirilerek büyütme/küçültme yapılabilir. */<br />

setbkcolor(WHITE);<br />

beyaz */<br />

setcolor(RED);<br />

rengi kırmızı */<br />

/* zemin rengi<br />

/* Fonksiyonun


29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

x=-20.0;<br />

[-20,20] aralığında */<br />

do<br />

{<br />

y = 5*sin(x);<br />

fonksiyonu */<br />

/* x değerleri<br />

/* y=5*sin(x)<br />

X = 320 + x*olcek; /* Lineer<br />

Dönüşüm denklemleri */<br />

Y = 240 - y*olcek;<br />

line(X, Y, X, Y);<br />

çiziliyor... */<br />

return 0;<br />

}<br />

x += 0.01;<br />

}while( x


Makro bildirimleri veya Yönergeleri (direktive) derleme öncesi komutlarıdır. Bunlar tipik<br />

olarak:<br />

• programları değiştirmek<br />

• program parçalarını kaynak programında birleştirmek<br />

• derleme sırasında bazı uyarı mesajlarını aktif veya pasif hale getirmek<br />

için kullanılır. Genelde makro bildirimleri kaynak dosyaların en başında verilir.<br />

C dilinde kullanılan Yönergeler (önişlemci komutları) şunlardır:<br />

#include #define #pragma<br />

#error #undef #ifdef #ifndef<br />

#if #else #elif #endif<br />

20.1 #include Yönergesi<br />

Bu önişlemci verilen dosyanın içeriğini, kullanıldığı yerde kaynak dosyasının içine ekler.<br />

Çoğunlukla derleyiciye ait komut kütüphanelerinde bulunan fonksiyonların prototiplerinin ve<br />

diğer çeşitli tanımlamaların bulunlunduğu (h uzantılı) başlık dosyalarının programa dahil<br />

edilmesinde kullanılır[2]. İki tür kullanımı vardır:<br />

veya<br />

#include <br />

#include "dosya_adı.h"<br />

• Birinci kullanımda dosyanın nerede bulunduğu derleyici için verilen ulaşım yolu ile<br />

belirlenir. Bu yol genellikle include dizini ile son bulur. Başlık dosyalarının saklandığı<br />

include dizini<br />

o Borland firmasına ait Turbo C derleyicisinde : C:\TC\INCLUDE<br />

o Linux ortamında : /usr/include şeklindedir.<br />

• İkinci kullanımlada dosyanın bulunduğu yer aktif dizin olarak kabul edilir. Aksi halde<br />

yol tam olarak verilmelidir.<br />

#include deyimi ile program ilave edilecek dosya C fonksiyonları içerebileceği gibi basit<br />

deyimler de içerebilir. Bunun için bir sınırlandırma yoktur. Hatta uzantıları .h olması bile<br />

gerekmez. Program 20.1 ve Program 20.2'yi inceleyin.<br />

Program 20.1: #include önişlemcisinin kullanımı için bir örnek<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

/* 20prg01.c: faktoriyel ve kombinasyon<br />

hesaplamaları */<br />

#include <br />

#include "komb.h"<br />

int main()<br />

{


10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

ÇIKTI<br />

int i;<br />

/* 0 dan 10 yekadar olan sayıların<br />

faktoriyelleri */<br />

for(i = 0; i


}<br />

Program 20.2: #include önişlemcisinin kullanımı için başka bir örnek<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

/* 20prg02.c:<br />

Klavyeden girilen bir doğal sayının, kaç<br />

basamaklı<br />

olduğunu bulup ekrana yazar.<br />

*/<br />

#include <br />

int main(){<br />

#include "bildirim.inc"<br />

printf("Bir dogal sayi gir: ");<br />

scanf("%d",&sayi);<br />

if(sayi0){<br />

n /= 10;<br />

b++;<br />

}<br />

printf("%d %d basamakli bir<br />

sayidir.\n",sayi,b);<br />

}<br />

return BASARILI;<br />

Dikkat edilirse Program 20.2 içinde değişkenler tanımlanmamıştır. 11. satırdaki bildirim.inc<br />

dosyası değişken bildirimlerini barındırmaktadır. Bu özellik (veya esneklik), çok büyük ve<br />

profesyonel programlarda kullanılmaktadır.<br />

ÇIKTI<br />

Bir dogal sayi gir: 4578<br />

4578 4 basamakli bir sayidir.<br />

20.2 #define Yönergesi<br />

Bu önişlemci komutu, kaynak dosyada bir isim yerine başka bir isimin yerleştirilmesini<br />

sağlar. Programda kullanılan bu sembolik isimler başta ana program olmak üzere bütün alt<br />

programlarda da aynı değere sahiptir. Yani #define önişlemcisi ile tanımlanan her ne olursa<br />

olsun, tanımlama bütün fonksiyonlarda kullanılabilir. Bir çeşit genel (global) bildirim gibi<br />

davranır. Örneğin:


Program 20.3: #define önişlemcisinin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

/* 20prg03.c: #define önişlemcisinin kullanımı<br />

*/<br />

#include <br />

#define PROGRAM main()<br />

#define BASLA {<br />

#define BIT }<br />

#define YAZ printf<br />

PROGRAM<br />

BASLA<br />

YAZ("Merhaba C!..\n");<br />

BIT<br />

Program 20.3 derleme işleminden önce #define ile verilen ilk sembolik isimler yerine ikinci<br />

isimler yerleştirildikten sonra program aşağıdaki durmuma gelir:<br />

/* 20prg03.c: #define önişlemcisinin kullanımı */<br />

#include <br />

main()<br />

{<br />

printf("Merhaba C!..\n");<br />

}<br />

Bu önişlemciyi kullanak sembolik sabitler tanımlamak mümkündür. Örneğin:<br />

#define PI 3.1415926<br />

#define IKI_PI 2.0*PI<br />

#define YUZ 100<br />

gibi.<br />

#define önişlemcisinin kullanımı için iyi bir örnek Program 20.4 de verilmiştir. Program<br />

km/s biriminde verilen bir hızı m/s birimine çevirir[4].<br />

Program 20.4: #define önişlemcisinin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

/* 20prg04.c: km/s biriminde verilen hızı m/s<br />

cinsinden hesaplar */<br />

#include <br />

#define km *1000.0<br />

#define saat *3600.0<br />

main()<br />

{<br />

double yol,zaman,hiz;<br />

yol = 100 km;<br />

zaman = 1.2 saat;<br />

hiz = yol/zaman;


17:<br />

18:<br />

19:<br />

}<br />

printf("HIZ = %lf m/s\n",hiz);<br />

ÇIKTI<br />

HIZ = 23.148148 m/s<br />

5. ve 6. satırda tanımlanan sembolik sabitler km ve saat program içinde kullanıldığında sol<br />

taraflarındaki sayıyı sırasıyla 1000 ve 3600 ile çarparlar. 12. satırdaki yol değişkenine<br />

100*1000.0 değeri atanır. Benzer olarak 13. satırdaki zaman değişkenine 1.2*3600.0 sayısı<br />

atanır. Dikkat edilirse sembolik sabitler kullanıldığında programın okunurluğu artmakta ve<br />

bundan dolayı hata ayıklama kolaylaşmaktadır.<br />

#define önişlemcisi ile parametrik tanımlamalar veya global fonksiyonlar tanımlamak<br />

mümkün olur. Örneğin:<br />

Program 20.5: Makro fonksiyon tanimlama<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

/* 20prg05.c: Makro fonksiyon tanimlama. */<br />

#include <br />

#include <br />

/* makro fonksiyonlar */<br />

#define kare(x) (x*x)<br />

#define topl(x,y) (x+y)<br />

#define carp(x,y) (x*y)<br />

#define hipo(x,y) sqrt(x*x+y*y)<br />

main(void)<br />

{<br />

float a=3.0, b=4.0;<br />

}<br />

ÇIKTI<br />

printf("kare(2) = %f\n",kare(2));<br />

printf("topl(a,b) = %f\n",topl(a,b));<br />

printf("carp(a,b) = %f\n",carp(a,b));<br />

printf("hipo(a,b) = %f\n",hipo(a,b));<br />

kare(2) = 4.000000<br />

topl(a,b) = 7.000000<br />

carp(a,b) = 12.000000<br />

hipo(a,b) = 5.000000<br />

Programda tanımlanan kare(2) ifadesi (2)*(2) şeklinde yorumlar. Benzer durum diğer<br />

makrolar için de geçerlidir.<br />

Makrolar C'de çok sık kullanılır. Örneğin, tek boyutlu bir dizinin boyutu öğrenilmek<br />

istendiğinde aşağıdaki makro kullanılabilir:


#define BOYUT sizeof(DIZI)/sizof(DIZI[0])<br />

...<br />

int a[10], n;<br />

...<br />

n = BOYUT(a);<br />

Son satırdaki işlemle, n değişkeninine (a dizisinin boyutu) 10 değeri atanır.<br />

İşte ilginç bir makro daha. Daha önce anlatılan takas(a,b) fonksiyonu gösterici<br />

kullanmadan aşağıdaki makro ile yazılabilir:<br />

#define takas(x,y) {g=(x); (x)=(y); (y)=g;}<br />

...<br />

int x=22, y=33, g; /* g geçici bir değişken */<br />

...<br />

printf("%d %d\n",x,y); /* 22 33 */<br />

takas(a,b)<br />

printf("%d %d\n",a,b); /* 33 22 */<br />

...<br />

20.3 #undef Yönergesi<br />

#define ile tanımlanan bir isim, orjinal tanımlamaları kaldırmaksızın farklı değerler için<br />

tekrar tanımlanamaz.<br />

#define SIFRE 14576 /* ilk tanimlama */<br />

...<br />

#define SIFRE 22357 /* hata! tanımlama tekrarlandı. */<br />

Eğer #define ile tanımlanan bir ifade yeniden tanımlanmak istenirse, #undef önişlemcisi ile<br />

önceki tanımlama iptal edildikten sonra #define ile yenisi değiştirilir. Yani:<br />

#define SIFRE 14576 /* ilk tanimlama */<br />

...<br />

#undef SIFRE /* ilk tanımlamayı iptal et */<br />

#define SIFRE 22357 /* yeni tanımlama */<br />

20.4 #if, #elif, #else ve #endif Yönergeleri<br />

Bu önişlemciler, makro düzeyinde kontrol deyimleridir. Genel kullanım biçimi:<br />

#if (ifade1)<br />

tanımlama blogu1<br />

#elif (ifade2)<br />

tanımlama blogu2<br />

...<br />

#else<br />

tanımlama bloguN


#endif<br />

şeklindedir. Burada:<br />

• #if makrosu if deyimine<br />

• #elif makrosu else if deyimine<br />

• #else makrosu else deyimine<br />

• #endif makrosu if deyiminin sonuna<br />

karşılık gelmektedir. Bu makrolar, donanıma veya işletim sistemine uygun olarak değişik<br />

makroların tanımlanmasına izin verir. Örneğin:<br />

Program 20.6: Kontrol önişlemcilerinin kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

ÇIKTI<br />

/* 20prg06.c: Kontrol ön işlemcilerinin<br />

kullanımı */<br />

#include <br />

#if(sizeof(int)==2)<br />

#define ISLETIM_SISTEMI "16 bitlik isletim<br />

sistemi."<br />

#else<br />

#define ISLETIM_SISTEMI "32 bitlik isletim<br />

sistemi."<br />

#endif<br />

int main()<br />

{<br />

printf(ISLETIM_SISTEMI);<br />

return 0;<br />

}<br />

32 bitlik isletim sistemi.<br />

Bu program eski DOS işletim siteminde derlenip çalıştırıldığında, program çıktısı şöyle olur:<br />

ÇIKTI<br />

16 bitlik isletim sistemi.<br />

20.5 #ifdef ve #ifndef Yönergeleri<br />

• #ifdef önişlemcisi ile, bir ismin tanımlanmış olup olmadığı<br />

• #ifndef önişlemcisi ile, bir ismin tanımlanmamış olup olmadığı<br />

sorugulanır. Örneğin:<br />

#ifndef SIFRE<br />

#define SIFRE 22357


#endif<br />

gibi.<br />

Program 20.7: Tanımlanmış ise pi sayısını kullanır.<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

/* 20prg07.c: Tanımlanmış ise PI sayısını<br />

kullanır */<br />

#include <br />

#include <br />

#define PI 3.141593<br />

main()<br />

{<br />

double c, r = 21.3;<br />

}<br />

ÇIKTI<br />

#ifdef PI<br />

c = 2.0 * PI * r;<br />

printf("Dairenin cevresi = %lf\n",c);<br />

#else<br />

printf("PI saysisi tanimlanmamis.\n");<br />

#endif<br />

Dairenin cevresi = 133.831862<br />

20.6 #error Yönergesi<br />

Önişlemci bu deyimle karşılaşınca yanındaki mesajı ekrana yazar ve derleme işlemine son<br />

verir. Mesela, yazmış olduğunuz program 32 bitlik bir işletim sistemi (WINDOWS veya<br />

Linux gibi) için tasarlanmışsa ve program 16 bitlik işletim sisteminde (MSDOS gibi)<br />

derlenecekse kullanıcıya buna dair bir uyarı mesajı vermek uygun olur[2-4]. Örneğin:<br />

#if (sizeof(int)==2)<br />

#error Bu program 16 bitlik işletim sisteminde derlenemez !...<br />

#endif<br />

Eğer DOS altında çalışıyorsanız önişlemci derleme işlemine:<br />

Bu program 16 bitlik işletim sisteminde derlenemez !...<br />

mesajı ile son verir. Mesajın tırnak içine alınmadığına dikkat ediniz.<br />

20.7 Önceden Tanımlanmış Sembolik Sabitler<br />

Bazı sembolik sabitler derleyici tarafından önceden tanımlanmıştır. Bu sabitlerden bazıları<br />

Tablo 20.1 de verilmiştir.


Tablo 20.1: Önceden tanımlı bazı sembolik sabitler<br />

Sabit ismi<br />

Açıklama<br />

Önişlemci bu sabit yerine kaynak koddaki o anda bulunan satır<br />

__LINE__<br />

numarasını yerleştirir.<br />

__FILE__<br />

Kaynak dosyanın ismin tutar.<br />

Önişlemci bu sabit yerine derlemenin yapıldığı zaman tarihi (ay gün<br />

__DATE__<br />

yıl formatında) yazar.<br />

Önişlemci bu sabit yerine derlemenin yapıldığı zaman zamanı<br />

__TIME__<br />

(sa:dak:sn gün yıl formatında) yazar.<br />

C dilinde kullanılan kimi anahtar sözcükler standart değildir.<br />

__STDC__<br />

Derleyici eğer yalnızca standart C'nin anahtar sözcüklerini<br />

destekliyorsa bu sabit tanımlı varsayılır.<br />

M_PI<br />

Pi sayısını tutar (M_PI = 3.14159265358979323846). Ayrıca bkz:<br />

math.h<br />

M_E<br />

e sayısını tutar (M_E = 2.7182818284590452354). Ayrıca bkz:<br />

math.h<br />

Rastgele sayı üretec fonksiyonu rand() ile döndürlen en büyük sayıyı<br />

RAND_MAX<br />

tutar.<br />

(32 bit işletim sitemi için: RAND_MAX = 2147483647). Ayrıca bkz:<br />

stdlib.h<br />

Aşağıdaki örnekleri inceleyiniz:<br />

Program 20.8: C dilindeki bazı tanımlı sabitler<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

ÇIKTI<br />

/* 20prg08.c: Sembolik sabitler */<br />

#include <br />

main()<br />

{<br />

printf("Satir No : %d\n",__LINE__);<br />

printf("Dosya adi : %s\n",__FILE__);<br />

printf("Tarih : %s\n",__DATE__);<br />

printf("Saat : %s\n",__TIME__);<br />

}<br />

Satir No : 7<br />

Dosya adi : 20prg08.c<br />

Tarih : Sep 21 2008<br />

Saat : 01:58:56<br />

Program 20.9: C dilindeki bazı tanımlı sabitler<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

/* 20prg09.c: Sembolik sabitler */<br />

#include <br />

#include <br />

#include <br />

#ifndef __STDC__


08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

#error Bu derleyici ANSI C degil.<br />

#endif<br />

#ifndef RAND_MAX<br />

#error RAND_MAX tanımlı degil.<br />

#endif<br />

main()<br />

{<br />

double r = (double) rand()/RAND_MAX;<br />

double ikiPi = 2.0*M_PI;<br />

double birBoluE = 1.0/M_E;<br />

}<br />

ÇIKTI<br />

printf("r = %lf\n",r);<br />

printf("ikiPi = %lf\n",ikiPi);<br />

printf("birBoluE = %lf\n",birBoluE);<br />

r = 0.840188<br />

ikiPi = 6.283185<br />

birBoluE = 0.367879<br />

<strong>Ders</strong> 22: Derleme Seçenekleri<br />

• <strong>Giriş</strong><br />

• 22.1 Çalıştırılabilir Dosya Üretimi<br />

• 22.2 Turbo C Derleme Seçenekleri<br />

• 22.3 GCC Derleme Seçenekleri<br />

<strong>Giriş</strong><br />

Bazen bir kullanıcı derlemek istediği kaynak C programını başka C programları ile beraber<br />

kullanmak, sadece nesne kodu üretmek veya başka bir dilde yazılmış programı, C programı<br />

içinde kullanmak isteyebilir. Bir derleyiciye ait derleme seçenekleri ile bu tip işlemleri<br />

gerçekleştirmek mümkündür.<br />

Bu kısımda derleme ve bağlama işlemi, derleyicilerin sunduğu bazı derleme seçenekleri ve<br />

bunlar yardımıyla birden çok C programının nasıl birleştirileceği anlatılacaktır.<br />

22.1 Çalıştırılabilir Dosya Üretimi<br />

Programlama işlemi, bir programlama diline ait söz dizilimlerini içeren kaynak kodların<br />

yazılması ile başlar. Kaynak kod (source code), C, Fortran veya Pascal gibi yüksek seviyedeki


dillerin deyimleri barındıran bir düz metin dosyasında (plain text file) saklanır. Bu dosyalar<br />

geleneksel uzantılarla birbirinde ayrılabilir, örneğin c programları .c uzantılı, Pascal<br />

programları .pas uzantılı dosyalardır.<br />

Derleyici (compiler), bir programlama dilinde yazılmış olan kaynak kodunu başka bir dile<br />

(coğukez makine dili) çeviren yazılımdır. Her programlama dile kendi derleyicisine sahiptir.<br />

Derleyicinin çevirdiği kaynak kod, hedef kod veya nesne kodu (object code) olarak<br />

adlandırılır. Nesne kodu, bilgisayarın mikroişlemcisi (CPU) için gerekli makina kodlarını ve<br />

işletim sistemi için gerekli program uygulama arayüzlerini (API: Application Programming<br />

Interface) içerir. Nesne kodu çalıştırılabilir bir kod değildir, ama bütün programlama dilleri<br />

için aynıdır. Derleyicilerin ürettikleri nesne kodları genellikle .obj veya .o uzantılı dosyalarda<br />

saklanır.<br />

Sonraki adım, nesne kodunun özel bir bağlayıcı (linker) ile işlenmesidir. Bağlayıcı,<br />

derleyiciler tarafından üretilmiş bir veya daha fazla nesne kodunu birleştirip tek bir<br />

çalıştırılabilir dosya oluşturan yazılımdır. Her sistem kendi bağlayıcısına sahiptir.<br />

Bağlayıcının ürettiği çalıştırılabilir kod Windows ortamında .exe uzantılı dosyalarda saklanır.<br />

Linux ortamında çalıştırılabilir dosyaların çoğunlukla bir uzantısı yoktur.<br />

Kaynak kodunun derlenip çalıştırılabilir dosyanın oluşturulmasına ait işlem basamakları Şekil<br />

22.1'de gösterilmiştir.<br />

Şekil 22.1: Derleme-Bağlama-Çalıştırma işleminin akış diyagramı.<br />

C ve C++ dilleri için iki çeşit kaynak kodu vardır: .c veya .cpp uzantılı ana program ve bazı<br />

bildirimlerin bulunduğu .h veya .hpp uzantılı başlık dosyaları (header files).<br />

C (ve C++) dilinde derleme işlemi iki adım adımda yapılır. Birinci adımıda, derleme öncesi<br />

özel bir ön işlemci (preprocessor) programı devreye girer. Ana programdaki veya başlık<br />

dosyalarındaki diyez ('#') işareti ile başlayan satırlar aslında C (veya C++) diline ait olmayıp<br />

ön işlemci dilidir. Ön işlemci, bu satırlardaki deyimlere bakarak, bir katarı (string) alıp başka<br />

bir katarla değiştir. Örneğin:<br />

#include <br />

satırı ile stdio.h dosyasının metin içeriği programa dahil edilir. Ön işlemci deyimlerinin<br />

tamamı Bölüm 20'de anlatılatılmıştır.<br />

Ön işlemci programı, .c ve .h uzantılı düz metin (text) halindeki kaynak dosyasını okur, ve<br />

çıktı olarak başka bir düz metin dosyası üretir. Bu yeni dosya hiçbir ön işlemci deyimi<br />

içermeyen C (veya C++) derleyicisi tarafından işlenmeye hazır bir dosyadır. İkinci adımda bu<br />

dosya ile kaynak kodaları beraber derlenip sırasıyla nesne kodu ve çalıştırılabilir kod üretilir.<br />

Bu işlemlem Şekil 22.2 de özetlenmiştir.


Şekil 22.2: C ve C++ dilleri için, Ön işlemci-Derleme-Bağlama-Çalıştırma işleminin akış<br />

diyagramı.<br />

22.2 Turbo C Derleme Seçenekleri<br />

Turbo C derleyicisinin sunduğu derleme seçeneklerini görmek için, komut satırında tcc<br />

yazmak yeterlidir. TCC'nin sunduğu derleme seçenekleri Şekil 22.2'de listelenmiştir.<br />

Şekil 22.2: Turbo C'nin derleme seçenekleri.<br />

Seçenekler incelendiğinde standart bir derleme işleminden daha fazlasının yapılabileceği<br />

anlaşılır. Birkaç örnekle seçenekleri anlamaya çalışalım.<br />

Program 22.1, 1 den n ye kadar olan tam sayıların toplamını hesaplayıp ekrana yazar.<br />

Program 22.1: 1 den n ye kadar olan tam sayıların toplamını hesaplar


01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

/* 22prg01.c: 1 den n=10 a kadar olan tam<br />

sayıların toplamını ekrana yazar */<br />

#include <br />

int s(int);<br />

int main()<br />

{<br />

int n = 10;<br />

printf("1 + 2 + ... + %d = %d\n",n,s(n) );<br />

return 0;<br />

}<br />

/* 1 + 2 + ... + n toplamını hesaplar */<br />

int s(int m){<br />

int i,top=0;<br />

}<br />

for (i=1;i tcc 22prg01.c<br />

Bu işlemle 22prg01.exe adlı bir çalıştırılabilir dosya ve 22prg01.obj adlı bir nesne dosyası<br />

üretilir. Dosyalar listelenirse bu yeni dosyalar görülecektir.<br />

C:\TC> dir /w 22prg01.*<br />

22prg01.c 22prg01.exe 22prg01.obj<br />

22prg01.exe dosyasını çalıştırmak için, dosyanın adını yazmak yeterlidir.<br />

C:\TC> 22prg01<br />

1 + 2 + ... + 10 = 55<br />

Sadece asm uzantılı assembly kodu üretmek istendiğinde -S seçeneği kullanılır.<br />

C:\TC> tcc -S 22prg01.c<br />

C:\TC> dir /w 22prg01.*<br />

22prg01.asm 22prg01.c 22prg01.exe 22prg01.obj<br />

Sadece obj uzantılı nesne dosyası üretmek için -c seçeneği kullanılır.<br />

C:\TC> tcc -c 22prg01.c<br />

C:\TC> dir /w 22prg01.*<br />

22prg01.asm 22prg01.c 22prg01.exe 22prg01.obj<br />

Çalıştırılabilir dosyanın adını değiştirmek için -exxx seçeneği kullanılır.<br />

C:\TC> tcc -eyeni 22prg01.c<br />

C:\TC> dir /w yeni*<br />

yeni.exe<br />

C:\TC> yeni<br />

1 + 2 + ... + 10 = 55<br />

Büyük uygulamalarda alt progroramlar başka dosyalarda saklanır ve ana program ile beraber<br />

komut satırında derlenebilir. Aşağıdaki gibi aynı dizin içerisinde bululan herbiri ayrı<br />

dosyalarda saklanan dört fonksiyona ve bir ana programama sahip olduğumuzu varsayalım.<br />

/* topla.c: iki sayinin toplamini<br />

hesaplar */<br />

/* fark.c: iki sayinin farkini<br />

hesaplar */


int topla(int a,int b)<br />

{<br />

return (a+b);<br />

}<br />

/* carp.c: iki sayinin carpimini<br />

hesaplar */<br />

int carp(int a,int b)<br />

{<br />

return (a*b);<br />

}<br />

int fark(int a,int b)<br />

{<br />

return (a-b);<br />

}<br />

/* iki sayinin oranini hesaplar */<br />

int bol(int a,int b)<br />

{<br />

if(b) return (a/b);<br />

return 0;<br />

}<br />

/* ana.c: Ana program */<br />

#include <br />

int topla(int, int);<br />

int fark(int, int);<br />

int carp(int, int);<br />

int bol(int, int);<br />

int main()<br />

{<br />

int x=33, y=22;<br />

printf("topla(%d,%d) = %d\n",x,y,topla(x,y));<br />

printf(" fark(%d,%d) = %d\n",x,y,fark(x,y));<br />

printf(" carp(%d,%d) = %d\n",x,y,carp(x,y));<br />

printf(" bol(%d,%d) = %d\n",x,y,bol(x,y));<br />

}<br />

return 0;<br />

Sadece ana.c dosyası derlendiğinde aşağıdaki gibi bir topla, fark, carp ve bol<br />

fonksiyonlarının tanımsız olduğuna dair hata mesajı ekranda basılır:<br />

C:\TC> tcc ana.c<br />

Turbo C Version 2.01 Copyright (c) 1987, 1988 Borland International<br />

ana.c:<br />

Turbo Link Version 2.0 Copyright (c) 1987, 1988 Borland International<br />

Undefined symbol '_bol' in module ana.c<br />

Undefined symbol '_carp' in module ana.c<br />

Undefined symbol '_fark' in module ana.c<br />

Undefined symbol '_topla' in module ana.c<br />

Fakat derleme şu şekilde yapıldığında hata mesajı ortadan kalkar.<br />

C:\TC> tcc ana.c topla.c fark.c carp.c bol.c<br />

Bu işlemin sonucunda derleyici ana.exe, ana.obj ve topla.obj, fark.obj, carp.obj,<br />

bol.obj dosyalarını üretir. Tabiki tek çalıştırılabilir dosya ana.exe dir. Bu, bütün dosyaların<br />

ayrı ayrı derlenmiş olduğu anlamına gelir. ana.exe dosyası çalıştırıldığında program çıktısı<br />

şöyle olacaktır:<br />

C:\TC> ana<br />

topla(33,22) = 55<br />

fark(33,22) = 11<br />

carp(33,22) = 726<br />

bol(33,22) = 1


Alt programlar çok büyük ve karmaşık işlemler yaptığında, bu şekilde derleme yapmak pek<br />

sağlıklı değildir. Bunun yerine alt programların bulunduğu dosyalar bir kez -c seçeneği ile<br />

derlendiğinde üretilen obj uzantılı dosyalar başka programlar tarafından kullanılabilir.<br />

Şöyleki:<br />

C:\TC> tcc -c topla.c<br />

C:\TC> tcc -c fark.c<br />

C:\TC> tcc -c carp.c<br />

C:\TC> tcc -c bol.c<br />

Ana programla beraber derleme işlemi bize aynı sonucu verecektir:<br />

C:\TC> tcc ana.c topla.obj fark.obj carp.obj bol.obj<br />

Bu sayede ana programda bir değişiklik yapılsa bile alt programrın bir daha derlenmesine<br />

gerek kalmaz. Örneğin ana program şu şekilde bir satır ekleyelim:<br />

/* ana.c: Ana program */<br />

#include <br />

int topla(int, int);<br />

int fark(int, int);<br />

int carp(int, int);<br />

int bol(int, int);<br />

int main()<br />

{<br />

int x=33, y=22;<br />

printf("topla(%d,%d) = %d\n",x,y,topla(x,y));<br />

printf(" fark(%d,%d) = %d\n",x,y,fark(x,y));<br />

printf(" carp(%d,%d) = %d\n",x,y,carp(x,y));<br />

printf(" bol(%d,%d) = %d\n",x,y,bol(x,y));<br />

printf("<br />

ortalama = %f\n",topla(x,y)/2.0);<br />

}<br />

return 0;<br />

Derleme aşağıdaki gibi yapıldığında:<br />

C:\TC> tcc ana.c topla.obj fark.obj carp.obj bol.obj<br />

program çıktısı şöyle olur:<br />

C:\TC> ana<br />

topla(33,22) = 55<br />

fark(33,22) = 11<br />

carp(33,22) = 726<br />

bol(33,22) = 1<br />

ortalama = 27.500000<br />

C:\TC><br />

Özetle bir fonksiyon birkez derlenip ona ait obj dosyası üretildiğinde, artık o kod bütün<br />

programlar tarafından kullanılabilir demektir. Aşağıdaki derleme işlemi ile obj dosyaları ana<br />

programa bağlanmıştır diyebiliriz:<br />

C:\TC> tcc ana.c topla.obj fark.obj carp.obj bol.obj<br />

Bu durum Şekil 22.3 de tasvir edilmiştir.


Şekil 22.3: Birden çok dosyanın derlenmesi ve birleştirilmesi.<br />

22.3 GCC Derleme Seçenekleri<br />

GCC (GNU Compiler Collection) daha çok Linux ve MAC ortamında kullanılan bir komut<br />

satırı derleyicisidir. GCC'nin Windows ortamında çalıştırılabilen sürümü de mevcuttur, bkz.<br />

gcc.gnu.org. Bu kısımda GCC'nin Linux ortamındaki kullanımından bahsedilecektir. Ancak<br />

bütün işlemler Windows işletim sisteminde de geçerlidir.<br />

GCC derleme seçeneklerini komut satırından görmek için iki yol vardır. Bunlar:<br />

$ man gcc<br />

veya<br />

$ gcc --help<br />

Burada $ işareti Linux komut hazır işaretidir (command prompt). Bu komutlardan birincisi<br />

oldukça büyük, ayrıntılı ve yardım niteliğindedir, örneğin bkz:<br />

www.hmug.org/man/1/gcc.php. İkincisinin sonucu Şekil 22.4 deki gibidir.


Şekil 22.4: GCC'nin derleme seçenekleri.<br />

GCC ile 22prg01.c kaynak kodu şöyle derlenebilir:<br />

$ gcc 22prg01.c<br />

Bu işlem neticesinde sadece a.out adlı çalıştırılabilir bir dosya üretilir. Bu programı<br />

çalıştırmak için:<br />

$ ./a.out<br />

1 + 2 + ... + 10 = 55<br />

Çalıştırılabilir dosyanın adını değiştirmek için -o seçeneği kullanılır.<br />

$ gcc 22prg01.c -o 22prg01<br />

$ ./22prg01<br />

1 + 2 + ... + 10 = 55<br />

Sadece derleme yapmak için (Turbo C'de olduğu gibi) -c seçeneği kullanılır.<br />

$ gcc -c 22prg01.c<br />

Bu işlemin sonucunda 22prg01.o adlı nesne dosyası üretilir. Bu dosya, dosyalar<br />

listelendiğinde görülebilir:<br />

$ ls 22prg01*<br />

22prg01.c 22prg01.o 22prg01*


Bir C kaynak kodu kütüphanesinden bir fonksiyon içeriyorsa, GCC ile bu tür<br />

programlar -lm seçenği ile derlenmelidir. Program 22prg02.c, ilk 10 pozitif tam sayının on<br />

tabanındaki logaritmalarını ve doğal logaritmalarını ekrana gösterir. Program içerisinde<br />

kütüphanesindeki log ve log10 fonkiyonları kullanılmıştır.<br />

Program 22.2: 1 den 10 a kadar olan tam sayıların logaritmaları<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

/* 22prg02.c: 1 den n=10 a kadar olan tam<br />

sayıların logaritmalarını ekrana yazar */<br />

#include <br />

#include <br />

int main()<br />

{<br />

int i;<br />

for(i=1; i


$ gcc -c fark.c<br />

$ gcc -c carp.c<br />

$ gcc -c bol.c<br />

Derlenmiş alt programların ana program ile birleştirlmesi<br />

$ gcc ana.c topla.o fark.o carp.o bol.o -o ana<br />

$ ./ana<br />

topla(33,22) = 55<br />

fark(33,22) = 11<br />

carp(33,22) = 726<br />

bol(33,22) = 1<br />

ortalama = 27.500000<br />

$<br />

<strong>Ders</strong> 23: Tarih ve Saat Fonksiyonları<br />

• <strong>Giriş</strong><br />

• 23.1 time() Fonksiyonu<br />

• 23.2 ANSI C Tarih-Saat Fonksiyonları, Sabitleri ve Yapıları<br />

• 23.3 Mili Saniye ve Mikro Saniye Düzeyinde Çalışmak<br />

<strong>Giriş</strong><br />

Bazı uygulamalarda program içerisinde tarih ve saat bilgilerine ihtiyaç duyulabilir. C dilinde,<br />

tarih ve saat fonksiyonlarının bildirimleri, semblik sabitler ve standart yapılar <br />

başlık dosyasında tanımlanmıştır. Bu fonksiyonlar üç temel işlevi yerine getirir:<br />

• Takvim (Tarih) bilgileri<br />

• Yerel Saat<br />

• Saat Dilimleri<br />

Bu bölümde tarih ve saat fonksiyonları incelenmişitir.<br />

23.1 time() Fonksiyonu<br />

time() fonksiyonu 01/01/1970 tarihinden, programın çalıştığı tarihe ve saate kadar geçen<br />

sürenin saniye cinsinden değerini gönderir. Genel bildirimi:<br />

time_t time(time_t *zaman);<br />

şeklindedir. Burada:


• time_t sayısal bir tip (genllikle long int) olup zaman bilgisini temsil eder.<br />

• zaman tarih bilgisini tutan gösterici tipinde bir değişkendir.<br />

NOT<br />

Derleyici tarih bilgisi göstermezse time() fonksiyonu -1<br />

değerini gönderir.<br />

01/01/1970'den bu güne geçen süreyi iki yolla öğrenebiliriz:<br />

1. Geri dönüş değerini kullanarak<br />

2. time_t t;<br />

3. ...<br />

4. t = time(NULL);<br />

5. printf("zaman: %ld\n",t);<br />

6. fonksiyon parametresinden<br />

7. time_t t;<br />

8. ...<br />

9. time(&t);<br />

10. printf("zaman: %ld\n",t);<br />

Şimdi örnek uygulamayı Program 23.1'de görelim:<br />

Program 23.1: time() fonksiyonunun kullanımı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

ÇIKTI<br />

/* 23prg01.c: time() fonksiyonun kullanımı */<br />

#include <br />

#include <br />

int main ()<br />

{<br />

time_t saniye; /* long saniye; anlamında */<br />

saniye = time (NULL);<br />

puts("01/01/1970'den bu gune kadar gecen<br />

sure,");<br />

printf ("Saniye olarak %ld\n", saniye);<br />

/* 1 saat = 60*60 = 3600 sn. */<br />

printf ("Saat olarak %ld\n", saniye/3600);<br />

/* 1 gün = 24 saat = 24*60*60 = 86400 sn. */<br />

printf ("Gun olarak %ld\n", saniye/86400);<br />

return 0;<br />

}<br />

01/01/1970'den bu gune kadar gecen sure,<br />

Saniye olarak 1227606397<br />

Saat olarak 341001<br />

Gun olarak 14208


23.2 ANSI C Tarih-Saat Fonksiyonları, Sabitleri ve<br />

Yapıları<br />

Tablo 23.1'de ANSI C'de başlık dosyasında bildirilen tarih-saat fonksiyonları<br />

listelenmiştir.<br />

Tablo 18.1: time.h'te tanımlı tarih-saat fonksiyonları<br />

Fonksiyon Bildirimi<br />

char *asctime(const struct tm<br />

*zmn_g);<br />

clock_t clock(void);<br />

char *ctime(const time_t<br />

*zaman);<br />

Açıklama<br />

zmn_g göstericinin işaret ettiği veriyi, daha anlaşılabilir<br />

bir formatla katar bilgisine çevirir. zmn_g göstericisi,<br />

gmtime() ve localtime() fonksiyonlarının<br />

döndürdüğü, tm yapısını gösterir. Geri döndürelen<br />

katarın genel formatı:<br />

Www Mmm dd hh:mm:ss yyyy<br />

şeklindedir. Burada Www haftanın günü, Mmm ay bilgisi,<br />

dd ayın günü hh:mm:ss saat bilgisini ve yyyy yıl<br />

bilgisidir.<br />

Zaman tik-tak bilgisini döndürür.<br />

Geriye anlaşılır formatta yerel zamanı tutan bir katar<br />

döndürür. zaman, time_t tipinde bir uzun tamsayıdır.<br />

Katarın formatı: Www Mmm dd hh:mm:ss yyyy<br />

şeklindedir.<br />

double difftime(time_t zaman1,<br />

time_t zaman2);<br />

zaman2 - zaman1 farkını saniye cinsinden hesaplar.<br />

zaman'ı tm yapısına (İngiltere'deki Greenwitch'göre<br />

struct tm *gmtime(const time_t<br />

*zaman);<br />

struct tm *localtime(const<br />

time_t *zaman);<br />

time_t mktime(struct tm<br />

*zaman);<br />

time_t time(time_t *zaman);<br />

GMT cinsinden) çevirir. zaman genellikle time<br />

fonksiyonu ile döndürülür.<br />

zaman'ı tm yapısına (yerel saat cinsinden) çevirir. zaman<br />

genellikle time fonksiyonu ile döndürülür.<br />

tm tipinde, zaman göstericisine ait tarih-saat bilgisini<br />

gösterir.<br />

1 Ocak 1970'den bu ana kadar geçen sürenin zaman<br />

saniye cinsinden hesaplar.<br />

CLK_TCK<br />

clock_t ve time_t<br />

(clock ticks per second) makro sabit. Zaman tik-takları<br />

ve zamanın saniye cinsinden karşılığı arasında ilişkiyi<br />

tanımlar. Bu sabit Turbo C'de<br />

#define CLK_TCK 18.2<br />

şeklinde tanımlanmıştır.<br />

clock() ve time() fonksiyonlarının kullandığı veri<br />

tipleri. Bunlar genellikle genllikle long int tipleridir<br />

ve başlık dosyasında şöyle tanımlıdır.<br />

typedef long clock_t<br />

typedef long time_t<br />

asctime(), gmtime(), localtime() ve mktime() fonksiyonlarının kullandığı tm yapısı<br />

söyledir:


struct tm {<br />

int tm_sec; /* saniye, (0 - 59) */<br />

int tm_min; /* dakika, (0 - 59) */<br />

int tm_hour; /* saat, (0 - 23) */<br />

int tm_mday; /* ayın günü, (1 - 31) */<br />

int tm_mon; /* ay, (0 - 11), 0 = Ocak */<br />

int tm_year; /* yıl - 1900 */<br />

int tm_wday; /* haftanın günü, (0 - 6), 0 = Pazar */<br />

int tm_yday; /* yılın günü,(0 - 365) */<br />

int tm_isdst; /* gündüz (-1/0/1) */<br />

};<br />

Program 23.2:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

ÇIKTI<br />

/* 23prg02.c: asctime() ve localtime()<br />

fonksiyonlarının kullanımı */<br />

#include <br />

#include <br />

int main()<br />

{<br />

time_t t;<br />

struct tm *zaman_bilgisi;<br />

time (&t);<br />

zaman_bilgisi = localtime (&t);<br />

printf("Su anki tarih ve saat:<br />

%s",asctime(zaman_bilgisi));<br />

return 0;<br />

}<br />

Su anki tarih ve saat: Tue Nov 25 15:19:20 2008<br />

Program 23.3:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

ÇIKTI<br />

/* 23prg03.c: ctime() fonksiyonunun kullanımı */<br />

#include <br />

#include <br />

main()<br />

{<br />

time_t t;<br />

time(&t);<br />

printf("Su anki tarih ve saat: %s",ctime(&t));<br />

return 0;<br />

}


Su anki tarih ve saat: Tue Nov 25 17:08:02 2008<br />

Program 23.4:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

/* 23prg04.c: clock() fonksiyonunun kullanımı */<br />

#include <br />

#include <br />

void bekle(int zaman)<br />

{<br />

clock_t son;<br />

}<br />

ÇIKTI<br />

son = clock() + zaman * CLK_TCK;<br />

while( clock() < son) {}<br />

int main()<br />

{<br />

int n;<br />

printf ("Geri sayim basladi...\n");<br />

for (n=10; n>0; n--)<br />

{<br />

printf ("%d\n",n);<br />

bekle(1000);<br />

}<br />

printf ("ATES!\n");<br />

return 0;<br />

}<br />

Geri sayim basladi...<br />

10<br />

9<br />

8<br />

7<br />

6<br />

5<br />

4<br />

3<br />

2<br />

1<br />

ATES!<br />

Program 23.5:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

/* 23prg03.c: difftime() fonksiyonunun kullanımı<br />

*/<br />

#include <br />

#include


07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

ÇIKTI<br />

int main ()<br />

{<br />

time_t basla, bit;<br />

char ad[256];<br />

double fark;<br />

time (&basla);<br />

printf ("Lutfen adinizi girin: ");<br />

gets (ad);<br />

time (&bit);<br />

fark = difftime(bit, basla);<br />

printf("Merhaba %s.\n", ad);<br />

printf("Adini yazman %lf saniye<br />

surdu.\n",fark);<br />

return 0;<br />

}<br />

Lutfen adinizi girin: Ahmet<br />

Merhaba Ahmet.<br />

Adini yazman 2.000000 saniye surdu.<br />

Program 23.6:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

/* 23prg06.c: mktime() fonksiyonunun kullanımı<br />

*/<br />

#include <br />

#include <br />

int main ()<br />

{<br />

time_t t;<br />

struct tm *zaman;<br />

int yil, ay, gun;<br />

char *haftanin_gunu[] = { "Pazar",<br />

"Pazartesi",<br />

"Sali",<br />

"Carsamba",<br />

"Persembe", "Cuma",<br />

"Cumartesi"};<br />

/* tarih bilgisini oku */<br />

printf("Yılı girin: "); scanf ("%d",&yil);<br />

printf("Ayı girin: "); scanf ("%d",&ay);<br />

printf("Gunu girin: "); scanf ("%d",&gun);<br />

/* simdiki zaman bilgisini al */<br />

t = time(NULL);<br />

zaman = localtime(&t);<br />

zaman->tm_year = yil - 1900;<br />

zaman->tm_mon = ay - 1;<br />

zaman->tm_mday = gun;<br />

/* mktime fonksiyonun cagir */


32:<br />

33:<br />

mktime(zaman);<br />

printf("Girilen tarihteki gun<br />

haftanin_gunu[zaman->tm_wday]);<br />

%s.\n",<br />

}<br />

return 0;<br />

ÇIKTI<br />

Yılı girin: 2003<br />

Ayı girin: 8<br />

Gunu girin: 1<br />

Girilen tarihteki gun Cuma.<br />

Program 23.7:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

ÇIKTI<br />

/* 23prg07.c: gmtime() fonksiyonunun kullanımı<br />

*/<br />

#include <br />

#include <br />

#define TUR (2)<br />

#define ALM (1)<br />

#define ABD (-8)<br />

int main()<br />

{<br />

time_t t;<br />

struct tm *ptm;<br />

time (&t);<br />

ptm = gmtime(&t);<br />

printf("Su anki yerel saatler\n");<br />

printf("Istanbul : %02d:%02d\n", ptm-<br />

>tm_hour + TUR, ptm->tm_min);<br />

printf("Berlin : %02d:%02d\n", ptm-<br />

>tm_hour + ALM, ptm->tm_min);<br />

printf("Los Angeles: %02d:%02d\n", ptm-<br />

>tm_hour + ABD, ptm->tm_min);<br />

return 0;<br />

}<br />

Su anki yerel saatler<br />

Istanbul : 18:34<br />

Berlin : 17:34<br />

Los Angeles: 08:34<br />

Program 23.8:<br />

01: /* 23prg08.c: gerçek zamanı gösterimi */


02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

ÇIKTI<br />

#include <br />

#include <br />

int main()<br />

{<br />

time_t t;<br />

struct tm *zmn;<br />

puts("Cikis icin: CTRL+C");<br />

/* Sonsuz döngü */<br />

while(1)<br />

{<br />

time(&t);<br />

zmn = localtime(&t);<br />

printf("%02d:%02d:%02d\r",<br />

zmn->tm_hour, zmn->tm_min, zmn-<br />

>tm_sec);<br />

}<br />

return 0;<br />

}<br />

Cikis icin: CTRL+C<br />

17:08:43<br />

23.3 Mili Saniye ve Mikro Saniye Düzeyinde Çalışmak<br />

Bazı uygulamalarda saniyenin (s) alt birimleri, salise (sl), mili saniye (ms) ve mikro saniye<br />

(µs), düzeyinde çalışmak gerekebilir. Birçok derleyici, saniyenin belli kesirlerine kadar<br />

erişime izin veren fonksiyonları bünyesinde barındırır. Ancak, bu fonksiyonlar satandart C'de<br />

mevcut değildir.<br />

NOT<br />

1 sl = (1/100) s = 0,01 s<br />

1 ms = (1/1000) s = 0,001 s<br />

1 µs = (1/1000000) s = 0,000001 s<br />

gcc derleyicisinde başlık dosyası içinde tanımlı, gettimeofday() fonksiyonu<br />

ile mikro-saniye düzeyine erişim mümkündür.<br />

Program 23.9:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

/* 23prg09.c: saniyenin alt birimleri<br />

Derleyici gcc 4.1.2 */<br />

#include <br />

#include


06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

ÇIKTI<br />

#include <br />

int main()<br />

{<br />

struct timeval tv;<br />

struct timezone tz;<br />

struct tm *tm;<br />

long int sa, dk, sn, us;<br />

double sl, ms;<br />

gettimeofday(&tv,&tz);<br />

tm = localtime(&tv.tv_sec);<br />

sa = tm->tm_hour; /* saat */<br />

dk = tm->tm_min; /* dakika */<br />

sn = tm->tm_sec; /* saniye */<br />

sl = tv.tv_usec/1.0e4; /* salise */<br />

ms = tv.tv_usec/1.0e3; /* mili-saniye */<br />

us = tv.tv_usec; /* mikro-saniye */<br />

printf("%02ld:%02ld:%02ld ; %lf %lf %ld\n",<br />

sa, dk, sn, sl, ms, us);<br />

return 0;<br />

}<br />

13:53:38 ; 65.247900 652.479000 652479<br />

Program çalıştırıldığı andaki saniye 38 değerini göstermektedir. Daha doğrusu, program<br />

çalıştığı anda sistem saatinin saniye göstergesi 38. saniyeden 39. saniyeye geçmektedir.<br />

Çıktıdaki 652479 rakamı, 38. ve 39. saniyeler arası geçen zamanın µs cinsinden değeridir.<br />

Yani, saniyenin alt birimi 38 s + 652479 µs = 38.652479 s. demektir.<br />

Turbo C deleyicisinde, mili-saniye düzeyinde kadar erişim izni vardır. Bunun için, program<br />

içerisinde başlık dosyasında tanımlı ftime() fonksiyonu kullanılabilir.<br />

Program 23.9b:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

/* 23prg09b.c: saniyenin alt birimleri<br />

Derleyici Turbo C 2.0 */<br />

#include <br />

#include <br />

#include <br />

int main()<br />

{<br />

struct tm *zmn;<br />

struct timeb *tb;<br />

int sa, dk, sn;<br />

double sl, ms;


14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

ÇIKTI<br />

sa = zmn->tm_hour; /* saat */<br />

dk = zmn->tm_min; /* dakika */<br />

sn = zmn->tm_sec; /* saniye */<br />

sl = tb->millitm/10.0; /* salise */<br />

ms = tb->millitm; /* mili-saniye */<br />

ftime(tb);<br />

printf("%02d:%02d:%02d | %lf %lf\n", sa, dk,<br />

sn, sl, ms);<br />

return 0;<br />

}<br />

13:56:16 ; 35.600000 356.000000<br />

<strong>Ders</strong> 24: Monte Carlo Yöntemleri<br />

• <strong>Giriş</strong><br />

• 24.1 Uygulama Alanları<br />

• 24.2 Rastgele Sayılar<br />

• 24.3 ANSI C Fonksiyonları<br />

• 24.4 Basit Monte Carlo Programları<br />

<strong>Giriş</strong><br />

Bilimsel uygulamalarda problemler iki kısımda incelenebilir:<br />

• kesin = deterministik (deterministic)<br />

• tahmini = olası (random).<br />

Kesin sistemler, kuralları kanun hükmünde olan matematiksel yasalarla tanımlanabilen<br />

sistemlerdir; Örneğin yerçekimi yasası gibi. Fakat, tahmini sistemlerin kuralları muhtemel<br />

veya raslantısal (stocastic) olan istatiksel yöntemlerle belirlenir; Örneğin havaya atılan bir<br />

metal paranın yazı veya tura gelmesi gibi. Burada raslantıdan kasıt, tahmini sistemlerde,<br />

başlangıç koşulları kesin olarak tayin edilemediği için sonuca dair çözümün tahmin edilmesi<br />

anlamındadır. Yoksa, evrende raslantıya yer yoktur.<br />

Bilgisayar ortamında, yazılımsal (veya donanımsal) olarak rastgele sayılar (random numbers)<br />

üretmek mümkündür. Monte Carlo Yöntemleri, bu rastgele sayıları kullanarak tahmini<br />

sistemleri modelleyen algoritmalardır. Aslında, Monte Carlo, (Fransa) Monako'nun<br />

kumarhaneleriyle ünlü en zengin yerleşim yeridir. (bkz. Wikipedia: Monte Carlo). Bu yüzden,


tahmini sistemlerin modellenmeside kullanılan sayısal analiz yöntemlerine Monte Carlo<br />

(kısaca MC) ismi verilmiştir.<br />

Bu bölümde, yazılımsal olarak üretilen Rastgele Sayılar ve Sayısal Analiz'de kullanılan basit<br />

Monte Carlo Yöntemleri konu edilecektir.<br />

24.1 Uygulama Alanları<br />

Monte Carlo (MC), rastgele sayıları baz alarak tahmini sistemleri modeller. Hatta, bazı kesin<br />

sistemlerde de kullanılabilir; Örneğin rastgele sayılarla Pi sayısını veya bir fonksiyonun<br />

integralini hesaplamak gibi. MC yöntemleri, Fizik ve Mühendislik alanlarında pekçok<br />

uygulama alanı bulmuştur. Bunlardan başlıcaları:<br />

• [Matematik] Sayısal Analiz<br />

• [Fizik] Doğal olayların simülasyonu<br />

• [Fizik] Atom ve Molekül Fiziği, Nükleer Fizik ve özellikle Yüksek Enerji Fiziği<br />

modellerini test eden simülasyonlar<br />

• [Mühendislik] Deneysel aletlerin (örneğin detektör) simülasyonu<br />

• [Biyoloji] Hücre Similasyonu<br />

• [Ekonomi] Borsa Modelleri<br />

• [İstatistik] Dağılım Fonksiyonları<br />

Tahmini sistemleri modelleyebilmek için:<br />

• Rastgele Sayı üretmeyi ve kullanmayı<br />

• Basit MC programlarını oluşturmayı<br />

• İleri düzeyde hazırlanan MC üreteçlerini ve programları kullanmayı<br />

iyi öğrenmek gerekir.<br />

24.2 Rastgele Sayılar<br />

Bilgisayarların en çok uygulandığı alanlardan bir tanesi kuşkusuz doğa olaylarının<br />

modellenmesidir. Bazı durumlarda, bilgisayarın ürettiği rastgele sayılar kullanılarak belirsiz<br />

yani tahmini sistemler modellenebilir. Rastgele sayı özel bir dağılımdan seçilen kargaşık<br />

(caotic) bir sayıdır.


Bilgisayarlar kesin (deterministic) bir yapıda çalıştıkları için gerçek anlamda rastgele sayı<br />

üretemezler. Ancak, uygun algoritmlarla bir bilgisayarın düzgün bir dağılımdan seçilen ve<br />

genllikle [0,1] arasında gerçel değerler alan rastgele sayı üretmesi sağlanabilir. Bilgisayarların<br />

ürettiği bu rastgele sayılar yalancı rastgele sayı (pseudo-random numbers) olarak adlandırılır.<br />

Rastgele sayı üreten bu algoritmalara rastgele sayı üreteci (random number generator) denir.<br />

Günümüz derleyicilerinin bir çoğunda rastgele sayı üreteçleri için hazır kütüphane<br />

fonksiyonları tanımlanmıştır.<br />

Bu fonksiyonlar genellikle doğrusal bir denklem kullanarak, rastgele sayı dizisi üretir. 32-bit<br />

makinalarda, dizinin peryodu en az 2 31 ~ 10 9 (1 milyar) dur. Yani, bir rastgele sayı üreteci<br />

birbirinden farklı 1 milyar farklı sayı üretebilir. Bu kadar çok sayı günümüz bilgisaylarında<br />

bir kaç saniyede kolaylıkla oluşturulabilir.<br />

Rastgele sayı dizisini oluşturacak doğrusal denklemin genel biçimi şöyledir:<br />

x n+1 = ( a x n + b ) mod m<br />

burada mod modüler aritmetik işlemi anlamındadır. Dizinin ilk elemanı, x o , çekirdek (seed)<br />

olarak adlandırılır. a ve b sabitleri, dizi elemanları kargaşık ve düzgün dağılacak şekilde<br />

seçilir.<br />

1960 yılında IBM şirketi aşağıdaki meşhur RANDU algoritmasını kullanmıştır (a = 69069, b<br />

= 0):<br />

x n+1 = ( 69069 x n ) mod 2 31 -1<br />

Daha sonra Park ve Miller, aşağıdaki Minimal Standart algoritmasını önermiştir (a = 16807, b<br />

= 0):<br />

x n+1 = ( 16807 x n ) mod 2 31 -1<br />

Park-Miller algoritması ile oluşturulan rastgele sayı üreteci, aşağıdaki C fonksiyonu ile<br />

kotarılabilir:<br />

/*<br />

* Park-Miller algoritması ile [0,1] arasında<br />

* düzgün dağılmış rastgele sayı üretir.<br />

*/<br />

float rastgele(int *cekirdek)<br />

{<br />

const int im = 2147483647, ia = 16807;<br />

const int iq = 127773, ir = 2836;<br />

const float m = 128.0/im;<br />

int k;<br />

float r;<br />

k = *cekirdek / iq;<br />

*cekirdek = ia*(*cekirdek-k*iq) - ir*k;<br />

if(*cekirdek < 0) *cekirdek += im;<br />

r = m * (*cekirdek/128);<br />

}<br />

return r;<br />

Program 24.1'de, rastgele() fonksiyonu kullanılarak 10 sayı üretilmiştir. Program her<br />

çalıştırıldığında aynı sayılar üretilecektir. Bunun nedeni kümenin ilk elemanı ilk_sayi sabit<br />

olmasıdır.


Program 24.1: 10 rastgele sayı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

/* 24prg01.c<br />

rastgele() fonksiyonu ile 10 adet [0-1]<br />

arasında<br />

rastgel sayı üretir */<br />

#include <br />

float rastgele(int *);<br />

int main()<br />

{<br />

int ilk_sayi, i;<br />

float r;<br />

}<br />

/* dizinin çekirdeği (seed) */<br />

ilk_sayi = 123456789;<br />

for(i=1; i


0.633966<br />

24.3 ANSI C Fonksiyonları<br />

Standart C (ve C++), RANDU ve Minimal Standart'a göre daha verimli çalışan (stdlib.h<br />

başlık dosyasında bildirilen) aşağıdaki iki fonksiyonu kullanıcılarına sunmuştur:<br />

• int rand(void)<br />

0 ile RAND_MAX arasında tamsayı tipinde yalancı rastgele sayı üretilir.<br />

RAND_MAX, stdlib.h'de tanımlı sembolik bir sabittir. Değeri (derleyiciye bağlı olarak)<br />

en büyük int limiti ile sınırlıdır. Bu değer Turbo C (16-bit) derleyicisinde:<br />

#define RAND_MAX 32767<br />

şeklinde, gcc gibi (32-bit) uygulamalarda:<br />

#define RAND_MAX 2147483647<br />

şeklinde tanımlanmıştır.<br />

• void srand(unsigned int cekirdek)<br />

Rastgele sayı üreteci (rand()) için cekirdek değerini belirler.<br />

Aşağıda bu fonksiyonların uygulamaları gösterilmiştir. İnceleyiniz.<br />

Program 24.2:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

ÇIKTI<br />

/* 24prg02.c<br />

rand() ile 10 adet rastgele tamsayı sayı<br />

üretir */<br />

#include <br />

#include <br />

int main()<br />

{<br />

int i;<br />

/* rand fonksiyonu */<br />

for(i=1; i


1681692777<br />

1714636915<br />

1957747793<br />

424238335<br />

719885386<br />

1649760492<br />

596516649<br />

1189641421<br />

RAND_MAX = 2147483647<br />

Program 24.3:<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

ÇIKTI<br />

/* 24prg03.c<br />

rand() ile 10 adet [0,1] arasında rastgele<br />

gercel sayı üretir */<br />

#include <br />

#include <br />

int main()<br />

{<br />

int i;<br />

/* rand fonksiyonu */<br />

for(i=1; i


10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

ÇIKTI<br />

int i, cekirdek;<br />

/* cekirdeği değiştir */<br />

cekirdek = 31415926;<br />

srand(cekirdek);<br />

/* rand fonksiyonu */<br />

for(i=1; i


0.980876<br />

0.453894<br />

0.115219<br />

0.993930<br />

0.945253<br />

0.023599<br />

0.851912<br />

0.334151<br />

24.4 Basit Monte Carlo Programları<br />

Bu kısımda, rastgele sayılar kullanılarak üç basit MC uygulaması verilmiştir.<br />

• Uygulama 1: Yazı-Tura Simülasyonu<br />

• Uygulama 2: Zar Simülasyonu<br />

• Uygulama 3: MC ile Pi sayısının hesabı<br />

Uygulama 1: Yazı-Tura Simülasyonu<br />

Hilesiz bir para atıldığında, yazı veya tura gelme olasılığı (P, probability) eşit ve kuramsal<br />

olarak P = 1/2 dir. Düşünün ki bir para n kez atılsın ve gelen turaları sayıp ve t ile gösterelim.<br />

Deney sayısı, n, arttıkça t/n oranı kararlı (sabit) kalmaya başlar. Bu durumda, olasılığın<br />

istatiksel tanımı şöyle yapılır:<br />

P(t) = t/n<br />

n sonsuza giderken P(t) değeri P = 1/2 değerine yaklaşır.<br />

Şimdi, [0, 1] aralığından rastgele seçilen sayıları kullanarak, para atma deneyini yapalım.<br />

Rastgele sayı üreteçleri sayıları eşit olasılıkla üretir. r bir rastgele sayı olsun. r < 0.5<br />

durumuna tura, r >= 0.5 durumuna da yazı diyelim. Bu şekilde, bir döngü kullanarak deney<br />

sayısına (n) göre, yazı-tura simulasyonu yapılabilir. Program 24.6, klavyeden girilen n'ye<br />

göre, P(t) ve 1 - P(t) olasılıklarını hesaplar.<br />

Program 24.6: Yazı-Tura Simulasyonu<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

/* 24prg06.c<br />

MC Yazı-Tura Simulasyonu */<br />

#include <br />

#include <br />

#include


08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

ÇIKTI<br />

/* [0, 1] arası rastgele sayı gönderir */<br />

double rastgele(){<br />

double r = (double) rand()/RAND_MAX;<br />

return r;<br />

}<br />

int main()<br />

{<br />

int i, tura, yazi, n;<br />

double r, p;<br />

/* deney sayısı */<br />

printf("deney sayisini girin: ");<br />

scanf("%d",&n);<br />

/* rastgele sayı üretecini başlat */<br />

srand( time(NULL) );<br />

/* deneyleri başlat */<br />

for(tura=0, i=1; i


11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

}<br />

ÇIKTI<br />

double r = (double) rand()/RAND_MAX;<br />

return r;<br />

int main()<br />

{<br />

int i, j, tura, yazi, n;<br />

double r, p;<br />

/* rastgele sayı üretecini başlat */<br />

srand( time(NULL) );<br />

for(j=1; j


olur. Neden?<br />

Program 24.8: Zar Simulasyonu<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

/* 24prg08.c: MC Zar Simulasyonu<br />

Atılan bir çift zarın toplamının yedi olma<br />

olasılığını hesaplar.<br />

Olasılık kuramına göre, birçift zarın<br />

toplamının 7 olma olasılığı<br />

aşağıdaki formülden hesaplanabilir:<br />

Ptoplam(7) = P(1,6) + P(2,5) + P(3,4) +<br />

P(4,3) + P(5,2) + P(6,1)<br />

Diğer taraftan:<br />

P(1,6) = P(2,5) = P(3,4) = P(4,3) = P(5,2)<br />

= P(6,1) = 1/36'dır.<br />

Buna göre:<br />

Ptoplam(7) = 6*(1/36) = 1/6 = 0.16666..<br />

dır. */<br />

#include <br />

#include <br />

#include <br />

#include <br />

/* [0, 1] arası rastgele sayı gönderir */<br />

double rastgele(){<br />

double r = (double) rand()/RAND_MAX;<br />

return r;<br />

}<br />

int main()<br />

{<br />

int i, j, n, zar1, zar2, yedi;<br />

double p;<br />

/* rastgele sayı üretecini başlat */<br />

srand( time(NULL) );<br />

for(j=1; j


43:<br />

44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

50:<br />

51:<br />

52:<br />

53:<br />

54:<br />

p);<br />

}<br />

/* deneyleri başlat */<br />

for(yedi=0, i=1; i


olarak)<br />

şeklinde hesaplanabilir.<br />

Olayın canlandırılması adına, aşağıda nokta sayısının (n) farklı değerleri için oluşabilecek<br />

desenler gösterilmiştir.<br />

n = 10 nokta n = 100 nokta n = 200 nokta<br />

Program 24.9'da, MC yöntemi ile pi sayısının hesabı gösterilmiştir. Program ayrıca,<br />

hesaplanan pi ile math.h'de tanımlı sabit M_PI arasındaki hatanın yüzde olarak karşılığnı da<br />

ekranda gösterir. Program çıktısı incelendiğinde, hata n = 10 için yüzde 10, n = 1 milyar için<br />

yüzbinde 2 civarındadır.<br />

Program 24.9: MC ile Pi sayısının hesabı<br />

01:<br />

02:<br />

03:<br />

04:<br />

05:<br />

06:<br />

07:<br />

08:<br />

09:<br />

10:<br />

11:<br />

12:<br />

13:<br />

14:<br />

15:<br />

16:<br />

17:<br />

18:<br />

19:<br />

20:<br />

21:<br />

22:<br />

23:<br />

24:<br />

/* 24prg09.c:<br />

MC Yöntemi ile pi sayısının hesaplanması */<br />

#include <br />

#include <br />

#include <br />

#include <br />

/* [0, 1] arası rastgele sayı gönderir */<br />

double rastgele(){<br />

double r = (double) rand()/RAND_MAX;<br />

return r;<br />

}<br />

int main()<br />

{<br />

int i, j, n, m;<br />

double x, y, pi, hata;<br />

/* rastgele sayı üretecini başlat */<br />

srand( time(NULL) );<br />

for(j=1; j


25:<br />

26:<br />

27:<br />

28:<br />

29:<br />

30:<br />

31:<br />

32:<br />

33:<br />

34:<br />

35:<br />

36:<br />

37:<br />

38:<br />

39:<br />

40:<br />

41:<br />

42:<br />

43:<br />

44:<br />

45:<br />

46:<br />

47:<br />

48:<br />

49:<br />

ÇIKTI<br />

/* deney sayısı 10'un katları */<br />

n = pow(10, j);<br />

/* deneyleri başlat */<br />

for(m=0, i=1; i pi = 2.8000000 ,<br />

yuzde hata = %10.8732319<br />

100 : 78 --> pi = 3.1200000 ,<br />

yuzde hata = % 0.6873155<br />

1000 : 794 --> pi = 3.1760000 ,<br />

yuzde hata = % 1.0952199<br />

10000 : 7878 --> pi = 3.1512000 ,<br />

yuzde hata = % 0.3058113<br />

100000 : 78625 --> pi = 3.1450000 ,<br />

yuzde hata = % 0.1084592<br />

1000000 : 785728 --> pi = 3.1429120 ,<br />

yuzde hata = % 0.0419961<br />

10000000 : 7853164 --> pi = 3.1412656 ,<br />

yuzde hata = % 0.0104104<br />

100000000 : 78536996 --> pi = 3.1414798 ,<br />

yuzde hata = % 0.0035910<br />

1000000000 : 785380671 --> pi = 3.1415227 ,<br />

yuzde hata = % 0.0022272<br />

C / C++ Derleyicileri<br />

1. Dev-C++<br />

2. Salford (Silverfrost)<br />

3. GCC (GNU Compiler Collection)


4. Turbo C 2.01<br />

5. Eclipse IDE<br />

6. NetBeans IDE<br />

Dev-C++<br />

• Derleyicinin ilk üretildiği tarih: 1991-2009<br />

• Ekran Görüntüsü<br />

Salford (Silverfrost FTN95)<br />

• Derleyicinin üretildiği tarih: ?-2009


• Ekran Görüntüsü<br />

GCC (GNU Compiler Collection)<br />

• Derleyicinin üretildiği tarih: ?-2009<br />

• Ekran Görüntüsü


Turbo C<br />

• Derleyicinin üretildiği tarih: 1987-1988<br />

• Ekran Görüntüsü

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!