28.02.2015 Views

C Kitabı

Buraya açıklama gelecektir

Buraya açıklama gelecektir

SHOW MORE
SHOW LESS

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

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

Ders 1: Giriş<br />

• Giriş<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 />

Giriş<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 />

Derslerimizde 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


• Giriş<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 />

Giriş<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 />

Ders 3: Operatörler<br />

• Giriş<br />

• 3.1 Aritmetik Operatörler<br />

• 3.2 Atama Operatörleri<br />

• 3.3 sizeof Operatörü<br />

Giriş<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 />

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

• Giriş<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 />

Giriş<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 />

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

• Giriş<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 />

Giriş<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 />

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

• Giriş<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 />

Giriş<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 />

Ders 7: Döngüler<br />

• Giriş<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 />

Giriş<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


Giriş<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 />

Ders 9: Fonksiyonlar II (Alt programlar)<br />

• Giriş<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 />

Giriş<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 />

Ders 10: Diziler<br />

• Giriş<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 />

Giriş


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


Giriş<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 />

Ders 12: Katarlar (Stringler)<br />

• Giriş<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 />

Giriş<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 />

Ders 13: Dinamik Bellek Yönetimi<br />

• Giriş<br />

• 13.1 Dinamik Dizi Fonksiyonları<br />

• 13.2 Dinamik Matrisler<br />

Giriş<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 />

Ders 14: Gösterici Uygulamaları<br />

• Giriş<br />

• 14.1 Gösterici Uygulamarı<br />

Giriş<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


Ders 15: Yapılar ve Birlikler<br />

• Giriş<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 />

Giriş<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 />

Ders 16: Dosya Yönetimi<br />

• Giriş<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 />

Giriş<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 />

Ders 18: Port Denetimi<br />

• Giriş<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 />

Giriş<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 Giriş/Çı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 />

Ders 19: Grafik Kullanımı<br />

• Giriş<br />

• 19.1 Grafik Ekranına Geçiş<br />

• 19.2 Bazı Grafik Fonksiyonları<br />

• 19.3 Renk Kodları<br />

• 19.4 Örnekler<br />

Giriş<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 />

Ders 22: Derleme Seçenekleri<br />

• Giriş<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 />

Giriş<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 />

Ders 23: Tarih ve Saat Fonksiyonları<br />

• Giriş<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 />

Giriş<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 />

Ders 24: Monte Carlo Yöntemleri<br />

• Giriş<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 />

Giriş<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!