You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Ders</strong> 1: <strong>Giriş</strong><br />
• <strong>Giriş</strong><br />
• 1.1 Tarihçe<br />
• 1.2 Neden C?<br />
• 1.3 İlk C Programı<br />
• 1.4 Başlık Dosyaları<br />
• 1.5 Kaynak Kodunun Derlenmesi<br />
• 1.6 C Kodlarının Temel Özellikleri<br />
• 1.7 Kod Yazımı için Bazı Tavsiyeler<br />
<strong>Giriş</strong><br />
Bu ilk derste, bir C programın nasıl derlenip çalıştırılacağı ve Internet'te bulabileceğiz<br />
derleyicilerden bahsedilecektir. En basit C programının derleyip çalıştırdıktan sonra, geriye<br />
kalan sadece C Programlama Dili'nin kurallarını, yapısını ve deyimlerini öğrenmekten<br />
ibarettir.<br />
1.1 Tarihçe<br />
C Programlama Dili genel amaçlı orta seviyeli ve yapısal bir programlama dilidir. 1972<br />
yılında Dennis Ritchie tarafından Bell Telefon Labaraturvarında Unix işletim sistemi ile<br />
kullanılmak için tasarlanmıştır. C, özellikle sistem programlamada sembolik makine dili<br />
(Asembler) ile tercih edilmektedir. İşletim sistemleri, derleyiciler ve debug gibi aşağı seviyeli<br />
sistem programlarının yazılımında yoğun olarak C programlama dili kullanılır.<br />
C'nin yayılması ve gelişmesi, büyük bir bölümü C dili ile yazılan UNIX işletim sisteminin<br />
popüler olmasıyla başlamıştır. C Programlama Dili, hemen her alanda kullanılmaktadır.<br />
Günümüzde nesneye yönelik programlama dilleri (C++, Java) ve script dilleri (JavaScript,<br />
JavaApplet, PHP) gibi programlama dilleri C Programlama Dili'nden esinlenmiştir.<br />
C taşınabilir (portable) bir dildir. Yani herhangi bir C programı hiçbir değişikliğe uğramadan,<br />
veya çok az bir değişimle, başka bir derleyicide ve/veya işletim sisteminde derlenebilir.<br />
Örneğin, Windows işletim sistemlerinde yazılan bir C kodu, Linux, UNIX veya VAX gibi<br />
işletim sistemlerinde de derlenebilir. Taşınabilirlik, herkesin kabul ettiği bir standart ile<br />
gerçekleştirilebilir. Bugün, C Programla Dili için American National Standards Institute<br />
(ANSI) kurumunun Mart 2000'de belirlediği C99: ISO/IEC 9899:1999 standartı Standart C<br />
olarak kabul edilmiştir.<br />
Burada verilen C notarında, ağırlıklı olarak ANSI C veya diğer adıyla Standart C konu<br />
edilmiştir.<br />
1.2 Neden C?
C Programlama Dili'ni popüler kılan önemli nedenler aşağıda listelenmiştir:<br />
• C, güçlü ve esnek bir dildir. C ile işletim sistemi veya derleyici yazabilir, kelime<br />
işlemciler oluşturabilir veya grafik çizebilirsiniz.<br />
• C, iyi bir yazılım geliştirme ortamına sahiptir.<br />
• C, özel komut ve veri tipi tanımlamasına izin verir.<br />
• C, taşınabilir bir dildir.<br />
• C, gelişimini tamamlamış ve standardı oluşmuş bir dildir.<br />
• C, yapısal bir dildir. C kodları fonksiyon olarak adlandıralan alt programlardan<br />
oluşmuştur.<br />
• C++, Java, JavaScript, JavaApplet, PHP, C#, ... gibi diller C dilinden esinlenmiştir.<br />
1.3 İlk C Programı<br />
Program 1.1 de verilen C programı derlendikten sonra, ekrana 'Merhaba Dünya!' yazısını<br />
basan yalın bir C programıdır. Satır başlarına yerleştirilen 1:, 2: 3: ... rakamlarının<br />
yazılmasına gerek yoktur. Bu rakamlar sadece daha sonra program ile ilgili açıklama<br />
yapılırken, ilgili satırda bulunan kodlar izah edilirken kullanılacaktır. Bu programın<br />
bilgisayarda ilk.c adı ile kaydedilmiştir.<br />
Program 1.1: Derlendikten sonra ekrana 'Merhaba Dünya!' yazar<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
/* ilk.c: ilk C programi */<br />
#include <br />
main()<br />
{<br />
printf("Merhaba Dünya!\n");<br />
}<br />
/* ... */<br />
Programda, 1. satırda /* ... */ sembolleri görülmektedir. Bu ifadeler arasında<br />
yazılan herhangi bir metin, işlem vb. satırlar, derleyici tarafından işlenmez<br />
(değerlendirilmez). Yani /* */ ifadeleri açıklama operatörüdür.<br />
NOT<br />
Açıklama operatörü olarak C++ tarzı iki-bölü (//) de<br />
kullanılmaktadır. Günümüzde birçok C derleyicisi //<br />
operatörünü desteklemektedir. Bu operatörü kullanmadan<br />
önce derleyicinizin bu operatörü desteklediğinden emin<br />
olun.<br />
/*<br />
Bu satırlar derleyici tarafından<br />
değerlendirilmez. Ayrıca programın<br />
tarzı<br />
çalışma hızını da değiştirmez.<br />
*/<br />
C<br />
// Bu satırlar derleyici tarafından<br />
// değerlendirilmez. Ayrıca programın C++<br />
tarzı<br />
// çalışma hızını da değiştirmez.
#include <br />
2. satırdaki #include deyimi, programda eklenecek olan başlık dosyanını işaret eder.<br />
Bu örnekte verilen başlık dosyası (header file) stdio.h dir. #include <br />
ifadesi stdio.h dosyasının derleme işlemine dahil edileceğini anlatır[1]-[2].<br />
main()<br />
4. satırdaki main() özel bir fonksiyondur. Ana program bu dosyada saklanıyor<br />
anlamındadır. Programın yürütülmesine bu fonksiyondan başlanır. Dolayısıyla her C<br />
programında bir tane main() adlı fonksiyon olmalıdır.<br />
printf()<br />
6. satırdaki printf() standart kütüphane bulunan ekrana formatlı bilgi yazdırma<br />
fonksiyondur. stdio.h dosyası bu fonksiyonu kullanmak için program başına ilave<br />
edilmiştir. Aşağıda printf() fonksiyonunun basit kullanımı gösterilmiştir.<br />
Örnek kullanım şekli<br />
Ekranda yazılacak ifade<br />
printf("Element: Aluminyum");<br />
Element: Aluminyum<br />
printf("Atom numarası = %d",13); Atom numarası = 13<br />
printf("Yoğunluk = %f g/cm3",2.7);<br />
printf("Erime noktası = %f<br />
derece",660.32);<br />
1.4 Başlık Dosyaları<br />
Yoğunluk = 2.7 g/cm3<br />
Erime noktası = 660.32<br />
derece<br />
C dilinde bir program yazılırken, başlık dosyası (header file) olarak adlandırılan bir takım<br />
dosyalar #include önişlemcisi kullanılarak program içine dahil edilir. C kütüphanesinde<br />
bulunan birçok fonksiyon, başlık dosyaları içindeki bazı bildirimleri kullanır. Bu tür<br />
dosyaların uzantısı .h dir. ANSI C'deki standart başlık dosyaları şunlardır:<br />
assert.h locale.h stddef.h<br />
ctype.h math.h stdio.h<br />
errno.h setjmp.h stdlib.h<br />
float.h signal.h string.h<br />
limits.h stdarg.h time.h<br />
Bir çok C derleyicisinde yukarıdakilere ek olarak tanımlanmış başlık dosyaları da vardır.<br />
Bunlar derleyicinin yardım kısmından veya derleyicinin kullanım kılavuzundan öğrenilebilir.<br />
ilk.c programında kullanılan başlık dosyası stdio.h, #include ifadesi ile<br />
derleme işlemine dahil edilmiştir. stdio.h standard giriş/çıkış (STandarD-Input-Output)<br />
kütüphane fonksiyonları için bazı bildirimleri barındıran bir dosyasıdır. Programda kullanılan<br />
printf() fonksiyonunu kullanmadan önce bu başlık dosyası programın başına mutlaka ilave<br />
edilmelidir. Aksi halde derleme esnasında<br />
undefined reference to _printf<br />
şeklinde bir hata mesajı ile karşılaşılır.<br />
1.5 Kaynak Kodunun Derlenmesi<br />
C programları veya kaynak kodları (source code) uzantısı .c olan dosyalarda saklanır.<br />
Kaynak kod, bir C derleyicisi (C compiler) ile nesne koduna (object code) daha sonra uygun
ir bağlayıcı (linker) programı ile işletim sistemininde çalıştırılabilen (executable) bir koda<br />
dönüştürülür. Bazı işletim sistemleri ile kullanılan C Derleyicileri ve bu derleyicilerde ilk.c<br />
programının komut satırında nasıl derleneceği Tablo 1.1'de verilmiştir. Eğer ismi geçen<br />
derleyicinin bir editörü varsa ilk.c bu editör de derlenebilir.<br />
Tablo 1.1: İşletim sistemleri, bazı derleyiciler ve derleme komutları<br />
İşletim Sistemi Derleyici Derleme Çalıştırma<br />
Microsoft C cl ilk.c ilk.exe<br />
Borland Turbo C Web tcc ilk.c ilk.exe<br />
MS-DOS / Borland C bcc ilk.c ilk.exe<br />
Windows Zortec C ztc ilk.c ilk.exe<br />
GCC (GNU Compiler Collection) gcc ilk.c -o<br />
ilk.exe<br />
Windows için Web ilk.exe<br />
GCC (GNU Compiler Collection) gcc ilk.c -o<br />
UNIX / Linux<br />
Web<br />
ilk ilk<br />
./ilk veya nice<br />
Bunların dışında, komut satırını kullanmadan, kodlarınızı Windows ortamında çalışan GCC<br />
tabanlı DevC++ veya Salford Plato3 derleyicileri ile derlemek mümkün. Bu tip derleyicilerde<br />
hata ayıklama işlemini kolaylaştırmak için kodlar farlı renkte gösterilir. Fakat program<br />
çıktıları için kullanılan ekran klasik DOS ekranıdır. Şekil 1.1 ve 1.2"de bu programların ekran<br />
görüntüleri verilmiştir.<br />
Şekil 1.1: DevC++ derleyicine ait editör. Derleme ve çalıştırma işlemleri araç çubuğu<br />
üzerindeki butonlarla yapılır.
Şekil 1.2: Silverfrost Salford (Plato3) derleyicine ait editör. Derleme, bağlama ve çalıştırma<br />
işlemleri araç çubuğu üzerindeki butonlarla yapılır.<br />
<strong>Ders</strong>lerimizde kullanılan kaynak kodları, Turbo C ve GCC derleyicileri ile komutsatırında<br />
derlenmiştir. Turbo C derleyicisi isteğe bağlı editörden veya komut satırından derlenebilir.<br />
Editörü başlatmak için C:\TC> dizini altındaki TC.EXE dosyasının çalıştırılması yeterlidir.<br />
Şekil 1.3'de Turbo C editör ortamı gösterilmiştir.
Şekil 1.3: Turbo C derleyicisine ait editör. Derleme için F9, Derleme bağlama ve çalıştırma<br />
işlemleri için CTRL+F9 tuş kombinasyonu kullanılabilir..<br />
ilk.c nin Borland Turbo C ve GCC Programları ile derlenmesi ve çalıştırılması:<br />
DERLEME ve ÇALIŞTIRMA<br />
MS DOS (Turbo C)<br />
C:\TC> tcc ilk.c<br />
C:\TC> ilk.exe<br />
Linux (GCC)<br />
$ gcc ilk.c -o ilk<br />
$ ./ilk<br />
ilk.c nin çıktısı:<br />
ÇIKTI<br />
Merhaba Dünya!<br />
1.6 C Kodlarının Temel Özellikleri<br />
Bir C programı aşağıda verilen özellikleri mutlaka taşımalıdır.<br />
• Yazılımda kullanılacak olan her fonksiyon için ilgili başlık dosyası programın başına<br />
ileve edilmedlidir.<br />
• Her C programı main() fonksiyonunu içermelidir.<br />
• Program içinde kullanılacak olan değişkenler ve sabitler mutlaka tanımlanmalıdır.<br />
• Satırın sonuna ; işareti konmalıdır.<br />
• Her bloğun ve fonksiyonun başlangıcı ve bitişi sırasıyla { ve } sembolleridir.
• C dilinde yazılan kodlarda küçük-büyük harf ayrımı vardır (case sensitive).<br />
Örneğin A ile a derleyici tarafından farklı değerlendirilir.<br />
• Açıklama operatörü /* */ sembolleridir.<br />
1.7 Kod Yazımı için Bazı Tavsiyeler<br />
• Program açıklamaları ve döküman hazırlama program yazıldıkça yapın! Bu<br />
unutulmaması gereken çok önemli husustur.<br />
• Değişken, sabit ve fonksiyon adları anlamlı kelimelerden seçilip yeterince uzun<br />
olmalıdır. Eğer bu isimler bir kaç kelimeden oluşacak ise, kelimeler alt çizgi ( _ ) ile<br />
ayrılmalıdır veya her kelime büyük harfle başlamalıdır. Örneğin:<br />
•<br />
• int son_alinan_bit;<br />
• void KesmeSayisi();<br />
• float OrtalamaDeger = 12.7786;<br />
• Sabitlerin bütün harflerini büyük harfle yazın. Örneğin:<br />
•<br />
• #define PI 3.14;<br />
• const int STATUS=0x0379;<br />
• Her alt yapıya girerken birkaç boşluk veya TAB tuşunu kullanın. Bu okunabilirliği<br />
arttıracaktır. Örneğin:<br />
•<br />
• k = 0;<br />
• for(i=0; i
• <strong>Giriş</strong><br />
• 2.1 Veri Tipleri<br />
• 2.2 Değişkenler<br />
• 2.3 Sabitler<br />
• 2.4 Rakamsal Bilgiler<br />
• 2.5 Değişken Bildirim Yerleri ve Türleri<br />
• 2.6 Tip Dönüşümleri<br />
<strong>Giriş</strong><br />
Orta ve yüksek seviyeli dillerin hemen hemen hepsinde veri tipi ve değişken kavramı<br />
bulunmaktadır. Bu kısımda C programlama dilindeki temel veri tipleri, tanımlayıcılar,<br />
değişkenler ve sabitler konu edilecektir.<br />
2.1 Veri Tipleri<br />
Veri tipi (data type) program içinde kullanılacak değişken, sabit, fonksiyon isimleri gibi<br />
tanımlayıcıların tipini, yani bellekte ayrılacak bölgenin büyüklüğünü, belirlemek için<br />
kullanılır. Bir programcı, bir programlama dilinde ilk olarak öğrenmesi gereken, o dile ait veri<br />
tipleridir. Çünkü bu, programcının kullanacağı değişkenlerin ve sabitlerin sınırlarını belirler.<br />
C programlama dilinde dört tane temel veri tipi bulunmaktadır. Bunlar:<br />
char<br />
int<br />
float<br />
double<br />
Fakat bazı özel niteleyiciler vardır ki bunlar yukarıdaki temel tiplerin önüne gelerek onların<br />
türevlerini oluşturur. Bunlar:<br />
short<br />
long<br />
unsigned<br />
Bu niteleyiciler sayesinde değişkenin bellekte kaplayacağı alan isteğe göre değiştirilebilir.<br />
Kısa (short), uzun (long), ve normal (int) tamsayı arasında yalnızca uzunluk farkı vardır.<br />
Eğer normal tamsayı 32 bit (4 bayt) ise uzun tamsayı 64 bit (8 bayt) uzunluğunda ve kısa<br />
tamsayı 16 biti (2 bayt) geçmeyecek uzunluktadır. İşaretsiz (unsigned) ön eki kullanıldığı<br />
taktirde, veri tipi ile saklanacak değerin sıfır ve sıfırdan büyük olması sağlanır. İşaretli ve<br />
işaretsiz verilerin bellekteki uzunlukları aynıdır. Fakat, işaretsiz tipindeki verilerin üst limiti,<br />
işaretlinin iki katıdır.<br />
NOT<br />
Kısa ve uzun tamsayı tutacak tanımlayıcılar için int<br />
anahtar kelimesinin yazılmasına gerek yoktur.<br />
short s; /* short int s; anlamında */<br />
long k; /* long int k; anlamında */
Bir C programı içerisinde, veri tiplerinin bellekte kapladığı alan sizeof operatörü ile<br />
öğrenilebilir. İlgi cekici olan, bu alanların derleyiciye ve işletim sistemine bağlı olarak<br />
değişiklik göstermesidir. Program 2.1'de, sizeof operatörü kullanılarak, veri tiplerinin bellek<br />
uzunlularının nasıl ekrana yazdırılacağı gösterilmiştir. Programın çıktısı, farklı derleyiciler ve<br />
işletim sisteminde denendiğinde bu durum daha iyi anlaşılır. Lütfen inceleyin.<br />
Program 2.1: Değişken tipleri ve türevlerinin bellekte kapladıkları alanlar<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
ÇIKTI<br />
/* 02prg01.c : sizeof operatörünün kullanımı */<br />
#include <br />
main()<br />
{<br />
printf( "char<br />
sizeof(char));<br />
printf( "short<br />
sizeof(short));<br />
printf( "int<br />
sizeof(int));<br />
printf( "long<br />
sizeof(long));<br />
: %d bayt\n",<br />
: %d bayt\n",<br />
: %d bayt\n",<br />
: %d bayt\n",<br />
printf( "unsigned char : %d bayt\n",<br />
sizeof(unsigned char));<br />
printf( "unsigned short : %d bayt\n",<br />
sizeof(unsigned short));<br />
printf( "unsigned int<br />
sizeof(unsigned int));<br />
printf( "unsigned long<br />
sizeof(unsigned long));<br />
printf( "float<br />
sizeof(float));<br />
printf( "double<br />
sizeof(double));<br />
printf( "long double<br />
sizeof(long double));<br />
}<br />
: %d bayt\n",<br />
: %d bayt\n",<br />
: %d bayt\n",<br />
: %d bayt\n",<br />
: %d bayt\n",<br />
Windows (32 bit) Turbo C Windows (32 bit) Salford<br />
Linux (32 bit) GCC<br />
Linux (64<br />
bit) GCC
char : 1<br />
bayt<br />
short : 2<br />
bayt<br />
int : 2<br />
bayt<br />
long : 4<br />
bayt<br />
unsigned char : 1<br />
bayt<br />
unsigned short : 2<br />
bayt<br />
unsigned int : 2<br />
bayt<br />
unsigned long : 4<br />
bayt<br />
float : 4<br />
bayt<br />
double : 8<br />
bayt<br />
long double : 10<br />
bayt<br />
char : 1<br />
bayt<br />
short : 2<br />
bayt<br />
int : 4<br />
bayt<br />
long : 4<br />
bayt<br />
unsigned char : 1<br />
bayt<br />
unsigned short : 2<br />
bayt<br />
unsigned int : 4<br />
bayt<br />
unsigned long : 4<br />
bayt<br />
float : 4<br />
bayt<br />
double : 8<br />
bayt<br />
long double : 10<br />
bayt<br />
char : 1<br />
bayt<br />
short : 2<br />
bayt<br />
int : 4<br />
bayt<br />
long : 4<br />
bayt<br />
unsigned char : 1<br />
bayt<br />
unsigned short : 2<br />
bayt<br />
unsigned int : 4<br />
bayt<br />
unsigned long : 4<br />
bayt<br />
float : 4<br />
bayt<br />
double : 8<br />
bayt<br />
long double : 12<br />
bayt<br />
char<br />
: 1 bayt<br />
short<br />
: 2 bayt<br />
int<br />
: 4 bayt<br />
long<br />
: 8 bayt<br />
unsigned<br />
char :<br />
1 bayt<br />
unsigned<br />
short :<br />
2 bayt<br />
unsigned<br />
int :<br />
4 bayt<br />
unsigned<br />
long :<br />
8 bayt<br />
float<br />
: 4 bayt<br />
double<br />
: 8 bayt<br />
long<br />
double<br />
: 16<br />
bayt<br />
int veritipi ve türevleri ile hesaplanabilecek en küçük ve en büyük tamsayılar için aşağıdaki<br />
formül kullanılabilir:<br />
Alt sınır = -2 8*sizeof(tip)<br />
Üst sınır = 2 8*sizeof(tip) -1<br />
Örneğin 4 baytlık bir int tipi için:<br />
Alt sınır = -2 8*sizeof(int) = -2 32 = -2147483648<br />
Üst sınır = 2 8*sizeof(int) -1 = 2 32 -1 = 2147483647<br />
Tablo 2.1'de bütün tipler, bellekte kapladıkları alanlar ve hesaplanabilcek (bellekte doğru<br />
olarak saklanabilecek) en büyük ve en küçük sayılar listelenmiştir.<br />
Tablo 2.1: Değişken tipleri ve bellekte kapladıkları alanlar<br />
Veri Tipi Açıklama<br />
Bellekte<br />
işgal ettiği<br />
Alt sınır<br />
boyut<br />
Üst sınır<br />
(bayt)<br />
char Tek bir -128 127<br />
karakter veya<br />
unsigned<br />
1<br />
küçük<br />
char<br />
tamsayı için<br />
0 255<br />
short int Kısa tamsayı<br />
-32,768 32,767<br />
unsigned<br />
2<br />
için<br />
short int<br />
0 65,535
-2,147,483,648 2,147,483,647<br />
int<br />
Tamsayı için 4<br />
0 4,294,967,295<br />
int<br />
unsigned<br />
-<br />
long int Uzun<br />
tamsayı için 8 9,223,372,036,854,775,808 9,223,372,036,854,775,807<br />
unsigned<br />
long int<br />
0 18,446,744,073,709,551,615<br />
Tek duyarlı<br />
gerçel sayı<br />
float<br />
4<br />
için (7<br />
-3.4e +/- 38 +3.4e +/- 38<br />
basamak)<br />
Çift duyarlı<br />
gerçel sayı<br />
double<br />
8<br />
için (15<br />
-1.7e +/- 308 +1.7e +/- 308<br />
basamak)<br />
2.2 Değişkenler<br />
Değişkenler bilgisayarın geçici belleğinde bilginin saklandığı gözlere verilen sembolik<br />
adlardır. Bir C programında, bir değişken tanımlandığında bu değişken için bellekte bir yer<br />
ayrılır. Her değişkenin tuttuğu değerin nasıl bir veri olduğunu gösteren (önceki bölümde<br />
anlatılan) bir veri tipi vardır [1], [3].<br />
C programlama dilinde, değişkenler ve sabitler programın başında bulunmalıdır. Bazı<br />
uygulamalarda değişkenin bir başlangıç değerinin olması istenir. Böyle durumlarda değişken<br />
bildirilirken başlangıç değeri verilebilir. Örneğin:<br />
char isim='X', z; /* değer atamak zorunlu değil */<br />
int sayi=0, n;<br />
float toplam=0.0, sonuc=22.14;<br />
Değişken isimleri verirken bazı kurallara uymak zorunludur. Bunlar:<br />
• Değişken adları en fazla 32 karakterden oluşabilir. 32 karakterden uzun değişken<br />
adları ilk 32 karakteri değerlendirilir. Geriye kalan karakterler işleme tabi tutulmaz.<br />
• Değişken adları ingiliz alfabesinde bulunan karakterler (A-Z) veya (a-z) yada rakamlar<br />
(0-9) ile yazılmalıdır. Türkçe karakterler, özel karakter veya boşluk karakteri<br />
kullanılamaz.<br />
• Değişken adları herhangi bir rakam ile başlayamaz. Ilk karakter bir harf olamalıdır.<br />
Sonrakiler rakamlardan oluşabilir.<br />
• Aşağıda verilen kelimeler ANSI C 'nin anahtar kelimeleridir (key words) ve değişken<br />
ismi olarak kullanılamaz.<br />
•<br />
• auto double int struct<br />
• break else long switch<br />
• case enum register typedef<br />
• char extern return union
• const float short unsigned<br />
• continue for signed void<br />
• default goto sizeof volatile<br />
• do if static while<br />
Bu kurallara göre aşağadaki değişken (sabit, fonksiyon) adlarının geçerliliğini inceleyiniz.<br />
Değişken/Sabit/Fonksiyon/Yapı Adı Geçerlilik Açıklama<br />
asal geçerli -<br />
Momentum geçerli -<br />
ivme geçerli -<br />
olasilik geçerli -<br />
IsikHizi geçerli -<br />
isik_hizi geçerli Alt çizgi karakteri '_' kullanılabilir<br />
isik hizi geçersiz Boşluk karakteri kullanılamaz<br />
ışık_hızı geçersiz Türkçe karakter kullanılamaz<br />
1Bit geçersiz rakam ile başlanamaz<br />
typedef geçersiz Anahtar kelimelerden birisi kullanılamaz<br />
2.3 Sabitler<br />
Sabit bildirimi, başlangıç değeri verilen değişken bildirimi gibi yapılır. Ancak, veri tipinin<br />
önüne const anahtar sözcüğü konmalıdır. Örneğin:<br />
const float PI = 3.142857;<br />
const double NOT= 12345.8596235489;<br />
const int EOF= -1;<br />
const char[] = "devam etmek için bir tuşa basın...";<br />
gibi sabit bildirimleri geçerli olup bunların içerikleri program boyunca değiştirilemez.<br />
Yalnızca kullanılabilir. Genellikle, sabit olarak bildirilen değişken isimleri büyük harflerle,<br />
diğer değişken isimlerinin ise küçük harflerle yazılması (gösterilmesi) C programcıları<br />
tarafından geleneksel hale gelmiştir.<br />
Birçok C programında sabitler #define önişlemci komutu ile de tanımlandığını görebilirsiniz.<br />
Bu komutla sabit bildirimi, bir program parçasına ve makro fonksiyon tanımlaması<br />
yapılabilir. Bir program geliştirilirken simgesel sabitlerin kullanılması programın<br />
okunurluğunu arttırır ve bazen gerekli de olabilir. Aşağıda verilen simgesel sabit bildirimleri<br />
geçerlidir.<br />
#define MAX 100<br />
#define DATA 0x0378<br />
#define YARICAP 14.22
2.4 Rakamsal Bilgiler<br />
C programlama dili içinde tanımlanabilecek sabit rakamlar rakamsal bilgi (literal) olarak<br />
adlandırılır. Her veri tipi kendi rakamsal bilgisine sahiptir. Bu bilgiler, kaynak kod içerisinde,<br />
özel değerleri ifade eder. Örneğin aşağıdaki atama işleminde 25 ve 17.2 sayıları gibi:<br />
i = 25; /* 25, int tipinde bir rakamsal bilgidir */<br />
r = 17.2; /* 17.2, double tipinde bir rakamsal bilgidir */<br />
C dilinde bütün tamsayı sabitler varsayılan (default) olarak int tipinde, gerçel sayı sabitler<br />
varsayılan olarak double tipindedir. Ancak sabitleri gösteren rakamların sonuna eklenecek U<br />
(veya u), L (veya l) ve F (veya f) harfleri ile bu durum değiştirilebilir. Bu yüzden, aşağıdaki<br />
atamalar aynı anlamda değildir.<br />
i = 25; /* int rakam */<br />
i = 25U; /* unsigned int rakam */<br />
i = 25L; /* long int rakam */<br />
i = 25UL; /* unsigned long rakam */<br />
i = 25L; /* long int rakam */<br />
r = 17.2; /* double rakam */<br />
r = 17.2L; /* long double rakam */<br />
r = 17.2F; /* float rakam */<br />
Tamsayı (int) rakamsal bilgiler, 8 (oktal) ve 16 (hexadesimal) sayı tabanında da<br />
gösterilebilir. Bunun için sabit rakamın başına, 8 tabanı için 0 (sıfır) ve 16 tabanını için 0x<br />
sembolleri eklenir. 16'lık sistemdeki hafler büyük (A, B, C, D, E ve F) veya küçük (a, b, c ,d,<br />
e ve f) olabilir. Buna gösterime göre, aşağıdaki atmalar aynı anlamadadır:<br />
i = 75; /* i = 75, 10 tabanında */<br />
i = 0113; /* i = 75, 8 tabanında */<br />
i = 0x4b; /* i = 75, 16 tabanında */<br />
i = 0x4B; /* i = 75, 16 tabanında */<br />
Gerçel sayılar ondalıklı veya üstel olmak üzere iki biçimde gösterilebilir. Örneğin 123.456<br />
sayısının aynı anlama gelen dört farklı gösterimi aşağıda verilmiştir. Üstel gösterimde,<br />
1.23456e+2 veya 1.23456E+2 sayısı matematikteki 1.23456 x 10 2 gösterimi ile eşdeğerdir.<br />
x = 123.456; /* ondalıklı gösterimi */<br />
x = 123.456e+0; /* üstel gösterim */<br />
x = 1.23456e+2; /* üstel gösterim */<br />
x = 1234.56E-1; /* üstel gösterim */<br />
Karakter sabitler, bir harf için tek tırnak, birden çok karakter için çift tırnak içinde belirtilirler.<br />
'A' /* bir karakter */<br />
"Merhaba Dunya" /* bir karakter kümesi */<br />
Program 2.1'de, program içinde tanımlanan değişken sabitlerin ekrana nasıl yazdırılacağı<br />
gösterilmiştir.<br />
Program 2.2: Değişkenlerin ve sabitlerin ekrana yazdırılması<br />
01: /* 02prg02.c : Değişkenler ve sabitlerin ekrana
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
ÇIKTI<br />
yazdırılması */<br />
#include <br />
#define PI 3.141593<br />
int main()<br />
{<br />
const int MAX = 100;<br />
char c = 'a';<br />
char *s = "Bu bir sicim";<br />
int i = 22;<br />
float f = 33.3;<br />
double d = 44.4;<br />
printf("PI = %lf\n",PI);<br />
printf("MAX= %d\n", MAX);<br />
printf("c = %c\n", c);<br />
printf("s = %s\n", s);<br />
printf("i = %d\n", i);<br />
printf("f = %f\n", f);<br />
printf("d = %lf\n",d);<br />
return 0;<br />
}<br />
PI = 3.141593<br />
MAX= 100<br />
c = a<br />
s = Bu bir sicim<br />
i = 22<br />
f = 33.299999<br />
d = 44.400000<br />
2.5 Değişken Bildirim Yerleri ve Türleri<br />
Yerel (local) Bildirim<br />
Yerel değişkenler kullanıldığı fonksiyon içerisinde bildirilir. Yalnızca bildirildiği fonksiyon<br />
içerisinde tanınır ve kullanılabilir.<br />
int topla(int a,int b)<br />
{<br />
/* yerel (local) değişken c nin bildirimi */<br />
int c;<br />
c = a + b;<br />
return c;<br />
}<br />
Genel (general) Bildirim
Genel değişkenler bütün fonksiyonların dışında bildirilir. Bir değişken program boyunca<br />
sürekli olarak kullanılıyorsa genel olarak bildirilmelidir.<br />
#include <br />
void karesi();<br />
/* m ve n global tip değişkendir.<br />
Bu iki değişken tüm program boyunca kullanılmaktadır. */<br />
int m,n;<br />
main()<br />
{<br />
m=7;<br />
karesi();<br />
printf("%d nin karesi %d dir",m,n);<br />
}<br />
void karesi(){<br />
n = m*m;<br />
}<br />
2.6 Tip Dönüşümleri<br />
Bir formül içerisinde bir çok değişken veya sabit olabilir. Bu değişken ve sabitler birbirinden<br />
farklı tipte olursa, hesap sonucunun hangi tipte olacağı önemlidir. Bir bağıntıda, içeriği<br />
dönüşüme uğrayan değişkenler eski içeriklerini korurlar. Dönüştürme işlemi için geçiçi bellek<br />
alanı kullanılır; dönüştürülen değer kullanıldıktan sonra o alan serbest bırakılır.<br />
char kr;<br />
int tam;<br />
long int ltam;<br />
unsigned int utam;<br />
short int stam;<br />
float f;<br />
double d;<br />
bildirimlerine göre:<br />
Bağıntı Sonuç Tipi<br />
------- ----------<br />
kr+5 int<br />
kr+5.0 double<br />
d+tam double<br />
f+d-2 double<br />
utam-tam unsigned<br />
ltam*tam long<br />
tam/2 int<br />
tam/2.0 double<br />
NOT<br />
Tamsayılar arası bölme kesme hatalarına (truncation error)<br />
neden<br />
olur.<br />
Bunun anlamı iki tamsayının oranı yine bir tamsayıdır.
örneğin: 4/2=2; ama 3/2=1 (1.5 değil).<br />
Bir değişkenin sabit değerin veya bağıntının önüne tür veya takı (cast) yazılarak sonucun<br />
hangi tip çıkması istendiği söylenebilir. Genel yazım biçimi:<br />
(tür tipi) bağıntı;<br />
Örneğin:<br />
int x=9;<br />
float a,b,c;<br />
double d;<br />
...<br />
a = x/4;<br />
b = x/4.0;<br />
c = (float) x/4;<br />
işleminin sonucunda a değişkenine 2.0, b ve c değişkenlerine 2.25 değeri aktarılır. Yani 9/4<br />
ile 9/4.0 farklı anlamdadır.<br />
<strong>Ders</strong> 3: Operatörler<br />
• <strong>Giriş</strong><br />
• 3.1 Aritmetik Operatörler<br />
• 3.2 Atama Operatörleri<br />
• 3.3 sizeof Operatörü<br />
<strong>Giriş</strong><br />
Operatörler, değişkenler veya sabitler üzerinde matematiksel ve karşılaştırma işlemlerini<br />
yapan simgelerdir. Yani bir operatör bir veya daha fazla nesne (değişken) üzerinde işlem<br />
yapan sembollerdir. Bu kısımdam aritmetik operatörler, atama operatörleri ve sizeof<br />
operatörü anlatıcaktır. Karşılaştırma Operatörleri, Mantıksal Operatörler ve Bit Düzeyinde<br />
işlem yapan operatörler daha sonraki bölümlerde incelenektir.<br />
3.1 Aritmetik Operatörler<br />
Değişken veya sabitler üzerinde temel aritmetik işlemleri gerçekleyen operatörlerdir. Bunlar<br />
Tablo 3.1'de listelenmiştir.<br />
Tablo 3.1: Aritmetik Operatörler<br />
Operatör Açıklama Örnek Anlamı<br />
+ toplama x + y x ve y nin toplamı<br />
- çıkarma x - y x ve y nin farkı<br />
* carpma x * y x ve y nin çarpımı<br />
/ bölme x / y x ve y nin oranı
% artık bölme x % y x / y den kalan sayı<br />
3.2 Atama Operatörleri<br />
Bu operatörler bir değişkene, bir sabit vaya bir aritmetik ifade atamak (eşitlemek) için<br />
kullanılır.<br />
Birleşik atama: bazı ifadelerde işlem operatörü ile atama operatörü birlikte kullanılarak,<br />
ifadeler daha kısa yazılabilir. Eğer ifade<br />
değişken = değişken [operatör] aritmetik ifade;<br />
şeklinde ise, daha kısa bir biçimde<br />
değişken [operatör]= aritmetik ifade;<br />
olarak yazılabilir. Bu operatörler Tablo 3.2'de listelenmiştir.<br />
Tablo 3.2: Atama Operatörleri<br />
Operatör Açıklama Örnek Anlamı<br />
= atama x = 7; x = 7;<br />
+= ekleyerek atama x += 3 x = x + 3<br />
-= eksilterek atama x -= 5 x = x - 5<br />
*= çarparak atama x *= 4 x = x * 4<br />
/= bölerek atama x /= 2 x = x / 2<br />
%= bölüp, kalanını atama x %= 9 x = x % 9<br />
++ bir arttırma x++ veya ++x x = x + 1<br />
-- bir azaltma x-- veya --x x = x - 1<br />
Bu tanımlamalara göre, aşağıdaki atamaları inceleyiniz:<br />
/* bir arttırma işlemleri */<br />
i++;<br />
++i;<br />
i += 1;<br />
i = i + 1;<br />
/* karmaşık atamalar */<br />
f *= i; // f = f * i; anlamında<br />
f *= i+1; // f = f * (i+1); anlamında<br />
z /= 1 + x; // z = z / (1+x); anlamında<br />
Bir arttırma veya eksiltme operatörlerini kullanırken dikkatli olunmalıdır. Çünkü aşağıdaki<br />
türden atamalar bazen karışıklığa neden olur.<br />
a = 5; // a = 5<br />
b = a++; // a = 6 ve b = 5<br />
c = ++a; // a = 7 ve c = 7
Program 3.1: Aritmetik ve atama operatörlerinin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
ÇIKTI<br />
/* 03prg01.c: Aritmetik ve atama operatorlerinin<br />
kullanimi */<br />
#include <br />
main()<br />
{<br />
int x, y; /* yerel degikenlerin bildirimi<br />
*/<br />
x = 1; /* x in baslangic degeri */<br />
y = 3; /* y nin baslangic degeri */<br />
printf(" x = %d ve y = %d, olarak<br />
veriliyor.\n", x, y);<br />
x = x + y;<br />
printf("x
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
ÇIKTI<br />
int i; /* bir tamsayı */<br />
int dizi[5]; /* 5 elemanlı bir<br />
tamsayı dizi */<br />
double d; /* bir gercel sayı */<br />
double mizan[6]; /* 6 elemanlı bir<br />
gercel dizi */<br />
char c; /* tek bir karakter */<br />
char str[] = "masa"; /* bir karakter<br />
topluluğu */<br />
printf("sizeof(int) = %d\n",sizeof(int));<br />
printf("sizeof(i) = %d\n",sizeof(i));<br />
printf("sizeof(dizi) =<br />
%d\n\n",sizeof(dizi));<br />
printf("sizeof(double)=<br />
%d\n",sizeof(double));<br />
printf("sizeof(d) = %d\n",sizeof(d));<br />
printf("sizeof(mizan) =<br />
%d\n\n",sizeof(mizan));<br />
printf("sizeof(char) = %d\n",sizeof(char));<br />
printf("sizeof(c) = %d\n",sizeof(c));<br />
printf("sizeof(str) = %d\n",sizeof(str));<br />
return 0;<br />
}<br />
sizeof(int) = 4<br />
sizeof(i) = 4<br />
sizeof(dizi) = 20<br />
sizeof(double)= 8<br />
sizeof(d) = 8<br />
sizeof(mizan) = 48<br />
sizeof(char) = 1<br />
sizeof(c) = 1<br />
sizeof(str) = 5<br />
Programda sizeof(int) değeri ile sizeof(i) değerinin aynı olduğu görülür. dizinin<br />
boyutu 5 olduğu için, sizeof(dizi) = sizeof(int)*5 = 20 şeklinde hesaplanmaktadır.<br />
Diğerleri için benzer durum söz konusu. Ancak, str 4 elemanlı bir dizi olduğu halde<br />
sizeof(str) = 5 dir. Neden? Bunu ilerideki bölümlerde öğreneceğiz.<br />
<strong>Ders</strong> 4: Temel <strong>Giriş</strong>/Çıkış Fonksiyonları<br />
• <strong>Giriş</strong><br />
• 4.1 printf() Fonksiyonu
• 4.2 scanf() Fonksiyonu<br />
• 4.3 puts() Fonksiyonu<br />
• 4.4 gets() Fonksiyonu<br />
• 4.5 getchar() Fonksiyonu<br />
• 4.6 Formatlı Çıktı<br />
<strong>Giriş</strong><br />
Temel giriş/çıkış fonksiyonları, bütün programla dillerinde mevcuttur. Bu tür fonksiyonlar,<br />
kullanıcıya ekrana veya yazıcıya bilgi yazdırmasına, ve bilgisayara klavyeden veri girişi<br />
yapmasına izin verir. Temel giriş/çıkış fonksiyonları kullanılırken stdio.h başlık dosyası<br />
programın başına eklenmelidir. Bu kısımda, en çok kullanılan giriş/çıkış fonksiyonları<br />
anlatılacaktır.<br />
4.1 printf() Fonksiyonu<br />
Standart C kütüphanesinde bulunan printf() fonksiyonu, değişkenlerin tuttuğu değerleri,<br />
onların adreslerini veya bir mesajı ekrana belli bir düzenle (format) standart çıkışa (stdout),<br />
yani ekrana, yazdırmak için kullanılan fonksiyondur. Daha önce yazılan örnek programlarda<br />
printf() fonksiyonundan yararlanmıştık. Şimdi bu fonksiyonun nasıl kullanıldığına bakalım.<br />
Genel yazım biçimi:<br />
int printf(const char *format, ...);<br />
Basit olarak ekrana Hata oluştu!.. şeklinde bir mesaj yazırma işlemi:<br />
printf("Hata Oluştu!..");<br />
şeklindedir. Çoğu zaman ekrana, programda kullanılan bir değişkenin değeri yazdırılmak<br />
istenebilir. Örneğin ekrana bir tamsayı değişkeninin içeriğini basırımak için, printf()<br />
....<br />
int x = 12;<br />
printf("x in değeri %d dir", x);<br />
....<br />
gibi kullanılır. Bu program parçasının ekran çıktısı şöyle olacaktır:<br />
x in değeri 12 dir<br />
Bu örnekte printf fonksiyonuna iki parametre aktarılmıştır. Birincisi ekranda gösterilecek ve<br />
çift tırnaklar arasına yazılan ifadeler, ikincisi ise ekranda sayısal değeri gösterilmek istenen<br />
değişken (x).<br />
*format üç kısımdan oluşmaktadır:<br />
I. Düz metin (literal string): yazdırılmak istenen ileti.
II.<br />
Örneğin: printf("Ben gelmedim kavga için..."); gibi.<br />
Konrol karakterleri (escape squence): değişkenlerin ve sabitlerin nasıl yazılacağını<br />
belirtmek veya imlecin alt satıra geçirilmesi gibi bazı işlemlerin gerçekleştirilmesi için<br />
kullanılır. Bu karakterler Tablo 4.1'de listelenmiştir.<br />
Örneğin: printf("\tDostun evi gönlüdür...\n"); gibi.<br />
Tablo 4.1: Kontrol karakterleri<br />
Karakter Anlamı<br />
\a Ses üretir (alert)<br />
\b imleci bir sola kaydır (backspace)<br />
\f Sayfa atla. Bir sonraki sayfanın başına geç (formfeed)<br />
\n Bir alt satıra geç (newline)<br />
\r Satır başı yap (carriage return)<br />
\t Yatay TAB (horizontal TAB)<br />
\v Dikey TAB (vertical TAB)<br />
\" Çift tırnak karakterini ekrana yaz<br />
\' Tek tırnak karakterini ekrana yaz<br />
\\ \ karakterini ekrana yaz<br />
%% % karakterini ekrana yaz<br />
III.<br />
Tip belirleyici (conversion specifier): % işareti ile başlar ve bir veya iki karakterden<br />
oluşur (%d gibi). Ekrana yazdırılmak istenen değişkenin tipi, % işaretinden sonra<br />
belirtilir (Bkz. Tablo 4.2) Örneğin: printf("x in değeri %d dir"); gibi.<br />
Tablo 4.2: Tip karakterleri<br />
Tip Karakteri Anlamı Yazdırılacak veri tipi<br />
%c tek bir karakter char<br />
%s karakter dizisi (string) char<br />
%d işaretli ondalık tamsayı int, short<br />
%ld uzun işaretli ondalık tamsayı long<br />
%u işaretsiz ondalık tamsayı unsigned int, unsigned short<br />
%lu işaretsiz uzun tamsayı unsigned long<br />
%f Gerçel sayı float<br />
%lf Çift duayarlı gerçel sayı double<br />
Tip karakterlerini kullanarak, birden çok veri tipi yazdırılabilir. Örneğin:<br />
...<br />
int not= 12;<br />
float pi = 3.14;<br />
char kr = 'A';<br />
gibi.<br />
printf(" not = %d , pi = %f ve kr = %c dir", not, pi, kr);<br />
...<br />
printf() fonksiyonu esnektir. Parametreler herhangi bir C deyimi olabilir. Örneğin x ve y
nin toplamı şöyle yazılabilir:<br />
printf("%d", x+y);<br />
printf fonksiyonu kullanımı Program 4.1'de verilmiştir.<br />
Program 4.1: printf() fonksiyonunun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
/* 04prg01.c<br />
Sayısal değerleri ekrana yazdırmak için<br />
printf fonksiyonunun kullanımı */<br />
#include <br />
main()<br />
{<br />
int a = 2, b = 10, c = 50;<br />
float f = 1.05, g = 25.5, h = -0.1, yuzde;<br />
printf("3 tamsayi : %d %d %d\n", a, b,<br />
c);<br />
printf("3 tamsayi [TAB] : %d \t%d \t%d\n",<br />
a, b, c);<br />
printf("\n");<br />
printf("3 reel sayi (yanyana) : %f %f %f\n",<br />
f, g, h);<br />
printf("3 reel sayi (altalta) :<br />
\n%f\n%f\n%f\n\n", f, g, h);<br />
yuzde = 220 * 25/100.0;<br />
printf("220 nin %%25 i %f dir\n", yuzde);<br />
printf("%f/%f isleminin sonucu = %f\n", g,<br />
f, g / f);<br />
printf("\nprogram sonunda beep sesi<br />
cikar...\a");<br />
}<br />
return 0;<br />
ÇIKTI<br />
3 tamsayi : 2 10 50<br />
3 tamsayi [TAB] : 2 10 50<br />
3 reel sayi (yanyana) : 1.050000 25.500000 -0.100000<br />
3 reel sayi (altalta) :<br />
1.050000<br />
25.500000<br />
-0.100000<br />
220 nin %25 i 55.000000 dir<br />
25.500000/1.050000 isleminin sonucu = 24.285715<br />
program sonunda beep sesi cikar...
printf fonksiyonunun geri dönüş değeri int tipindedir. Bu geri dönüş değeri çıktının kaç<br />
karakter olduğunu gösterir. Yani, printf fonksiyonu, *format ile tanımlanmış karakter<br />
topluluğunun kaç bayt olduğu hesaplar[6]. Program 4.2, printf'in bu yönünüde ortaya<br />
çıkaran bir programdır.<br />
Program 4.2: printf() fonksiyonunun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
/* 04prg02.c<br />
printf fonksiyonunun geri dönüş değerini<br />
gösterir */<br />
#include <br />
int main()<br />
{<br />
int karSay;<br />
int sayi = 1234;<br />
karSay = printf("Ugurlu sayim = %d\n",sayi);<br />
printf("Ust satirda karakter sayisi: %d<br />
dir\n", karSay);<br />
}<br />
ÇIKTI<br />
return 0;<br />
Ugurlu sayim = 1234<br />
Ust satirda karakter sayisi: 20 dir<br />
11. satırdaki işlemle, hem ekrana Ugurlu sayim = 1234 iletisi bastırılmakta, hem de karSay<br />
değişkenine bu iletinin uzunluğu atanmaktadır. Ekrana basılan karakterlerin sayısı (\n<br />
karakteri dahil) 20 dir.<br />
4.2 scanf() Fonksiyonu<br />
Birçok programda ekrana verilerin bastırılmasının yanısıra klavyeden veri okunması<br />
gerekebilir. scanf() fonksiyonu klavyeden veri okumak için kullanılan fonksiyondur.<br />
printf() gibi scanf() fonksiyonuda Tablo 4.1 ve Tablo 4.2'de verilen karakterleri kullanır.<br />
Örneğin klaveden bir x tamsayısı okumak için:<br />
scanf("%d",&x);<br />
satırını yazmak yeterli olacaktır. Burada & işareti adres operatörü olarak adlandırılır ve Böüm<br />
11'de ayıntılı olarak açıklanacaktır. Klavyeden iki farklı sayı okunmak istendiğnde scanf()<br />
fonksiyonu şöyle kullanılabilir:<br />
scanf("%d %f",&x,&y);
veriler klavyeden<br />
16 1.56<br />
yada<br />
16 1.56<br />
veya<br />
16<br />
1.56<br />
şekilinde girilebilir. Program 4.3'de scanf() fonsiyonunun kullanımı gösterilmiştir.<br />
Program 4.3: scanf() fonksiyonun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
ÇIKTI<br />
/* 04prg03.c<br />
scanf() fonksiyonu ile int ve float<br />
tipindeki verilerin okunması */<br />
#include <br />
main()<br />
{<br />
int t;<br />
float g;<br />
printf("Bir gercel sayi girin: ");<br />
scanf("%f",&g);<br />
printf("Bir tamsayi girin : ");<br />
scanf("%d",&t);<br />
printf("\n");<br />
printf("\t %f * %f = %f\n",g,g,g*g);<br />
printf("\t %d * %d = %d\n",t,t,t*t);<br />
return 0;<br />
}<br />
Bir gercel sayi girin: 1.34<br />
Bir tamsayi girin : 12<br />
1.340000 * 1.340000 = 1.795600<br />
12 * 12 = 144<br />
4.3 puts() Fonksiyonu<br />
Ekrana yazdırılacak ifade bir karakter topluluğu ise, printf()'e alternatif olarak puts()<br />
fonksiyonu kullanılabilir. Ancak puts(), ekrana bu karakter topluluğu yazdıktan sonra,<br />
imleci alt satıra geçirir. Buna göre:<br />
printf("Sevgi varlığın mayasıdır.\n");<br />
ile<br />
puts("Sevgi varlığın mayasıdır.");<br />
kullanımları eşdeğerdir.
puts() fonksiyonu Tablo 4.1 de verilen kontrol karakterleri ile kullanılabilir.<br />
puts("Bu birinci satır...\nBu ikinci satır.");<br />
Bu birinci satır...<br />
Bu ikinci satır.<br />
4.4 gets() Fonksiyonu<br />
Klavyeden bir karakter topluluğu okumak için kullanılır. Okuma işlemi yeni satır<br />
karakteriyle(\n) karşılasılıncaya kadar sürer. puts() - gets() arsındaki ilişki, printf() -<br />
scanf() arasındaki gibidir. Yani,<br />
ile<br />
scanf("%s",str);<br />
gets(str);<br />
aynı anlamdadır. puts() - gets() fonksiyonlarının kullanımı daha sonra ayrıntılı<br />
işlenecektir.<br />
4.5 getchar() Fonksiyonu<br />
Bu fonksiyon ile standart girişten bir karakter okunur. Programı istenen bir yerde dudurup, bir<br />
karakater girinceye kadar bekletir. Örneğin:<br />
...<br />
for(i=0; i
Stringlerde %s yerine %ws<br />
biçimindeki kullanım ile sağlanır. Burada w yazılacak olan sayının alan genişliği olarak<br />
adlandırılır. Gerçel bir değişken ekrana yazılacaksa, değişkenin virgülden sonra kaç<br />
basamağının yazdırılacağı k sayısı ile belirlenir. Ancak w > k + 2 olmalıdır.<br />
int i=583,j=1453;<br />
printf("%d %d\n",i,j); /* serbest biçim */<br />
printf("%5d %8d\n",i,j); /* formatlı */<br />
program parçasının ekran çıktısı şöyledir:<br />
ÇIKTI<br />
583 1453<br />
583 1453<br />
Birinci satır serbest formatta ikinci satır ise formatlı yazılmıştır. i değişkeninin tuttuğu 583<br />
sayısı %5d formatıyla yazdırılınca, bu sayı için 5 alan genişliği tanımlanır arakasından sağdan<br />
başlayarak sayı bu alana yazılır. Benzer olarak j değişkeni, 8 alan genişlikli bir bölgeye<br />
yazılır.<br />
Gerçel sayılarda iş biraz daha karışık. Örneğin:<br />
int x=123.456;<br />
printf("%f\n",x); /* serbest biçim */<br />
printf("%8.2f\n",x); /* formatlı */<br />
program parçası çalıştırıldığında aşağıdaki sonuç gözlenir:<br />
ÇIKTI<br />
123.456001<br />
123.46<br />
Birinci satır serbest formatta ikinci satır ise formatlı yazılmıştır. İkinci satırda x değişkeni için<br />
ayrılan alan genişliği 8 ve noktadan sonra 2 basamağa kadar hassasiyet önemsenmiştir. Dikkat<br />
edilirse noktadan sonra sayı uygun bir şekilde yuvarlanmış ve sayı sağa dayalı olarak<br />
yazılmıştır.<br />
Son olarak formatlı çıktı ile ilgili bir örnek Program 4.4'de verilmiştir. İnceleyiniz.<br />
Program 4.4: printf() in formatlı kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
/* 04prg04.c: Formatlı çıktı */<br />
#include <br />
main()<br />
{<br />
float x = 7324.25, y = 244.531;<br />
int i = 1299;<br />
char *c = "Merhaba C";
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
}<br />
printf("%10d\n" ,i);<br />
printf("%10s\n" ,c);<br />
printf("%10.5f\n",x);<br />
printf("%10.1f\n",y);<br />
return 0;<br />
ÇIKTI<br />
1299<br />
Merhaba C<br />
7324.25000<br />
244.5<br />
<strong>Ders</strong> 5: Temel Kütüphane Fonksiyonları<br />
• <strong>Giriş</strong><br />
• 5.1 Matematiksel Fonksiyonlar (math.h)<br />
• 5.2 Standart Kütüphane Fonksiyonları (stdlib.h)<br />
• 5.3 Karakter Üzerinde İşlem Yapan Fonksiyonlar (ctype.h)<br />
<strong>Giriş</strong><br />
Bu kısımda, C Programlama Dili'nde sık kullanılan ve diğer bölümlerde yararlanacağımız<br />
kütüphane fonksiyonlarının bazıları işlenecektir. Kütüphane fonksiyonu C dilinde önceden<br />
tanımlanmış hazır fonksiyonlarıdır. C dilinde birçok iş bu fonksiyonlarla yapılmaktadır.<br />
Her kütüphane fonksiyonu bir başlık dosyasında tanımlanmıştır. Bu yüzden bir kütüphane<br />
fonksiyonunu kullanmadan önce, onun hangi başlık dosyası ile kullanılması gerektiğini<br />
bilmelisiniz.<br />
5.1 Matematiksel Fonksiyonlar (math.h)<br />
Matematiksel fonksiyonların hemen hemen hepsi double veri tipindedir. Bu fonksiyonlardan<br />
biri program içinde kullanılacaksa math.h başlık dosyası program içine eklenmelidir. En çok<br />
kullanılan matematiksel fonksiyonlar Tablo 5.1'de listelenmiştir.<br />
Tablo 5.1: math.h kütüphanesinde tanımlı bazı fonksiyonlar
Fonksiyon Bildirimi Açıklama Örnek Sonuç<br />
int abs(int x); x tamsayısının mutlak değerini hesaplar abs(-4) 4<br />
x gerçel sayısının mutlak değerini<br />
double fabs(double x); fabs(-4.0) 4.000000<br />
hesaplar<br />
double floor(double x'e (x'den büyük) en yakın tamsayıyı<br />
abs(-2.7)<br />
x);<br />
3.000000<br />
gönderir<br />
x'e (x'den küçük) en yakın tamsayıyı<br />
double ceil(double x); abs(5.6)<br />
gönderir<br />
5.000000<br />
double sqrt(double x); pozitif x sayısının karekökünü hesaplar sqrt(4.0) 2.000000<br />
double pow(double x,<br />
double y);<br />
x y pow(2.,<br />
değerini hesaplar<br />
3.)<br />
8.000000<br />
pozitif x sayısının doğal logaritmasını<br />
double log(double x);<br />
log(4.0)<br />
hesaplar, ln(x)<br />
1.386294<br />
double log10(double pozitif x sayısının 10 tabanındaki<br />
log10(4.0)<br />
x);<br />
0.602060<br />
logaritmasını hesaplar<br />
radyan cinsinden girilien x sayısının sinüs<br />
double sin(double x);<br />
sin(3.14) 0.001593<br />
değerini hesaplar<br />
radyan cinsinden girilien x sayısının<br />
-<br />
double cos(double x);<br />
cos(3.14)<br />
kosinüs değerini hesaplar<br />
0.999999<br />
radyan cinsinden girilien x sayısının<br />
-<br />
double tan(double x);<br />
tan(3.14)<br />
tanjant değerini hesaplar<br />
0.001593<br />
sinüs değeri x olan açıyı gönderir. Açı -<br />
double asin(double x); asin(0.5) 0.523599<br />
pi/2 ile pi/2 arasındadır.<br />
cosinüs değeri x olan açıyı gönderir. Açı<br />
double acos(double x); acos(0.5) 1.047198<br />
-pi/2 ile pi/2 arasındadır.<br />
tanjant değeri x olan açıyı gönderir. Açı -<br />
double atan(double x); atan(0.5) 0.463648<br />
pi/2 ile pi/2 arasındadır.<br />
NOT<br />
Bir programda math.h kütüphanesi kullanılacakca, GCC<br />
derleyicisi -lm seçeneği ile birlikte kullanılmalıdır.<br />
Örneğin test.c içinde math.h'i kullanıyorsa derleme:<br />
gcc -lm test.c -o test<br />
şeklinde yapılmalıdır. Aksi halde bir hata mesajı ile<br />
karşılaşılır.<br />
Trigonometrik (sin, cos, tan) fonksiyonlar kendisine parametre olarak gelen değeri radyan<br />
olarak kabul eder ve sonucu hesaplar. Eğer açılar derece cinsinden hesaplanması gerekiyorsa<br />
şu dönüşüm kullanılanılabilir:<br />
radyan = (3.141593/180.0) * derece;<br />
Program 5.1: sin(), cos(), and tan() fonksiyonlarının kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
/* 05prg01.c<br />
30 dercelik açının sinüs, kosinüs, tanjant ve<br />
kotanjant değerleri */<br />
#include
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
ÇIKTI<br />
#include <br />
#define PI 3.141593<br />
int main()<br />
{<br />
double aci = 30.0;<br />
aci *= PI/180.0; /* radyana çevir */<br />
puts("30 derecenin");<br />
printf("sinusu : %lf\n", sin(aci));<br />
printf("kosinusu : %lf\n", cos(aci));<br />
printf("tanjanti : %lf\n", tan(aci));<br />
printf("kotanjanti: %lf\n", 1.0/tan(aci));<br />
return 0;<br />
}<br />
30 derecenin<br />
sinusu : 0.500000<br />
kosinusu : 0.866025<br />
tanjanti : 0.577350<br />
kotanjanti: 1.732051<br />
5.2 Standart Kütüphane Fonksiyonları (stdlib.h)<br />
Standart kütüphanede, programı sonlandıran, dinamik bellek yönetiminde kullanılan veya<br />
rastgele sayı üretme vb. işlevleri yerine getiren bir çok fonksiyon mevcuttur. Bu kısımda,<br />
bunlardan bir kaçı Tablo 5.2'de listelenmiştir.<br />
Tablo 5.2: stdlib.h kütüphanesinde tanımlı bazı fonksiyonlar<br />
Fonksiyon<br />
Bildirimi<br />
int atoi(const<br />
char *s);<br />
long atol(const<br />
char *s);<br />
double atof(const<br />
char *s);<br />
void<br />
durum);<br />
exit(int<br />
int rand(void);<br />
max(a,b)<br />
Açıklama Örnek Sonuç<br />
Bir karakter topluluğunu tamsayıya<br />
atoi("-12345")<br />
çevirir<br />
-12345<br />
Bir karakter topluluğunu uzun<br />
tamsayıya çevirir<br />
Bir karakter topluluğunu gercel<br />
atof("-123.546")<br />
sayıya çevirir<br />
-123.456<br />
Programı sonlandırarak kontrolü<br />
exit(1)<br />
işletim sistemine geri verir.<br />
-<br />
0 ile RAND_MAX arasında rastgele<br />
sayı<br />
üretir.<br />
rand() 50485132<br />
RAND_MAX, stdlib.h içinde<br />
atol("1234567890") 1234567890<br />
tanımlanmış bir sembolik sabittir<br />
stdlib.h'de tanımlanmış iki<br />
sayıdan en büyüğünü bulan makro max(5, 9) 9
min(a,b)<br />
fonksiyon<br />
stdlib.h'de tanımlanmış iki<br />
sayıdan en küçüğünü bulan makro<br />
fonksiyon<br />
min(5, 9) 5<br />
Program 5.2: rand() fonksiyonu kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
ÇIKTI<br />
/* 05prg02.c<br />
0-100 arasında 10 tane rasgele sayı üretir */<br />
#include <br />
#include <br />
int main()<br />
{<br />
int i, ri;<br />
for(i=1; i
isdigit(c) c bir rakam ise 0 dan farklı, değilse 0 gönderir isdigit('4') 2<br />
islower(c) c a-z arasında ise 0 dan farklı, değilse 0 gönderir islower('P') 0<br />
isupper(c) c A-Z arasında ise 0 dan farklı, değilse 0 gönderir islower('P') 4<br />
c sayısı ile verilen ASCII koda sahip karakteri elde<br />
toascii(c)<br />
toascii(65) A<br />
eden makro<br />
tolower(c) c karakterini küçük harfe çevirir tolower('D') d<br />
toupper(c) c karakterini büyük harfe çevirir toupper('b') B<br />
Program 5.3: ctype.h kütüphansinde bulunan bazı makroların kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
ÇIKTI<br />
/* 05prg03.c<br />
ASCII kodları 32-127 arasında olan<br />
karakterler üzerinde<br />
ctype.h kütüphanesinde tanımlı bazı<br />
makroların kullanımı */<br />
#include <br />
#include <br />
int main(void)<br />
{<br />
int i;<br />
char c;<br />
for(i=32; i
55 7 7 1<br />
56 8 8 1<br />
57 9 9 1<br />
58 : : 0<br />
59 ; ; 0<br />
60 < < 0<br />
61 = = 0<br />
62 > > 0<br />
63 ? ? 0<br />
64 @ @ 0<br />
65 A a 0<br />
66 B b 0<br />
67 C c 0<br />
68 D d 0<br />
69 E e 0<br />
70 F f 0<br />
71 G g 0<br />
72 H h 0<br />
73 I i 0<br />
74 J j 0<br />
75 K k 0<br />
76 L l 0<br />
77 M m 0<br />
78 N n 0<br />
79 O o 0<br />
80 P p 0<br />
81 Q q 0<br />
82 R r 0<br />
83 S s 0<br />
84 T t 0<br />
85 U u 0<br />
86 V v 0<br />
87 W w 0<br />
88 X x 0<br />
89 Y y 0<br />
90 Z z 0<br />
91 [ [ 0<br />
92 \ \ 0<br />
93 ] ] 0<br />
94 ^ ^ 0<br />
95 _ _ 0<br />
96 ` ` 0<br />
97 a a 0<br />
98 b b 0<br />
99 c c 0<br />
100 d d 0<br />
101 e e 0<br />
102 f f 0<br />
103 g g 0<br />
104 h h 0<br />
105 i i 0<br />
106 j j 0<br />
107 k k 0<br />
108 l l 0<br />
109 m m 0<br />
110 n n 0<br />
111 o o 0<br />
112 p p 0<br />
113 q q 0<br />
114 r r 0<br />
115 s s 0<br />
116 t t 0<br />
117 u u 0<br />
118 v v 0<br />
119 w w 0<br />
120 x x 0<br />
121 y y 0<br />
122 z z 0<br />
123 { { 0
124 | | 0<br />
125 } } 0<br />
126 ~ ~ 0<br />
<strong>Ders</strong> 6: Karşılaştırma Deyimleri<br />
• <strong>Giriş</strong><br />
• 6.1 Karşılaştırma Operatörleri ve Mantıksal Operatörler<br />
• 6.2 if, if-else Yapısı<br />
• 6.3 switch - case Yapısı<br />
• 6.4 ? Karşılaştırma Operatörü<br />
<strong>Giriş</strong><br />
Program içerisinde bazen iki veya daha fazla değerin karşılaştırılması gerekebilir. Bunun için,<br />
bütün programlama dillerinde karşılaştırma deyimleri mevcuttur. C dili, if, switch ve ?<br />
olmak üzere üç tip karşılaştırma işlemi yapmaya izin verir. Ancak ? bir operatördür. if<br />
karşılaştırma deyimi ile, diğer programlama dilinde olduğu gibi if-else yapısı da kurulabilir.<br />
switch deyimi, bir değişkenin içeriğine göre program akışını yönlendirir.<br />
6.1 Karşılaştırma Operatörleri ve Mantıksal Operatörler<br />
Tablo 6.1'de listelenen Karşılaştırma Operatörleri, sayısal değerleri veya karakterleri<br />
mukayese etmek için kullanılır.<br />
Tablo 6.1: Karşılaştırma Operatörleri<br />
Operatör Açıklama Örnek Anlamı<br />
> büyüktür x > y x, y den büyük mü?<br />
< küçüktür x < y x, y den küçük mü?<br />
== eşittir x == y x, y ye eşit mi?<br />
>= büyük-eşittir x >= y x, y den büyük yada eşit mi?<br />
C dilinde, bir mantıksal işlemin sonucu tamsayı 0 (sıfır) veya başka bir değer olur. 0 olumsuz<br />
0'dan farklı değerler olumlu olarak yorumlanır. Buna göre, aşağıdaki program parçasının<br />
...<br />
int x = 1, y = 2, s, u, z;<br />
s = 2 > 1;<br />
u = x > 3;<br />
z = x 0;<br />
printf("%d\t%d\t%d", s, u, z);<br />
...<br />
çıktısı:<br />
1 0 1<br />
şeklinde olur. Bunun nedeni:<br />
• 2 her zaman 1 den büyük olduğu için s değişkenine 1,<br />
• x = 1 < 3 olduğu için x değişkenine 0,<br />
• z = x 0; eşitliğin sağtarafının sonucu olumlu olduğu için z değişkenine<br />
1 atanır.<br />
6.2 if, if-else Yapısı<br />
Bu deyimler, koşullu işlem yapan deyimlerdir. if ve else tek bir karşılaştırma deyimi olup<br />
else kullanımı isteğe bağlıdır. Eğer bu koşul olumlu ise if den sonraki bölüm yürütülür ve<br />
else den sonraki bölüm atlanır. Koşul olumsuz ise if den sonraki küme atlanır ve eğer varsa,<br />
else den sonraki kümedeki işlemler gerçekleştirilir.<br />
if deyiminin yapının genel biçimi şöyledir:<br />
if(koşul)<br />
{<br />
...<br />
deyimler; (küme)<br />
...<br />
}<br />
if deyimi kullanılırken kümenin başlangıcı ve bitişini gösteren, küme parantezleri<br />
kullanılmasında kullanıcıya bir esneklik sunulmuştur. Eğer if deyiminden sonra icra edilecek<br />
deyimler tek satırdan oluşuyorsa, bu işaretlerin kullanılması zorunlu değildir. Yani, if<br />
deyimden sonra { ve } işaretleri kullanılmamışsa, bu deyimi takip eden sadece ilk satır işleme<br />
konur. Bu durum, else if, else deyimlerinde ve daha sonra işlenecek for ve while gibi<br />
döngü deyimlerinde de geçerlidir.<br />
Buna göre aşağıdaki kullanım<br />
ile<br />
if(x == y){<br />
puts("x ve y esit");<br />
}<br />
if(x == y)<br />
puts("x ve y esit");
eşdeğerdir.<br />
if deyiminin else ile birlikte kullanımı şu şekildedir:<br />
if(koşul){<br />
...<br />
deyimler; (küme1)<br />
...<br />
}<br />
else{<br />
...<br />
deyimler; (küme2)<br />
...<br />
}<br />
Bu yapının kullanılmasına dair bir örnek Program 6.1'de gösterilmiştir. Program, klavyeden<br />
girilen bir tamsayının çift olup olmadığını sınar. Bilindiği gibi, çift sayılar, 2 ile kalansız<br />
bölünebilen sayılardır.<br />
Program 6.1: if-else deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
/* 06prg01.c<br />
Klavyeden girilen bir sayının çift olup<br />
olmadığını sınar. */<br />
#include <br />
int main()<br />
{<br />
int sayi;<br />
}<br />
ÇIKTI<br />
printf("Bir sayi girin: ");<br />
scanf("%d",&sayi);<br />
if (sayi % 2 == 0)<br />
printf("sayi cifttir.\n");<br />
else<br />
printf("sayi tektir.\n");<br />
return 0;<br />
Bir sayi girin: 3<br />
sayi tektir.<br />
Mantıksal Operatörler kullanarak birden çok karşılaştırma birleştirilebilir. Buna iyi bir örnek<br />
Program 6.2'de gösterilmiştir. Program, bir yılın artık yıl olup olmadığını sınar. Bir yıl içinde,<br />
Şubat ayı 29 gün olursa o yıl artık yıl olarak adlandırılır. Artık yıl peryodik olarak 4 yılda bir<br />
gelir. Genel kanı "bir yıl 4 ile tam bölünebirse o yıl artık yıldır" şeklindedir. Fakat 1996 artık<br />
yıl iken 1800 artık yıl değildir. Genel sorgulama söyle olmalıdır: Eğer bir yıl
• 4 ile tam bölünüyorsa VE 100'e tam bölünmüyorsa VEYA<br />
• 400 'e tam bölünüryorsa<br />
o yıl artık yıldır.<br />
Program 6.2: if-else deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
/* 06prg02.c: Bir yılın artık yil olup<br />
olmadığını sınar. */<br />
#include <br />
void main()<br />
{<br />
int yil;<br />
printf("Bir yil girin: ");<br />
scanf("%d",&yil);<br />
if( yil % 4 == 0 && yil % 100 != 0 || yil %<br />
400 == 0 )<br />
printf("%d artik yil\n",yil);<br />
}<br />
ÇIKTI<br />
else<br />
printf("%d artik yil degil\n",yil);<br />
Bir yil girin: 1996<br />
1996 artik yil<br />
Eğer program içinde kullanılacak koşulların sayısı ikiden çok ise aşağıdaki yapı kullanılır:<br />
if(koşul_1)<br />
{<br />
...<br />
deyimler; (küme_1)<br />
...<br />
}<br />
else if(koşul_2)<br />
{<br />
...<br />
deyimler; (küme_2)<br />
...<br />
}<br />
.<br />
.<br />
.<br />
else if(koşul_n-1)<br />
{<br />
...<br />
deyimler; (küme_n-1)<br />
...<br />
}<br />
else
{<br />
}<br />
...<br />
deyimler; (küme_n)<br />
...<br />
Program 6.3, ax 2 + bx + c = 0 formundaki ikinci dereceden bir polinomun köklerini<br />
hesaplamaktadır. Programda delta değerinin sıfırdan küçük olması durumda köklerin<br />
karmaşık sayıya dönüşeceğide göz önüne alınmıştır. Bu program if, else if ve else yapısı<br />
göstermek için klasik bir örnektir.<br />
Program 6.3: if, else if, else yapısı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
/* 06prg03.c:<br />
ax*x + bx + c = 0 denkleminin (karmaşık<br />
sayılı kökler dahil) çözümü */<br />
#include <br />
#include <br />
int main()<br />
{<br />
float a, b, c, delta, x1, x2, x, kok_delta;<br />
printf("a, b, c degerlerini girin:\n");<br />
scanf("%f %f %f",&a,&b,&c);<br />
delta = b*b - 4.0*a*c;<br />
if( delta > 0.0 ){<br />
x1 = ( -b + sqrt(delta) )/( 2.0*a );<br />
x2 = ( -b - sqrt(delta) )/( 2.0*a );<br />
printf("\nReel kokler:");<br />
printf("\nx1 = %f",x1);<br />
printf("\nx2 = %f",x2);<br />
}<br />
else if( delta < 0.0 ){<br />
kok_delta = ( sqrt(-delta) ) / (2.0*a);<br />
x = -0.5*b/a;<br />
printf("\nKarmasik kokler:");<br />
printf("\nx1 = %f + (%f)i", x,<br />
kok_delta);<br />
printf("\nx2 = %f - (%f)i", x,<br />
kok_delta);<br />
}<br />
else{<br />
x = -0.5*b/a;<br />
}<br />
printf("\nKokler eşit:");<br />
printf("\nx1 = x2 = %f",x);<br />
}<br />
return 0;<br />
ÇIKTI
a, b, c degerlerini girin:<br />
2 4 -8<br />
Reel kokler:<br />
x1 = 1.236068<br />
x2 = -3.236068<br />
ÇIKTI<br />
a, b, c degerlerini girin:<br />
1 1 1<br />
Karmasik kokler:<br />
x1 = -0.500000 + (0.866025)i<br />
x2 = -0.500000 - (0.866025)i<br />
6.3 switch - case Yapısı<br />
Bu deyim bir değişkenin içeriğine bakarak, programın akışını bir çok seçenekten birine<br />
yönlendirir. case (durum) deyiminden sonra değişkenin durumu belirlenir ve takip eden gelen<br />
satırlar (deyimler) işleme konur. Bütün durumların aksi söz konu olduğunda<br />
gerçekleştirilmesi istenen deyimler default deyiminden sonraki kısımda bildirilir. Genel<br />
yazım biçimi:<br />
switch(değişken)<br />
{<br />
case sabit1:<br />
...<br />
deyimler;<br />
...<br />
case sabit2:<br />
...<br />
deyimler;<br />
...<br />
.<br />
.<br />
.<br />
case sabitn:<br />
...<br />
deyimler;<br />
...<br />
default:<br />
...<br />
hata deyimleri veya varsayılan deyimler;<br />
...<br />
}<br />
Program Program 6.4'te switch deyiminin basit bir kullanımı gösterilmiştir.<br />
Program 6.4: switch-case yapısının kullanımı<br />
01:<br />
02:<br />
03:<br />
/* 06prg04.c: switch - case yapısının kullanımı<br />
*/
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
ÇIKTI<br />
#include <br />
int main(void)<br />
{<br />
char kr;<br />
printf("Lutfen bir karakter girin\n");<br />
kr = getchar(); /* tek bir karakterin<br />
okunması */<br />
switch (kr)<br />
{<br />
case 'a':<br />
printf("a harfine bastiniz\n");<br />
case 'b':<br />
printf("b harfine bastiniz\n");<br />
default:<br />
printf("a veya b ye basmadiniz\n");<br />
}<br />
return 0;<br />
}<br />
Lutfen bir karakter girin<br />
a<br />
a harfine bastiniz<br />
b harfine bastiniz<br />
a veya b ye basmadiniz<br />
ÇIKTI<br />
Lutfen bir karakter girin<br />
b<br />
b harfine bastiniz<br />
a veya b ye basmadiniz<br />
ÇIKTI<br />
Lutfen bir karakter girin<br />
k<br />
a veya b ye basmadiniz<br />
ÇIKTI<br />
Lütfen bir karakter girin<br />
c<br />
a veya b ye basmadiniz<br />
Programda, klavyeden okunan tek bir karakter değişkenin içeriğine bakılıp uygun dallanmalar<br />
yaptırılmıştır. 11. satırda değişken getchar() fonksiyonu ile okutulmuştur. Eğer 'a' veya<br />
'b' karakterlerinden biri girilirse, ekrana bu harflerin girildiğine dair mesaj yazılacak, aksi
takdirde bu karakterin dışında bir karakterin giriş olarak kullanıldığı gösteren bir mesaj<br />
yazılacaktır. Örneğin 'c' karakteri klavyeden girilmiş ise a veya b ye basmadiniz gibi.<br />
Fakat 'a' karakterleri girildiğinde ekrana her üç durumda yazdırılmaktadır. Bunun sebebi,<br />
case 'a': durumunda sırasıyla 16, 18 ve 20. satırların işleme konmasıdır. Bunu engellemek<br />
için 16. satırdan sonra programın başka bir yere yönlendirilmesi gerekir. Bu yönlendirme<br />
break deyimi ile yapılır. Derleyici bu deyim ile karşılaştığında, bulunduğu yapının içinden<br />
koşulsuz olarak ayrılır ve takip eden işleme başlar.<br />
Program 6.4'te case 'a': durumu için 16, 18 ve 20. satırlar da işleme konumuştu. Eğer<br />
klavyeden 'a' karakterini girip ekrana sadece a harfine bastiniz iletisi yazdırılmak<br />
isteniyorsa, 20. satıra break deyimi ilave edilmelidir. break deyiminin kullanımı Program<br />
6.5'te gösterilmiştir.<br />
Program 6.5: switch-case yapısı ve break kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
ÇIKTI<br />
/* 06prg05.c: switch - case yapısı ve break<br />
kullanımı */<br />
#include <br />
int main(void)<br />
{<br />
char kr;<br />
printf("Lutfen bir karakter girin\n");<br />
kr = getchar(); /* tek bir karakterin<br />
okunması */<br />
return 0;<br />
}<br />
switch (kr)<br />
{<br />
case 'a':<br />
printf("a harfine bastiniz\n");<br />
break;<br />
case 'b':<br />
printf("b harfine bastiniz\n");<br />
break;<br />
default:<br />
printf("a veya b ye basmadiniz\n");<br />
break;<br />
}<br />
Lutfen bir karakter girin<br />
a<br />
a harfine bastiniz<br />
ÇIKTI<br />
Lutfen bir karakter girin<br />
k
a veya b ye basmadiniz<br />
Program 6.6 switch-case yapısın farklı bir kullanımı ile ilgili bir örnektir. Programda, önce<br />
iki sayı isteniyor ardından yapılan seçimle bu sayıların toplamı, farkı, çarpımı veya oranı<br />
ekrana yazdırılıyor.<br />
Program 6.6: switch-case yapısı ve break kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
/* 06prg06.c: switch-case yapısı */<br />
#include <br />
#include <br />
int main(void)<br />
{<br />
int secim;<br />
float x,y, sonuc;<br />
}<br />
ÇIKTI<br />
printf("Iki sayi girin: ");<br />
scanf("%f %f",&x,&y);<br />
puts("*** Menu ***");<br />
puts("[1] Toplama");<br />
puts("[2] Cikarma");<br />
puts("[3] Carpma");<br />
puts("[4] Bolme");<br />
printf("Seciminiz: ");<br />
scanf("%d",&secim);<br />
switch( secim )<br />
{<br />
case 1:<br />
sonuc = x + y;<br />
printf("Toplam = %f\n",sonuc);<br />
break;<br />
case 2:<br />
sonuc = x-y;<br />
printf("Fark = %f\n",sonuc);<br />
break;<br />
case 3:<br />
sonuc = x * y;<br />
printf("Carpim = %f\n",sonuc);<br />
break;<br />
case 4:<br />
sonuc = x/y;<br />
printf("Oran = %f\n",sonuc);<br />
break;<br />
default:<br />
puts("Yanlis secim !\a");<br />
}<br />
return 0;<br />
Iki sayi girin: 3 8
*** Menu ***<br />
[1] Toplama<br />
[2] Cikarma<br />
[3] Carpma<br />
[4] Bolme<br />
Seciminiz: 1<br />
Toplam = 11.000000<br />
ÇIKTI<br />
Iki sayi girin: 3 8<br />
*** Menu ***<br />
[1] Toplama<br />
[2] Cikarma<br />
[3] Carpma<br />
[4] Bolme<br />
Seciminiz: 7<br />
Yanlis secim !<br />
switch-case yapısı if-else yapısının bir alternatifidir. Yani, Program 6.6'daki switchcase<br />
kısmı, if-else yapısı ile de aşağıdaki gibi yazılabilirdi. İnceleyiniz.<br />
switch( secim )<br />
{<br />
case 1:<br />
sonuc = x + y;<br />
printf("Toplam =<br />
%f\n",sonuc);<br />
break;<br />
case 2:<br />
sonuc = x-y;<br />
printf("Fark =<br />
%f\n",sonuc);<br />
break;<br />
case 3:<br />
sonuc = x * y;<br />
printf("Carpim =<br />
%f\n",sonuc);<br />
break;<br />
case 4:<br />
sonuc = x/y;<br />
printf("Oran =<br />
%f\n",sonuc);<br />
break;<br />
!\a");<br />
}<br />
default:<br />
puts("Yanlis<br />
secim<br />
if(secim == 1){<br />
sonuc = x + y;<br />
printf("Toplam =<br />
%f\n",sonuc);<br />
}<br />
else if(secim == 2){<br />
sonuc = x-y;<br />
printf("Fark =<br />
%f\n",sonuc);<br />
}<br />
else if(secim == 3 ){<br />
sonuc = x * y;<br />
printf("Carpim =<br />
%f\n",sonuc);<br />
}<br />
else if(secim == 4){<br />
sonuc = x/y;<br />
printf("Oran =<br />
%f\n",sonuc);<br />
}<br />
else{<br />
!\a");<br />
}<br />
puts("Yanlis<br />
secim<br />
6.4 ? Karşılaştırma Operatörü<br />
Bu operatör, if-else karşılaştırma deyiminin yaptığı işi sınırlı olarak yapan bir operatördür.<br />
Genel yazım biçimi:<br />
(koşul) ? deyim1 : deyim2;
İlk önce koşul sınanır. Eğer koşul olumluysa deyim1 aksi takdirde deyim2 değerlendirilir.<br />
deyim1 ve deyim2 de atama işlemi yapılamaz. Ancak koşul deyiminde atama işlemi<br />
yapılabilir. deyim1 ve deyim2 yerine fonksiyon da kullanılabilir. Aşağıda bu deyimin<br />
kullanımına ait örnekler verilmiştir.<br />
x = ( a > b ) ? a : b;<br />
Yukarıdaki ifadede koşul a'nın b'den büyük olmasıdır. Eğer olumluysa x adlı değişkene a,<br />
değilse b değeri atanır. Bu şekilde kullanım if-else yapısı ile kurulmak istenirse:<br />
if( a > b ) x = a;<br />
else x = b;<br />
şeklinde olacaktır. Program 6.7 ? karşılaştırma operatörünün basit bir kullanımını<br />
göstermektedir.<br />
Program 6.7: ? ve if kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
ÇIKTI<br />
/* 06prg07.c: ? ve if-else yapısının kullanımı<br />
*/<br />
#include <br />
int main(void)<br />
{<br />
float x, y, z;<br />
printf("x : "); scanf("%f",&x);<br />
printf("y : "); scanf("%f",&y);<br />
if(y)<br />
/* y, 0'dan<br />
farklı mı? */<br />
z = ( y > x ) ? x/y : x*y; /* y>x ise z<br />
= x/y, değilse z = x*y */<br />
else<br />
z = 0.0;<br />
printf("z = %f\n",z);<br />
return 0;<br />
}<br />
x : 3<br />
y : 5<br />
z = 0.600000<br />
ÇIKTI<br />
x : 11<br />
y : 0<br />
z = 0.000000
12. satırdaki if deyimindeki koşul biraz farklıdır. Genel olarak koşul bu şekilde bildirilirse,<br />
koşulun 0 dan farklı olup olmadığı sınanır. Yani:<br />
if(y)<br />
ile<br />
if( y != 0 )<br />
aynı anlamdadır.<br />
Bu kullanım çok yagındır. Eğer y, 0 dan farklı ise koşul olumlu olarak değerlendirilecektir.<br />
13. satırda ? ile bir sınama yapılmaktadır. Eğer y, x den büyük ise z değişkenine x/y, aksi<br />
takdirde x*y değeri atanmaktadır. Eğer y = 0 ise z değişkenine 0 değeri atanmaktadır.<br />
<strong>Ders</strong> 7: Döngüler<br />
• <strong>Giriş</strong><br />
• 7.1 while Döngüsü<br />
• 7.2 do ... while Döngüsü<br />
• 7.3 for Döngüsü<br />
• 7.4 İç içe Geçmiş Döngüler<br />
• 7.5 Sonsuz Döngü<br />
• 7.6 break Deyimi<br />
• 7.7 continue Deyimi<br />
<strong>Giriş</strong><br />
Döngü (loop) deyimleri, bir kümenin belli bir koşul altında tekrar edilmesi için kullanılır. C<br />
programlama dilinde, while, do...while ve for olmak üzere üç tip döngü deyimi vardır.<br />
Diğer programlama dillerinde olduğu gibi, bu deyimlerle istenildiği kadar iç-içe döngü yapısı<br />
kullanılabilir.<br />
7.1 while Döngüsü<br />
Tekrarlama deyimidir. Bir küme ya da deyim while kullanılarak bir çok kez yinelenebilir.<br />
Yinelenmesi için koşul sınaması döngüye girilmeden yapılır. Koşul olumlu olduğu sürece<br />
çevrim yinelenir. Bu deyimin kullanımı Program 7.1 de gösterilmiştir. Genel yazım biçimi:<br />
while(koşul)<br />
{<br />
...<br />
döngüdeki deyimler; [küme]<br />
...<br />
}
Program 7.1: while döngüsü<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
ÇIKTI<br />
/* 07prg01.c: while döngüsü */<br />
#include <br />
main()<br />
{<br />
int x=0;<br />
while(x
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
ÇIKTI<br />
#include <br />
main()<br />
{<br />
int sayi;<br />
do<br />
{<br />
printf("Bir sayi girin : ");<br />
scanf("%d",&sayi);<br />
printf("iki kati : %d\n",2*sayi);<br />
}while( sayi>0 ); /* koşul */<br />
puts("Döngü sona erdi.");<br />
return 0;<br />
}<br />
Bir sayi girin : 1<br />
iki kati : 2<br />
Bir sayi girin : 3<br />
iki kati : 6<br />
Bir sayi girin : 4<br />
iki kati : 8<br />
Bir sayi girin : -3<br />
iki kati : -6<br />
Cevrim sona erdi.<br />
15. satırdaki koşul olumlu olduğu sürece (sayi>0 olduğu sürece), klavyeden yeni bir değer<br />
12. satırda okunur. Aksi takdirde (sayi
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
*/<br />
ÇIKTI<br />
#include <br />
int main()<br />
{<br />
long i, n, faktor;<br />
printf("Faktoriyeli hesaplanacak sayi girin :<br />
");<br />
scanf("%ld",&n);<br />
faktor=1;<br />
for(i=1; i
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
ÇIKTI<br />
/* 07prg04.c: Sayı sistemi<br />
%d : desimal 10 tabanındaki sayı<br />
%o : oktal 8 tabanındaki sayı<br />
%x : hexadesimal 16 tabanındaki sayı (küçük<br />
harf)<br />
%X : hexadesimal 16 tabanındaki sayı (büyük<br />
harf) */<br />
#include <br />
int main()<br />
{<br />
int i;<br />
for (i=0; i
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
ÇIKTI<br />
= 3^3 + 7^3 + 1^3.<br />
Bu program İç-içe geçmiş 3 döngü ile bütün<br />
Aramstrong sayıları bulur. */<br />
#include <br />
int main()<br />
{<br />
int a,b,c, kup, sayi, k=1;<br />
for(a=1; a
for döngüsünde, başlangıç, koşul ve artım parametrelerinden herhangi birini kullanmak<br />
isteğe bağlıdır. Her hangi biri verilmediğinde döngünün nasıl davranacağı iyi<br />
yorumlanmalıdır. Örneğin for döngüsünün hiçbir parametresi verilmezse, döngü sonsuz<br />
çevrime girer. Yani:<br />
gibi.<br />
for(;;)<br />
printf("Sonsuz döngü içindeyim...\n");<br />
7.6 break Deyimi<br />
Bir C programında, bir işlem gerçekleştirilirken, işlemin sona erdirilmesi bu deyim ile yapılır.<br />
Örneğin, döngü deyimleri içindekiler yürütülürken, çevrimin, koşuldan bağımsız kesin olarak<br />
sonlanması gerektiğinde bu deyim kullanılır. Mesela:<br />
...<br />
do{<br />
scanf("%d",&x);<br />
}while(1);<br />
...<br />
if(x==0) break;<br />
printf("%f",1.0/x);<br />
Yukarıdaki program parçasında, do ... while döngüsündeki koşul daima olumludur. Bu<br />
durumda döngü sonsuzdur. Fakat döngü içinde if deyimindeki koşul gerçekleşirse, döngü<br />
koşuluna bakılmaksızın terkedilir. Bu işlemi sağlayan break deyimidir.<br />
Program 7.6 klavyeden girilen sayı pozitif olduğu sürece sayının faktoriyelini hesaplar. Sayı<br />
negatif olduğunda döngü break ile sonlandırılır. Inceleyiniz.<br />
Program 7.6: break deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
/* 07prg06.c: n>=0 olduğu sürece n! değerini<br />
hesaplar */<br />
#include <br />
int main()<br />
{<br />
long int i,n,faktor;<br />
while(1) /* sonsuz döngü */<br />
{<br />
printf("Faktoriyeli hesaplanacak sayi<br />
girin : ");<br />
scanf("%ld",&n);<br />
if(n
20:<br />
21:<br />
22:<br />
23:<br />
ÇIKTI<br />
}<br />
return 0;<br />
}<br />
printf("%ld! = %ld\n",n,faktor);<br />
Faktoriyeli hesaplanacak sayi girin : 2<br />
2! = 2<br />
Faktoriyeli hesaplanacak sayi girin : 3<br />
3! = 6<br />
Faktoriyeli hesaplanacak sayi girin : 5<br />
5! = 120<br />
Faktoriyeli hesaplanacak sayi girin : 9<br />
9! = 362880<br />
Faktoriyeli hesaplanacak sayi girin : 0<br />
0! = 1<br />
Faktoriyeli hesaplanacak sayi girin : -4<br />
7.7 continue Deyimi<br />
Bir döngü içerisinde continue deyimi ile karşılaşılırsa, ondan sonra gelen deyimler atlanır ve<br />
döngü bir sonraki çevrime girer. Örneğin:<br />
...<br />
for(x=-50;i
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
ÇIKTI<br />
#include <br />
int main()<br />
{<br />
int x,y,k=1;<br />
for (x=-3;x
<strong>Giriş</strong><br />
C Programlama Dili fonksiyon olarak adlandırılan alt programların birleştirilmesi kavramına<br />
dayanır. Bir C programı bir yada daha çok fonksiyonun bir araya gelmesi ile oluşur. Bu<br />
özellik bütün Yapısal Diller'in (C, Fortran, Pascal, ...) temelini oluşturur. Yapısal Diller'e<br />
hakim olmak için fonksiyon oluşturmayı ve kullanmayı iyi öğrenmek gerekir.<br />
Bu bölümde, C Programlama Dili'ndeki fonksiyon kavramı, sonraki bölümde (Bölüm 9) esnek<br />
argümanlı fonksiyonlar ve main() fonksiyonu irdelenecektir.<br />
8.1 Fonksiyon Kavramı<br />
Fonksiyon, belirli sayıda verileri kullanarak bunları işleyen ve bir sonuç üreten komut<br />
grubudur. Her fonksiyonun bir adı ve fonksiyona gelen değerleri gösteren argumanları<br />
(bağımsız değişkenleri) vardır. Genel olarak bir fonksiyon Şekil 8.1'deki gibi bir kutu ile<br />
temsil edilir:<br />
Şekil 8.1:Bir fonksiyonun kutu gösterimi<br />
Fonksiyonların girdilerine parametreler yada argumanlar denir. Bir fonksiyon bu<br />
parametreleri alıp bir işleme tabi tutar ve bir değer hesaplar. Bu değer, çıktı veya geri dönüş<br />
değeri (return value) olarak adlandırılır. Unutmayın ki, bir fonksiyonun kaç girişi olursa olsun<br />
sadece bir çıkışı vardır.<br />
C Programlama Dili, kullanıcısına bu türden fonksiyon yazmasına izin verir. C dilinde<br />
hazırlanan bir fonksiyonun genel yapısı şöyledir:<br />
FonksiyonTipi FonksiyonAdı(argüman listesi)<br />
argumanların tip bildirimleri<br />
{<br />
Yerel değişkenlerin bildirimi<br />
...<br />
fonksiyon içindeki deyimler veya diğer fonksiyonlar<br />
...<br />
return geri dönüş değeri;<br />
}<br />
Örneğin iki sayının toplamının hesaplayacak bir fonksiyon şöyle tanımlanabilir:
* klasik biçim */<br />
int topla(x,y)<br />
int x,y<br />
{<br />
int sonuc;<br />
sonuc = x + y;<br />
return sonuc;<br />
}<br />
veya<br />
/* modern biçim */<br />
int topla(int x,int y)<br />
{<br />
int sonuc;<br />
sonuc = x + y;<br />
return sonuc;<br />
}<br />
veya<br />
/* modern biçim */<br />
int topla(int x,int y)<br />
{<br />
return (x+y);<br />
}<br />
Bu örnekte, fonksiyonun kimlik kartı! ve kutu gösterimi şöyledir:<br />
• Fonksiyon tipi: int<br />
• Fonksiyon adı : topla<br />
• parametreler : x ve y<br />
• geri dönüş değeri: x+y<br />
Her üç program parçasında da return (geri dönüş) deyimi kullanılmaktadır. Bu deyim C<br />
programlama dilinin anahtar sözcüklerinden biridir ve fonksiyon içerisinde sonucu, kendisini<br />
çağıran yere göndemek için kullanılır. Yani topla fonksiyonu herhangi bir programın<br />
içerisinde kullanıldığında, fonksiyonun üreteceği sonuç return deyiminden sonra belirtilen<br />
değişken veya işlem olacaktır. Örneğin fonksiyon:<br />
...<br />
int t;<br />
...<br />
t = topla(9,6);<br />
...<br />
şeklinde kullanılırsa, t değişkenine 9+6=15 değeri atanır. topla() fonksiyonunun kullanımı<br />
Program 8.1'in üzerinde açıklanmıştır.<br />
8.2 Fonksiyon Bildirimi<br />
Bir fonksiyonun bildirimi iki türlü yapılır:<br />
1. Ana programdan önce:<br />
2. ...
3. int topla(int x,int y) /* fonksiyon */<br />
4. {<br />
5. ...<br />
6. }<br />
7. ...<br />
8. main()<br />
9. {<br />
10. ...<br />
11. }<br />
12. Ana programdan sonra: Bu durumda fonksiyon örneği (function prototype) ana<br />
programdan önce bildirilmelidir.<br />
13. ...<br />
14. int topla(int x, int y); /* fonksiyon örneği */<br />
15. ...<br />
16. main()<br />
17. {<br />
18. ...<br />
19. }<br />
20. ...<br />
21. int topla(int x, int y) /* fonksiyon */<br />
22. {<br />
23. ...<br />
24. }<br />
Bir C programı içinde, yazmış olduğunuz fonksiyonlar genellikle bu iki tipte kullanılır. İkinci<br />
kullanımda fonksiyon prototipi mutlaka bildirilmelidir. Aksi halde bir hata mesajı ile<br />
karşılaşılır. Fonksiyon prototipinde arguman isimlerinin yazılması zorunlu değildir. Sadece<br />
arguman tiplerini belirtmek de yeterlidir. Yukarıdaki topla fonksiyona ait prototip:<br />
int topla(int x, int y);<br />
şekinde yazılabileği gibi<br />
int topla(int, int);<br />
şeklinde de yazılabilir.<br />
Buraya kadar anlatılanlar Program 8.1 üzeride özetlenmiştir.<br />
Program 8.1: topla fonksiyonunun ana programda kullanılması<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
/* 08prg01.c: iki sayıyı toplar ve sonucu<br />
ekranda gösterir */<br />
#include <br />
int topla(int, int); /*** fonksiyon prototipi<br />
***/<br />
int main()<br />
{<br />
int toplam,a,b;<br />
printf("Iki sayi girin : ");<br />
scanf("%d %d",&a,&b);<br />
/* fonksiyon çağırılıp, a ve b değerleri<br />
parametre olarak aktarılıyor.<br />
topla(a,b) = a + b değeri toplam<br />
değişkenine atanması */<br />
toplam = topla(a,b);
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
printf("%d ve %d nin toplami %d dir.\n",<br />
a,b,toplam);<br />
}<br />
ÇIKTI<br />
return 0;<br />
/*** fonksiyon tanımlanması ***/<br />
/* Bu fonksiyon iki tamsayıyı toplar */<br />
int topla( int x, int y )<br />
{<br />
int sonuc;<br />
sonuc = x + y;<br />
return sonuc;<br />
}<br />
Iki sayi girin : 5 12<br />
5 ve 12 nin toplami 17 dir.<br />
Programda, klavyeden okunan a ve b değişkenleri fonksiyonuna parametre olarak<br />
aktarılmıştır. Bu değişkenlerin isimleri ile topla fonksiyonunda kullanılan değişkenlerin (x<br />
ve y) isimleri aynı olması zorunlu değildir. Burara a ve b değişkenleri sırasıyla x ve y<br />
değişkenleri yerine konmuştur. 16. satırda toplam adlı tamsayı değişkenine topla<br />
fonksiyonunun dönüş değeri (a + b değeri) atanmıştır.<br />
Belki karmaşık gelmiş olabilir. Fakat Program 8.1 daha kısa şöyle yazılabilirdi:<br />
Program 8.1b: topla fonksiyonunun ana programda kullanılması<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
/* 08prg01b.c: iki sayıyı toplar ve sonucu<br />
ekranda gösterir */<br />
#include <br />
int topla( int x, int y ){<br />
return (x+y);<br />
}<br />
int main(void)<br />
{<br />
int toplam,a,b;<br />
printf("Iki sayi girin : ");<br />
scanf("%d %d",&a,&b);<br />
toplam = topla(a,b);<br />
printf("%d ve %d nin toplami %d dir.\n",<br />
a,b,toplam);<br />
return 0;<br />
}
8.3 Geri Dönüş Değerleri<br />
return anahtar sözcüğünün iki önemli işlevi vardır:<br />
1. fonksiyonun geri dönüş değerini oluşturur<br />
2. fonksiyonu sonlandırır<br />
Bu deyiminden sonra bir değişken, işlem, sabit veya başka bir fonksiyon yazılabilir. Örneğin:<br />
return (a+b/c); /* parantez kullanmak zorunlu değil */<br />
return 10; /* değişken kullanmak mecbur değil */<br />
return topla(a,b)/2.0; /* önce topla fonksiyonu çalışır */<br />
Bir fonksiyonda birden çok geri dönüş değeri kullanılabilir. Fakat, ilk karşılaşılan return<br />
deyiminden sonra fonksiyon sonlananır ve çağrılan yere bu değer gönderilir. Örneğin<br />
aşağıdaki harf fonksiyonunda beş tane return deyimi kullanılmıştır.<br />
char harf(int not)<br />
{<br />
if( not>=0 && not=50 && not=70 && not=80 && not=90 ) return 'A';<br />
}<br />
Bu fonksiyon kendisine parametre olarak gelen 0-100 arasındaki bir notun harf karşılığını<br />
gönderir. Aslında geri gönderilen değer bir tanedir. Eğer bu fonksiyon aşağıdaki gibi<br />
çağrılırsa:<br />
char harfim;<br />
...<br />
harfim = harf(78);<br />
...<br />
harfim değişkenine 'C' değeri (karakteri) atanır.<br />
Program 8.2'de bildirilen artik_yil fonksiyonu, kendisine parametre olarak gelen bir<br />
tamsayıyı yıl bilgisi olarak kabul eder. Eğer yıl artık yıl ise 1 aksi halde 0 gönderir.<br />
Programda iki tane return deyimi kullanıldığına dikkat ediniz. Artık yıl tanımı Bölüm 6'da<br />
verilmişti.<br />
Program 8.2: iki return deyimi kullanan bir fonksiyon<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
/* 08prg02.c: Bir fonksiyonda iki return deyimi<br />
*/<br />
#include <br />
int artik_yil(int); /* fonksiyon prototipi */
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
void main()<br />
{<br />
int yil;<br />
}<br />
ÇIKTI<br />
printf("Bir yil girin: ");<br />
scanf("%d",&yil);<br />
if( artik_yil(yil) )<br />
printf("%d artik yil\n",yil);<br />
else<br />
printf("%d artik yil degil\n",yil);<br />
/* yil artıl yıl ise 1 aksi halde 0 gönderir */<br />
int artik_yil(int yil)<br />
{<br />
if( yil % 4 == 0 &&<br />
yil % 100 != 0 ||<br />
yil % 400 == 0 ) return 1;<br />
else return 0;<br />
}<br />
Bir yil girin: 1996<br />
1996 artik yil<br />
8.4 void Fonksiyonlar<br />
Bir fonksiyonun her zaman geri dönüş değerinin olması gerekmez. Bu durumda return<br />
deyimi kullanılmayabilir. Eğer bu anahtar kelime yoksa, fonksiyon ana bloğu bitince<br />
kendiliğinden sonlanır. Böyle fonksiyonların tipi void (boş, hükümsüz) olarak belirtilmelidir.<br />
Bu tip fonksiyonlar başka bir yerde kullanılırken, herhangi bir değişkene atanması söz konusu<br />
değildir, çünkü geri dönüş değeri yoktur. Ancak, void fonksiyonlara parametre aktarımı<br />
yapmak mümkündür.<br />
Program 8.3'de void fonksiyona örnek olarak bankamatik fonksiyonu ve kullanımı<br />
gösterilmiştir. Bu fonksiyon kendisine parametre olarak gelen YTL cinsinden para miktarını<br />
20, 10 ve 5 YTL'lik birimler halinde hesaplar. Girilen miktar 5 YTL'nin bir katı değilse,<br />
ekrana uygun bir mesaj gönderir. bankamatik fonksiyonu bir dizi hesap yapmasına rağmen<br />
geriye hiç bir değer göndermez.<br />
Program 8.3: void tipinde bir fonksiyon kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
/* 08prg03.c: Basit bankamatik simulasyonu.<br />
İstenen para miktarını 20, 10 ve 5'lik<br />
birimlere böler<br />
ve sonucu ekrana gösterir. */<br />
#include <br />
void bankamatik(int para)<br />
{
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
int a,yirmilik,onluk,beslik;<br />
a = para;<br />
if(a%5==0)<br />
{<br />
yirmilik = a/20;<br />
a -= yirmilik*20;<br />
onluk = a/10;<br />
a -= onluk*10;<br />
beslik = a/5;<br />
a -= beslik*5;<br />
printf("\nYirmilik = %d",yirmilik);<br />
printf("\nOnluk = %d",onluk);<br />
printf("\nBeslik = %d\n",beslik);<br />
}<br />
else<br />
printf("Girilen miktar 5 YTL ve katlari<br />
olmali!\a\n");<br />
}<br />
/* return deyimi yok !*/<br />
int main()<br />
{<br />
int miktar;<br />
printf("Cekilecek para miktari (YTL) = ");<br />
scanf("%d",&miktar);<br />
bankamatik(miktar);<br />
değişkene atanmamış ! */<br />
/* fonksiyon bir<br />
}<br />
retrun 0;<br />
ÇIKTI<br />
Cekilecek para miktari = 135<br />
Yirmilik = 6<br />
Onluk = 1<br />
Beslik = 1<br />
ÇIKTI<br />
Cekilecek para miktari = 456<br />
Girilen miktar 5 YTL ve katlari olmali!<br />
void anahtar sözcüğü C'ye sonradan dahil edilmiştir. Standart C'de (ANSI C) bu deyimin<br />
kullanılması zorunlu değildir. Ancak bu deyim okunabilirliği arttırmaktadır. Örneğin:<br />
void bankamatik(int para) bankamatik(int para)<br />
{ {
... ...<br />
} }<br />
şeklindeki kullanımlar geçerli ve aynı anlamdadır.<br />
Başka bir void fonksiyon örneği Program 8.4'de verilmiştir. Programdaki kutu_ciz<br />
fonksiyonu, iki for döngüsü kullanarak 'X' karakterlerinden oluşan basit bir kutu çizimi<br />
yapar. Programda de sadece 18. satır defalarca işleme konur. Program çalıştırıldığında<br />
8*35=280 adet 'X' karakteri ekrana bastırılır. İnceleyiniz.<br />
Program 8.4: basit kutu çizen fonksiyon<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
/* 08prg04.c: Basit bir kutu çizen fonksiyon */<br />
#include <br />
void kutu_ciz( int satir, int sutun )<br />
{<br />
int sut;<br />
for ( ; satir > 0; satir--)<br />
{<br />
for (sut = sutun; sut > 0; sut--)<br />
printf("X");<br />
}<br />
ÇIKTI<br />
}<br />
int main(){<br />
printf("\n");<br />
kutu_ciz(8,35);<br />
return 0;<br />
}<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br />
8.5 Fonksiyon Parametreleri<br />
Fonksiyon parametreleri (argümanları) klasik ve modern olmak üzere iki türlü tanımanabilir.<br />
Örneğin aşağıdaki fonksiyon kendisine parametre olarak gelen tamsayının faktoriyelini<br />
gönderir. Bu fonksiyonun parametresi (n):<br />
int faktoriyel(n) /* kalsik biçim */<br />
int n<br />
{
int i=1, f=1;<br />
while(i
Şekil 8.2: Ana programdan alt programların (fonksiyonların) çağırılması.<br />
Fonksiyonu çağırmak için, fonksiyonun adını yazmak yeterlidir.<br />
Fonksiyonların sadece ana program tarafından çağrılması zorunlu değildir. Bir fonksiyon<br />
başka bir fonksiyon tarafından da çağrılabilir. Bu tür kullanıma dair bir örnek Program 8.5'de<br />
verilmiştir. yilin_gunu fonksiyonu, verilen bir tarihin yılın kaçıncı günü olduğunu hesaplar<br />
ve çağrıldığı yere gönderir. İnceleyiniz.<br />
Program 8.5: bir fonksiyonun başka bir fonksiyon tarafından çağrılması<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
/* 08prg05.c: Verilen bir tarihin yılın kaçıncı<br />
günü olduğunu hesaplar. */<br />
#include <br />
int yilin_gunu(int, int, int);<br />
int artik_yil(int);<br />
int main(void)<br />
{<br />
int gun = 1; /* tarih: 01 Ağustos 2003 */<br />
int ay = 8;<br />
int yil = 2003;<br />
printf("%02d %02d %d yilinin\n",gun,ay,yil );<br />
printf("%d. gunudur\n",yilin_gunu(gun,ay,yil)<br />
);<br />
}<br />
return 0;<br />
/* yil artıl yıl ise 1 aksi halde 0 gönderir */<br />
int artik_yil(int yil)<br />
{<br />
if( yil%4==0 && yil%100!=0 || yil%400==0 )<br />
return 1;<br />
else return 0;<br />
}
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
/* yılın kaçıncı günü olduğunu hesaplar ve o<br />
günü gönderirir */<br />
int yilin_gunu(int gun, int ay, int yil)<br />
{<br />
int ygun = gun;<br />
switch(ay-1)<br />
{<br />
case 12: ygun += 31;<br />
case 11: ygun += 30;<br />
case 10: ygun += 31;<br />
case 9: ygun += 30;<br />
case 8: ygun += 31;<br />
case 7: ygun += 31;<br />
case 6: ygun += 30;<br />
case 5: ygun += 31;<br />
case 4: ygun += 30;<br />
case 3: ygun += 31;<br />
case 2: ygun += 28 + artik_yil(yil); /*<br />
28+1 veya 28+0 */<br />
case 1: ygun += 31;<br />
}<br />
}<br />
return ygun;<br />
ÇIKTI<br />
01 08 2003 yilinin<br />
213. gunudur<br />
8.7 Makro Fonksiyon Tanımlaması<br />
Başlık dosyalarında, bol miktarda makro fonksiyon uygulamalarına rastlanır. Makro<br />
tanımlaması #define önişlemci komutu kullanılarak yapılır. Örneğin aşağıdaki makro<br />
fonksiyonlar geçerlidir.<br />
#define kare(x) (x)*(x)<br />
#define delta(a,b,c) ((b)*(b)-4*(a)(c))<br />
#define yaz() puts("Devam etmek için bir tuşa basın...")<br />
Bu şekilde tanımlanan fonksiyonların kullanımı diğerleri gibidir. Yalnızca programın başında<br />
tanımlanır. Ancak, bu tanımlamalarla fonksiyon bellekte bir yer işgal etmez. Basit bir makro<br />
fonksiyon uygulaması Program 8.6'da gösterilmiştir. buyuk(a,b) makrosu a>b ise a değerini<br />
aksi halde b değerini gönderir.<br />
Program 8.6: Makro fonksiyon uygulaması<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
/* 08prg06.c: makro fonksiyon uygulaması */<br />
#include <br />
#define buyuk(a,b) ( (a>b) ? a:b)
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
ÇIKTI<br />
int main()<br />
{<br />
int x,y,eb;<br />
printf("iki sayı girin: ");<br />
scanf("%d,%d",&x,&y);<br />
eb = buyuk(x,y);<br />
printf("buyuk olan %d\n",eb);<br />
return 0;<br />
}<br />
iki sayı girin: 8,6<br />
buyuk olan 8<br />
<strong>Ders</strong> 9: Fonksiyonlar II (Alt programlar)<br />
• <strong>Giriş</strong><br />
• 9.1 Esnek Argümanlı Fonksiyonlar<br />
• 9.2 main Fonksiyonu<br />
• 9.3 main Fonksiyonuna Parametre Aktarımı<br />
• 9.4 Komut Satırı Örnekleri<br />
<strong>Giriş</strong><br />
Bu kısımda, esnek argümanlı fonksiyonlar, main() fonksiyonu ve komut satırından main()<br />
fonksiyonuna parametre aktarımı incelenektir.<br />
9.1 Esnek Argümanlı Fonksiyonlar<br />
Aşağıdaki gibi üçüncü dereceden bir polinom düşünelim:<br />
P(x) = a + bx + cx 2 + dx 3<br />
burada a, b, c, d katsayıları gerçel sayı sabitleridir. Bu polinomu temsil eden en basit<br />
fonksiyon şöyle tanımlanabilir.<br />
double p(double x, double a, double b, double c, double d)<br />
{<br />
double p = a + b*x + c*x*x + d*x*x*x;
}<br />
return p;<br />
Buna göre, x = 1.7 için, P(x) = 1 - 2x değerini hesaplamak için bu fonksiyon aşağıdaki gibi<br />
çağırılmalıdır:<br />
sonuc = p(1.7, 1.0, -2.0, 0.0, 0.0);<br />
Burada, kullanılmayan katsayılar için 0.0 değeri mutlaka fonksiyona geçirilmelidir.<br />
Kullanılmayan argumanlar geçirilmeden de fonksiyonu çağırmak mümkündür. C++, Fortran<br />
90 gibi dillerde olduğu gibi, C Programlama Dili, kullanıcılarına argümanları esnek olarak<br />
geçirme imkanı verir. Bunun anlamı, belli kurallar sağlandığında, p() fonksiyonu aşağıdaki<br />
gibi çağrılabilmesidir:<br />
/* x n a b */<br />
sonuc = p(1.7, 2, 1.0, -2.0);<br />
Esnek argümanlar için iki temel kural vardır:<br />
• Esnek argümanlar kullanımı isteğe bağlıdır.<br />
• Esnek argümanları oluşturan küme ardışık olarak listeye eklenmelidir.<br />
Bu türden argümanlar, aşağıdaki gibi, fonksiyonun parametre listesi kısmında ... ile<br />
belirtilir.<br />
double p(double x, int n, ...)<br />
{<br />
}<br />
Esnek Argumanlı Fonksiyon tanımlaması yapabilmek için stdarg.h kütüphanesinde üç tane<br />
makro fonksiyon tanımlanmıştır. Bu fonksiyonlar Tablo 9.1'de listelenmiştir.<br />
Tablo 9.1: stdarg.h'te tanımlı tip ve makro fonksiyonlar<br />
Tip / Fonksiyon Açıklama<br />
va_list ardışık esnek argümalar için tip belirleyici<br />
va_start(ap,<br />
n)<br />
va_arg(ap,<br />
tip)<br />
va_end(ap)<br />
va_list tipinde bildirilmiş ap göstericisi için bellekten n elemanlı yer<br />
ayırır.<br />
Veri tipi tip ile belirlenmiş küme elemanlarına eriştirir.<br />
va_list tipinde bildirilmiş ap göstericisi için bellekten bölgeyi boşaltır.<br />
Bu kurallar ışığında, p() fonksiyonunun genel kullanımı Program 9.1'de gösterilmiştir. p(),<br />
kendisine parametre olarak gelen x, n ve a i katsayılarına göre<br />
P(x,n) = a 0 + a 1 x + a 2 x 2 + ... + a n x n<br />
polinomu hesaplar. a i (i = 0, 1, 2, ..., n) katsayları esnek argüman olarak bildirilmiştir.<br />
Program 9.1: Sonu -1 ile biten kümeyi ekrana yazar<br />
01:<br />
02:<br />
03:<br />
04:<br />
/* 09prg01.c: Polinom hesabı */<br />
#include <br />
#include
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
50:<br />
51:<br />
52:<br />
53:<br />
54:<br />
55:<br />
56:<br />
57:<br />
58:<br />
59:<br />
60:<br />
61:<br />
62:<br />
#include <br />
/* fonksiyon örneği */<br />
double p(double, int, ...);<br />
int main(void){<br />
double x = 1.7;<br />
printf("x = %lf icin:\n",x);<br />
printf("p(x, 1, 1.0) = %lf\n",<br />
p(x, 1, 1.0));<br />
printf("p(x, 2, 1.0, -2.0) = %lf\n",<br />
p(x, 2, 1.0, -2.0));<br />
printf("p(x, 3, 1.0, -2.0, 0.2) = %lf\n",<br />
p(x, 3, 1.0, -2.0, 0.2));<br />
printf("p(x, 4, 1.0, -2.0, 0.2, 1.1) =<br />
%lf\n",<br />
p(x, 4, 1.0, -2.0, 0.2, 1.1));<br />
printf("p(x, 5, 1.0, -2.0, 0.2, 1.1, -0.6) =<br />
%lf\n",<br />
p(x, 5, 1.0, -2.0, 0.2, 1.1, -0.6));<br />
}<br />
return 0;<br />
/* Verilen x, n ve ai katsayıları için,<br />
P(x,n) = a0 + a1*x + a2*x^2 + ... + an*x^n<br />
polinomu hesaplar.<br />
a0, a1, ..., an katsayları esnek arguman<br />
olarak bildirilmiştir. */<br />
double p(double x, int n, ...)<br />
{<br />
double a, t = 0.0;<br />
int i;<br />
/* arguman göstericisi; ag va_list tipinde */<br />
va_list ag;<br />
/* ag için bellekten n adet hücre ayır */<br />
va_start(ag, n);<br />
for(i=0; i
}<br />
ÇIKTI<br />
x = 1.700000 icin:<br />
p(x, 1, 1.0) = 1.000000<br />
p(x, 2, 1.0, -2.0) = -2.400000<br />
p(x, 3, 1.0, -2.0, 0.2) = -1.822000<br />
p(x, 4, 1.0, -2.0, 0.2, 1.1) = 3.582300<br />
p(x, 5, 1.0, -2.0, 0.2, 1.1, -0.6) = -1.428960<br />
Program 9.2'de, argümanları esnek olarak bildirilmiş topla(int n, ...) fonksiyonu, n tane<br />
tamsayının sayının toplamını hesaplar.<br />
Program 9.2: n tane sayının toplamını hesaplar<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
/* 09prg02.c<br />
n tane sayının toplamının hesaplanması */<br />
#include <br />
#include <br />
int topla(int, ...);<br />
int main(void)<br />
{<br />
printf("topla(2, 11,22)<br />
topla(2, 11,22));<br />
printf("topla(3, 11,22,33)<br />
topla(3, 11,22,33));<br />
printf("topla(4, 11,22,33,44)<br />
topla(4, 11,22,33,44));<br />
= %d\n",<br />
= %d\n",<br />
= %d\n",<br />
printf("topla(5, 11,22,33,44,55) = %d\n",<br />
topla(5, 11,22,33,44,55));<br />
printf("topla(6, 11,22,33,44,55,66) = %d\n",<br />
topla(6, 11,22,33,44,66,66));<br />
return 0;<br />
}<br />
/* Esnek argumanla tanımlanmış n tane tamsayının<br />
sayının<br />
toplamını gönderir */<br />
int topla(int n, ...)<br />
{<br />
va_list ap;<br />
int i, top = 0;<br />
va_start(ap, n);<br />
for (i=1; i
ÇIKTI<br />
topla(2, 11,22) = 33<br />
topla(3, 11,22,33) = 66<br />
topla(3, 11,22,33,44) = 110<br />
topla(5, 11,22,33,44,55) = 165<br />
topla(6, 11,22,33,44,55,66) = 242<br />
Argüman sayısı bilidirilmeden de bir küme üzerinde işlem yapılabilir. Ancak bu durumda<br />
kümenin boyutu başka bir yöntemle hesaplanmalıdır. Program 9.3'de, argümanları esnek<br />
olarak bildirilmiş argyaz(int arg, ...) fonksiyonu, son elemanı -1 olan bir kümenin<br />
elemanlarını ekrana yazar. Kümenin sonu (yani boyutu) -1 ile belirlenmiş olur.<br />
Program 9.3: Sonu -1 ile biten kümeyi ekrana yazar<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
/* 09prg03.c: Esnek argumanların yazdırılması<br />
*/<br />
#include <br />
#include <br />
/* herbiri int tipinde ve sonu -1 ile biten<br />
kümeyi ekrana yazar */<br />
void argyaz(int arg, ...)<br />
{<br />
va_list ap;<br />
int i;<br />
}<br />
va_start(ap, arg);<br />
for (i = arg; i != -1; i = va_arg(ap, int))<br />
printf("%d ", i);<br />
va_end(ap);<br />
putchar('\n');<br />
int main(void)<br />
{<br />
argyaz(5, 2, 14, 84, 97, 15, 24, 48, -1);<br />
argyaz(84, 51, -1);<br />
argyaz(-1);<br />
argyaz(1, -1);<br />
}<br />
ÇIKTI<br />
return 0;<br />
5 2 14 84 97 15 24 48<br />
84 51<br />
1
9.2 main Fonksiyonu<br />
Ana program anlamına gelen main de bir fonksiyondur. C programlarının başlangıcı ve sonu<br />
bu fonksiyonla belirlenir. Buna göre, bir C (veya C++) programı sadece bir tane main<br />
içerebilir.<br />
main fonksiyonu da geri dönüş değeri kullanabilir. main fonksiyonunun geri dönüş değerinin<br />
görevi, programın çalışması bittikten sonra sonucu işletim sistemine göndermektir. Program<br />
içinde return deyimi ile iletilen değer 0 olduğunda, bu işletim sistemi tarafından "program<br />
başarılı olarak sonlandı" olarak değerlendir. Başka bir deyişle,<br />
return 0;<br />
program, kullanıcının talebi doğrultusunda (olumlu anlamda) "yapması gereken işi yaptı"<br />
mesajını işletim sistemine bildirilir. 0'dan farklı herhangi bir değer ise programın sorunlu<br />
sonlandığı anlamına gelecektir. Bu yüzden bütün C programlarımızın sonuna return 0; ilave<br />
ediyoruz.<br />
Bazı programcılar main fonksiyonunun başına şey yazmaz.<br />
main()<br />
{<br />
...<br />
return 0;<br />
}<br />
Bu durumda geri dönüş değeri tamsayı (int) kabul edilir. Bu şekilde kullanımda, yeni tip<br />
derleyiciler uyarı (warning) mesajı verebilirler. Bu yüzden, aşağıdaki kullanımı tavsiye<br />
ediyoruz.<br />
int main()<br />
{<br />
...<br />
return 0;<br />
}<br />
Eğer ana programdan bir değer döndürülmeyecekse, main fonksiyonunun önüne aşağıdaki<br />
gibi void deyimi eklelenmelidir. Ancak bu bazı derleyiciler tarafından hata olarak<br />
yorumlanır. Bu nedenle, aşağıdaki kullanımlar pek tavsiye edilmez.<br />
yada<br />
void main()<br />
{<br />
...<br />
}<br />
void main(void)<br />
{<br />
...<br />
}
9.3 main() Fonksiyonuna Parametre Aktarımı<br />
NOT<br />
Bu ve sonraki kısımda (9.3) anlatılanlar Bölüm 10, 11 ve 16<br />
okunduktan sonra daha iyi anlaşılacaktır. Ancak, konu<br />
akışını bozmamak için, bu konunun buraya konması uygun<br />
bulunmuştur.<br />
Ana programa parametre aktarımı, derlenmiş (çalıştırılabilir) bir program komut satırından<br />
(işletim sistemi ortamından) çalıştırılacağı zaman yapılır. Parametre aktarımı, programın adı<br />
yazılıp bir boşluk bırakıldıktan hemen sonra yapılır. Parametreler, komut satırından sayısal<br />
olarak girilse bile program içinde karakter topluluğu (string) olarak gelir. Bu durumda, bu<br />
ifadeleri sayısal değerlere çeviren (atoi(), atol(), atof() gibi) fonksiyonlar kullanılır.<br />
Genel kullanım biçimi:<br />
...<br />
int main(arguman_sayısı, arguman_vektörü)<br />
int arguman_sayısı;<br />
char *arguman_vektörü[];<br />
{<br />
.<br />
.<br />
.<br />
if(arguman_sayısı < ...){<br />
printf("Eksik parametre !\n");<br />
exit(1);<br />
}<br />
if(arguman_sayısı > ...){<br />
printf("Cok fazla parametre !\n");<br />
exit(1);<br />
}<br />
.<br />
... arguman_vektörü[0] ... /* 1. eleman program adı */<br />
... arguman_vektörü[1] ... /* 2. eleman 1. parametre */<br />
... arguman_vektörü[2] ... /* 3. eleman 2. parametre */<br />
.<br />
}<br />
Program 9.1, komut satırından girilen iki sayının toplamını hesaplar.<br />
Program 9.1: Komut satırından girilen iki sayının toplamını hesaplar<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
/* topla.c<br />
Komut satırından girilen iki sayının<br />
toplamını hesaplar.<br />
Kullanımı: topla sayı1 sayı2 */<br />
#include <br />
#include <br />
int main(int argsay, char *argvek[]){<br />
int toplam;<br />
if(argsay < 3){<br />
printf("Eksik parametre !\n");
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
}<br />
}<br />
exit(1);<br />
if(argsay > 3){<br />
printf("Cok fazla parametre !\n");<br />
exit(1);<br />
}<br />
toplam = atoi(argvek[1]) + atoi(argvek[2]);<br />
printf("Toplamlari %d\n",toplam);<br />
return 0;<br />
Program 9.1, topla.c derlendikten sonra üretilen Windows ortamında üretilen topla.exe ve<br />
Linux ortamında üretilen topla dosyasının çalıştırılması şöyledir:<br />
• Turbo C 2.0 Derlecisi kullanılarak (topla.c programı C:\TC adlı dizinin altına<br />
kaydedildiği<br />
varsayılmıştır)
• Dev-C++ Derlecisi kullanılarak (topla.c programı C:\Users\bingul\Desktop<br />
adlı dizinin altına kaydedildiği varsayılmıştır)<br />
• Linux gcc derleyicisi kullanılarak (topla.c programı /home/bingul/ adlı dizinin<br />
altına kaydedildiği varsayılmıştır)<br />
Komut satırında yazılan dosya adı dahil toplam parametre sayısı 3 tür. Bunlar:<br />
topla 4 9<br />
| | |<br />
V V V<br />
argvek[0] argvek[1] argvek[2]<br />
şeklindedir.<br />
Program 9.1, komut satırından girilen iki sayının toplamını hesaplar. Bu programın daha<br />
gelişmiş hali Program 9.2'de verilmiştir. Program 9.2 çalıştırıldığında, komut satırından<br />
girilen iki sayı ve bir operatör bekler. Girilen operatöre göre beş aritmetik işlemden birinini<br />
yapıp sonucu ekranda gösterir. İnceleyiniz.
Program 9.2: Komut satırından girilen iki sayı ve bir operatör bilgisine göre 5 işlemden<br />
birini hesaplar<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
/* hesap.c: Komut satırından girilen iki sayı<br />
üzerinde 5 işlem yapar.<br />
*/<br />
Kullanımı: hesap <br />
#include <br />
#include <br />
int main(int args, char **argv)<br />
{<br />
int s1, s2;<br />
float sonuc;<br />
char op;<br />
if(args != 4){<br />
printf("Eksik veya fazla parametre !\n");<br />
printf("Kullanimi: hesap <br />
\n");<br />
return 1;<br />
}<br />
s1 = atoi(argv[1]); /* 1. parametre:<br />
sayi1 */<br />
op = argv[2][0]; /* 2. parametrenin<br />
ilk karakteri: operator */<br />
s2 = atoi(argv[3]); /* 3. parametre:<br />
sayi2 */<br />
switch(op)<br />
{<br />
case '+':<br />
sonuc = s1 + s2; break;<br />
case '-':<br />
sonuc = s1 - s2; break;<br />
case '*':<br />
sonuc = s1 * s2; break;<br />
case '/':<br />
sonuc = (float) s1 / s2; break;<br />
case '%':<br />
sonuc = s1 % s2; break;<br />
default:<br />
sonuc = 0.0;<br />
printf("Yanlis operator %c\n",op);<br />
printf("Operatorler: +, -, *, / veya<br />
%%\n");<br />
}<br />
printf("sonuc = %f\n",sonuc);<br />
return 0;<br />
}<br />
Program hesap.c adlı dosyada saklandığı varsayılırsa, programın Linux ortamındaki çıktısı<br />
şöyle olacaktır:
9.4 Komut Satırı Örnekleri<br />
Aşağıda verilen iki program, Linux işletim sistemindeki cp ve wc komutlarının basit kaynak<br />
kodlarıdır:<br />
• cp (copy) komutu, bir text dosyasının kopyasını oluşturur.<br />
Kullanımı: cp kaynak_dosya hedef_dosya<br />
• wc (word count) komutu, bir dosyanın kaç karakter, kelime satırdan oluştuğunu bulup<br />
ekrana<br />
yazar.<br />
Kullanımı: wc dosya_adı<br />
<strong>Ders</strong> 10: Diziler<br />
• <strong>Giriş</strong><br />
• 10.1 Dizilerin Bildirimi<br />
• 10.2 Dizilere Başlangıç Değeri Verme<br />
• 10.3 Dizileri Yazdırma/Okuma<br />
• 10.4 Sıralama (Sorting)<br />
• 10.5 Karakter Dizileri (Strings)<br />
• 10.6 Çok Boyutlu Diziler<br />
• 10.7 Dizilerin Fonksiyonlarda Kullanılması<br />
<strong>Giriş</strong>
Dizi, aynı tipteki verilere tek bir isimle erişmek için kullanılan bir kümedir. Bu küme<br />
matematikteki küme kavramından biraz farklıdır. Bir dizi bildirildikten sonra, dizinin bütün<br />
elemanları bellekte peşpeşe saklanır [1]. Bu yüzden dizilere tek bir isim altında çok sayıda<br />
değişken içeren bellek bölgesi de denir. Buna göre, bir diziyi dizi yapan iki temel özellik<br />
vardır [2]:<br />
• dizi elemanların bellekte (program çalıştığı sürece) sürekli biçimde bulunması<br />
• dizi elemanların aynı türden değişkenler olması<br />
10.1 Dizilerin Bildirimi<br />
Bir dizi çok sayıda değişken barındırdığından, bunları birbirinden ayırdetmek için indis adı<br />
verilen bir bilgiye ihtiyaç vardır. C Programlama Dili'nde, bir dizi hangi tipte tanımlanmış<br />
olursa olsun başlangıç indisi her zaman 0'dır.<br />
Bir dizinin bildirim işleminin genel biçimi söyledir:<br />
veriTipi dizi_adı[eleman_sayısı];<br />
Örneğin, 5 elemanlı, kütle verilerini bellekte tutmak için, kutle dizisi şöyle tanımlanabilir:<br />
float kutle[5];<br />
Bu dizinin elemanlarına bir değer atama işlemi şöyle yapılabilir:<br />
kutle[0] = 8.471<br />
kutle[1] = 3.683<br />
kutle[2] = 9.107<br />
kutle[3] = 4.739<br />
kutle[4] = 3.918<br />
NOT<br />
1. elemanın indisi 0,<br />
5. elemanın indisinin 4 olduğuna dikkat edin.<br />
Bildirim sırasında dizilerin eleman sayısı tamsayı türünden bir sabit ifadesiyle belirtilmesi<br />
zorunludur. Örneğin:<br />
int n = 100;<br />
int a[n];<br />
şeklindeki tanımlama, dizi uzunluğunun değişken (n) ile belirtilmesi nedeniyle geçersizdir.<br />
Bunun yerine, dizilerin eleman sayısı aşağıdaki gibi sembolik sabitlerle belirtmek<br />
mümkündür.<br />
#define n 100<br />
...<br />
int a[n];<br />
Bir dizinin bellekte kapladığı alanın bayt cinsinden karşılığı sizeof operatörü ile<br />
öğrenilebilir.<br />
int a[5], b, c;<br />
...<br />
b = sizeof(a); /* bellekte kapladığı alan: b = 4*5 =<br />
20 bayt */
*/<br />
c = sizeof(a) / sizeof(int); /* Dizinin boyutu : c = 20/4 = 5<br />
10.2 Dizilere Başlangıç Değeri Verme<br />
Bir diziye başlangıç değerleri aşağıdaki gibi kısa formda atanabilir:<br />
float kutle[5]= { 8.471, 3.683, 9.107, 4.739, 3.918 };<br />
int maliyet[3] = { 25, 72, 94 };<br />
double a[4] = { 10.0, 5.2, 7.5, 0.0};<br />
Küme parantezlerinin sonlandırıcı ; karakteri ile bittiğine dikkat ediniz.<br />
Bir dizinin uzunluğu belirtilmeden de başlangıç değeri atamak mümkündür.<br />
int a[] = { 100, 200, 300, 400 };<br />
float v[] = { 9.8, 11.0, 7.5, 0.0, 12.5};<br />
Derleyici bu şekilde bir atama ile karşılaştığında, küme parantezi içindeki eleman sayısını<br />
hesaplar ve dizinin o uzunlukta açıldığını varsayar. Yukarıdaki örnekte, a dizisinin 4, v<br />
dizisinin 5 elemanlı olduğu varsayılır.<br />
10.3 Dizileri Yazdırma/Okuma<br />
printf ve scanf fonksiyonları bir dizinin okunması ve yazdırılması için de kullanılır.<br />
Örneğin bir A dizisinin aşağıdaki gibi bildirildiğini varsayalım:<br />
int A[10];<br />
Bu dizinin elemanlarını klavyeden okumak için:<br />
for(i=0; i
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
ÇIKTI<br />
#include <br />
#define N 10<br />
int main()<br />
{<br />
int i;<br />
float x[N], ort, toplam = 0.0;<br />
for(i=0; i
Program 10.2: 10 sayının ortalamasını ve standart sapmasını hesaplar<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
/* 10prg02.c<br />
10 tane sayının aritmetik ortlamasını ve<br />
standart sapmasını hespalar. */<br />
#include <br />
#include <br />
#define N 10<br />
int main(void)<br />
{<br />
int i;<br />
float x[N], toplam = 0.0, ort, std_sap = 0.0;<br />
}<br />
ÇIKTI<br />
/* ortalama hesabı */<br />
for(i=0; i
Bazı uygulamalarda bir grup sayının büyükten küçüğe, veya küçükten büyüğe, doğru<br />
sıralanması gerekebilir. Bu tip sıralama problemleri için çeşitli algoritmalar geliştirilmiştir.<br />
Sıralama mantığını anlamadan önce bir dizinin en büyük (veya en küçük) elemanının nasıl<br />
bulunduğunu inceleyelim. Program 10.3, bir dizinin en büyük elemanını bulup ekrana yazar.<br />
Program 10.3: Bir dizinin en büyük elemanının bulunuşu<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
ÇIKTI<br />
/* 10prg03.c<br />
Bir dizinin en büyük elemanını bulup ekrana<br />
yazar */<br />
#include <br />
int main(void)<br />
{<br />
int a[10] = {100, -250, 400, 125 ,550, 900,<br />
689, 450, 347, 700};<br />
int k, eb;<br />
/* ilk eleman en büyük kabul ediliyor */<br />
eb = a[0];<br />
for(k=1; keb ) eb = a[k];<br />
printf("En buyuk eleman = %d\n",eb);<br />
return 0;<br />
}<br />
En buyuk eleman = 900<br />
En büyük sayıyı bulan bu algoritma oldukça kolaydır. 12. satırda eb = a[0]; ataması ile<br />
dizinin ilk elemanının en büyük olduğu varsayılır. Daha sonra büyüğe rastladıkça (15. satır)<br />
eb = a[k]; ile eb değişmektedir.<br />
Program 10.3 bir dizinin en büyük elemanını bulur. En büyük elemanın kaçıncı indis (eleman)<br />
olduğu sorgulanmak istendiğinde: programdaki koşul yapısını aşağıdaki gibi değiştirmek<br />
yeterlidir. eb değiştikçe, i değişkeni en büyük elemanın indisini tutar.<br />
for(k=0; k eb ){<br />
eb = a[k];<br />
i = k;<br />
}<br />
}<br />
n elemanlı bir dizinin, elemanlarını büyükten küçüğe doğru sıralamak için çok popüler iki<br />
algoritma aşağıda verilmiştir[2].<br />
Seçerek Sıralama (Selection Sort):<br />
En büyük elemanı bul başa koy biçimindeki sıramadır. Algoritmanın uygulaması Program
10.4'de<br />
gösterilmiştir.<br />
Bu algoritmada kullanılan kombinasyon sayısı (algoritmanın karmaşıklığı): n*(n-1)/2 dir.<br />
Program 10.4: Seçerek Sıralama (Selection Sort) Algoritması<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
ÇIKTI<br />
/* 09prg04.c<br />
Seçerek Sıralama (Selection Sort) Algoritması<br />
ile bir<br />
dizinin elemanlarını büyükten küçüğe dogru<br />
sıralar */<br />
#include <br />
#define n 10<br />
int main(void)<br />
{<br />
int a[n] = {100, -250, 400, 125 ,550, 900,<br />
689, 450, 347, 700};<br />
int i, j, k, eb;<br />
/* Dizinin kendisi */<br />
printf("Once : ");<br />
for(k=0;k
Kabarcık Sıralama (Bubble Sort):<br />
Yanyana elemanları karşılaştırarak yer değiştir biçimde sıralamadır. Algoritmanın uygulaması<br />
Program 10.5'de gösterilmiştir.<br />
Bu algoritmanın karmaşıklığı: (n-1) 2 dir.<br />
Program 10.5: Kabarcık Sıralama (Bubble Sort) Algoritması<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
/* 09prg05.c<br />
Kabarcık Sıralama (Bubble Sort) Algoritması<br />
ile bir<br />
dizinin elemanlarını büyükten küçüğe dogru<br />
sıralar */<br />
#include <br />
#define n 10<br />
int main(void)<br />
{<br />
int a[n] = {100, -250, 400, 125 ,550, 900,<br />
689, 450, 347, 700};<br />
int j,k,gecici;<br />
/* Dizinin kendisi */<br />
printf("Once : ");<br />
for(k=0; k
C dilinde, karakter dizileri oldukça sık kullanılır. Sadece karakter dizilerine özel olarak,<br />
karakter dizilerinin sonuna sonlandırcı karakter olarak adlandırılan bir simge eklenir.<br />
Sonlandırcı karakter, işlemlerin hızlı ve etkin bir biçimde yapılabilmesine olanak sağlar[2].<br />
Sonlandırıcı karakter:<br />
• dizinin bittiği yeri gösterir,<br />
• ASCII tablosunun sıfır numaralı ('\0') karakteridir.<br />
Karakter dizilerine iki şekilde başlangıç değeri verilebilir.<br />
char s[7] = {'d','e','n','e','m','e','\0'};<br />
yada<br />
char s[7] = "deneme";<br />
Birinci tanımlamada sonlandırıcı karakter programcı tarafından konmalıdır. Ikinci<br />
tanımlamada ise buna gerek yoktur. Çünkü, sonlandırıcı karakter bu atamayla, derleyici<br />
tarafından eklenir.<br />
NOT<br />
char s[7] = "deneme";<br />
ataması geçeli olmasına rağmen, aşağıdaki atama<br />
geçersizdir:<br />
char<br />
char s = "deneme";<br />
Karakter dizileri gets() fonksiyonu ile klavyeden okunabilir.<br />
char ad[20];<br />
...<br />
gets(ad);<br />
s[7];<br />
Program 10.6'da bir karakter dizisinin uzunluğunun nasıl bulunduğu, Program 10.7'de ise bir<br />
karakter dizisinin tersyüz edilişi gösterilmiştir. İnceleyiniz.<br />
Program 10.6: Bir karakter dizisinin uzunluğunu bulur<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
/* 09prg06.c: Bir karakter dizisinin uzunluğunu<br />
bulur */<br />
#include <br />
int main(void)<br />
{<br />
char s[40];<br />
int k = 0;<br />
/* diziyi oku */<br />
printf("Bir seyler yazin : ");<br />
gets(s);<br />
/* sonlandırıcı karaktere kadar karakterleri<br />
say */<br />
while( s[k]!='\0' )<br />
k++;
20:<br />
21:<br />
ÇIKTI<br />
printf("Dizinin uzunlugu : %d\n",k);<br />
return 0;<br />
}<br />
Birseyler yazin : Gazintep Universitesi<br />
Dizinin uzunlugu : 21<br />
Program 10.7: Bir karakter dizisinin tersini bulur<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
ÇIKTI<br />
/* 09prg07.c: Bir karakter dizisini tersyüz eder<br />
*/<br />
#include <br />
int main(void)<br />
{<br />
char s[40], gecici;<br />
int i, n;<br />
/* diziyi oku */<br />
printf("Bir seyler yazin : ");<br />
gets(s);<br />
/* sonlandırıcı karaktere kadar */<br />
for(n=0; s[n] != '\0'; n++)<br />
;<br />
for(i=0; i
Bir dizi birden çok boyuta sahip olabilir. Örneğin iki boyutlu b dizisi şöyle tanımlanabilir:<br />
float b[9][4];<br />
İki boyutlu diziler matris olarak adlandırılır. ilk boyuta satır, ikinci boyuta sütün denir.<br />
Yukarıda b matrisinin eleman sayısı 9x4=36 dır. Bu durumda, genel olarak bir dizi şöyle<br />
gösterilir:<br />
Tablo 10.1: Dizlerin Bildirimi<br />
Dizi Çeşiti Genel Bildirimi Örnek<br />
Tek boyutlu diziler (Vektörler) tip dizi_adı[eleman_sayısı] int veri[10];<br />
İki boyutlu diziler (Matrisler) tip dizi_adı[satır_sayısı][sutun_sayısı] float mat[5][4<br />
Çok boyutlu diziler tip dizi_adı[boyut_1][boyut_2]...[boyut_n]; double x[2][4]<br />
Çok boyutlu diziler tek boyuta indir generek bellekte tutulurlar. Tek indisli dizilerde olduğu<br />
gibi, çok indisli dizilere de başlangıç değeri vermek mümkün. Örneğin 3 satır ve 4 sütünlu<br />
(3x4=12 elemanlı) bir x matrisinin elemanları şöyle tanımlanabilir:<br />
int x[3][4] = {11,34,42,60, 72,99,10,50, 80,66,21,38};<br />
yada<br />
int x[3][4] = {11,34,42,60, /* 1. satır elemanları */<br />
72,99,10,50, /* 2. satır elemanları */<br />
80,66,21,38}; /* 3. satır elemanları */<br />
Bu matris ekrana matris formunda yazılmak istendiğinde:<br />
for(i=0; i
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
}<br />
int b[SAT][SUT] = {1, 2, 3, 4, 5, 6};<br />
int c[SAT][SUT];<br />
int i, j;<br />
puts("A Matrisi:");<br />
for(i=0; i
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
{<br />
ÇIKTI<br />
int a[N][N], b[N][N], c[N][N];<br />
int i,j,k,toplam;<br />
puts("A Matrisini girin:");<br />
for(i=0; i
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
/* 10prg10.c: bir dizinin yazdırılması */<br />
#include <br />
void dizi_yaz(float x[], int n);<br />
int main(){<br />
float kutle[5]= { 8.471, 3.683, 9.107, 4.739,<br />
3.918 };<br />
}<br />
dizi_yaz(kutle, 5);<br />
return 0;<br />
void dizi_yaz(float x[], int n)<br />
{<br />
int i;<br />
}<br />
ÇIKTI<br />
for(i=0; i
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
int enBuyuk(int a[], int n)<br />
{<br />
int k, en_buyuk_eleman;<br />
}<br />
ÇIKTI<br />
/* ilk eleman en büyük kabul ediliyor */<br />
en_buyuk_eleman = a[0];<br />
for(k=1; ken_buyuk_eleman )<br />
en_buyuk_eleman = a[k];<br />
return en_buyuk_eleman;<br />
int main()<br />
{<br />
int a[10] = {100, -250, 400, 125 ,550, 900,<br />
689, 450, 347, 700};<br />
int eb;<br />
eb = enBuyuk(a,10);<br />
printf("En buyuk eleman = %d\n",eb);<br />
return 0;<br />
}<br />
En buyuk eleman = 900<br />
Son olarak, bir kare matrisin iz (trace) değerini bulup ekrana yazan bir fonksiyon Program<br />
10.12'de verilmişitir. Bir kare matrisin izi, matrisin asal köşegen üzerinde bulunan<br />
elemanların toplamı olarak tanımlıdır. Bu tanıma göre, aşağıdaki matrisin izi 2 + 8 + 4 = 14<br />
tür..<br />
İz matematiksel olarak şöyle gösterilir:<br />
Program 10.12: Bir matrisin izi<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
/* 10prg12.c<br />
Bir 3x3 bir matrisin izinin fonksiyonla<br />
bulunması */<br />
#include <br />
double iz(double a[][3], int);<br />
int main()
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
{<br />
double a[3][3], izA;<br />
int i,j;<br />
puts("matrisi girin:");<br />
for(i=0; i
<strong>Giriş</strong><br />
Hemen hemen bütün programlama dillerinin temelinde gösterici (pointer) veri tipi<br />
bulunmaktadır. Bir çok dil gösterici kullanımını kullanıcıya sunmamıştır veya çok sınırlı<br />
olarak sunmuştur. Fakat C Progrmalam Dili'nde göstericiler yoğun olarak kullanılır. Hatta<br />
gösterici kavramı C dilinin bel kemiğidir. Kavranması biraz güç olan göstericiler için -latife<br />
yapılıp- C kullanıcılarını "gösterici kullanabilenler ve kullanmayanlar" olmak üzere iki gruba<br />
ayıranlar da olmuştur. Özetle, bir C programcısı gösterici kavramını anlamadan C diline<br />
hakim olamaz.<br />
Türkçe yazılan C kitaplarda pointer kelimesi yerine aşağıdaki ifadelerden biri karşılaşılabilir:<br />
pointer = işaretçi = gösterici = gösterge<br />
Anlatımda, gösterici terimini kullanacağız.<br />
11.1 Değişken ve Bellek Adresi<br />
Bilgisayarın ana belleği (RAM) sıralı kaydetme gözlerinden oluşmuştur. Her göze bir adres<br />
atanmıştır. Bu adreslerin değerleri 0 ila belleğin sahip olduğu üst değere bağlı olarak<br />
değişebilir. Örneğin 64 MB bir bellek, 64*1024*1024 = 67108864 adet gözden oluşur.<br />
Bir programlama dillinde, belli bir tipte değişken tanımlanıp ve bir değer atandığında, o<br />
değişkene dört temel özellik eşlik eder:<br />
1. değişkenin adı<br />
2. değişkenin tipi<br />
3. değişkenin sahip olduğu değer (içerik)<br />
4. değişkenin bellekteki adresi<br />
Örneğin tam adlı bir tamsayı değişkenini aşağıdaki gibi tanımladığımızı varsayalım:<br />
int tam = 33;<br />
Bu değişken için, int tipinde bellekte (genellikle herbiri 1 bayt olan 4 bayt büyüklüğünde) bir<br />
hücre ayrılır ve o hücreye 33 sayısı ikilik (binary) sayı sitemindeki karşılığı olan 4 baytlık (32<br />
bitlik):<br />
00000000 00000000 00000000 00100001<br />
sayısı elektronik olarak yazılır. tam değişkenine ait dört temel özellik Şekil 11.1'deki gibi<br />
gösterilebilir:
Şekil 11.1: Bir değişkene eşlik eden dört temel özellik<br />
Bellek adresleri genellikle onaltılık (hexadecimal) sayı sisteminde ifade edilir. 0x3fffd14<br />
sayısı onluk (decimal) sayı sisteminde 67108116 sayına karşık gelir. Bunun anlamı, tam<br />
değişkeni, program çalıştığı sürece, bellekte 67108116. - 67108120. numaralı gözler<br />
arasındaki 4 baytlık hücreyi işgal edecek olmasıdır. Şekil 11.1'deki gösterim, basit ama<br />
anlaşılır bir tasvirdir. Gerçekte, int tipindeki tam değişkeninin bellekteki yerleşimi ve içeriği<br />
(değeri) Şekil 11.2'de gösterildiği gibi olacaktır.<br />
Şekil 11.2: tam adlı değişkenin bellekteki gerçek konumu ve ikilik düzendeki içeriği<br />
Değişkenin saklı olduğu adres, & karakteri ile tanımlı adres operatörü ile öğrenilebilir. Bu<br />
operatör bir değişkenin önüne konursa, o değişkenin içeriği ile değil adresi ile ilgileniliyor<br />
anlamına gelir. Aşağıdaki program parçasının:<br />
çıktısı:<br />
int tam = 33;<br />
printf("icerik: %d\n",tam);<br />
printf("adres : %p\n",&tam);<br />
icerik: 33
adres : 3fffd14<br />
şeklindedir. Burada birinci satır tam değişkeninin içeriği, ikinci ise adresidir. Adres<br />
yazdırılırken %p tip belirleyicisinin kullanıldığına dikkat ediniz.<br />
11.2 Gösterici Nedir?<br />
Gösterici, bellek alanındaki bir gözün adresinin saklandığı değişkendir. Göstericilere veriler<br />
(yani değişkenlerin içeriği) değil de, o verilerin bellekte saklı olduğu hücrenin başlangıç<br />
adresleri atanır. Kısaca gösterici adres tutan bir değişkendir.<br />
Bir gösterici, diğer değişkenler gibi, sayısal bir değişkendir. Bu sebeple kullanılmadan önce<br />
program içinde bildirilmelidir. Gösterici tipindeki değişkenler şöyle tanımlanır:<br />
tip_adı *gösterici_adı;<br />
Burada tip_adı herhangi bir C tip adı olabilir. Değişkenin önünedeki * karakteri<br />
yönlendirme (indirection) operatörü olarak adlandırılır ve bu değişkenin veri değil bir adres<br />
bilgisi tutacağını işaret eder. Örneğin:<br />
char *kr; /* tek bir karakter için */<br />
int *x; /* bir tamsayı için */<br />
float *deger, sonuc; /* deger gösterici tipinde, sonuc sıradan<br />
bir gerçel değişkenler */<br />
Yukarıda bildirilen göstericilerden; kr bir karakterin, x bir tamsayının ve deger bir gerçel<br />
sayının bellekte saklı olduğu yerlerin adreslerini tutar.<br />
Bir göstericiye, bir değişkenin adresini atamak için adres operatörünü kullanabiliriz. Örneğin<br />
tamsayı tipindeki tam adlı bir değişken ve ptam bir gösterici olsun. Derleyicide, aşağıdaki gibi<br />
bir atama yapıldığında:<br />
int *ptam, tam = 33;<br />
.<br />
.<br />
.<br />
ptam = &tam;<br />
ptam göstericisinin tam değişkeninin saklandığı adresi tutacaktır. Bu durum Şekil 11.3'deki<br />
gibi tasvir edilir.
Şekil 11.3: Göstericinin bir değişkenin adresini göstermesi<br />
Şekil 11.3'deki gösterimde, ptam göstericisinin içeriği tam değişkeninin içeriği (33) değil<br />
adresidir (0x3fffd14). Ayrıca, ptam değişkeni, bellekte başka bir hücrede saklandığına ve bu<br />
hücrenin int değil int * tipinde bir bölge olduğuna dikkat ediniz. Buraya kadar anlatılanlar,<br />
Program 11.1'de özetlenmiştir.<br />
Program 11.1: Bir değişkenin içeriğini ve adresini ekrana yazdırma<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
/* 10prg01.c: ilk gösterici programı */<br />
#include <br />
int main()<br />
{<br />
int *ptam, tam = 33;<br />
ptam = &tam;<br />
printf("tam: icerik = %d\n", tam);<br />
printf("tam: adres = %p\n",&tam);<br />
printf("tam: adres = %p\n",ptam);<br />
return 0;<br />
}<br />
7. satırda değişkenler bildirilmiştir. 9. satırdaki atama ile tam değişkeninin adresi, ptam<br />
göstericisine atanmıştır. Bu satırdan itibaren ptam, tam değişkeninin gösterir. 11. satıda tam'ın<br />
içeriği (33 sayısı), 12. ve 13. satırda tam'ın adresi, %p tip karakteri ile, ekrana yazdırılmıştır.<br />
Ekran çıktısı incelendiğinde, &tam ve ptam içereriğinin aynı anlamda olduğu görülür.<br />
ÇIKTI<br />
tam: icerik = 33<br />
tam: adres = 0x3fffd14<br />
tam: adres = 0x3fffd14<br />
tam adlı değişkenin içeriğine ptam gösterici üzerinde de erişilebilir. Bunun için program<br />
içinde ptam değişkeninin önüne yönelendirme operatörü (*) koymak yeterlidir. Yani *ptam,<br />
tam değişkeninin adresini değil içeriğini tutar. Buna göre:<br />
*ptam = 44;
komutuyla, ptam'ın adresini tuttuğu hücreye 44 değeri atanır. Bu durum, Program 11.2'de<br />
gösterilmiştir.<br />
Program 11.2: Bir değişkenin içeriğini ve adresini ekrana yazdırma<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
ÇIKTI<br />
/* 10prg02.c: ikinci gösterici programı */<br />
#include <br />
int main()<br />
{<br />
int *ptam, tam = 33;<br />
ptam = &tam; /* ptam -> tam */<br />
printf("&tam = %p\n",&tam);<br />
printf("ptam = %p\n",ptam);<br />
printf("\n");<br />
printf("tam = %d\n",tam);<br />
printf("*ptam = %d\n",*ptam);<br />
printf("\n");<br />
*ptam = 44; /* tam = 44 anlamında */<br />
printf("tam = %d\n",tam);<br />
printf("*ptam = %d\n",*ptam);<br />
return 0;<br />
}<br />
&tam = 0x3fffd14<br />
ptam = 0x3fffd14<br />
tam = 33<br />
*ptam = 33<br />
tam = 44<br />
*ptam = 44<br />
Özetle ptam = &tam atamasıyla:<br />
• *ptam ve tam, tam adlı değişkenin içeriği ile ilgilidir.<br />
• ptam ve &tam, tam adlı değişkenin adresi ile ilgilidir.<br />
• * yönlendirme ve & adres operatörüdür.<br />
11.3 Gösterici Aritmetiği<br />
Göstericiler kullanılırken, bazen göstericinin gösterdiği adres taban alınıp, o adresten önceki<br />
veya sonraki adreslere erişilmesi istenebilir. Bu durum, göstericiler üzerinde, aritmetik<br />
işlemcilerin kullanılmasını gerektirir. Göstericiler üzerinde yalnızca toplama (+), çıkarma (-),<br />
bir arttırma (++) ve bir eksiltme (--) operatörleri işlemleri yapılabilir.
Aşağıdaki gibi üç tane gösterici bildirilmiş olsun:<br />
char *kar;<br />
int *tam;<br />
double *ger;<br />
Bu göstericiler sırasıyla, bir karakter, bir tamsayı ve bir gerçel sayının bellekte saklanacağı<br />
adreslerini tutar. Herhangi bir anda, tuttukları adresler de sırasıyla 10000 (0x2710), 20000<br />
(0x4e20) ve 30000 (0x7530) olsun. Buna göre aşağıdaki atama işelemlerinin sonucu:<br />
kar++;<br />
tam++;<br />
ger++;<br />
sırasyla 10001 (0x2711), 20004 (0x4e24) ve 30008 (0x7538) olur. Bir göstericiye ekleme<br />
yapıldığında, o anda tuttuğu adres ile eklenen sayı doğrudan toplanmaz. Böyle olsaydı, bu<br />
atamaların sonuçları sırasıyla 10001, 20001 ve 30001 olurdu. Gerçekte, göstericiye bir<br />
eklemek, göstericinin gösterdiği yerdeki veriden hemen sonraki verinin adresini<br />
hesaplamaktır.<br />
Genel olarak, bir göstericiye n sayısını eklemek (veya çıkarmak), bekllekte gösterdiği veriden<br />
sonra (veya önce) gelen n. elemanın adresini hesaplamaktır. Buna göre aşağıdaki atamalar<br />
şöyle yorumlanır.<br />
kar++; /* kar = kar + sizeof(char) */<br />
tam = tam + 5; /* tam = tam + 5*sizeof(int) */<br />
ger = ger - 3; /* ger = ger - 3*sizeof(double) */<br />
Program 11.3, bu bölümde anlatlanları özetlemektedir. İnceleyiniz.<br />
Program 11.3: Gösterici aritmetiği<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
/* 10prg03.c: gösterici aritmetiği */<br />
#include <br />
int main()<br />
{<br />
char *pk, k = 'a';<br />
int *pt, t = 22;<br />
double *pg, g = 5.5;<br />
pk = &k;<br />
pt = &t;<br />
pg = &g;<br />
printf("Onceki adresler: pk= %p pt= %p<br />
pg= %p \n", pk, pt, pg);<br />
pk++;<br />
pt--;<br />
pg = pg + 10;<br />
printf("Sonraki adresler: pk= %p pt= %p<br />
pg= %p \n", pk, pt, pg);
ÇIKTI<br />
return 0;<br />
}<br />
Onceki adresler: pk= 0xbfbbe88f pt= 0xbfbbe888<br />
pg= 0xbfbbe880<br />
Sonraki adresler: pk= 0xbfbbe890 pt= 0xbfbbe884<br />
pg= 0xbfbbe8d0<br />
11.4 Gösterici ve Diziler Arasındaki İlişki<br />
C dilinde göstericiler ve diziler arasında yakın bir ilişki vardır. Bir dizinin adı, dizinin ilk<br />
elemanının adresini saklayan bir göstericidir. Bu yüzden, bir dizinin herhangi bir elemanına<br />
gösterici ile de erişilebilir. Örneğin:<br />
int kutle[5], *p, *q;<br />
şeklinde bir bildirim yapılsın. Buna göre aşağıda yapılan atamalar geçerlidir:<br />
atandı */<br />
atandı */<br />
atandı */<br />
p = &kutle[0]; /* birinci elemanın adresi p göstericisne<br />
p = kutle; /* birinci elemanın adresi p göstericisne<br />
q = &kutle[4]; /* son elemanın adresi q göstericisne<br />
İlk iki satırdaki atamalar aynı anlamdadır. Dizi adı bir gösterici olduğu için, doğrudan aynı<br />
tipteki bir göstericiye atanabilir. Ayrıca, i bir tamsayı olmak üzere,<br />
ile<br />
kutle[i];<br />
*(p+i);<br />
aynı anlamdadır. Bunun sebebi, p göstericisi kutle dizisinin başlangıç adresini tutmuş<br />
olmasıdır. p+i işlemi ile i+1. elemanın adresi, ve *(p+i) ile de bu adresteki değer hesaplanır.<br />
NOT<br />
Bir dizinin, i. elemanına erişmek için *(p+i) işlemi<br />
yapılması zorunludur. Yani<br />
*p+i;<br />
/* p nin gösterdiği değere (dizinin ilk<br />
elemanına) i sayısını ekle */<br />
*(p+i); /* p nin gösterdiği adresten i blok<br />
ötedeki sayıyı hesapla */<br />
anlamındadır. Çünkü, * operatörü + operatörüne göre işlem<br />
önceliğine sahiptir.<br />
Program 11.4'de tanımlanan fonksiyon kendine parameter olarak gelen n elemanlı bir dizinin<br />
aritmetik ortlamasını hesaplar.<br />
Program 11.4: Bir dizi ile gösterici arasındaki ilişki
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
/* 10prg04.c: gösterici dizi ilişkisi */<br />
#include <br />
double ortalama(double dizi[], int n);<br />
int main()<br />
{<br />
double a[5] = {1.1, 2.2, 3.3, 4.4, 5.5};<br />
double o;<br />
o = ortalama(a,5);<br />
printf("Dizinin ortalaması = %lf\n",o);<br />
return 0;<br />
}<br />
double ortalama(double dizi[], int n)<br />
{<br />
double *p, t=0.0;<br />
int i;<br />
}<br />
ÇIKTI<br />
p = dizi; /* veya p = &dizi[0] */<br />
for(i=0; i
C (ve C++) programlama dilinde fonksiyon parametreleri değer geçerek (pass by value) yada<br />
adres geçerek (pass by reference) olarak geçilebilir. Bu şekilde geçirilen parametreler,<br />
fonksiyon içersinde değiştirilse bile, fonksiyon çağılıldıktan sonra bu değişim çağrılan yerdeki<br />
değerini değiştirmez. Fakat, bir parametre adres geçerek aktarılısa, fonksiyon içindeki<br />
değişikler geçilen parametreyi etkiler. Adres geçerek aktarım, gösterici kullanmayı zorunlu<br />
kılar.<br />
Örneğin, Program 11.5'de fonksiyonlara değer ve adres geçerek aktarımın nasıl yapılacağı<br />
gösterilmiştir.<br />
Program 11.5: Bir değişkenin içeriğini ve adresini ekrana yazdırma<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
/* 10prg05.c: Değer geçerek ve adres geçerek<br />
aktarım */<br />
#include <br />
void f1(int ); /* iki fonksiyon */<br />
void f2(int *);<br />
int main()<br />
{<br />
int x = 55;<br />
printf("x in degeri,\n");<br />
printf("Fonksiyonlar cagrilmadan once:<br />
%d\n",x);<br />
/* f1 fonksiyonu çağrılıyor...*/<br />
f1(x);<br />
printf("f1 cagirildiktan sonra :<br />
%d\n",x);<br />
/* f2 fonksiyonu çağrılıyor...*/<br />
f2(&x);<br />
printf("f2 cagirildiktan sonra :<br />
%d\n",x);<br />
return 0;<br />
}<br />
/* Değer geçerek aktarım */<br />
void f1(int n){<br />
n = 66;<br />
printf("f1 fonksiyonu icinde :<br />
%d\n",n);<br />
}<br />
/* Adres geçerek aktarım */<br />
void f2(int *n){<br />
*n = 77;<br />
printf("f2 fonksiyonu icinde :<br />
%d\n",*n);<br />
}
5. ve 6. satırlada kendine geçilen parametrenin değerini alan f1 fonksiyonu ve parametrenin<br />
adresini alan f2 adlı iki fonksiyon örneği belirtilmişdir. 11. satırdaki x değişkeni 16. ve 21.<br />
satırlarda, f1(x) ve f2(&x) fonksiyonlarına, sırasıyla değer ve adres geçerek aktarılmıştır. f1<br />
içinde x (n = 66; işlemi ile) değişime uğramış, fakat çağrılma işleminin sonucunda, x'in<br />
değeri değişmemiştir. Ancak f2 içinde x'in ( *n = 77 işlemi ile) değişimi, çağrıldıktan<br />
sonrada korunmuştur. Yani, adres geçerek yaplıan aktarımda, f2'ye aktarılan değer değil adres<br />
olduğu için, yollanan x parametresi f2 içinde değişikliğe uğrayacak ve bu değişim çağrıldığı<br />
21. satırdan itibaren devam edecektir.<br />
ÇIKTI<br />
x in degeri,<br />
Fonksiyonlar cagrilmadan once: 55<br />
f1 fonksiyonu icinde : 66<br />
f1 cagirildiktan sonra : 55<br />
f2 fonksiyonu icinde : 77<br />
f2 cagirildiktan sonra : 77<br />
Program 11.6'da iki tamsayı değişkeninin nasıl takas (swap) edileceği gösterilmiştir. Bu<br />
işlemi C porgramlama dilinde, eğer değişkenler global olarak bildirilmemişse, gösterici<br />
kullanmadan bu işlemi yapmak imkansızdır.<br />
Program 11.6: İki tamsayının birbiri ile takas edilmesi<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
/* 10prg06.c: iki sayının birbiri ile takas<br />
edilmesi */<br />
#include <br />
void takas(int *, int *);<br />
int main()<br />
{<br />
int a, b;<br />
a=22; b=33;<br />
printf("takas oncesi : a=%d b=%d\n",a,b);<br />
takas(&a, &b);<br />
printf("takas sonrasi: a=%d b=%d\n",a,b);<br />
return 0;<br />
}<br />
void takas(int *x, int *y)<br />
{<br />
int z;<br />
}<br />
z = *x;<br />
*x = *y;<br />
*y = z;
ÇIKTI<br />
takas oncesi : a=22 b=33<br />
takas sonrasi: a=33 b=22<br />
11.6 NULL Gösterici<br />
Bir göstericinin bellekte herhangi bir adresi göstermesi, veya öncden göstermiş olduğu adres<br />
iptal edilmesi istemirse NULL sabiti kullanılır. Bu sabit derleyicide ASCII karakter tablosunun<br />
ilk karakteridir ve '\0' ile sembolize edilir.<br />
int *ptr, a = 12;<br />
.<br />
.<br />
ptr = &a; /* ptr bellekte a değişkenin saklandığı yeri<br />
gösteriyor */<br />
.<br />
.<br />
ptr = NULL; /* ptr bellekte hiç bir hücreyi göstermiyor */<br />
*ptr = 8 /* hata! NULL göstericinin gösterdiği yere bir<br />
değer atanamaz */<br />
11.7 void Tipindeki Göstericiler<br />
void göstericiler herhangi bir veri tipine ait olmayan göstericilerdir. Bu özelliğinden dolayı,<br />
void gösterici genel gösterici (generic pointer) olarak da adlandırılır.<br />
void göstericiler, void anahtar sözcüğü ile bildirilir. Örneğin:<br />
gibi.<br />
void *adr;<br />
void göstericiler yalnızca adres saklamak için kullanılır. Bu yüzden diğer göstericiler<br />
arasında atama işlemlerinde kullanılabilir. Örneğin aşağıdaki atamada derleyici bir uyarı veya<br />
hata mesajı vermez:<br />
void *v;<br />
char *c;<br />
.<br />
.<br />
.<br />
v = c; /* sorun yok !*/<br />
Program 11.7'de void tipindeki bir göstericinin, program içinde, farklı tipteki verileri nasıl<br />
göstereceği ve kullanılacağı örneklenmiştir. İnceleyiniz.<br />
Program 11.7: void gösterici ile farklı tipteki verileri gösterme<br />
01:<br />
02:<br />
/* 10prg07.c: void gosterici (generic pointer)<br />
uygulamasi */
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
#include <br />
void yaz(void *);<br />
int main()<br />
{<br />
char kar = 'a';<br />
int tam = 66;<br />
double ger = 1.2;<br />
void *veri;<br />
veri = &kar;<br />
printf("veri -> kar: veri %c karakter<br />
degerini gosteriyor\n", *(char *) veri);<br />
veri = &tam;<br />
printf("veri -> tam: simdi veri %d tamsayi<br />
degerini gosteriyor\n", *(int *) veri);<br />
veri = &ger;<br />
printf("veri -> ger: simdi de veri %lf<br />
gercel sayi degerini gosteriyor\n", *(double *)<br />
veri);<br />
}<br />
return 0;<br />
ÇIKTI<br />
veri -> kar: veri a karakter degerini gosteriyor<br />
veri -> tam: simdi veri 66 tamsayi degerini<br />
gosteriyor<br />
veri -> ger: simdi de veri 1.200000 gercel sayi<br />
degerini gosteriyor<br />
Benzer olarak, fonksiyon parameterelerinin kopyalanması sırasında da bu türden atama<br />
işlemleri kullanılabilir. Uygulamada, tipten bağımsız adres işlemlerinin yapıldığı<br />
fonksiyonlarda, parametre değişkeni olarak void göstericiler kullanılır. Örneğin<br />
void free (void *p)<br />
{<br />
.<br />
.<br />
.<br />
}<br />
Parametresi void *p olan free fonksiyonu, herhangi türden gösterici ile çağrılabilir.<br />
<strong>Ders</strong> 12: Katarlar (Stringler)<br />
• <strong>Giriş</strong><br />
• 12.1 Katar Bildirimi
• 12.2 Katarlara Başlangıç Değeri Atama<br />
• 12.3 Katar Üzerinde İşlem Yapan Standart G/Ç Fonksiyonları<br />
• 12.4 Bazı Katar Fonksiyonları<br />
• 12.5 Katarların Fonksiyonlarda Kullanılması<br />
<strong>Giriş</strong><br />
Katarlar anlaşılması en zor konulardan biridir. C programlama dilinde iki tırnak içine alınan<br />
her ifadeye katar denir. Örneğin:<br />
"Izmir"<br />
"sonuc = %d\n"<br />
"Devam etmek icin ENTER tusuna basin."<br />
Türkçe yazılan C kitaplarda, ingilizce string kelimesi yerine aşağıdaki ifadelerden biri<br />
karşılaşılabilir:<br />
katar = karakter topluluğu = karakter dizisi = sözce = sicim<br />
Anlatımda, katar terimini kullanacağız.<br />
12.1 Katar Bildirimi<br />
Katarlar, char tipinde bildirilen karakter dizileridir ve harfler, rakamlar, veya bazı<br />
sembolleriden oluşur. C dilinde katar bildirimi için bir tip deyimi yoktur. Bu yüzden, bir<br />
katara bir dizi veya gösterici gözüyle bakılır. Genel olarak bir katarın bildirimi:<br />
yada<br />
char katar_adı[eleman_sayısı];<br />
char *katar_adı;<br />
şeklinde yapılır. Örneğin bir öğrencinin isim bilgisi ad adlı bir katarla tutulmak istenirse:<br />
yada<br />
char ad[10];<br />
char *ad;<br />
şeklinde programın başında bildirilmelidir.<br />
12.2 Katarlara Başlangıç Değeri Atama<br />
Diğer dizi bildirimlerinde olduğu gibi, karakter dizilerine başlangıç değeri verilebilir. Örneğin<br />
aşağıda verilen iki bildirim aynı anlamdadır:<br />
char s[5]={'I','z','m','i','r','\0'};<br />
char s[5]="Izmir";
Birinci satırdaki bildirimde '\0' (NULL) sonlandırıcı karakter dizisinin sonlandığını gösterir.<br />
Daha önce de bahsedildiği gibi sonlandırıcı karakter, karakter dizileri üzerinde işlemlerin hızlı<br />
ve etkin bir biçimde yapılabilmesine olanak sağlar. İkinci bildirimde buna gerek yoktur.<br />
Eğer bir karakter dizisinin kaç eleman sayısı belirtilmezse, başlangıçta bildirilen karakter<br />
sayısı kaç tane ise dizinin eleman sayısı o kadar olduğu varsayılır.<br />
char s[] = "Ankara"; /* 6 elemanlı */<br />
Eğer bildirim gösterici ile yapılmak isterirse:<br />
yada<br />
Ancak<br />
char *s = "Ankara"; /* 6 elemanlı */<br />
char *s;<br />
s = "Ankara";<br />
char s[6];<br />
s = "Ankara";<br />
şeklindeki bir atama geçersizdir. Çünkü bu şekilde yapılan bildirimde s bir değişken değil<br />
dizidir.<br />
Elemanları katar olan diziler tanımlamak mümkündür. Örneğin en uzunu 7 karakter olan 5<br />
farklı isim bir çatı altında şöyle toplanabilir:<br />
yada<br />
yada<br />
char isim[5][8] = { "Semra", "Mustafa", "Ceyhun", "Asli", "Leyla" };<br />
char isim[][8] = { "Semra", "Mustafa", "Ceyhun", "Asli", "Leyla" };<br />
char *isim[5] = { "Semra", "Mustafa", "Ceyhun", "Asli", "Leyla" };<br />
Görüldüğü gibi, bu tip tanımlamalarda birinci boyut (satır) dizinin eleman sayısını, ikinci<br />
boyut (sütun) her bir elemanın sahip olabileceği maksimum karakter sayısını gösterir.<br />
NOT<br />
Katar ifadelerinde doğrudan çift tırnak " veya ters bölü \<br />
karakterleri kullanılamaz. Bu durumda katar ifadeleri<br />
içerisinde<br />
" yerine \"<br />
\ yerine \\<br />
kullanılmalıdır. Örneğin:<br />
char *mes = "\"ilk.c\" dosyasinin yeri:";<br />
char *yol = "C:\\WINDOWS\\DESKTOP\\C";<br />
...<br />
puts(mes);<br />
puts(yol);<br />
ile ekrana aşağıdaki satırlar bastırlır:<br />
"ilk.c" dosyasinin yeri:<br />
C:\WINDOWS\DESKTOP\C
12.3 Katarlar Üzerinde İşlem Yapan Standart G/Ç<br />
Fonksiyonları<br />
printf() ve scanf() fonksiyonları diğer tiplerde olduğu gibi formatlı okuma/yazma amaçlı<br />
kullanılır. Katar formatı %s dir. Örneğin:<br />
char str[20];<br />
...<br />
scanf("%s",str);<br />
printf("%s\n",str);<br />
satırları ile klavyeden okunan katarın ilk 20 karakteri ekrana yazdırlabilir. Burada printf()<br />
fonksiyonu:<br />
printf(str);<br />
şeklinde de kullanılabir. Bu durumda, katar ekrana yazdırılır fakat imlec (cursor) bir alt satıra<br />
geçmez.<br />
gets() fonksiyonu klavyeden karakter dizisi almakta kullanılan bir C fonksiyonudur. Bu<br />
fonksiyon, klavyeden girilen karakterleri diziye yerleştirdikten sonra dizinin sonuna otomatik<br />
olarak NULL ('\0') karakterini ekler.<br />
char str[20];<br />
...<br />
gets(str);<br />
NOT<br />
gets() fonksiyonunu kullanmak biraz tehlikeli olabilir.<br />
Çünkü, gets() ile okuma yapılırken katarın büyüklüğünü<br />
dikkate alınmaz. Örneğin:<br />
char s[10];<br />
gets(s);<br />
şeklindeki okuma işleminde s en fazla 10 karakter<br />
saklayabilirken, gets() ile 100 karakter girilirse, derleyici<br />
bütün karakterleri saklamaya çalışır. Bu durumda, program<br />
sağlıklı çalışmaz ve hata verir. Bu yüzden bazı derleyiciler,<br />
gets() kullanıldığında aşağıdaki gibi bir uyarı verir.<br />
warning: the `gets' function is dangerous and should<br />
not be used.<br />
Sonuç olarak, scanf() fonksiyonunu kullanmanız tavsiye<br />
edilir.<br />
puts() fonksiyonu bir karakter dizisini ekrana yazdırmak için kullanılır. Bu fonksiyon diziyi<br />
ekrana yazdırdıktan sonra imleci (cursor) bir sonraki satıra geçirir.<br />
char *str = "Hangi cilgin bana zincir vuracakmis sasarim";<br />
...<br />
puts(str);<br />
puts(str) ile printf("%s\n",str) işlevsel olarak birbirine eşdeğerdir.
Buraya kadar anlatılanlar Program 12.1-3 de özetlenmiştir.<br />
Program 12.1: Bir katarın farklı yöntemlerle ekrana yazdırılması<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
ÇIKTI<br />
/* 12prg01.c<br />
Bir katarın farklı yöntemlerle ekrana<br />
yazılması */<br />
#include <br />
int main()<br />
{<br />
char dizi[7] = {'S', 'e', 'l', 'a', 'm',<br />
'!', '\0'};<br />
int i;<br />
/* Herbir karakteri ayrı ayrı alt alta yaz<br />
*/<br />
printf("Dizi elemanlari:\n");<br />
for (i=0; i
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
ÇIKTI<br />
karakterlerinin sayısı hesaplar */<br />
#include <br />
int main()<br />
{<br />
char str[20];<br />
int i,sayac=0;<br />
printf("Bir string girin: ");<br />
gets(str);<br />
for(i=0; str[i] != '\0'; i++)<br />
if( str[i] == 'm') sayac++;<br />
printf("'m' karakteri sayisi = %d\n",sayac);<br />
return 0;<br />
}<br />
Bir katar girin: marmara<br />
'm' karakteri sayisi = 2<br />
13. satırdaki döngüde, str[i]!='\0', koşulu ile sonlandırıcı karaktere gelinip gelinmedği<br />
sorgulanmaktadır. 14. satırda katar içindeki 'm' karakterine rastlanırsa sayac değeri bir<br />
artmaktadır. Katar sonuna kadar bütün 'm' karakterlerinin toplamı hesaplanıp ekrana<br />
yazdırılmıştır.<br />
Program 12.2'deki döngü şöyle de yazılabilirdi:<br />
...<br />
for(i=0; str[i]; i++)<br />
if(str[i] == 'm') sayac++;<br />
...<br />
Buradaki işlemle str[i], NULL karakterinden farklı olduğu sürece döngü devam ettirilmiştir.<br />
Aşağıdaki program elemanlı katar olan bir karakter dizisini ekrana yazar.<br />
Program 12.3: Bir katarı yazdırma<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
/* 12prg03.c: Bir elemanları katar olan karakter<br />
dizisini yazdırma */<br />
#include <br />
int main()<br />
{<br />
char *gun[7] = { "Pazartesi", "Sali",<br />
"Carsamba",<br />
"Cumartesi", "Pazar" };<br />
int i;<br />
"Persembe",<br />
"Cuma",
14:<br />
15:<br />
16:<br />
ÇIKTI<br />
for(i=0; i
Program 12.4: strcmp fonksiyonunun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
/* 12prg04.c: Basit bir şifre programı.<br />
Kullanıcı en fazla 3 kez yanlış şifre<br />
girebilir. */<br />
#include <br />
#include <br />
int main()<br />
{<br />
char sifre[8];<br />
int sonuc, hak=3;<br />
while( hak-- > 0 )<br />
{<br />
printf("Sifre : ");<br />
gets(sifre);<br />
al */<br />
sonuc = strcmp(sifre,"elma%xj4");<br />
if( sonuc==0 ){<br />
kontrol */<br />
puts("sifre dogru");<br />
break;<br />
}<br />
else<br />
puts("sifre yanlis");<br />
}<br />
/* şifreyi<br />
/* şifre<br />
}<br />
return 0;<br />
ÇIKTI<br />
Sifre : admin<br />
sifre yanlis<br />
Sifre : root<br />
sifre yanlis<br />
Sifre : elma%xj4<br />
sifre dogru<br />
Program 12.5: strcpy fonksiyonunun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
/* 12prg05.c: Bir katarı diğerine kopyalama */<br />
#include <br />
#include <br />
int main()<br />
{<br />
char str1[] = "Deneme";<br />
char str2[15], str3[15];<br />
int i;<br />
/* strcpy kullanarak kopyalama */
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
ÇIKTI<br />
strcpy(str2, str1);<br />
/* strcpy kullanmadan kopyalama */<br />
for(i=0; str1[i]; i++)<br />
str3[i] = str1[i];<br />
str3[i] = '\0'; /* sonlandırıcı ekle */<br />
/* sonuçlar ekrana */<br />
printf("str1 : %s\n",str1);<br />
printf("str2 : %s\n",str2);<br />
printf("str3 : %s\n",str3);<br />
return 0;<br />
}<br />
str1 : Deneme<br />
str2 : Deneme<br />
str3 : Deneme<br />
Program 12.6: strcat fonksiyonunun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
ÇIKTI<br />
/* 12prg06.c: Bir katarı diğerine ekler */<br />
#include <br />
#include <br />
int main()<br />
{<br />
char mesaj[20] = "Selam "; /* 1. katar */<br />
char isim[10]; /* 2. katar */<br />
printf("Adiniz ? : ");<br />
scanf("%s",isim);<br />
/* ekle */<br />
strcat(mesaj, isim);<br />
printf("%s\n",mesaj);<br />
return 0;<br />
}<br />
Adiniz ? : Mert<br />
Selam Mert<br />
Program 12.7: strlen fonksiyonunun kullanımı<br />
01:<br />
02:<br />
03:<br />
/* 12prg07.c: Bir karakter dizisinin uzunluğunu<br />
bulur */
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
ÇIKTI<br />
#include <br />
#include <br />
int main()<br />
{<br />
char s[20];<br />
int k = 0;<br />
printf("Bir seyler yazin : ");<br />
scanf("%s",s);<br />
/* sonlandırıcı karaktere kadar */<br />
while( s[k] != '\0' )<br />
k++;<br />
puts("Dizinin uzunlugu");<br />
printf("strlen kullanarak =<br />
%d\n",strlen(s));<br />
printf("strlen kullanmadan = %d\n",k);<br />
return 0;<br />
}<br />
Bir seyler yazin : deneme stringi<br />
Dizinin uzunlugu<br />
strlen kullanarak = 14<br />
strlen kullanmadan = 14<br />
Program 12.8: Isim sırlama<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
/* 12prg08.c<br />
Kabarcık Sıralama (Bubble Sort) Algoritması<br />
ile<br />
isimleri alfabetik sırayla listeler */<br />
#include <br />
#include <br />
#define n 5<br />
int main()<br />
{<br />
char isim[n][8] = { "Semra", "Mustafa",<br />
"Ceyhun", "Asli", "Leyla" };<br />
char gecici[8];<br />
int i,j,k;<br />
puts("Once:\n------");<br />
for(i=0; i
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
{<br />
}<br />
strcpy(gecici ,isim[j]);<br />
strcpy(isim[j] ,isim[j+1]);<br />
strcpy(isim[j+1],gecici);<br />
puts("\nSonra:\n------");<br />
for(i=0; i
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
printf("Uzunlugu (struzn) : %d\n",struzn(s));<br />
printf("Uzunlugu (strlen) : %d\n",strlen(s));<br />
return 0;<br />
}<br />
/* bir karakter dizisinin uzunluğunu hesaplar */<br />
int struzn(char *str)<br />
{<br />
int n = 0;<br />
}<br />
ÇIKTI<br />
while(str[n])<br />
n++;<br />
return n;<br />
Bir katar girin: Programlama<br />
Uzunlugu (struzn) : 11<br />
Uzunlugu (strlen) : 11<br />
Program 12.10: strrev dengi bir fonksiyon: strcev<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
/* 12prg10.c: Bir katarın tersini veren bir<br />
fonksiyon */<br />
#include <br />
#include <br />
char *strcev(char *);<br />
int main()<br />
{<br />
char s[50];<br />
printf("Bir katar girin: ");<br />
scanf("%s",s);<br />
printf("Katar, s : %s\n",s);<br />
printf("Tersi, strcev(s) : %s\n",strcev(s));<br />
return 0;<br />
}<br />
/* str katarını ters-yüz eder */<br />
char *strcev(char *str)<br />
{<br />
int i,n;<br />
char gecici;<br />
n = strlen(str);<br />
for(i=0; i
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
ÇIKTI<br />
}<br />
str[i] = str[n-i-1];<br />
str[n-i-1] = gecici;<br />
return str; /* geri dönüş değeri bir gösterici<br />
*/<br />
}<br />
Bir katar girin: Programlama<br />
Katar, s : Programlama<br />
Tersi, strcev(s) : amalmargorP<br />
<strong>Ders</strong> 13: Dinamik Bellek Yönetimi<br />
• <strong>Giriş</strong><br />
• 13.1 Dinamik Dizi Fonksiyonları<br />
• 13.2 Dinamik Matrisler<br />
<strong>Giriş</strong><br />
Bir C programı içerisinde, dizilerin boyutu ve kaç elemanlı olduğu program başında<br />
belirtilirse, derleyici o dizi için gereken bellek alanını (bölgesini) program sonlanıncaya kadar<br />
saklı tutar ve bu alan başka bir amaç için kullanılamaz [1]. Bu türden diziler statik dizi olarak<br />
isimlendirilir. Statik dizinin boyutu programın çalışması esnasında (run time) değiştirilemez.<br />
Fakat, programın çalışırken bir dizinin boyutu ve eleman sayısı bazı yöntemler kullanılarak<br />
değiştirilebilir. Bu tür dizilere dinamik dizi denir. Dinamik diziler için gereken bellek<br />
bölgesi, derleyici tarafından işletim sisteminden istenir, kullanılır ve daha sonra istenirse bu<br />
bölge boşaltırılır. Bu bölümde, dinamik dizi kavramı ve dinamik bellek yönetimi<br />
anlatılacaktır.<br />
13.1 Dinamik Dizi Fonksiyonları<br />
ANSI C'de, dinamik diziler işaretçi kullanılarak ve standart kütüphanedeki malloc(),<br />
calloc(), realloc() ve free() fonksiyonlarının yardımıyla ile oluşturulur veya boşaltılır.<br />
Bu fonksiyonlar Tablo 13.1 de listelenmiştir.<br />
Tablo 13.1: stdlib.h kütüphanesindeki dinamik bellek fonksiyonları<br />
Dinamik Bellek Fonksiyonu<br />
void *malloc(size_t eleman_sayısı);<br />
Açıklama<br />
Bellekte herbiri size_t tipinde olan<br />
eleman_sayısı kadar yer (bellek bloğu)<br />
ayırır. Bu yer verilmezse geriye NULL gönderir.
void *calloc(size_t eleman_sayısı,<br />
size_t nbayt);<br />
void *realloc(void *ptr, size_t<br />
nbayt);<br />
void free(void *ptr);<br />
Bellekte herbiri nbayt kadar yer işgal edecek<br />
eleman_sayısı kadar boş yer ayırır ve bütün<br />
bitleri sıfırlar. Bu yer ayrılamazsa geriye NULL<br />
gönderir.<br />
ptr işaretçisi ile gösterilen bellek bloğunu,<br />
nbayt kadar büyüterek veya küçülterek<br />
değiştirir. Bu iş gerçekleşmezse geriye NULL<br />
gönderir.<br />
Daha önce ayrılan adresi ptr'de saklanan<br />
bellek alanının boşaltır.<br />
Tamsayı tipinde bir dinamik dizi tanımlanırken aşağıdaki işlem basamakları izlenmelidir:<br />
/* dinamik dizi bildirimi */<br />
int *dizi;<br />
/* eleman saysını belirle */<br />
scanf("%d",&n);<br />
/* n tane bellek bloğu isteniyor */<br />
dizi = (int *) malloc( sizeof(int)*n );<br />
/* Boş yer varmı sorgulanıyor */<br />
if( dizi == NULL )<br />
printf("Yetersiz bellek alanı\n"), exit(1);<br />
...<br />
/* dizi burada kullanılıyor */<br />
...<br />
/* bellek bloğu boşaltılıyor */<br />
free(dizi);<br />
Program 13.1, eleman sayısı klavyeden girilen bir dizinin aritmetik ortalamasını hesaplar.<br />
Eleman sayısı sıfır veya negatif bir değer olduğunda, sonsuz döngüden çıkılır ve program<br />
sonlanır. İnceleyiniz.<br />
Program 13.1: Dinamik dizi ile ortalama hesabı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
/* 13prg01.c: Dinamik dizi ile ortalama hesabı<br />
*/<br />
#include <br />
#include <br />
int main(){<br />
int n,i;<br />
float *x, toplam, ort;<br />
while(1)<br />
{<br />
/* dizinin eleman sayısı okunuyor */<br />
printf("\nEleman sayısını girin: ");<br />
scanf("%d",&n);
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
);<br />
ÇIKTI<br />
/* eleman sayısı
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
char *altKatar(char *str, int, int);<br />
int main()<br />
{<br />
int i;<br />
char *s, *parca;<br />
s = "programlama";<br />
for(i=0; s[i]; i++)<br />
{<br />
parca = altKatar(s, 0, i);<br />
puts(parca);<br />
}<br />
return 0;<br />
}<br />
/* str'nin p1. elemanindan p2. elemanina kadar<br />
olan alt katarını gonderir. */<br />
char *altKatar(char *str, int p1, int p2)<br />
{<br />
int i, j=0, n;<br />
static char *alt;<br />
n = p2 - p1;<br />
}<br />
ÇIKTI<br />
/* bellekten yer ayrılıyor... */<br />
alt = (char *) malloc( n*sizeof(char) );<br />
for(i=p1; i
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
50:<br />
/* 13prg02.c: Dinamik matris tanımlama */<br />
#include <br />
#include <br />
int main()<br />
{<br />
int **matris;<br />
int satir, kolon;<br />
int s, k;<br />
int i;<br />
printf("Matrisin satır sayısı: ");<br />
scanf("%d", &satir);<br />
printf("Matrisin kolon sayısı: ");<br />
scanf("%d", &kolon);<br />
/* dıştaki dizi için bellek alanı isteniyor<br />
*/<br />
matris = (int **) calloc(satir,<br />
sizeof(int));<br />
/* içteki dizi için bellek alanı isteniyor<br />
*/<br />
for(i = 0; i < satir; i++)<br />
matris[i] = (int *) calloc(kolon,<br />
sizeof(int));<br />
/* matrisin elemanları okunuyor */<br />
for(s = 0; s < satir; s++)<br />
for(k = 0; k < kolon; k++) {<br />
printf("Matrisin elemanı girin:<br />
matris[%d][%d] = ", s, k);<br />
scanf("%d", &(matris[s][k]));<br />
}<br />
printf("\nGirilen matris:\n");<br />
for(s = 0; s < satir; s++) {<br />
for(k = 0; k < kolon; k++)<br />
printf("%4d", matris[s][k]);<br />
}<br />
printf("\n");<br />
/* içteki dizi boşaltılıyor */<br />
for(i = 0; i < satir; i++)<br />
free((void *) matris[i]);<br />
/* dıştaki dizi boşaltılıyor */<br />
free((void *) matris);<br />
}<br />
return(0);<br />
ÇIKTI<br />
Matrisin satır sayısı: 2<br />
Matrisin kolon sayısı: 3
Matrisin elemanı girin: matris[0][0] = 1<br />
Matrisin elemanı girin: matris[0][1] = 2<br />
Matrisin elemanı girin: matris[0][2] = 3<br />
Matrisin elemanı girin: matris[1][0] = 5<br />
Matrisin elemanı girin: matris[1][1] = 6<br />
Matrisin elemanı girin: matris[1][2] = 8<br />
Girilen matris:<br />
1 2 3<br />
5 6 8<br />
<strong>Ders</strong> 14: Gösterici Uygulamaları<br />
• <strong>Giriş</strong><br />
• 14.1 Gösterici Uygulamarı<br />
<strong>Giriş</strong><br />
Bu bölümde bazı gösterici uygulamaları gösterilmiştir.<br />
14.1 Gösterici Uygulamarı<br />
i. Rastgele dizi<br />
ii. Bir dizinin elemanlarını küçükten büyüğe doğru sıralama<br />
iii. Bir dizinin kare kökünü hesaplayan fonksiyon<br />
iv. Dinamik matris çarpımı<br />
Program 14.1: Rastgele dizi<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
/* 14prg01.c: Rastgele Dizi */<br />
#include <br />
#include <br />
/* dizinin ilk n elemanına [0,1] arasında<br />
rastgele sayı atar */<br />
void rastgele(double *dizi, int n){<br />
int i;<br />
}<br />
for(i=0; i
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
}<br />
srand(1234567);<br />
rastgele(x, 5);<br />
puts("Rastgele dizi elemanları:");<br />
for(i=0; i
38:<br />
39:<br />
}<br />
printf("\n");<br />
return 0;<br />
ÇIKTI<br />
Once : 22 44 11 55 33<br />
Sonra: 11 22 33 44 55<br />
Program 14.3: Bir dizinin kare kökünü hesaplayan fonksiyon<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
/* 14prg03.c: Bir dizinin kare kökünü hesaplayan<br />
fonksiyon */<br />
#include <br />
#include <br />
#include <br />
double *kare_kok(double *, int);<br />
int main()<br />
{<br />
double A[5] = {1.0, 2.0, 4.0, 8.0, 16.0};<br />
double *B;<br />
int i;<br />
}<br />
printf("A dizisi: ");<br />
for(i=0; i
45: c[i] = sqrt(dizi[i]);<br />
}<br />
return c;<br />
ÇIKTI<br />
A dizisi: 1.000000 2.000000 4.000000 8.000000<br />
16.000000<br />
B dizisi: 1.000000 1.414214 2.000000 2.828427<br />
4.000000<br />
Program 14.4: Dinamik Matris Çarpımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
/* 14prg04.c: Dinamik Matris Çarpımı<br />
Bu program A(mxn) matrisi ile B(pxq)<br />
matrisini çarpımını hesaplar.<br />
Çarpım matrisi C(mxq), C = AB dir. Çarpımın<br />
sonucu matris_carp()<br />
fonksiyonu ile hesaplanır.<br />
Örnek:<br />
~~~~~~<br />
[ 1 0 2 ] [ 3 1 ] [ 1 0<br />
2 ] [ 3 1 ] [ 5 1 ]<br />
A = [-1 3 1 ] B =[ 2 1 ] ==> C = AB = [-1 3<br />
1 ] [ 2 1 ] = [ 4 2 ]<br />
[ 1 0 ]<br />
[ 1 0 ]<br />
*/<br />
#include <br />
#include <br />
double **matris_carp(double **, int, int,<br />
double **, int, int);<br />
int main()<br />
{<br />
double **A;<br />
double **B;<br />
double **C;<br />
int i, j;<br />
/* A matrisi için bellekten yer ayır */<br />
A = (double **) calloc( 2, sizeof(double));<br />
for(i = 0; i < 2; i++)<br />
A[i] = (double *) calloc(3,<br />
sizeof(double));<br />
/* B matrisi için bellekten yer ayır */<br />
B = (double **) calloc( 3, sizeof(double));<br />
for(i = 0; i < 3; i++)<br />
B[i] = (double *) calloc(2,<br />
sizeof(double));
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
50:<br />
51:<br />
52:<br />
53:<br />
54:<br />
55:<br />
56:<br />
57:<br />
58:<br />
59:<br />
60:<br />
61:<br />
62:<br />
63:<br />
64:<br />
65:<br />
66:<br />
67:<br />
68:<br />
69:<br />
70:<br />
71:<br />
72:<br />
73:<br />
74:<br />
75:<br />
76:<br />
77:<br />
78:<br />
79:<br />
80:<br />
81:<br />
82:<br />
83:<br />
84:<br />
85:<br />
86:<br />
}<br />
/* A matrisinin elemanları */<br />
A[0][0] = 1.0; A[0][1] = 0.0; A[0][2] = 2.0;<br />
A[1][0] =-1.0; A[1][1] = 3.0; A[1][2] = 1.0;<br />
/* B matrisinin elemanları */<br />
B[0][0] = 3.0; B[0][1] = 1.0;<br />
B[1][0] = 2.0; B[1][1] = 1.0;<br />
B[2][0] = 1.0; B[2][1] = 0.0;<br />
/* C = AB matrisi */<br />
C = matris_carp(A,2,3, B,3,2);<br />
for(i=0; i
<strong>Ders</strong> 15: Yapılar ve Birlikler<br />
• <strong>Giriş</strong><br />
• 15.1 enum Deyimi (Enumeration Constants)<br />
• 15.2 Yapı, struct Deyimi (Structures)<br />
• 15.3 typedef Deyimi<br />
• 15.4 Birlik, union Deyimi<br />
<strong>Giriş</strong><br />
C, kullanıcının kendi veri tipini tanımlamasına müsaade eder. Bu kısımda böyle veritiplerinin<br />
nasıl oluşturulacağı anlatılacaktır.<br />
15.1 enum Deyimi (Enumeration Constants)<br />
Bu tip, değişkenin alabileceği değerlerin belli (sabit) olduğu durumlarda programı daha<br />
okunabilir hale getirmek için kullanılır. Genel yazım biçimi:<br />
enum tip_adı{değer_1, değer_2, ..., değer_n} değişken_adı;<br />
tip_adı programcı tarafından verilen tip ismidir. değişken_adı ise program içinde<br />
kullanılacak olan değişkenin adıdır. Eğer kullanılmazsa program içinde daha sonra enum ile<br />
birlikte kullanılır. Örneğin:<br />
enum bolumler{programcilik, donanim, muhasebe, motor};<br />
tanımı ile derleyici programcilik için 0, donanim için 1, muhasebe için 2 ve motor için 3<br />
değerini kabul ederek atamaları buna göre yapar. Değişken adı bildirilirse daha sonra enum<br />
kullanmaya gerek kalmaz. Örneğin:<br />
enum renkler {kirmizi, mavi, sari} renk;<br />
enum gunler {pazartesi, sali, carsamba, persembe, cuma, cumartesi,<br />
pazar};<br />
gibi yapılan sabit tanımlamaları program içinde kullanılabilir:<br />
enum bolumler bolum;<br />
enum gunler gun;<br />
...<br />
bolum = muhasebe; /* bolum = 2 anlamında */<br />
gun = cuma; /* gun = 4 anlamında */<br />
renk = kirmizi; /* renk = 0 anlamında */<br />
Program 15.1 enum anahtar kelimesinin basit kullanımları gösterilmiştir.<br />
Program 15.1: enum kullanımı
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
/* 15prg01.c: Klavyeden girilen bir sayının tek<br />
olup olmadığını sınar */<br />
#include <br />
enum BOOLEAN{ FALSE, TRUE }; /* 0, 1 */<br />
int tek(int n){ return (n % 2); }<br />
int main()<br />
{<br />
enum BOOLEAN sonuc;<br />
int x;<br />
}<br />
ÇIKTI<br />
printf("Bir sayi girin: ");<br />
scanf("%d",&x);<br />
sonuc = tek(x); /* tek mi? */<br />
if( sonuc == TRUE )<br />
puts("Girilen sayi tek ");<br />
else<br />
puts("Girilen sayi cift");<br />
return 0;<br />
Bir sayi girin: 5<br />
Girilen sayi tek<br />
enum bloğu içinde tanımlanmış değişkenlerin sahip sabit olacağı değerler Program 15.2<br />
olduğu gibi programcı tarafından belirlenebilir.<br />
Program 15.2: enum kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
/* 15prg02.c: Beş sabit bölüm için enum<br />
kullanımı */<br />
enum bolumler{<br />
programcilik = 1, /* 1 */<br />
donanim, /* 2 */<br />
muhasebe, /* 3 */<br />
motor, /* 4 */<br />
buro /* 5 */<br />
} bolum;<br />
int main()<br />
{<br />
bolum = donanim;<br />
printf("bolum : %d\n",bolum);<br />
bolum += 2; /* bolum = motor */<br />
printf("Yeni bolum : %d\n",bolum);
22: return 0;<br />
}<br />
ÇIKTI<br />
bolum : 2<br />
Yeni bolum : 4<br />
15.2 Yapı, struct Deyimi (Structures)<br />
Aralarında mantıksal bir ilişki bulunan farklı türden bilgiler "yapılar (structures)" içerisinde<br />
mantıksal bir bütün olarak ifade edilebilir. Yapılar diziler gibi bellekte sürekli kalır. Bir yapı<br />
içerisindeki elemanlara üye (member) denir. Üyelerin herbiri farklı veri tipine sahip olabilir.<br />
Bu sayede, kendi tipinizi üretebilirsiniz.<br />
Genel yapı bildirimi:<br />
struct yapı_adı{<br />
tip yapı_değişken_ismi;<br />
tip yapı_değişken_ismi;<br />
...<br />
};<br />
NOT<br />
enum ile sabit bildirimi yapılırken<br />
struct ile değişken bildirimi yapılır.<br />
Bir öğrenciye ait bilgileri bir çatı altında aşağıdaki gibi toplanabilir:<br />
/* kayit veri tipi! */<br />
struct kayit{<br />
/* üyeler */<br />
char ad[10];<br />
long no;<br />
short sinif;<br />
};<br />
Bu tipte bir değişken tanımlama:<br />
struct kayit ogr1, ogr2;<br />
şeklinde olabilir. ogr1 değişkeni ile tanımlanan 1. öğrencinin numarasına bir değer atama<br />
işlemi:<br />
ogr1.no = 2012597;<br />
şeklinde yapılır. Bu deyimin kullanımı Program 15.3, ve 15.4'de gösterilmiştir. Inceleyiniz.<br />
Program 15.3: struct deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
/* 15prg03.c<br />
Bir öğrenciye ait bilgilerin struct deyimi<br />
ile bir çatı altında toplanması */<br />
#include
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
ÇIKTI<br />
/* kayit yapısı */<br />
struct kayit{<br />
char ad[10];<br />
long no;<br />
int sinif;<br />
};<br />
int main()<br />
{<br />
struct kayit ogr;<br />
tipinde */<br />
/* ogr değişkeni kayit<br />
printf("Ogrenci Nosu : ");<br />
scanf("%ld",&ogr.no);<br />
printf("Ogrenci Adi : "); scanf("%s" ,<br />
ogr.ad);<br />
printf("Ogrenci Sinifi: "); scanf("%d"<br />
,&ogr.sinif);<br />
printf("\n*** Girilen bilgiler ***");<br />
printf("\nNo : %ld",ogr.no);<br />
printf("\nAdi : %s ",ogr.ad);<br />
printf("\nSinifi: %d ",ogr.sinif);<br />
return 0;<br />
}<br />
Ogrenci Nosu : 948589<br />
Ogrenci Adi : Ahmet<br />
Ogrenci Sinifi: 2<br />
*** Girilen bilgiler ***<br />
No : 948589<br />
Adi : Ahmet<br />
Sinifi: 2<br />
Yapılar, diğer değişkenler gibi, fonksiyonlara parametre olarak geçirelilebilir.<br />
Program 15.4: struct deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
/* 15prg04.c<br />
Yapıların bir fonksiyona parametere olarak<br />
aktarılabilmesi */<br />
#include <br />
struct TARIH{<br />
int gun,ay,yil;<br />
};<br />
void goster(struct TARIH x){<br />
printf("Tarih: %02d-%02d-%4d\n", x.gun,<br />
x.ay, x.yil);<br />
}<br />
int main()<br />
{<br />
struct TARIH n; /* n değişkeni TARIH tipinde
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
*/<br />
n.gun = 1;<br />
n.ay = 8;<br />
n.yil = 2003;<br />
goster(n);<br />
ÇIKTI<br />
return 0;<br />
}<br />
Tarih: 01-08-2003<br />
Yapılarla da, gösterici tanımlamaları yapılabilir. Ancak, bir yapı gösteren göstericinin,<br />
gösterdiği yere yönlendirme operatörü, ->, ile erişilir.<br />
Program 15.5: struct deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
/* 15prg05.c: Bir yapı gösteren gösterici */<br />
#include <br />
struct Meyve{<br />
float agirlik;<br />
float fiyat;<br />
};<br />
int main()<br />
{<br />
struct Meyve *muz, elma;<br />
float muzTutar, elmaTutar;<br />
/* muz Meyve tipinde bir gösterici */<br />
muz->agirlik = 2.50;<br />
muz->fiyat = 3.50;<br />
muzTutar = muz->fiyat * muz->agirlik;<br />
/* elma Meyve tipinde bir değişken */<br />
elma.agirlik = 2.00;<br />
elma.fiyat = 1.75;<br />
elmaTutar = elma.fiyat * elma.agirlik;<br />
printf("Meyve Agırlık Birim Fiyatı<br />
TUTAR (TL)\n");<br />
printf("----- ------- ------------ ---<br />
--------\n");<br />
printf("Muz %7.2f %7.2f<br />
%7.2f\n",<br />
muz->agirlik, muz->fiyat, muzTutar);<br />
printf("Elma %7.2f %7.2f<br />
%7.2f\n",<br />
elma.agirlik, elma.fiyat, elmaTutar);<br />
return 0;<br />
}
ÇIKTI<br />
Meyve Agırlık Birim Fiyatı TUTAR (TL)<br />
----- ------- ------------ -----------<br />
Muz 2.50 3.50 8.75<br />
Elma 2.00 1.75 3.50<br />
15.3 typedef Deyimi<br />
struct ile oluşturulan yapıda typedef deyimi kullanılırsa, bu yapıdan değişken tanımlamak<br />
için tekrar struct deyiminin kullanılmasına gerek kalmaz.<br />
typedef struct kayit{<br />
char ad[10];<br />
long no;<br />
short sinif;<br />
} ogr1,ogr2;<br />
Program 15.4 küçük bir değişiklike Program 15.6'de yeniden yazılmıştır. Inceleyiniz.<br />
Program 15.6: typedef - struct deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
ÇIKTI<br />
/* 15prg06.c<br />
Yapıların bir fonksiyona parametere olarak<br />
aktarılabilmesi.<br />
typedef deyimi kullanıldığında struct<br />
deyimine gerek yoktur */<br />
#include <br />
typedef struct{<br />
int gun,ay,yil;<br />
}TARIH;<br />
void goster(TARIH x){<br />
printf("Tarih: %02d-%02d-%4d\n", x.gun,<br />
x.ay, x.yil);<br />
}<br />
int main(void)<br />
{<br />
TARIH n;<br />
n.gun = 1;<br />
n.ay = 8;<br />
n.yil = 2003;<br />
goster(n);<br />
return 0;<br />
}<br />
Tarih: 01-08-2003
typedef başka kullanımı da vardır. C dilinde program kodları bu deyimle tamamen<br />
türkçeleştirilebilir. Örneğin bu deyim:<br />
typedef int tamsayi;<br />
şeklinde kullanılırsa programda daha sonra int tipinde bir değişken tanımlarken şu biçimde<br />
kullanılmasına izin verilir.<br />
tamsayi x,y; /* int x,y anlaminda */<br />
15.1 Birlik, union Deyimi<br />
Birlikler de yapılar gibi sürekli belleğe yerleşen nesnelerdir. Birlikler yapılara göre seyrek<br />
kullanılır. Bir programda veya fonksiyonda değişkenlerin aynı bellek alanını paylaşması için<br />
ortaklık bildirimi union deyimi ile yapılır. Bu da belleğin daha verimli kullanılmasına imkan<br />
verir. Bu tipte bildirim yapılırken struct yerine union yazılır. Genel yazım biçimi:<br />
union birlik_adı{<br />
tip birlik_değişken_ismi;<br />
tip birlik_değişken_ismi;<br />
...<br />
};<br />
union paylas{<br />
float f;<br />
int i;<br />
char kr;<br />
};<br />
Yukarıdaki bildirim yapıldığında, değişkenler için bellekte bir yer ayrılmaz. Değişken<br />
bildirimi:<br />
union paylas bir,iki;<br />
şeklinde yapılır. Üyelere erişmek aşağıdaki gibi olur:<br />
bir.kr= 'A';<br />
iki.f = 3.14;<br />
bir.i = 2000;<br />
Program 15.7: typedef - deyiminin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
/* 15prg07.c<br />
union x ve y nin aynı bellek alanını işgal<br />
ettiğinin kanıtı */<br />
#include <br />
union paylas{<br />
int x;<br />
int y;<br />
}z;<br />
int main()<br />
{<br />
int *xAdres,*yAdres;
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
ÇIKTI<br />
z.x = 11;<br />
xAdres = &z.x;<br />
printf("x = %d y = %d\n",z.x, z.y);<br />
z.y = 22;<br />
yAdres = &z.y;<br />
printf("y = %d y = %d\n",z.x, z.y);<br />
printf("xAdres = %p yAdres = %p\n",xAdres,<br />
yAdres);<br />
return 0;<br />
}<br />
x = 11 y = 11<br />
y = 22 y = 22<br />
xAdres = 0x804974c<br />
yAdres = 0x804974c<br />
<strong>Ders</strong> 16: Dosya Yönetimi<br />
• <strong>Giriş</strong><br />
• 16.1 Dosya Açma ve Kapama<br />
• 16.2 Metin ve İkili Dosyalar<br />
• 16.3 Dosya Fonksiyonları<br />
• 16.4 Standart Dosyalar<br />
<strong>Giriş</strong><br />
Birçok programda, bazı verilerin disk üzerinde saklanmasına gerek duyulur. Bütün<br />
programlama dillerinde, sabit disk sürücüsü (Hard Disk Drive, HDD) üzerindeki verileri<br />
okumak veya diske veri yazmak için hazır fonksiyonlar tanımlanmıştır. C programlama<br />
dilinde, disk dosyasına erişim iki yöntemle yapılır. Bunlar üst düzey ve alt düzey olarak<br />
adlandırılır. Üst düzey G/Ç yöntemi ANSI C tarafından desteklenmektedir. Bu kısımda Üst<br />
düzey G/Ç konu edilecektir[1].<br />
16.1 Dosya Açma ve Kapama<br />
Bir dosyaya okuma/yazma yapmak için onun açılması gerekir. Dosya açmak için fopen(),<br />
kapatmak için fclose() fonksiyonu kullanılır. Bu fonksiyonlar stdio.h başlık dosyasında<br />
tanımlanmıştır.<br />
Genel olarak, dosya açma kapama adımları şu şekildedir:<br />
FILE *dosya; /* dosya göstericisi */<br />
dosya = fopen(const char dosya_adı, const char mod);
...<br />
dosya işlemleri<br />
...<br />
fclose(dosya);<br />
Burada FILE, stdio.h içerisinde bildirilmiş bir yapıdır. mod ile açılacak olan dosyanın ne<br />
amaçla açılacağı belirlenir[2].<br />
Tablo 16.1: Dosya açma modları<br />
Açılış Modu İşlem Türü<br />
Salt okunur (read only). Dosyanın açılabilmesi için önceden oluştrulmuş<br />
r<br />
olması gerekir. Bu modda açılmş olan bir dosyaya yazma yapılamaz.<br />
Yalnızca yazma (write only). Dosya diskte kayıtlı olsun veya olamsın dosya<br />
w<br />
yeniden oluşturulur. Bu modda açılmış olan bir dosyadan okuma yapılamaz.<br />
Ekleme (append). Kayıtlı bir dosyanın sonuna veri eklemek için açılır. Bu<br />
a<br />
modda açılmış olan bir dosyadan okuma yapılamaz.<br />
Okuma ve yazma. Bu modda açılmış olan bir dosyanın daha önce varolması<br />
r+<br />
gerekir.<br />
Okuma ve yazma. Bu modda açılmış olan bir dosya var olsun veya olmasın<br />
w+<br />
dosya yeniden oluşturulur.<br />
a+ Okuma ve yazma. Kayıtlı bir dosyanın sonuna veri eklemek için açılır.<br />
deneme.dat adlı bir dosyanın, yazmak için açılıp açılmadığını test etmek için aşağıdaki kod<br />
kullanılır:<br />
FILE *yaz; /* dosya göstericisi */<br />
yaz = fopen("deneme.dat", "w");<br />
if( yaz == NULL ){<br />
puts("dosya acilmiyor...");<br />
exit(1);<br />
}<br />
...<br />
/* açılırsa! dosya işlemleri */<br />
...<br />
fclose(yaz);<br />
NOT<br />
deneme.dat dosyası ile ana program aynı dizin içinde<br />
olmalıdır. Aksi halde, dosyanın tam yolu bildirilmelidir.<br />
Örneğin dosyanın yolu: C:\WINDOWS\DESKTOP\deneme.dat<br />
ise dosya açılırken<br />
yaz = fopen("C:\\WINDOWS\\DESKTOP\\deneme.dat",<br />
"w");<br />
şeklinde açık yol bildirilmelidir. Aynı işlem Linux ortamında
da<br />
geçerlidir.<br />
gibi.<br />
yaz = fopen("/home/bingul/DATA/deneme.dat","w");<br />
16.2 Metin ve İkili Dosyalar<br />
İşletim sistemlerinde genelde iki çeşit dosya kullanımına rastlanmaktadır. Bunlar metin (text)<br />
ve ikili (binary) dosyalar olmak üzere ikiye ayrılır. Dosyanın hangi türden olduğu açılırken<br />
fopen() fonksiyonu ile belirtilebilir.<br />
Açılış modunda metin dosyaları için t, ikili dosyalar için b eklenir. Örneğin "r+t" şeklinde<br />
bir açılış modu var olan bir dosyanın okuma yazma ve metin olarak açılacağı anlamına gelir.<br />
Benzer olarak "wb" açılış modu dosyanın ikili modda oluşturulacağını gösterir. Fakat bu<br />
belirleme yapılmamışsa, varsayılan açılış modu metindir (yani t).<br />
16.3 Dosya Fonksiyonları<br />
Bu kısımda, Tablo 16.2'de verilen dosyalama foksiyonlarının bazılarının kullanımı, örnek<br />
programlar üzerinde anlatılmıştır.<br />
Tablo 16.2: Üst düzey dosyalama fonksiyonları<br />
Fonksiyon<br />
fopen()<br />
fclose()<br />
putc()<br />
getc()<br />
feof()<br />
fprintf()<br />
fscanf()<br />
fputs()<br />
fgets()<br />
fwrite()<br />
fread()<br />
Görevi<br />
Dosya oluşturur, açar<br />
Dosyayı kapatır<br />
Dosyaya bir karakter yazar<br />
Dosyadan bir karakter okur<br />
Dosya sonuna gelindiğini sorgular<br />
Dosyaya formatlı veri yazar<br />
Dosyadan formatlı veri okur<br />
Dosyaya katar yazar<br />
Dosyadan katar okur<br />
Dosyaya dizi yazar<br />
Dosyadan dizi okur<br />
Program 16.1: Bir dosyaya veri yazma<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
/* 16prg01.c:<br />
10 öğrenciye ait bilgileri 'ogrenci.txt'<br />
dosyasına kaydeder. */<br />
#include <br />
#include <br />
int main()<br />
{
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
ÇIKTI<br />
FILE *dg; /* dosya göstericisi */<br />
const int n = 10; /* öğrenci sayısı */<br />
char ad[10];<br />
int no, Not, i=0;<br />
dg = fopen("ogrenci.txt", "w");<br />
if( dg == NULL )<br />
puts("ogrenci.txt dosyasi acilmadi. !\n"),<br />
exit(1);<br />
puts("10 ogrenciye ait bilgileri girin:");<br />
while( i++
C:\TC> edit ogrenci.txt<br />
$ edit ogrenci.txt<br />
yada<br />
$ pico ogrenci.txt<br />
NOT<br />
ogrenci.txt dosyası daha önce oluşturulmuşsa Program<br />
16.1 önceki verileri silip yerine yeni verileri yazacaktır. Bu<br />
dosyaya yeni bir veri eklemek için fopen() fonksiyonunu 'a'<br />
modu ile kullanılmalıdır.<br />
Bir dosyadan veri okumanın bir çok şekli vardır. Veri okuma işlemine basit bir örnek Program<br />
16.2 de sunulumuştur. Bu program ogrenci.txt dosyasında kayıtlı öğrencilerden, en düşük<br />
notu, en yüksek notu ve sınıf ortalamasını (0'lar hariç) hesaplamaktadır.<br />
Program 16.2: Bir dosyadan veri okuma<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
/* 16prg02.c:<br />
ogrenci.txt dosyasından no, isim ve not<br />
bilgileri okur ve<br />
notlar arasından en büyüğü, en küçüğü ve<br />
sınıf ortlamasını (0'lar hariç) hesaplar. */<br />
#include <br />
#include <br />
int main()<br />
{<br />
FILE *dg; /* dosya işaretçisi */<br />
char Ad[10];<br />
int Not, No, eb, ek, n, top;<br />
float ort;<br />
if( (dg=fopen("ogrenci.txt","r")) == NULL )<br />
puts("Dosya açılmadı !\n"), exit(1);<br />
/* başlangıç değerleri ata */<br />
ek = 1000; /* çok büyük */<br />
eb = -1000; /* çok küçük */<br />
top = 0; /* notların toplamı */<br />
n = 0; /* notu 0'dan farlı<br />
öğrencilerin toplamı */<br />
while( !feof(dg) ) /*<br />
dosyanın sonuna kadar */<br />
{<br />
fscanf(dg,"%d %s %d",&No,Ad,&Not); /*<br />
verileri oku! */<br />
if(Not>eb) eb = Not;<br />
büyük ve en küçük bulunuyor... */<br />
if(Not
44:<br />
45:<br />
ÇIKTI<br />
fclose(dg); /*<br />
dosyayı kapat */<br />
ort = (float) top/n; /*<br />
ortalama (0 lar hariç!) */<br />
printf("En yuksek not = %2d\n",eb); /*<br />
sonuçlar ekrana ... */<br />
printf("En dusuk not = %2d\n",ek);<br />
printf("Ortalama = %4.1f\n",ort);<br />
return 0;<br />
}<br />
En yuksek not = 92<br />
En dusuk not = 0<br />
Ortalama = 69.2<br />
Bir program içinde birden çok dosya açmak mümkündür. Örneğin bir dosyadan okunan<br />
veriler farklı bir formatta başka bir dosyaya yazılması istenebilir.Program 16.3 kelvin.sck<br />
dosyasında bulunan 100 adet kelvin cinsinden sıcaklık bilgilerini derece karşılıklarını<br />
derece.sck dosyasına yazar. Bu iki sıcaklık arasındaki çevrim kuralı: K = 273 + C<br />
şeklindedir.<br />
Program 16.3: Bir dosyada saklı verileri farklı bir biçimde başka bir dosyaya yazma<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
/* 16prg03.c<br />
'kelvin.sck' dosyasında bulunan 100 adet<br />
kelvin cinsinden sıcaklık<br />
bilgilerini derece karşılıklarını<br />
'derece.sck' dosyasına yazar.<br />
Bu iki sıcaklık arasındaki çevrim kuralı: K =<br />
273 + C şeklindedir. */<br />
#include <br />
#include <br />
int main(void)<br />
{<br />
/* dosya göstericileri */<br />
FILE *oku, *yaz;<br />
/* Dosya adları */<br />
char *kaynak_dosya = "kelvin.sck";<br />
char *hedef_dosya = "derece.sck";<br />
float K,D;<br />
int i=0, n=100;<br />
/* Dosylara erişim mümkün mü ? */<br />
if( (oku=fopen(kaynak_dosya, "r")) == NULL )<br />
{<br />
printf("%s dosyası acilmadi.\n",<br />
kaynak_dosya);
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
exit(1);<br />
}<br />
if( (yaz=fopen(hedef_dosya, "w")) == NULL )<br />
{<br />
printf("%s acilmadi.\n", hedef_dosya);<br />
exit(2);<br />
}<br />
for(i=0; i derece.sck<br />
cevirme islemi tamamlandi.<br />
16.4 Standart Dosyalar<br />
C Programlama Dili'nde bilgisayarın sahip olduğu ekran, klavye ve portlar birer dosya olarak<br />
tanımlanmıştır. Bu dosyalara standart dosyalar denir. Program çalışmaya başladığında beş<br />
adet standart dosya otomatik olarak açılır. C, stdio.h başlık dosyasında tanımlanan bütün bu<br />
standart dosyalara birer sembolik isim vermiştir[3]. Bu isimler Tablo 16.3'de listelenmiştir.<br />
Tablo 16.3: Standart Dosyalar<br />
Dosya adı<br />
stdout<br />
stderr<br />
stdin<br />
stdprn<br />
stdaux<br />
Görevi<br />
Standart çıkış ortamı (ekran)<br />
Standart hata çıkış ortamı (ekran)<br />
Standart giriş ortamı (klavye)<br />
Standart LPT (paralel port)<br />
Standart COM (seri port)<br />
Bu dosyaların sembolik isimleri birer dosya göstericisidir. Bu sebeple FILE yapısal değişkeni<br />
ile kullanılabilen dosya fonksiyonları bu dosyalar için de kullanılabilir. Örneğin, ekrana<br />
(standart çıkışa) bir yazı bastırmak için:
fprintf(stdout,"Merhaba C\n");<br />
Bilgilerin yazıcıya gönderilmesi için yine fprintf fonksiyonu kullanılır. Örneğin:<br />
fprintf(stdprn,"Merhaba C\n");<br />
satırı yazıcıya Merhaba C iletinini gönderir.<br />
Ayrıca, LPT1 veya PRN ismini dosya ismi olarak kullanıp yazıcıya basım yapmak da<br />
mümkündür [4]. Örneğin:<br />
FILE *dg;<br />
...<br />
dg = fopen("LPT1","wt");<br />
fprintf(dg,"Merhaba C\n");<br />
...<br />
flcose(dg);<br />
NOT<br />
Tablo 16.3 de verilen standart dosyalardan stdprn ve<br />
stdaux Turbo C'de tanımlı iken Standart C'de tanımlı<br />
değildir. (bkz: stdio.h)<br />
Program 16.4 Turbo C derleyicisinde derlendiğinde hem ekrana hemde yazıcıya birer mesaj<br />
yazar.<br />
Program 16.4: Standart dosyaların kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
ÇIKTI<br />
/* 16prg04.c<br />
Standart dosyaları kullanarak hem ekrana<br />
hemde<br />
yazıcıya birer mesaj yazar. (sadece Turbo C)<br />
*/<br />
#include <br />
int main()<br />
{<br />
fprintf(stdout,"Bu mesaj *ekrana*<br />
yazilacak ...\n");<br />
fprintf(stdprn,"Bu mesaj *yaziciya*<br />
yazilacak ...\n");<br />
return 0;<br />
}<br />
Bu mesaj *ekrana* yazilacak ...<br />
NOT<br />
Eğer yazıcı bağlı yada açık değilse, işletim sistemi<br />
kullanıcıyı uyaracak ve programın çıktısı şöyle olacaktır:<br />
Bu mesaj *ekrana* yazilacak ...<br />
Yazma hatası yazılan aygıt PRN
Durdur, yeNiden dene, Yoksay, ipTal?d<br />
<strong>Ders</strong> 18: Port Denetimi<br />
• <strong>Giriş</strong><br />
• 18.1 Port Kavramı<br />
• 18.2 Port G/Ç Fonksiyonları<br />
• 18.3 Paralel Port Örnekleri<br />
• 18.4 Seri Port Örnekleri<br />
• 18.5 Linux'de Portlara Erişim<br />
<strong>Giriş</strong><br />
Bu kısımda, ağırlıklı olarak Windows işletim sistemlerinde çalışan (Turbo C, Dev-C++ gibi)<br />
derleyicilerin bünyesinde bulunan port fonksiyonları ve kullanımları anlatılacaktır. Linux<br />
işletim sisteminde benzer uygulamaların nasıl yapılacağı bölüm sonunda verilmiştir.<br />
Bir program içerisinden donanımsal birimlere erişmek veya onları kullanmak için birçok yol<br />
vardır. En basiti, bu gibi birimlere aynı bellek gözüne erişilmiyormuş gibi gösterici kullanarak<br />
erişmektir; ancak bu durum sistem mimarisinden dolayı her zaman mümkün olmayabilir. Bu<br />
durumda, ilgili birimlere erişmek için derleyicilerin sahip olduğu hazır kütüphane<br />
fonksiyonları kullanılır[1].<br />
NOT<br />
• Windows XP ve Vista işletim sistemileri, güvenlik<br />
nedeniyle, C derleyicilerine ait portlara erişim<br />
fonksiyonlarını kullanmaya da izin vermeyebilir.<br />
• Linux işletim sistemi kullanıcıları ana kullanıcı (root)<br />
olmadığı sürece, portlara erişim izni yoktur.<br />
18.1 Port Kavramı<br />
Anakartın üzerinde bir bilgisayarın en önemli bileşenleri (Veriyolları, Portlar, CPU, RAM,<br />
BIOS, ChipSet, ROM, I/O devrelerinin çoğu) bulunur. Anakart, sistemin çalışmasını organize<br />
eder. Bu organizasyon anakart üzerinde bulunan yongalar (entegre devreler) sayesinde<br />
gerçekleşir. Anakart üzerinde bilgisayara veri giriş/çıkış için kullanılan pinlere veya
elektriksel bağlantı noktalarına port denir. Örneğin: Paralel port (LPT), seri port (COM),<br />
AGP portu, PCI portları gibi.<br />
Daha fazla bilgi için burayı tıklayın.<br />
18.2 Port <strong>Giriş</strong>/Çıkış Fonksiyonları<br />
Bir bilgisayarın portlarına erişmek için birçok fonksiyon vardır. Tablo 18.1'de, Turbo C<br />
derleyicisinde bululunan ve bu konu ile ilgili birkaç fonksiyon tanıtılmıştır.<br />
NOT<br />
Turbo C derleyicisinde, port fonksiyonları kullanılabilmesi<br />
için dos.h başlık dosyası programa ilave edilmelidir.<br />
Tablo 18.1: dos.h'te tanımlı bazı port erişim fonksiyonları<br />
Port Fonksiyonu<br />
Açıklama<br />
void outp(int port_adresi,int bayt_degeri); Porta bir baytlık veri yazar<br />
void outport(int port_adresi,int deger);<br />
Porta bir kelime * yazar<br />
void outportb(int port_adresi,unsigned char deger); Porta bir baytlık veri yazar<br />
int inp(int port_adresi);<br />
Porttan bir baytlık veri okur<br />
int inport(int port_adresi);<br />
Porttan bir kelime okur<br />
char inportb(int port_adresi);<br />
Porttan bir baytlık veri okur<br />
(*) kelime (word) : Porta yazılacak veya porttan okunacak, bir tamsayının bellekte<br />
kaplayacağı alanı temsil eder. (Bu alan sizeof() operatörü ile öğrenilebilir)<br />
Port foksiyonlarının kullanımı, örnek programlar üzerinde, bir sonraki bölümlerde<br />
incelenmiştir. Bütün programlar Turbo C derleyicisinde denemiştir. Eger bu derleyiciye sahip<br />
degilseniz, buradan inderbilirsiniz.<br />
18.3 Paralel Port Örnekleri<br />
Bu bölümde, bir önceki kısımda verilen port fonksiyonları ile, bir PC'nin paralel portunun<br />
nasıl denetleneceği 6 tane örnek programda anlatılmıştır.<br />
NOT<br />
Standart bir PC'de LPT nin alt portlarının adresleri,<br />
DATA için 0x378, STATUS için 0x379 ve CONTROL<br />
0x37A dır;<br />
Program 18.1: outp fonksiyonunun kulanımı<br />
01:<br />
02:<br />
/* 18prg01.c: outp örneği */
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
ÇIKTI<br />
#include <br />
#include <br />
#define DATA 0x0378<br />
int main()<br />
{<br />
int deger = 25;<br />
outp(DATA, deger);<br />
printf("\n%X nolu adrese %d degeri<br />
yazildi.", DATA, deger);<br />
return 0;<br />
}<br />
378 adresine 25 degeri yazildi.<br />
Program 18.1'de 6. satırda tanımlanan porta, 12.satırda 25 değeri yazılmaktadır. Bu değer PC<br />
paralel portunun DATA uçlarına yazılır. Bu sebeple 25 değeri ikili sistemde (binary) ifade<br />
edilip 8 bite bölünür, yani 25 = 00011001 şekinde DATA portuna yazılır. Burada 1 portun<br />
ilgili bacağına +5V DC sinyalini gönderir. 0 olan bağlantı noktalarına ise sinyal gönderilmez.<br />
Bu değerler basit bir voltmetre ile ölçülüp test edilebilir.<br />
Porta yazılmak veya porttan okunmak istenen veriyi ikili (binary) olarak görüntülemek yararlı<br />
olabilir. Program 18.2'de cevir_taban2 fonksiyonu bu amaçla yazılmıştır.<br />
Program 18.2: outportb fonksiyonun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
/* 18prg02.c: outportb fonksiyonu */<br />
#include <br />
#include <br />
#include <br />
#define DATA 0x0378<br />
long cevir_taban2(int);<br />
int main()<br />
{<br />
int deger = 0x19; /* deger = 25 */<br />
outportb(DATA,deger);<br />
printf("\nDATA portuna gonderilen deger %d :<br />
%08ld",deger, cevir_taban2(deger));<br />
return 0;<br />
}
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
/* Bu fonksiyon 10 tabanındaki bir sayıyı<br />
2 tabınındaki karşılığını hesaplar. */<br />
long cevir_taban2(int x)<br />
{<br />
int i = 0, k;<br />
long bin = 0;<br />
}<br />
ÇIKTI<br />
while( x>0 )<br />
{<br />
if(x%2) k = 1;<br />
else k = 0;<br />
bin += k*pow(10,i++);<br />
x /= 2;<br />
}<br />
return bin;<br />
DATA portuna gonderilen deger 25 : 00011001<br />
9. satırdaki cevir_taban2 fonksiyonu, kendisine parametere olarak gelen bir tamsayıyı iki<br />
tabana çevirir. Ekranda porta yazılan değer ve onun iki tabanındaki karşılığı, uygun bir<br />
formatla, 8 bit halinde gösterilmiştir.<br />
inp() ve inportb() fonksiyonları, PC bağlantı noktalarından sırasıyla bir karakter ve bir<br />
baytlık veri okumak mümkündür. Program 18.3, bu fonksiyonlar ile nasıl veri okunacağına<br />
dair iyi bir fikir verir.<br />
Program 18.3: inp ve inportb fonksiyonlarıyla paralel porta atanan varsayılan değerleri<br />
öğrenme<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
/* 18prg03.c: inp ve inportb fonksiyonlarının<br />
kullanımı */<br />
#include <br />
#include <br />
#define DATA 0x0378<br />
#define STATUS DATA+1<br />
#define CONTROL DATA+2<br />
int main()<br />
{<br />
int veri;<br />
puts("Paralel porta atanan degerler (Hex):");<br />
veri = inp(DATA);<br />
printf( "Data portu : %X\n",veri );<br />
veri = inp(STATUS);<br />
printf( "Status portu : %X\n",veri );
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
ÇIKTI<br />
veri = inportb(CONTROL);<br />
printf( "Kontrol portu : %X\n",veri );<br />
return 0;<br />
}<br />
Paralel porta atanan degerler (Hex):<br />
Data portu : 4<br />
Status portu : 7F<br />
Kontrol portu : CC<br />
Programın elde ettiği değerler, porta hiç bir müdehale olmadan elde edilmiştir ve her<br />
bilgisayarda başka bir sonuç verebilir. Bu fonksiyonların tek parameteresi olduğuna dikkat<br />
ediniz.<br />
Bir porta herhangi bir veri yazıldıktan sonra, bu veri o portun saklayıcısına (register) yazılır<br />
ve yeni bilgi yazılmadıkça orada kalır. Program 18.4 CONTROL portuna ouportb ile yazılan<br />
bir verinin inportb fonksiyonu ile okunması gösterilmiştir.<br />
Program 18.4: inportb ve outportb fonksiyonlarının kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
ÇIKTI<br />
/* 18prg04.c: inportb ve outportb örneği */<br />
#include <br />
#include <br />
#define PORT 0x037A<br />
int main()<br />
{<br />
int deger;<br />
deger = inportb(PORT); /* varsayılan deger<br />
*/<br />
printf("\nPorta veri yazilmadan onceki deger<br />
: %X",deger);<br />
deger = 0x0A; /* deger = 10 */<br />
outportb(PORT, deger);<br />
deger = inportb(PORT);<br />
printf("\nPorta veri yazdiktan sonraki deger<br />
: %X",deger);<br />
return 0;<br />
}<br />
Porta veri yazilmadan onceki deger : CC
Porta veri yazdiktan sonraki deger : CA<br />
Program 18.4'ün çıktısı incelendiğinde, portta varsayılan değerin CCh, veri yazıldıktan<br />
sonraki değerin CAh olduğu görülmektedir. CONTROL portunun ilk 4-bitine müdehale<br />
edilebildiği halde ikinci 4-biti değiştirilememiş. Neden?<br />
18.4 Seri Port Örnekleri<br />
Bu bölümde, yine Standart C'de olmayan bilgisayarın seri portları üzerinden iletişim konu<br />
edilecektir.<br />
NOT<br />
Standart bir PC'de COM1 için ilk adres 0x3F8, COM2 için<br />
0x2F8 dir;<br />
Standart PC'lerin seri iletişim portlarına erişim UART olarak adlandırılan bir birim üzerinden<br />
gerçekleştirilir. Bu birim anakat üzerindeki bir entegre devredir. Ancak temel olarak bilinmesi<br />
gereken alma saklayıcısına ve gönderme saklayıcısına nasıl erişileceği ve UART'ın<br />
ayarlarının nasıl yapılacağıdır. Program 18.5'de bir dosya içeriğinin karakter karakter seri port<br />
üzerinden karşı tarafa nasıl gönderileceği görülmektedir[1].<br />
Program 18.5: Bir metin dosyasının içeriğini seri porta aktarır.<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
/* 18prg05.c: Bir metin dosyasının içeriğini<br />
seri porta aktarır */<br />
#include <br />
#include <br />
#include <br />
int main()<br />
{<br />
char kr;<br />
FILE *dosya;<br />
/* UART'ın ayarlanması */<br />
outportb(0x3FB,0x80);<br />
outport (0x3F8,0x0C);<br />
outportb(0x3FB,0x1B); /* 9600 bps.dur biti<br />
1.cift eslik, 8 bit veri*/<br />
/* dosya açılıyor */<br />
if ( (dosya=fopen("deneme.txt", "r")) ==<br />
NULL) {<br />
puts ("Hata olustu! Dosya acilmadi.");<br />
exit(1);<br />
}<br />
while( !feof(dosya) )<br />
{<br />
kr=getc(dosya); /*<br />
dosyadan bir karakter oku */<br />
while ( (inportb(0x3FD) & 0x20)==0 ); /*
31:<br />
32:<br />
gönderme saklayicisi sınanıyor */<br />
ouportb(0x3F8,kr); /*<br />
porta gönderiliyor */<br />
}<br />
fclose(dosya); /*<br />
dosya kapatiliyor */<br />
return 0;<br />
}<br />
Bir UART iletişim işine geçmeden önce ayarlanmalıdır; yani, iletişim hızı, hata biti kullanıp<br />
kullanılmayacağı gibi birtakım bilgilerin yerleştirimi yapılmalıdır. UART'ın herhangi bir<br />
andaki durumu, yani veri göndermeye hazır olup olmadığı, yeni veri gelip gelmediği gibi<br />
bilgiler hat durum saklayıcısı üzerindeki bitlere bakılarak anlaşılır. Örneğin, UART'a<br />
gönderilmesi için bir veri yazılmadan önce, göndermek için uygun olup olmadığı<br />
sınanmalıdır. Program 18.6'de seri port üzerinden gelen karakterleri alıp ekrana nasıl yazıldığı<br />
görülmektedir[1].<br />
Program 18.6: Seri port üzerinden gelen karakterleri alıp ekrana yazar.<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
/* 18prg06.c: Seri port üzerinden gelen<br />
karakterleri alıp ekrana yazar */<br />
#include <br />
#include <br />
int main()<br />
{<br />
char kr;<br />
/* UART'ın ayarlanması */<br />
outportb(0x3FB,0x80);<br />
outport (0x3F8,0x0C);<br />
outportb(0x3FB,0x1B); /* 9600 bps.dur biti<br />
1.cift eslik, 8 bit veri*/<br />
while(1)<br />
{<br />
while( (inportb(0x3FD) & 0x01)==0 ); /*<br />
yeni karakter gelene kadar bekle */<br />
kr=inportb(0x3F8); /*<br />
geleni al ve kr'ye yerleştir */<br />
printf("%c", kr);<br />
}<br />
return 0;<br />
}<br />
Soru: Son iki programı öyle değiştirin ki, birinin klavyesinden girilen, diğerinin ekranında<br />
görülsün.<br />
18.5 Linux'de Portlara Erişim
Linux işletim sisteminde portlara erişmek için birkaç yol vardır. Burada, gcc derleyicisinin<br />
içine gömülebilen assemble dili kullanılarak oluşturulan port fonksiyonları gösterilecektir.<br />
Linux'de ana kullanıcı (root) olmadıkça veya ana kullanıcı izin vermedikçe portlara erişmeniz<br />
mümkün değildir. Bu yüzden, önce programın portlara erişim izni verip vermediği<br />
sınanmalıdır. Bunun için, /usr/include/sys/io.h dosyası içinde tanımlı ioperm()<br />
fonksiyonu kullanılabilir.<br />
Program 18.7 de basit bir port erişim programı verilmiştir. Kullanıcıların, programın başına<br />
ilave edebileceği başlık dosyaları için ayrıca bkz. Bölüm 20.<br />
Program 18.7: Linux'de port erişimi<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
/* 18prg07.c<br />
Linux işletim sisteminde portlara erişim */<br />
#include <br />
#include <br />
#include <br />
#include "linuxPort.h"<br />
int main()<br />
{<br />
int deger = 25;<br />
/* porta erişim izni var mı?<br />
sadece root ve onun izin verdiği<br />
kullanıcılar erişebilir ) */<br />
if( port_erisim() ) exit(1);<br />
outportb(DATA, deger);<br />
printf("\n%X nolu adrese %d degeri<br />
yazildi.", DATA, deger);<br />
return 0;<br />
}<br />
17. satırdaki port_erisim() fonksiyonu ioperm() fonksiyonunu çağırıp erişim iznini<br />
denetler. port_erisim(), aşağıda verilen linuxPort.h dosyası içinde tanımlanmıştır.<br />
linuxPort.h bütün Linux tabanlı işletim sistemlerinde bulunan gcc derleyici ile<br />
kullanılabilir.<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
/********************************************************************<br />
*<br />
**<br />
**<br />
** linuxPort.h<br />
**<br />
**<br />
**<br />
** Linux işletim sisteminde kullanılabilecek port fonksiyonları<br />
**<br />
**<br />
**
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
50:<br />
51:<br />
52:<br />
53:<br />
54:<br />
55:<br />
56:<br />
57:<br />
58:<br />
59:<br />
60:<br />
61:<br />
62:<br />
63:<br />
64:<br />
65:<br />
66:<br />
67:<br />
68:<br />
69:<br />
70:<br />
71:<br />
72:<br />
73:<br />
** Oluşturma tarihi: Haziran 2006<br />
**<br />
** Enson güncelleme: Kasım 2008<br />
**<br />
**<br />
**<br />
*********************************************************************<br />
/<br />
//<br />
// Standart PC için Port adresleri ----------------------------------<br />
--<br />
//<br />
#define DATA 0x378<br />
#define STATUS 0x379<br />
#define CONTROL 0x37A<br />
#define COM1 0x3F8<br />
#define COM2 0x2F8<br />
#define MCR 0x3FC // Modem Control Register (8 bit)<br />
#define MSR 0x3FE // Modem Status Register (8 bit)<br />
#define KEYB1 0x060<br />
#define KEYB2 0x064<br />
//<br />
// port erişim fonksiyonları ----------------------------------------<br />
--<br />
// Bu fonksiyonlar, gcc derleyicisinde dosyasında<br />
mevcuttur<br />
//<br />
void outportb(unsigned short port, unsigned char data)<br />
{<br />
__asm__ __volatile__ ("outb %1, %0"<br />
:<br />
: "dN" (port),<br />
"a" (data));<br />
}<br />
void outport(unsigned short port, unsigned short data)<br />
{<br />
__asm__ __volatile__ ("outw %1, %0"<br />
:<br />
: "dN" (port),<br />
"a" (data));<br />
}<br />
unsigned char inportb(unsigned short port)<br />
{<br />
unsigned char rv;<br />
__asm__ __volatile__ ("inb %1, %0"<br />
: "=a" (rv)<br />
: "dN" (port));<br />
return rv;<br />
}<br />
unsigned short inport(unsigned short port)<br />
{<br />
unsigned short rv;<br />
__asm__ __volatile__ ("inw %1, %0"<br />
: "=a" (rv)
74:<br />
75:<br />
76:<br />
77:<br />
78:<br />
79:<br />
80:<br />
81:<br />
82:<br />
83:<br />
84:<br />
85:<br />
86:<br />
87:<br />
88:<br />
89:<br />
90:<br />
91:<br />
92:<br />
93:<br />
94:<br />
95:<br />
96:<br />
97:<br />
98:<br />
99:<br />
100<br />
:<br />
101<br />
:<br />
102<br />
:<br />
103<br />
:<br />
104<br />
:<br />
105<br />
:<br />
106<br />
:<br />
107<br />
:<br />
108<br />
:<br />
109<br />
:<br />
110<br />
:<br />
111<br />
:<br />
112<br />
:<br />
113<br />
:<br />
114<br />
:<br />
115<br />
:<br />
116<br />
:<br />
117<br />
}<br />
: "dN" (port));<br />
return rv;<br />
//<br />
// erisim izinlerini kontrol et -------------------------------------<br />
//<br />
int port_erisim(void)<br />
{<br />
int i, erisim = 0;<br />
/* paralel porta erisim izni var mi? */<br />
for(i=0; i
:<br />
118<br />
:<br />
}<br />
outportb(COM1 + 3 , 0x03); // 8 bit, parity yok, 1 dur biti<br />
outportb(COM1 + 2 , 0xC0); // FIFO Kontrol saklayıcısı<br />
<strong>Ders</strong> 19: Grafik Kullanımı<br />
• <strong>Giriş</strong><br />
• 19.1 Grafik Ekranına Geçiş<br />
• 19.2 Bazı Grafik Fonksiyonları<br />
• 19.3 Renk Kodları<br />
• 19.4 Örnekler<br />
<strong>Giriş</strong><br />
Bu kısımda sadece Turbo C derleyicisine ait basit grafik uygulamaları kısaca anlatılmıştır.<br />
Örneklerde verilen grafik fonksiyonları ANSI C de bulunmamaktadır. Bu yüzden bir çok C<br />
derleyicisi, kendi bünyesinde farklı grafik fonksiyonlarına sahiptir. Örneğin Linux<br />
ortamındaki grafik kullanmak için g2 kütüphanesi geliştirilmiştir.<br />
19.1 Grafik Ekranına Geçiş<br />
Turbo C'de, Grafik sistemine geçmek için, initgraph() fonksiyonunu kullanılır. Bütün<br />
çizimler sadece DOS ortamında çalışır. Grafik fonksiyonlarının kullanılması için graphics.h<br />
başlık dosyası programın başına ilave edilmelidir. Grafik işlemleri için temel işlemler:<br />
#include <br />
#include <br />
...<br />
int surucu = DETECT, grmod, hata_kodu; /* DETECT grafik<br />
sürücüsünü otomatik seçer */<br />
.<br />
.<br />
.<br />
initgraph(&surucu, &grmod, ""); /* grafik ekranını başlat<br />
*/<br />
hata_kodu = graphresult(); /* hata_kodu al */<br />
if (hata_kodu != grOk) /* hata_kodu 0 dan farklı<br />
ise başlatma */<br />
{<br />
puts("Hata olustu.");<br />
puts("Grafik ekrani baslatilamiyor.");<br />
exit(1);<br />
}
.<br />
. /* grafik işlemleri ... */<br />
.<br />
closegraph(); /* grafik ekranını kapat */<br />
şeklindedir.<br />
NOT<br />
initgraph fonksiyonundaki 3. parametre ("") boş<br />
bırakıldığında kaynak dosyanın C:\TC dizininde olması<br />
zorunludur.<br />
Eğer kaynak dosya başka bir dizinin altında ise o zaman<br />
initgraph(&surucu, &grmod, "C:\\TC");<br />
şeklinde kullanılmalıdır.<br />
Turbo C'de varsayılan grafik modu (640,480) çözünürlüğe ayarlanmıştır. Bu modda, Çizim<br />
ekrenının sol-üst köşesine ait koordinat (0,0) olarak tanımlıdır. Varsayılan moddaki bazı<br />
koordinatlar Şekil 19.1'de gösterilmiştir.<br />
Şekil 19.1: Turbo C varsayılan moddaki koordinatlar<br />
19.2 Bazı Grafik Fonksiyonları<br />
Bu bölümde Turbo C grafik fonksiyonlarının bazıları tanıtılmıştır. Bunların dışında biçok<br />
fonksiyon vardır. Bu fonksiyonlar derleyicinin başvuru kitabından veya derleyicinin yardım<br />
kısmından öğrenilebilir.<br />
Tablo 19.1: graphics.h'te tanımlı bazı grafik fonksiyonları<br />
Fonksiyon<br />
moveto(x,y);<br />
Açıklama<br />
Son noktayı (x,y) noktasına taşır
lineto(x,y);<br />
line(x1,y1,x2,y2);<br />
circle(x,y,r);<br />
arc(x,y,baş_açı,bit_açı,r);<br />
ellipse(x,y,baş_açı,bit_açı,xr,yr);<br />
putpixel(x,y,renk);<br />
rectangle(sol,üst,sağ,alt);<br />
bar(sol,üst,sağ,alt);<br />
bar3d(sol,üst,sağ,alt,derinlik,şapka);<br />
setcolor(renk);<br />
setbkcolor(renk);<br />
outtext(*katar);<br />
outtextxy(x,y,*katar);<br />
settextstyle(font,yön,boyut);<br />
cleardevice();<br />
closegraph();<br />
Son noktadan (x,y) noktasına düz bir<br />
çizgi çizer.<br />
(x1,y1) noktasından (x2,y2) noktasına<br />
düz bir çizgi çizer.<br />
Merkezi (x,y) olmak üzere yarıçapı r<br />
olan bir çember çizer.<br />
Merkezi (x,y) noktasında ve yarıçapı r<br />
olan, baş_açı açısından dan başlayıp<br />
bit_açı açısına kadar bir yay çizer.<br />
Elipsin bir parçası olan yayı, merkezi<br />
(x,y) ve yarıçapları xr, yr olacak biçimde<br />
baş_açı açısındandan başlayarak<br />
bit_açı açısına kadar bir yay çizer.<br />
(x,y) noktasına verilen renkte bir nokta<br />
çizer.<br />
Sol üst köşesi (sol,üst) ve sağ alt köşesi<br />
(sağ,alt) koordinatlarında olacak şekilde<br />
bir dikdörtgen çizer.<br />
İki boyutlu ve taralı bir bar çizer.<br />
Üç boyutlu ön yüzeyi taralı bar çizer.<br />
Şapka 0 ise barın üst kısmı çizilmez.<br />
Çizilen olan şeklin rengini belirler<br />
Arka alanın rengini belirler.<br />
Grafik ekranında katar yazdırır.<br />
Grafik ekranında yazılacak katar'ı, (x,y)<br />
ile belirlenen noktadan başlayarak yazar.<br />
Ekranda yazılacak olan bir katarın<br />
yazıtipini, yönünü ve boyutunu belirler.<br />
yön=0 ise yatay, yön=1 ise dikey yazar.<br />
Ekranı temizler. DOS'taki CLS komutu<br />
gibi.<br />
Grafik ekranını kapatıp normal yazı<br />
ekranına (DOS ekranı) döner.<br />
19.3 Renk Kodları<br />
Grafik ekranında kullanılan renkler 0-15 arasında renk kodları, yada simgesel sabit karşılıkları<br />
ile tanımlıdır. Bu tanımlamaların tamamı graphics.h'de şöyle bildirilmiştir (bkz<br />
graphics.h):<br />
enum COLORS {<br />
BLACK, /* koyu renkler */<br />
BLUE,<br />
GREEN,<br />
CYAN,<br />
RED,
MAGENTA,<br />
BROWN,<br />
LIGHTGRAY,<br />
DARKGRAY,<br />
LIGHTBLUE, /* açık renkler */<br />
LIGHTGREEN,<br />
LIGHTCYAN,<br />
LIGHTRED,<br />
LIGHTMAGENTA,<br />
YELLOW,<br />
WHITE<br />
};<br />
Ayrıca bu kodları liste halinde Tablo 19.2 de bulabilirsiniz.<br />
Tablo 19.2: conio.h ve graphics.h'te tanımlı Standart CGA Video Renk Kodları<br />
Renk (TR) Renk (EN)<br />
Renk<br />
Örneği<br />
Renk Kodu<br />
Siyah BLACK 0<br />
Mavi BLUE 1<br />
Yeşil GREEN 2<br />
? CYAN 3<br />
Kırmızı RED 4<br />
Menekşe MAGENTA 5<br />
Kahverengi BROWN 6<br />
Açık Gri LIGHTGRAY 7<br />
Koyu Gri DARKGRAY 8<br />
Açık Mavi LIGHTBLUE 9<br />
Açık Yeşil LIGHTGREEN 10<br />
Açık ? LIGHTCYAN 11<br />
Açık Kırmızı LIGHTRED 12<br />
Açık Menekşe LIGHTMAGENTA 13<br />
Sarı YELLOW 14<br />
Beyaz WHITE 15<br />
19.4 Örnekler<br />
NOT<br />
Buradaki örnek programlar Turbo C'nin editör ortamında<br />
derlenmiştir.<br />
Program 19.1: Grafik ekranında; bir çizgi, bir çember, bir yay, bir dikdörtgen ve bir elips<br />
çizer<br />
01:<br />
02:<br />
03:<br />
04:<br />
/* 19prg01.c<br />
Çizim ekranında bir çizgi, bir çember,<br />
bir yay, bir dikdörtgen ve bir elips çizer.<br />
*/
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
#include <br />
#include <br />
int main()<br />
{<br />
int sur = DETECT, gmod;<br />
/* grafik ekranını başlat */<br />
initgraph(&sur,&gmod,"");<br />
line (12, 12, 298, 198);<br />
circle (200, 100, 75);<br />
arc (200, 100, 90, 180, 50);<br />
rectangle (10, 10, 300, 200);<br />
ellipse (320, 240, 0, 180, 50, 70);<br />
return 0;<br />
}<br />
getchar();<br />
closegraph(); /* grafik ekranını kapat */<br />
Program<br />
çıktısı<br />
Program 19.2: outtext, outtextxy, setcolor, settextstyle, setlinestyle fonksiyonları<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
/* 19prg02.c<br />
Bu program ekranda yatay ve dikey iki yazı<br />
yazar ve<br />
farklı kalınlıkta iki çizgi çizer. */<br />
#include <br />
#include <br />
int main()<br />
{<br />
int surucu=DETECT,mod;<br />
initgraph(&surucu,&mod,"C:\\TC");<br />
setcolor(3);<br />
outtext("Merhaba C.");<br />
setcolor(10);<br />
outtextxy(30,40,"Bu yazi YATAY");<br />
setcolor(YELLOW);
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
return 0;<br />
}<br />
settextstyle(1,1,5);<br />
outtextxy(50,60,"Bu yazi DIKEY");<br />
setcolor(WHITE);<br />
setlinestyle(3,0,1);<br />
line(320,240,500,350);<br />
setcolor(RED);<br />
setlinestyle(1,1,3);<br />
circle(320,240,100);<br />
getchar();<br />
closegraph();<br />
Program<br />
çıktısı<br />
Program 19.3: y=f(x) ile belirlenen bir fonksiyonu çizer<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
/* 19prg03.c<br />
x : [-20, 20] aralığında y= 5 * sin(x)<br />
fonksiyonunun grafiğini çizer. */<br />
#include <br />
#include <br />
#include <br />
int main()<br />
{<br />
int sur = DETECT, grmode;<br />
float x,y,olcek;<br />
int X,Y;<br />
initgraph(&sur, &grmode, "C:\\TC");<br />
setcolor(BLUE);<br />
coordinatları mavi */<br />
line(0,240,640,240);<br />
line(320,0,320,480);<br />
/* x-y<br />
olcek = 15.0; /* Ölçek<br />
değiştirilerek büyütme/küçültme yapılabilir. */<br />
setbkcolor(WHITE);<br />
beyaz */<br />
setcolor(RED);<br />
rengi kırmızı */<br />
/* zemin rengi<br />
/* Fonksiyonun
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
x=-20.0;<br />
[-20,20] aralığında */<br />
do<br />
{<br />
y = 5*sin(x);<br />
fonksiyonu */<br />
/* x değerleri<br />
/* y=5*sin(x)<br />
X = 320 + x*olcek; /* Lineer<br />
Dönüşüm denklemleri */<br />
Y = 240 - y*olcek;<br />
line(X, Y, X, Y);<br />
çiziliyor... */<br />
return 0;<br />
}<br />
x += 0.01;<br />
}while( x
Makro bildirimleri veya Yönergeleri (direktive) derleme öncesi komutlarıdır. Bunlar tipik<br />
olarak:<br />
• programları değiştirmek<br />
• program parçalarını kaynak programında birleştirmek<br />
• derleme sırasında bazı uyarı mesajlarını aktif veya pasif hale getirmek<br />
için kullanılır. Genelde makro bildirimleri kaynak dosyaların en başında verilir.<br />
C dilinde kullanılan Yönergeler (önişlemci komutları) şunlardır:<br />
#include #define #pragma<br />
#error #undef #ifdef #ifndef<br />
#if #else #elif #endif<br />
20.1 #include Yönergesi<br />
Bu önişlemci verilen dosyanın içeriğini, kullanıldığı yerde kaynak dosyasının içine ekler.<br />
Çoğunlukla derleyiciye ait komut kütüphanelerinde bulunan fonksiyonların prototiplerinin ve<br />
diğer çeşitli tanımlamaların bulunlunduğu (h uzantılı) başlık dosyalarının programa dahil<br />
edilmesinde kullanılır[2]. İki tür kullanımı vardır:<br />
veya<br />
#include <br />
#include "dosya_adı.h"<br />
• Birinci kullanımda dosyanın nerede bulunduğu derleyici için verilen ulaşım yolu ile<br />
belirlenir. Bu yol genellikle include dizini ile son bulur. Başlık dosyalarının saklandığı<br />
include dizini<br />
o Borland firmasına ait Turbo C derleyicisinde : C:\TC\INCLUDE<br />
o Linux ortamında : /usr/include şeklindedir.<br />
• İkinci kullanımlada dosyanın bulunduğu yer aktif dizin olarak kabul edilir. Aksi halde<br />
yol tam olarak verilmelidir.<br />
#include deyimi ile program ilave edilecek dosya C fonksiyonları içerebileceği gibi basit<br />
deyimler de içerebilir. Bunun için bir sınırlandırma yoktur. Hatta uzantıları .h olması bile<br />
gerekmez. Program 20.1 ve Program 20.2'yi inceleyin.<br />
Program 20.1: #include önişlemcisinin kullanımı için bir örnek<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
/* 20prg01.c: faktoriyel ve kombinasyon<br />
hesaplamaları */<br />
#include <br />
#include "komb.h"<br />
int main()<br />
{
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
ÇIKTI<br />
int i;<br />
/* 0 dan 10 yekadar olan sayıların<br />
faktoriyelleri */<br />
for(i = 0; i
}<br />
Program 20.2: #include önişlemcisinin kullanımı için başka bir örnek<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
/* 20prg02.c:<br />
Klavyeden girilen bir doğal sayının, kaç<br />
basamaklı<br />
olduğunu bulup ekrana yazar.<br />
*/<br />
#include <br />
int main(){<br />
#include "bildirim.inc"<br />
printf("Bir dogal sayi gir: ");<br />
scanf("%d",&sayi);<br />
if(sayi0){<br />
n /= 10;<br />
b++;<br />
}<br />
printf("%d %d basamakli bir<br />
sayidir.\n",sayi,b);<br />
}<br />
return BASARILI;<br />
Dikkat edilirse Program 20.2 içinde değişkenler tanımlanmamıştır. 11. satırdaki bildirim.inc<br />
dosyası değişken bildirimlerini barındırmaktadır. Bu özellik (veya esneklik), çok büyük ve<br />
profesyonel programlarda kullanılmaktadır.<br />
ÇIKTI<br />
Bir dogal sayi gir: 4578<br />
4578 4 basamakli bir sayidir.<br />
20.2 #define Yönergesi<br />
Bu önişlemci komutu, kaynak dosyada bir isim yerine başka bir isimin yerleştirilmesini<br />
sağlar. Programda kullanılan bu sembolik isimler başta ana program olmak üzere bütün alt<br />
programlarda da aynı değere sahiptir. Yani #define önişlemcisi ile tanımlanan her ne olursa<br />
olsun, tanımlama bütün fonksiyonlarda kullanılabilir. Bir çeşit genel (global) bildirim gibi<br />
davranır. Örneğin:
Program 20.3: #define önişlemcisinin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
/* 20prg03.c: #define önişlemcisinin kullanımı<br />
*/<br />
#include <br />
#define PROGRAM main()<br />
#define BASLA {<br />
#define BIT }<br />
#define YAZ printf<br />
PROGRAM<br />
BASLA<br />
YAZ("Merhaba C!..\n");<br />
BIT<br />
Program 20.3 derleme işleminden önce #define ile verilen ilk sembolik isimler yerine ikinci<br />
isimler yerleştirildikten sonra program aşağıdaki durmuma gelir:<br />
/* 20prg03.c: #define önişlemcisinin kullanımı */<br />
#include <br />
main()<br />
{<br />
printf("Merhaba C!..\n");<br />
}<br />
Bu önişlemciyi kullanak sembolik sabitler tanımlamak mümkündür. Örneğin:<br />
#define PI 3.1415926<br />
#define IKI_PI 2.0*PI<br />
#define YUZ 100<br />
gibi.<br />
#define önişlemcisinin kullanımı için iyi bir örnek Program 20.4 de verilmiştir. Program<br />
km/s biriminde verilen bir hızı m/s birimine çevirir[4].<br />
Program 20.4: #define önişlemcisinin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
/* 20prg04.c: km/s biriminde verilen hızı m/s<br />
cinsinden hesaplar */<br />
#include <br />
#define km *1000.0<br />
#define saat *3600.0<br />
main()<br />
{<br />
double yol,zaman,hiz;<br />
yol = 100 km;<br />
zaman = 1.2 saat;<br />
hiz = yol/zaman;
17:<br />
18:<br />
19:<br />
}<br />
printf("HIZ = %lf m/s\n",hiz);<br />
ÇIKTI<br />
HIZ = 23.148148 m/s<br />
5. ve 6. satırda tanımlanan sembolik sabitler km ve saat program içinde kullanıldığında sol<br />
taraflarındaki sayıyı sırasıyla 1000 ve 3600 ile çarparlar. 12. satırdaki yol değişkenine<br />
100*1000.0 değeri atanır. Benzer olarak 13. satırdaki zaman değişkenine 1.2*3600.0 sayısı<br />
atanır. Dikkat edilirse sembolik sabitler kullanıldığında programın okunurluğu artmakta ve<br />
bundan dolayı hata ayıklama kolaylaşmaktadır.<br />
#define önişlemcisi ile parametrik tanımlamalar veya global fonksiyonlar tanımlamak<br />
mümkün olur. Örneğin:<br />
Program 20.5: Makro fonksiyon tanimlama<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
/* 20prg05.c: Makro fonksiyon tanimlama. */<br />
#include <br />
#include <br />
/* makro fonksiyonlar */<br />
#define kare(x) (x*x)<br />
#define topl(x,y) (x+y)<br />
#define carp(x,y) (x*y)<br />
#define hipo(x,y) sqrt(x*x+y*y)<br />
main(void)<br />
{<br />
float a=3.0, b=4.0;<br />
}<br />
ÇIKTI<br />
printf("kare(2) = %f\n",kare(2));<br />
printf("topl(a,b) = %f\n",topl(a,b));<br />
printf("carp(a,b) = %f\n",carp(a,b));<br />
printf("hipo(a,b) = %f\n",hipo(a,b));<br />
kare(2) = 4.000000<br />
topl(a,b) = 7.000000<br />
carp(a,b) = 12.000000<br />
hipo(a,b) = 5.000000<br />
Programda tanımlanan kare(2) ifadesi (2)*(2) şeklinde yorumlar. Benzer durum diğer<br />
makrolar için de geçerlidir.<br />
Makrolar C'de çok sık kullanılır. Örneğin, tek boyutlu bir dizinin boyutu öğrenilmek<br />
istendiğinde aşağıdaki makro kullanılabilir:
#define BOYUT sizeof(DIZI)/sizof(DIZI[0])<br />
...<br />
int a[10], n;<br />
...<br />
n = BOYUT(a);<br />
Son satırdaki işlemle, n değişkeninine (a dizisinin boyutu) 10 değeri atanır.<br />
İşte ilginç bir makro daha. Daha önce anlatılan takas(a,b) fonksiyonu gösterici<br />
kullanmadan aşağıdaki makro ile yazılabilir:<br />
#define takas(x,y) {g=(x); (x)=(y); (y)=g;}<br />
...<br />
int x=22, y=33, g; /* g geçici bir değişken */<br />
...<br />
printf("%d %d\n",x,y); /* 22 33 */<br />
takas(a,b)<br />
printf("%d %d\n",a,b); /* 33 22 */<br />
...<br />
20.3 #undef Yönergesi<br />
#define ile tanımlanan bir isim, orjinal tanımlamaları kaldırmaksızın farklı değerler için<br />
tekrar tanımlanamaz.<br />
#define SIFRE 14576 /* ilk tanimlama */<br />
...<br />
#define SIFRE 22357 /* hata! tanımlama tekrarlandı. */<br />
Eğer #define ile tanımlanan bir ifade yeniden tanımlanmak istenirse, #undef önişlemcisi ile<br />
önceki tanımlama iptal edildikten sonra #define ile yenisi değiştirilir. Yani:<br />
#define SIFRE 14576 /* ilk tanimlama */<br />
...<br />
#undef SIFRE /* ilk tanımlamayı iptal et */<br />
#define SIFRE 22357 /* yeni tanımlama */<br />
20.4 #if, #elif, #else ve #endif Yönergeleri<br />
Bu önişlemciler, makro düzeyinde kontrol deyimleridir. Genel kullanım biçimi:<br />
#if (ifade1)<br />
tanımlama blogu1<br />
#elif (ifade2)<br />
tanımlama blogu2<br />
...<br />
#else<br />
tanımlama bloguN
#endif<br />
şeklindedir. Burada:<br />
• #if makrosu if deyimine<br />
• #elif makrosu else if deyimine<br />
• #else makrosu else deyimine<br />
• #endif makrosu if deyiminin sonuna<br />
karşılık gelmektedir. Bu makrolar, donanıma veya işletim sistemine uygun olarak değişik<br />
makroların tanımlanmasına izin verir. Örneğin:<br />
Program 20.6: Kontrol önişlemcilerinin kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
ÇIKTI<br />
/* 20prg06.c: Kontrol ön işlemcilerinin<br />
kullanımı */<br />
#include <br />
#if(sizeof(int)==2)<br />
#define ISLETIM_SISTEMI "16 bitlik isletim<br />
sistemi."<br />
#else<br />
#define ISLETIM_SISTEMI "32 bitlik isletim<br />
sistemi."<br />
#endif<br />
int main()<br />
{<br />
printf(ISLETIM_SISTEMI);<br />
return 0;<br />
}<br />
32 bitlik isletim sistemi.<br />
Bu program eski DOS işletim siteminde derlenip çalıştırıldığında, program çıktısı şöyle olur:<br />
ÇIKTI<br />
16 bitlik isletim sistemi.<br />
20.5 #ifdef ve #ifndef Yönergeleri<br />
• #ifdef önişlemcisi ile, bir ismin tanımlanmış olup olmadığı<br />
• #ifndef önişlemcisi ile, bir ismin tanımlanmamış olup olmadığı<br />
sorugulanır. Örneğin:<br />
#ifndef SIFRE<br />
#define SIFRE 22357
#endif<br />
gibi.<br />
Program 20.7: Tanımlanmış ise pi sayısını kullanır.<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
/* 20prg07.c: Tanımlanmış ise PI sayısını<br />
kullanır */<br />
#include <br />
#include <br />
#define PI 3.141593<br />
main()<br />
{<br />
double c, r = 21.3;<br />
}<br />
ÇIKTI<br />
#ifdef PI<br />
c = 2.0 * PI * r;<br />
printf("Dairenin cevresi = %lf\n",c);<br />
#else<br />
printf("PI saysisi tanimlanmamis.\n");<br />
#endif<br />
Dairenin cevresi = 133.831862<br />
20.6 #error Yönergesi<br />
Önişlemci bu deyimle karşılaşınca yanındaki mesajı ekrana yazar ve derleme işlemine son<br />
verir. Mesela, yazmış olduğunuz program 32 bitlik bir işletim sistemi (WINDOWS veya<br />
Linux gibi) için tasarlanmışsa ve program 16 bitlik işletim sisteminde (MSDOS gibi)<br />
derlenecekse kullanıcıya buna dair bir uyarı mesajı vermek uygun olur[2-4]. Örneğin:<br />
#if (sizeof(int)==2)<br />
#error Bu program 16 bitlik işletim sisteminde derlenemez !...<br />
#endif<br />
Eğer DOS altında çalışıyorsanız önişlemci derleme işlemine:<br />
Bu program 16 bitlik işletim sisteminde derlenemez !...<br />
mesajı ile son verir. Mesajın tırnak içine alınmadığına dikkat ediniz.<br />
20.7 Önceden Tanımlanmış Sembolik Sabitler<br />
Bazı sembolik sabitler derleyici tarafından önceden tanımlanmıştır. Bu sabitlerden bazıları<br />
Tablo 20.1 de verilmiştir.
Tablo 20.1: Önceden tanımlı bazı sembolik sabitler<br />
Sabit ismi<br />
Açıklama<br />
Önişlemci bu sabit yerine kaynak koddaki o anda bulunan satır<br />
__LINE__<br />
numarasını yerleştirir.<br />
__FILE__<br />
Kaynak dosyanın ismin tutar.<br />
Önişlemci bu sabit yerine derlemenin yapıldığı zaman tarihi (ay gün<br />
__DATE__<br />
yıl formatında) yazar.<br />
Önişlemci bu sabit yerine derlemenin yapıldığı zaman zamanı<br />
__TIME__<br />
(sa:dak:sn gün yıl formatında) yazar.<br />
C dilinde kullanılan kimi anahtar sözcükler standart değildir.<br />
__STDC__<br />
Derleyici eğer yalnızca standart C'nin anahtar sözcüklerini<br />
destekliyorsa bu sabit tanımlı varsayılır.<br />
M_PI<br />
Pi sayısını tutar (M_PI = 3.14159265358979323846). Ayrıca bkz:<br />
math.h<br />
M_E<br />
e sayısını tutar (M_E = 2.7182818284590452354). Ayrıca bkz:<br />
math.h<br />
Rastgele sayı üretec fonksiyonu rand() ile döndürlen en büyük sayıyı<br />
RAND_MAX<br />
tutar.<br />
(32 bit işletim sitemi için: RAND_MAX = 2147483647). Ayrıca bkz:<br />
stdlib.h<br />
Aşağıdaki örnekleri inceleyiniz:<br />
Program 20.8: C dilindeki bazı tanımlı sabitler<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
ÇIKTI<br />
/* 20prg08.c: Sembolik sabitler */<br />
#include <br />
main()<br />
{<br />
printf("Satir No : %d\n",__LINE__);<br />
printf("Dosya adi : %s\n",__FILE__);<br />
printf("Tarih : %s\n",__DATE__);<br />
printf("Saat : %s\n",__TIME__);<br />
}<br />
Satir No : 7<br />
Dosya adi : 20prg08.c<br />
Tarih : Sep 21 2008<br />
Saat : 01:58:56<br />
Program 20.9: C dilindeki bazı tanımlı sabitler<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
/* 20prg09.c: Sembolik sabitler */<br />
#include <br />
#include <br />
#include <br />
#ifndef __STDC__
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
#error Bu derleyici ANSI C degil.<br />
#endif<br />
#ifndef RAND_MAX<br />
#error RAND_MAX tanımlı degil.<br />
#endif<br />
main()<br />
{<br />
double r = (double) rand()/RAND_MAX;<br />
double ikiPi = 2.0*M_PI;<br />
double birBoluE = 1.0/M_E;<br />
}<br />
ÇIKTI<br />
printf("r = %lf\n",r);<br />
printf("ikiPi = %lf\n",ikiPi);<br />
printf("birBoluE = %lf\n",birBoluE);<br />
r = 0.840188<br />
ikiPi = 6.283185<br />
birBoluE = 0.367879<br />
<strong>Ders</strong> 22: Derleme Seçenekleri<br />
• <strong>Giriş</strong><br />
• 22.1 Çalıştırılabilir Dosya Üretimi<br />
• 22.2 Turbo C Derleme Seçenekleri<br />
• 22.3 GCC Derleme Seçenekleri<br />
<strong>Giriş</strong><br />
Bazen bir kullanıcı derlemek istediği kaynak C programını başka C programları ile beraber<br />
kullanmak, sadece nesne kodu üretmek veya başka bir dilde yazılmış programı, C programı<br />
içinde kullanmak isteyebilir. Bir derleyiciye ait derleme seçenekleri ile bu tip işlemleri<br />
gerçekleştirmek mümkündür.<br />
Bu kısımda derleme ve bağlama işlemi, derleyicilerin sunduğu bazı derleme seçenekleri ve<br />
bunlar yardımıyla birden çok C programının nasıl birleştirileceği anlatılacaktır.<br />
22.1 Çalıştırılabilir Dosya Üretimi<br />
Programlama işlemi, bir programlama diline ait söz dizilimlerini içeren kaynak kodların<br />
yazılması ile başlar. Kaynak kod (source code), C, Fortran veya Pascal gibi yüksek seviyedeki
dillerin deyimleri barındıran bir düz metin dosyasında (plain text file) saklanır. Bu dosyalar<br />
geleneksel uzantılarla birbirinde ayrılabilir, örneğin c programları .c uzantılı, Pascal<br />
programları .pas uzantılı dosyalardır.<br />
Derleyici (compiler), bir programlama dilinde yazılmış olan kaynak kodunu başka bir dile<br />
(coğukez makine dili) çeviren yazılımdır. Her programlama dile kendi derleyicisine sahiptir.<br />
Derleyicinin çevirdiği kaynak kod, hedef kod veya nesne kodu (object code) olarak<br />
adlandırılır. Nesne kodu, bilgisayarın mikroişlemcisi (CPU) için gerekli makina kodlarını ve<br />
işletim sistemi için gerekli program uygulama arayüzlerini (API: Application Programming<br />
Interface) içerir. Nesne kodu çalıştırılabilir bir kod değildir, ama bütün programlama dilleri<br />
için aynıdır. Derleyicilerin ürettikleri nesne kodları genellikle .obj veya .o uzantılı dosyalarda<br />
saklanır.<br />
Sonraki adım, nesne kodunun özel bir bağlayıcı (linker) ile işlenmesidir. Bağlayıcı,<br />
derleyiciler tarafından üretilmiş bir veya daha fazla nesne kodunu birleştirip tek bir<br />
çalıştırılabilir dosya oluşturan yazılımdır. Her sistem kendi bağlayıcısına sahiptir.<br />
Bağlayıcının ürettiği çalıştırılabilir kod Windows ortamında .exe uzantılı dosyalarda saklanır.<br />
Linux ortamında çalıştırılabilir dosyaların çoğunlukla bir uzantısı yoktur.<br />
Kaynak kodunun derlenip çalıştırılabilir dosyanın oluşturulmasına ait işlem basamakları Şekil<br />
22.1'de gösterilmiştir.<br />
Şekil 22.1: Derleme-Bağlama-Çalıştırma işleminin akış diyagramı.<br />
C ve C++ dilleri için iki çeşit kaynak kodu vardır: .c veya .cpp uzantılı ana program ve bazı<br />
bildirimlerin bulunduğu .h veya .hpp uzantılı başlık dosyaları (header files).<br />
C (ve C++) dilinde derleme işlemi iki adım adımda yapılır. Birinci adımıda, derleme öncesi<br />
özel bir ön işlemci (preprocessor) programı devreye girer. Ana programdaki veya başlık<br />
dosyalarındaki diyez ('#') işareti ile başlayan satırlar aslında C (veya C++) diline ait olmayıp<br />
ön işlemci dilidir. Ön işlemci, bu satırlardaki deyimlere bakarak, bir katarı (string) alıp başka<br />
bir katarla değiştir. Örneğin:<br />
#include <br />
satırı ile stdio.h dosyasının metin içeriği programa dahil edilir. Ön işlemci deyimlerinin<br />
tamamı Bölüm 20'de anlatılatılmıştır.<br />
Ön işlemci programı, .c ve .h uzantılı düz metin (text) halindeki kaynak dosyasını okur, ve<br />
çıktı olarak başka bir düz metin dosyası üretir. Bu yeni dosya hiçbir ön işlemci deyimi<br />
içermeyen C (veya C++) derleyicisi tarafından işlenmeye hazır bir dosyadır. İkinci adımda bu<br />
dosya ile kaynak kodaları beraber derlenip sırasıyla nesne kodu ve çalıştırılabilir kod üretilir.<br />
Bu işlemlem Şekil 22.2 de özetlenmiştir.
Şekil 22.2: C ve C++ dilleri için, Ön işlemci-Derleme-Bağlama-Çalıştırma işleminin akış<br />
diyagramı.<br />
22.2 Turbo C Derleme Seçenekleri<br />
Turbo C derleyicisinin sunduğu derleme seçeneklerini görmek için, komut satırında tcc<br />
yazmak yeterlidir. TCC'nin sunduğu derleme seçenekleri Şekil 22.2'de listelenmiştir.<br />
Şekil 22.2: Turbo C'nin derleme seçenekleri.<br />
Seçenekler incelendiğinde standart bir derleme işleminden daha fazlasının yapılabileceği<br />
anlaşılır. Birkaç örnekle seçenekleri anlamaya çalışalım.<br />
Program 22.1, 1 den n ye kadar olan tam sayıların toplamını hesaplayıp ekrana yazar.<br />
Program 22.1: 1 den n ye kadar olan tam sayıların toplamını hesaplar
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
/* 22prg01.c: 1 den n=10 a kadar olan tam<br />
sayıların toplamını ekrana yazar */<br />
#include <br />
int s(int);<br />
int main()<br />
{<br />
int n = 10;<br />
printf("1 + 2 + ... + %d = %d\n",n,s(n) );<br />
return 0;<br />
}<br />
/* 1 + 2 + ... + n toplamını hesaplar */<br />
int s(int m){<br />
int i,top=0;<br />
}<br />
for (i=1;i tcc 22prg01.c<br />
Bu işlemle 22prg01.exe adlı bir çalıştırılabilir dosya ve 22prg01.obj adlı bir nesne dosyası<br />
üretilir. Dosyalar listelenirse bu yeni dosyalar görülecektir.<br />
C:\TC> dir /w 22prg01.*<br />
22prg01.c 22prg01.exe 22prg01.obj<br />
22prg01.exe dosyasını çalıştırmak için, dosyanın adını yazmak yeterlidir.<br />
C:\TC> 22prg01<br />
1 + 2 + ... + 10 = 55<br />
Sadece asm uzantılı assembly kodu üretmek istendiğinde -S seçeneği kullanılır.<br />
C:\TC> tcc -S 22prg01.c<br />
C:\TC> dir /w 22prg01.*<br />
22prg01.asm 22prg01.c 22prg01.exe 22prg01.obj<br />
Sadece obj uzantılı nesne dosyası üretmek için -c seçeneği kullanılır.<br />
C:\TC> tcc -c 22prg01.c<br />
C:\TC> dir /w 22prg01.*<br />
22prg01.asm 22prg01.c 22prg01.exe 22prg01.obj<br />
Çalıştırılabilir dosyanın adını değiştirmek için -exxx seçeneği kullanılır.<br />
C:\TC> tcc -eyeni 22prg01.c<br />
C:\TC> dir /w yeni*<br />
yeni.exe<br />
C:\TC> yeni<br />
1 + 2 + ... + 10 = 55<br />
Büyük uygulamalarda alt progroramlar başka dosyalarda saklanır ve ana program ile beraber<br />
komut satırında derlenebilir. Aşağıdaki gibi aynı dizin içerisinde bululan herbiri ayrı<br />
dosyalarda saklanan dört fonksiyona ve bir ana programama sahip olduğumuzu varsayalım.<br />
/* topla.c: iki sayinin toplamini<br />
hesaplar */<br />
/* fark.c: iki sayinin farkini<br />
hesaplar */
int topla(int a,int b)<br />
{<br />
return (a+b);<br />
}<br />
/* carp.c: iki sayinin carpimini<br />
hesaplar */<br />
int carp(int a,int b)<br />
{<br />
return (a*b);<br />
}<br />
int fark(int a,int b)<br />
{<br />
return (a-b);<br />
}<br />
/* iki sayinin oranini hesaplar */<br />
int bol(int a,int b)<br />
{<br />
if(b) return (a/b);<br />
return 0;<br />
}<br />
/* ana.c: Ana program */<br />
#include <br />
int topla(int, int);<br />
int fark(int, int);<br />
int carp(int, int);<br />
int bol(int, int);<br />
int main()<br />
{<br />
int x=33, y=22;<br />
printf("topla(%d,%d) = %d\n",x,y,topla(x,y));<br />
printf(" fark(%d,%d) = %d\n",x,y,fark(x,y));<br />
printf(" carp(%d,%d) = %d\n",x,y,carp(x,y));<br />
printf(" bol(%d,%d) = %d\n",x,y,bol(x,y));<br />
}<br />
return 0;<br />
Sadece ana.c dosyası derlendiğinde aşağıdaki gibi bir topla, fark, carp ve bol<br />
fonksiyonlarının tanımsız olduğuna dair hata mesajı ekranda basılır:<br />
C:\TC> tcc ana.c<br />
Turbo C Version 2.01 Copyright (c) 1987, 1988 Borland International<br />
ana.c:<br />
Turbo Link Version 2.0 Copyright (c) 1987, 1988 Borland International<br />
Undefined symbol '_bol' in module ana.c<br />
Undefined symbol '_carp' in module ana.c<br />
Undefined symbol '_fark' in module ana.c<br />
Undefined symbol '_topla' in module ana.c<br />
Fakat derleme şu şekilde yapıldığında hata mesajı ortadan kalkar.<br />
C:\TC> tcc ana.c topla.c fark.c carp.c bol.c<br />
Bu işlemin sonucunda derleyici ana.exe, ana.obj ve topla.obj, fark.obj, carp.obj,<br />
bol.obj dosyalarını üretir. Tabiki tek çalıştırılabilir dosya ana.exe dir. Bu, bütün dosyaların<br />
ayrı ayrı derlenmiş olduğu anlamına gelir. ana.exe dosyası çalıştırıldığında program çıktısı<br />
şöyle olacaktır:<br />
C:\TC> ana<br />
topla(33,22) = 55<br />
fark(33,22) = 11<br />
carp(33,22) = 726<br />
bol(33,22) = 1
Alt programlar çok büyük ve karmaşık işlemler yaptığında, bu şekilde derleme yapmak pek<br />
sağlıklı değildir. Bunun yerine alt programların bulunduğu dosyalar bir kez -c seçeneği ile<br />
derlendiğinde üretilen obj uzantılı dosyalar başka programlar tarafından kullanılabilir.<br />
Şöyleki:<br />
C:\TC> tcc -c topla.c<br />
C:\TC> tcc -c fark.c<br />
C:\TC> tcc -c carp.c<br />
C:\TC> tcc -c bol.c<br />
Ana programla beraber derleme işlemi bize aynı sonucu verecektir:<br />
C:\TC> tcc ana.c topla.obj fark.obj carp.obj bol.obj<br />
Bu sayede ana programda bir değişiklik yapılsa bile alt programrın bir daha derlenmesine<br />
gerek kalmaz. Örneğin ana program şu şekilde bir satır ekleyelim:<br />
/* ana.c: Ana program */<br />
#include <br />
int topla(int, int);<br />
int fark(int, int);<br />
int carp(int, int);<br />
int bol(int, int);<br />
int main()<br />
{<br />
int x=33, y=22;<br />
printf("topla(%d,%d) = %d\n",x,y,topla(x,y));<br />
printf(" fark(%d,%d) = %d\n",x,y,fark(x,y));<br />
printf(" carp(%d,%d) = %d\n",x,y,carp(x,y));<br />
printf(" bol(%d,%d) = %d\n",x,y,bol(x,y));<br />
printf("<br />
ortalama = %f\n",topla(x,y)/2.0);<br />
}<br />
return 0;<br />
Derleme aşağıdaki gibi yapıldığında:<br />
C:\TC> tcc ana.c topla.obj fark.obj carp.obj bol.obj<br />
program çıktısı şöyle olur:<br />
C:\TC> ana<br />
topla(33,22) = 55<br />
fark(33,22) = 11<br />
carp(33,22) = 726<br />
bol(33,22) = 1<br />
ortalama = 27.500000<br />
C:\TC><br />
Özetle bir fonksiyon birkez derlenip ona ait obj dosyası üretildiğinde, artık o kod bütün<br />
programlar tarafından kullanılabilir demektir. Aşağıdaki derleme işlemi ile obj dosyaları ana<br />
programa bağlanmıştır diyebiliriz:<br />
C:\TC> tcc ana.c topla.obj fark.obj carp.obj bol.obj<br />
Bu durum Şekil 22.3 de tasvir edilmiştir.
Şekil 22.3: Birden çok dosyanın derlenmesi ve birleştirilmesi.<br />
22.3 GCC Derleme Seçenekleri<br />
GCC (GNU Compiler Collection) daha çok Linux ve MAC ortamında kullanılan bir komut<br />
satırı derleyicisidir. GCC'nin Windows ortamında çalıştırılabilen sürümü de mevcuttur, bkz.<br />
gcc.gnu.org. Bu kısımda GCC'nin Linux ortamındaki kullanımından bahsedilecektir. Ancak<br />
bütün işlemler Windows işletim sisteminde de geçerlidir.<br />
GCC derleme seçeneklerini komut satırından görmek için iki yol vardır. Bunlar:<br />
$ man gcc<br />
veya<br />
$ gcc --help<br />
Burada $ işareti Linux komut hazır işaretidir (command prompt). Bu komutlardan birincisi<br />
oldukça büyük, ayrıntılı ve yardım niteliğindedir, örneğin bkz:<br />
www.hmug.org/man/1/gcc.php. İkincisinin sonucu Şekil 22.4 deki gibidir.
Şekil 22.4: GCC'nin derleme seçenekleri.<br />
GCC ile 22prg01.c kaynak kodu şöyle derlenebilir:<br />
$ gcc 22prg01.c<br />
Bu işlem neticesinde sadece a.out adlı çalıştırılabilir bir dosya üretilir. Bu programı<br />
çalıştırmak için:<br />
$ ./a.out<br />
1 + 2 + ... + 10 = 55<br />
Çalıştırılabilir dosyanın adını değiştirmek için -o seçeneği kullanılır.<br />
$ gcc 22prg01.c -o 22prg01<br />
$ ./22prg01<br />
1 + 2 + ... + 10 = 55<br />
Sadece derleme yapmak için (Turbo C'de olduğu gibi) -c seçeneği kullanılır.<br />
$ gcc -c 22prg01.c<br />
Bu işlemin sonucunda 22prg01.o adlı nesne dosyası üretilir. Bu dosya, dosyalar<br />
listelendiğinde görülebilir:<br />
$ ls 22prg01*<br />
22prg01.c 22prg01.o 22prg01*
Bir C kaynak kodu kütüphanesinden bir fonksiyon içeriyorsa, GCC ile bu tür<br />
programlar -lm seçenği ile derlenmelidir. Program 22prg02.c, ilk 10 pozitif tam sayının on<br />
tabanındaki logaritmalarını ve doğal logaritmalarını ekrana gösterir. Program içerisinde<br />
kütüphanesindeki log ve log10 fonkiyonları kullanılmıştır.<br />
Program 22.2: 1 den 10 a kadar olan tam sayıların logaritmaları<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
/* 22prg02.c: 1 den n=10 a kadar olan tam<br />
sayıların logaritmalarını ekrana yazar */<br />
#include <br />
#include <br />
int main()<br />
{<br />
int i;<br />
for(i=1; i
$ gcc -c fark.c<br />
$ gcc -c carp.c<br />
$ gcc -c bol.c<br />
Derlenmiş alt programların ana program ile birleştirlmesi<br />
$ gcc ana.c topla.o fark.o carp.o bol.o -o ana<br />
$ ./ana<br />
topla(33,22) = 55<br />
fark(33,22) = 11<br />
carp(33,22) = 726<br />
bol(33,22) = 1<br />
ortalama = 27.500000<br />
$<br />
<strong>Ders</strong> 23: Tarih ve Saat Fonksiyonları<br />
• <strong>Giriş</strong><br />
• 23.1 time() Fonksiyonu<br />
• 23.2 ANSI C Tarih-Saat Fonksiyonları, Sabitleri ve Yapıları<br />
• 23.3 Mili Saniye ve Mikro Saniye Düzeyinde Çalışmak<br />
<strong>Giriş</strong><br />
Bazı uygulamalarda program içerisinde tarih ve saat bilgilerine ihtiyaç duyulabilir. C dilinde,<br />
tarih ve saat fonksiyonlarının bildirimleri, semblik sabitler ve standart yapılar <br />
başlık dosyasında tanımlanmıştır. Bu fonksiyonlar üç temel işlevi yerine getirir:<br />
• Takvim (Tarih) bilgileri<br />
• Yerel Saat<br />
• Saat Dilimleri<br />
Bu bölümde tarih ve saat fonksiyonları incelenmişitir.<br />
23.1 time() Fonksiyonu<br />
time() fonksiyonu 01/01/1970 tarihinden, programın çalıştığı tarihe ve saate kadar geçen<br />
sürenin saniye cinsinden değerini gönderir. Genel bildirimi:<br />
time_t time(time_t *zaman);<br />
şeklindedir. Burada:
• time_t sayısal bir tip (genllikle long int) olup zaman bilgisini temsil eder.<br />
• zaman tarih bilgisini tutan gösterici tipinde bir değişkendir.<br />
NOT<br />
Derleyici tarih bilgisi göstermezse time() fonksiyonu -1<br />
değerini gönderir.<br />
01/01/1970'den bu güne geçen süreyi iki yolla öğrenebiliriz:<br />
1. Geri dönüş değerini kullanarak<br />
2. time_t t;<br />
3. ...<br />
4. t = time(NULL);<br />
5. printf("zaman: %ld\n",t);<br />
6. fonksiyon parametresinden<br />
7. time_t t;<br />
8. ...<br />
9. time(&t);<br />
10. printf("zaman: %ld\n",t);<br />
Şimdi örnek uygulamayı Program 23.1'de görelim:<br />
Program 23.1: time() fonksiyonunun kullanımı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
ÇIKTI<br />
/* 23prg01.c: time() fonksiyonun kullanımı */<br />
#include <br />
#include <br />
int main ()<br />
{<br />
time_t saniye; /* long saniye; anlamında */<br />
saniye = time (NULL);<br />
puts("01/01/1970'den bu gune kadar gecen<br />
sure,");<br />
printf ("Saniye olarak %ld\n", saniye);<br />
/* 1 saat = 60*60 = 3600 sn. */<br />
printf ("Saat olarak %ld\n", saniye/3600);<br />
/* 1 gün = 24 saat = 24*60*60 = 86400 sn. */<br />
printf ("Gun olarak %ld\n", saniye/86400);<br />
return 0;<br />
}<br />
01/01/1970'den bu gune kadar gecen sure,<br />
Saniye olarak 1227606397<br />
Saat olarak 341001<br />
Gun olarak 14208
23.2 ANSI C Tarih-Saat Fonksiyonları, Sabitleri ve<br />
Yapıları<br />
Tablo 23.1'de ANSI C'de başlık dosyasında bildirilen tarih-saat fonksiyonları<br />
listelenmiştir.<br />
Tablo 18.1: time.h'te tanımlı tarih-saat fonksiyonları<br />
Fonksiyon Bildirimi<br />
char *asctime(const struct tm<br />
*zmn_g);<br />
clock_t clock(void);<br />
char *ctime(const time_t<br />
*zaman);<br />
Açıklama<br />
zmn_g göstericinin işaret ettiği veriyi, daha anlaşılabilir<br />
bir formatla katar bilgisine çevirir. zmn_g göstericisi,<br />
gmtime() ve localtime() fonksiyonlarının<br />
döndürdüğü, tm yapısını gösterir. Geri döndürelen<br />
katarın genel formatı:<br />
Www Mmm dd hh:mm:ss yyyy<br />
şeklindedir. Burada Www haftanın günü, Mmm ay bilgisi,<br />
dd ayın günü hh:mm:ss saat bilgisini ve yyyy yıl<br />
bilgisidir.<br />
Zaman tik-tak bilgisini döndürür.<br />
Geriye anlaşılır formatta yerel zamanı tutan bir katar<br />
döndürür. zaman, time_t tipinde bir uzun tamsayıdır.<br />
Katarın formatı: Www Mmm dd hh:mm:ss yyyy<br />
şeklindedir.<br />
double difftime(time_t zaman1,<br />
time_t zaman2);<br />
zaman2 - zaman1 farkını saniye cinsinden hesaplar.<br />
zaman'ı tm yapısına (İngiltere'deki Greenwitch'göre<br />
struct tm *gmtime(const time_t<br />
*zaman);<br />
struct tm *localtime(const<br />
time_t *zaman);<br />
time_t mktime(struct tm<br />
*zaman);<br />
time_t time(time_t *zaman);<br />
GMT cinsinden) çevirir. zaman genellikle time<br />
fonksiyonu ile döndürülür.<br />
zaman'ı tm yapısına (yerel saat cinsinden) çevirir. zaman<br />
genellikle time fonksiyonu ile döndürülür.<br />
tm tipinde, zaman göstericisine ait tarih-saat bilgisini<br />
gösterir.<br />
1 Ocak 1970'den bu ana kadar geçen sürenin zaman<br />
saniye cinsinden hesaplar.<br />
CLK_TCK<br />
clock_t ve time_t<br />
(clock ticks per second) makro sabit. Zaman tik-takları<br />
ve zamanın saniye cinsinden karşılığı arasında ilişkiyi<br />
tanımlar. Bu sabit Turbo C'de<br />
#define CLK_TCK 18.2<br />
şeklinde tanımlanmıştır.<br />
clock() ve time() fonksiyonlarının kullandığı veri<br />
tipleri. Bunlar genellikle genllikle long int tipleridir<br />
ve başlık dosyasında şöyle tanımlıdır.<br />
typedef long clock_t<br />
typedef long time_t<br />
asctime(), gmtime(), localtime() ve mktime() fonksiyonlarının kullandığı tm yapısı<br />
söyledir:
struct tm {<br />
int tm_sec; /* saniye, (0 - 59) */<br />
int tm_min; /* dakika, (0 - 59) */<br />
int tm_hour; /* saat, (0 - 23) */<br />
int tm_mday; /* ayın günü, (1 - 31) */<br />
int tm_mon; /* ay, (0 - 11), 0 = Ocak */<br />
int tm_year; /* yıl - 1900 */<br />
int tm_wday; /* haftanın günü, (0 - 6), 0 = Pazar */<br />
int tm_yday; /* yılın günü,(0 - 365) */<br />
int tm_isdst; /* gündüz (-1/0/1) */<br />
};<br />
Program 23.2:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
ÇIKTI<br />
/* 23prg02.c: asctime() ve localtime()<br />
fonksiyonlarının kullanımı */<br />
#include <br />
#include <br />
int main()<br />
{<br />
time_t t;<br />
struct tm *zaman_bilgisi;<br />
time (&t);<br />
zaman_bilgisi = localtime (&t);<br />
printf("Su anki tarih ve saat:<br />
%s",asctime(zaman_bilgisi));<br />
return 0;<br />
}<br />
Su anki tarih ve saat: Tue Nov 25 15:19:20 2008<br />
Program 23.3:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
ÇIKTI<br />
/* 23prg03.c: ctime() fonksiyonunun kullanımı */<br />
#include <br />
#include <br />
main()<br />
{<br />
time_t t;<br />
time(&t);<br />
printf("Su anki tarih ve saat: %s",ctime(&t));<br />
return 0;<br />
}
Su anki tarih ve saat: Tue Nov 25 17:08:02 2008<br />
Program 23.4:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
/* 23prg04.c: clock() fonksiyonunun kullanımı */<br />
#include <br />
#include <br />
void bekle(int zaman)<br />
{<br />
clock_t son;<br />
}<br />
ÇIKTI<br />
son = clock() + zaman * CLK_TCK;<br />
while( clock() < son) {}<br />
int main()<br />
{<br />
int n;<br />
printf ("Geri sayim basladi...\n");<br />
for (n=10; n>0; n--)<br />
{<br />
printf ("%d\n",n);<br />
bekle(1000);<br />
}<br />
printf ("ATES!\n");<br />
return 0;<br />
}<br />
Geri sayim basladi...<br />
10<br />
9<br />
8<br />
7<br />
6<br />
5<br />
4<br />
3<br />
2<br />
1<br />
ATES!<br />
Program 23.5:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
/* 23prg03.c: difftime() fonksiyonunun kullanımı<br />
*/<br />
#include <br />
#include
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
ÇIKTI<br />
int main ()<br />
{<br />
time_t basla, bit;<br />
char ad[256];<br />
double fark;<br />
time (&basla);<br />
printf ("Lutfen adinizi girin: ");<br />
gets (ad);<br />
time (&bit);<br />
fark = difftime(bit, basla);<br />
printf("Merhaba %s.\n", ad);<br />
printf("Adini yazman %lf saniye<br />
surdu.\n",fark);<br />
return 0;<br />
}<br />
Lutfen adinizi girin: Ahmet<br />
Merhaba Ahmet.<br />
Adini yazman 2.000000 saniye surdu.<br />
Program 23.6:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
/* 23prg06.c: mktime() fonksiyonunun kullanımı<br />
*/<br />
#include <br />
#include <br />
int main ()<br />
{<br />
time_t t;<br />
struct tm *zaman;<br />
int yil, ay, gun;<br />
char *haftanin_gunu[] = { "Pazar",<br />
"Pazartesi",<br />
"Sali",<br />
"Carsamba",<br />
"Persembe", "Cuma",<br />
"Cumartesi"};<br />
/* tarih bilgisini oku */<br />
printf("Yılı girin: "); scanf ("%d",&yil);<br />
printf("Ayı girin: "); scanf ("%d",&ay);<br />
printf("Gunu girin: "); scanf ("%d",&gun);<br />
/* simdiki zaman bilgisini al */<br />
t = time(NULL);<br />
zaman = localtime(&t);<br />
zaman->tm_year = yil - 1900;<br />
zaman->tm_mon = ay - 1;<br />
zaman->tm_mday = gun;<br />
/* mktime fonksiyonun cagir */
32:<br />
33:<br />
mktime(zaman);<br />
printf("Girilen tarihteki gun<br />
haftanin_gunu[zaman->tm_wday]);<br />
%s.\n",<br />
}<br />
return 0;<br />
ÇIKTI<br />
Yılı girin: 2003<br />
Ayı girin: 8<br />
Gunu girin: 1<br />
Girilen tarihteki gun Cuma.<br />
Program 23.7:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
ÇIKTI<br />
/* 23prg07.c: gmtime() fonksiyonunun kullanımı<br />
*/<br />
#include <br />
#include <br />
#define TUR (2)<br />
#define ALM (1)<br />
#define ABD (-8)<br />
int main()<br />
{<br />
time_t t;<br />
struct tm *ptm;<br />
time (&t);<br />
ptm = gmtime(&t);<br />
printf("Su anki yerel saatler\n");<br />
printf("Istanbul : %02d:%02d\n", ptm-<br />
>tm_hour + TUR, ptm->tm_min);<br />
printf("Berlin : %02d:%02d\n", ptm-<br />
>tm_hour + ALM, ptm->tm_min);<br />
printf("Los Angeles: %02d:%02d\n", ptm-<br />
>tm_hour + ABD, ptm->tm_min);<br />
return 0;<br />
}<br />
Su anki yerel saatler<br />
Istanbul : 18:34<br />
Berlin : 17:34<br />
Los Angeles: 08:34<br />
Program 23.8:<br />
01: /* 23prg08.c: gerçek zamanı gösterimi */
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
ÇIKTI<br />
#include <br />
#include <br />
int main()<br />
{<br />
time_t t;<br />
struct tm *zmn;<br />
puts("Cikis icin: CTRL+C");<br />
/* Sonsuz döngü */<br />
while(1)<br />
{<br />
time(&t);<br />
zmn = localtime(&t);<br />
printf("%02d:%02d:%02d\r",<br />
zmn->tm_hour, zmn->tm_min, zmn-<br />
>tm_sec);<br />
}<br />
return 0;<br />
}<br />
Cikis icin: CTRL+C<br />
17:08:43<br />
23.3 Mili Saniye ve Mikro Saniye Düzeyinde Çalışmak<br />
Bazı uygulamalarda saniyenin (s) alt birimleri, salise (sl), mili saniye (ms) ve mikro saniye<br />
(µs), düzeyinde çalışmak gerekebilir. Birçok derleyici, saniyenin belli kesirlerine kadar<br />
erişime izin veren fonksiyonları bünyesinde barındırır. Ancak, bu fonksiyonlar satandart C'de<br />
mevcut değildir.<br />
NOT<br />
1 sl = (1/100) s = 0,01 s<br />
1 ms = (1/1000) s = 0,001 s<br />
1 µs = (1/1000000) s = 0,000001 s<br />
gcc derleyicisinde başlık dosyası içinde tanımlı, gettimeofday() fonksiyonu<br />
ile mikro-saniye düzeyine erişim mümkündür.<br />
Program 23.9:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
/* 23prg09.c: saniyenin alt birimleri<br />
Derleyici gcc 4.1.2 */<br />
#include <br />
#include
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
ÇIKTI<br />
#include <br />
int main()<br />
{<br />
struct timeval tv;<br />
struct timezone tz;<br />
struct tm *tm;<br />
long int sa, dk, sn, us;<br />
double sl, ms;<br />
gettimeofday(&tv,&tz);<br />
tm = localtime(&tv.tv_sec);<br />
sa = tm->tm_hour; /* saat */<br />
dk = tm->tm_min; /* dakika */<br />
sn = tm->tm_sec; /* saniye */<br />
sl = tv.tv_usec/1.0e4; /* salise */<br />
ms = tv.tv_usec/1.0e3; /* mili-saniye */<br />
us = tv.tv_usec; /* mikro-saniye */<br />
printf("%02ld:%02ld:%02ld ; %lf %lf %ld\n",<br />
sa, dk, sn, sl, ms, us);<br />
return 0;<br />
}<br />
13:53:38 ; 65.247900 652.479000 652479<br />
Program çalıştırıldığı andaki saniye 38 değerini göstermektedir. Daha doğrusu, program<br />
çalıştığı anda sistem saatinin saniye göstergesi 38. saniyeden 39. saniyeye geçmektedir.<br />
Çıktıdaki 652479 rakamı, 38. ve 39. saniyeler arası geçen zamanın µs cinsinden değeridir.<br />
Yani, saniyenin alt birimi 38 s + 652479 µs = 38.652479 s. demektir.<br />
Turbo C deleyicisinde, mili-saniye düzeyinde kadar erişim izni vardır. Bunun için, program<br />
içerisinde başlık dosyasında tanımlı ftime() fonksiyonu kullanılabilir.<br />
Program 23.9b:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
/* 23prg09b.c: saniyenin alt birimleri<br />
Derleyici Turbo C 2.0 */<br />
#include <br />
#include <br />
#include <br />
int main()<br />
{<br />
struct tm *zmn;<br />
struct timeb *tb;<br />
int sa, dk, sn;<br />
double sl, ms;
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
ÇIKTI<br />
sa = zmn->tm_hour; /* saat */<br />
dk = zmn->tm_min; /* dakika */<br />
sn = zmn->tm_sec; /* saniye */<br />
sl = tb->millitm/10.0; /* salise */<br />
ms = tb->millitm; /* mili-saniye */<br />
ftime(tb);<br />
printf("%02d:%02d:%02d | %lf %lf\n", sa, dk,<br />
sn, sl, ms);<br />
return 0;<br />
}<br />
13:56:16 ; 35.600000 356.000000<br />
<strong>Ders</strong> 24: Monte Carlo Yöntemleri<br />
• <strong>Giriş</strong><br />
• 24.1 Uygulama Alanları<br />
• 24.2 Rastgele Sayılar<br />
• 24.3 ANSI C Fonksiyonları<br />
• 24.4 Basit Monte Carlo Programları<br />
<strong>Giriş</strong><br />
Bilimsel uygulamalarda problemler iki kısımda incelenebilir:<br />
• kesin = deterministik (deterministic)<br />
• tahmini = olası (random).<br />
Kesin sistemler, kuralları kanun hükmünde olan matematiksel yasalarla tanımlanabilen<br />
sistemlerdir; Örneğin yerçekimi yasası gibi. Fakat, tahmini sistemlerin kuralları muhtemel<br />
veya raslantısal (stocastic) olan istatiksel yöntemlerle belirlenir; Örneğin havaya atılan bir<br />
metal paranın yazı veya tura gelmesi gibi. Burada raslantıdan kasıt, tahmini sistemlerde,<br />
başlangıç koşulları kesin olarak tayin edilemediği için sonuca dair çözümün tahmin edilmesi<br />
anlamındadır. Yoksa, evrende raslantıya yer yoktur.<br />
Bilgisayar ortamında, yazılımsal (veya donanımsal) olarak rastgele sayılar (random numbers)<br />
üretmek mümkündür. Monte Carlo Yöntemleri, bu rastgele sayıları kullanarak tahmini<br />
sistemleri modelleyen algoritmalardır. Aslında, Monte Carlo, (Fransa) Monako'nun<br />
kumarhaneleriyle ünlü en zengin yerleşim yeridir. (bkz. Wikipedia: Monte Carlo). Bu yüzden,
tahmini sistemlerin modellenmeside kullanılan sayısal analiz yöntemlerine Monte Carlo<br />
(kısaca MC) ismi verilmiştir.<br />
Bu bölümde, yazılımsal olarak üretilen Rastgele Sayılar ve Sayısal Analiz'de kullanılan basit<br />
Monte Carlo Yöntemleri konu edilecektir.<br />
24.1 Uygulama Alanları<br />
Monte Carlo (MC), rastgele sayıları baz alarak tahmini sistemleri modeller. Hatta, bazı kesin<br />
sistemlerde de kullanılabilir; Örneğin rastgele sayılarla Pi sayısını veya bir fonksiyonun<br />
integralini hesaplamak gibi. MC yöntemleri, Fizik ve Mühendislik alanlarında pekçok<br />
uygulama alanı bulmuştur. Bunlardan başlıcaları:<br />
• [Matematik] Sayısal Analiz<br />
• [Fizik] Doğal olayların simülasyonu<br />
• [Fizik] Atom ve Molekül Fiziği, Nükleer Fizik ve özellikle Yüksek Enerji Fiziği<br />
modellerini test eden simülasyonlar<br />
• [Mühendislik] Deneysel aletlerin (örneğin detektör) simülasyonu<br />
• [Biyoloji] Hücre Similasyonu<br />
• [Ekonomi] Borsa Modelleri<br />
• [İstatistik] Dağılım Fonksiyonları<br />
Tahmini sistemleri modelleyebilmek için:<br />
• Rastgele Sayı üretmeyi ve kullanmayı<br />
• Basit MC programlarını oluşturmayı<br />
• İleri düzeyde hazırlanan MC üreteçlerini ve programları kullanmayı<br />
iyi öğrenmek gerekir.<br />
24.2 Rastgele Sayılar<br />
Bilgisayarların en çok uygulandığı alanlardan bir tanesi kuşkusuz doğa olaylarının<br />
modellenmesidir. Bazı durumlarda, bilgisayarın ürettiği rastgele sayılar kullanılarak belirsiz<br />
yani tahmini sistemler modellenebilir. Rastgele sayı özel bir dağılımdan seçilen kargaşık<br />
(caotic) bir sayıdır.
Bilgisayarlar kesin (deterministic) bir yapıda çalıştıkları için gerçek anlamda rastgele sayı<br />
üretemezler. Ancak, uygun algoritmlarla bir bilgisayarın düzgün bir dağılımdan seçilen ve<br />
genllikle [0,1] arasında gerçel değerler alan rastgele sayı üretmesi sağlanabilir. Bilgisayarların<br />
ürettiği bu rastgele sayılar yalancı rastgele sayı (pseudo-random numbers) olarak adlandırılır.<br />
Rastgele sayı üreten bu algoritmalara rastgele sayı üreteci (random number generator) denir.<br />
Günümüz derleyicilerinin bir çoğunda rastgele sayı üreteçleri için hazır kütüphane<br />
fonksiyonları tanımlanmıştır.<br />
Bu fonksiyonlar genellikle doğrusal bir denklem kullanarak, rastgele sayı dizisi üretir. 32-bit<br />
makinalarda, dizinin peryodu en az 2 31 ~ 10 9 (1 milyar) dur. Yani, bir rastgele sayı üreteci<br />
birbirinden farklı 1 milyar farklı sayı üretebilir. Bu kadar çok sayı günümüz bilgisaylarında<br />
bir kaç saniyede kolaylıkla oluşturulabilir.<br />
Rastgele sayı dizisini oluşturacak doğrusal denklemin genel biçimi şöyledir:<br />
x n+1 = ( a x n + b ) mod m<br />
burada mod modüler aritmetik işlemi anlamındadır. Dizinin ilk elemanı, x o , çekirdek (seed)<br />
olarak adlandırılır. a ve b sabitleri, dizi elemanları kargaşık ve düzgün dağılacak şekilde<br />
seçilir.<br />
1960 yılında IBM şirketi aşağıdaki meşhur RANDU algoritmasını kullanmıştır (a = 69069, b<br />
= 0):<br />
x n+1 = ( 69069 x n ) mod 2 31 -1<br />
Daha sonra Park ve Miller, aşağıdaki Minimal Standart algoritmasını önermiştir (a = 16807, b<br />
= 0):<br />
x n+1 = ( 16807 x n ) mod 2 31 -1<br />
Park-Miller algoritması ile oluşturulan rastgele sayı üreteci, aşağıdaki C fonksiyonu ile<br />
kotarılabilir:<br />
/*<br />
* Park-Miller algoritması ile [0,1] arasında<br />
* düzgün dağılmış rastgele sayı üretir.<br />
*/<br />
float rastgele(int *cekirdek)<br />
{<br />
const int im = 2147483647, ia = 16807;<br />
const int iq = 127773, ir = 2836;<br />
const float m = 128.0/im;<br />
int k;<br />
float r;<br />
k = *cekirdek / iq;<br />
*cekirdek = ia*(*cekirdek-k*iq) - ir*k;<br />
if(*cekirdek < 0) *cekirdek += im;<br />
r = m * (*cekirdek/128);<br />
}<br />
return r;<br />
Program 24.1'de, rastgele() fonksiyonu kullanılarak 10 sayı üretilmiştir. Program her<br />
çalıştırıldığında aynı sayılar üretilecektir. Bunun nedeni kümenin ilk elemanı ilk_sayi sabit<br />
olmasıdır.
Program 24.1: 10 rastgele sayı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
/* 24prg01.c<br />
rastgele() fonksiyonu ile 10 adet [0-1]<br />
arasında<br />
rastgel sayı üretir */<br />
#include <br />
float rastgele(int *);<br />
int main()<br />
{<br />
int ilk_sayi, i;<br />
float r;<br />
}<br />
/* dizinin çekirdeği (seed) */<br />
ilk_sayi = 123456789;<br />
for(i=1; i
0.633966<br />
24.3 ANSI C Fonksiyonları<br />
Standart C (ve C++), RANDU ve Minimal Standart'a göre daha verimli çalışan (stdlib.h<br />
başlık dosyasında bildirilen) aşağıdaki iki fonksiyonu kullanıcılarına sunmuştur:<br />
• int rand(void)<br />
0 ile RAND_MAX arasında tamsayı tipinde yalancı rastgele sayı üretilir.<br />
RAND_MAX, stdlib.h'de tanımlı sembolik bir sabittir. Değeri (derleyiciye bağlı olarak)<br />
en büyük int limiti ile sınırlıdır. Bu değer Turbo C (16-bit) derleyicisinde:<br />
#define RAND_MAX 32767<br />
şeklinde, gcc gibi (32-bit) uygulamalarda:<br />
#define RAND_MAX 2147483647<br />
şeklinde tanımlanmıştır.<br />
• void srand(unsigned int cekirdek)<br />
Rastgele sayı üreteci (rand()) için cekirdek değerini belirler.<br />
Aşağıda bu fonksiyonların uygulamaları gösterilmiştir. İnceleyiniz.<br />
Program 24.2:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
ÇIKTI<br />
/* 24prg02.c<br />
rand() ile 10 adet rastgele tamsayı sayı<br />
üretir */<br />
#include <br />
#include <br />
int main()<br />
{<br />
int i;<br />
/* rand fonksiyonu */<br />
for(i=1; i
1681692777<br />
1714636915<br />
1957747793<br />
424238335<br />
719885386<br />
1649760492<br />
596516649<br />
1189641421<br />
RAND_MAX = 2147483647<br />
Program 24.3:<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
ÇIKTI<br />
/* 24prg03.c<br />
rand() ile 10 adet [0,1] arasında rastgele<br />
gercel sayı üretir */<br />
#include <br />
#include <br />
int main()<br />
{<br />
int i;<br />
/* rand fonksiyonu */<br />
for(i=1; i
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
ÇIKTI<br />
int i, cekirdek;<br />
/* cekirdeği değiştir */<br />
cekirdek = 31415926;<br />
srand(cekirdek);<br />
/* rand fonksiyonu */<br />
for(i=1; i
0.980876<br />
0.453894<br />
0.115219<br />
0.993930<br />
0.945253<br />
0.023599<br />
0.851912<br />
0.334151<br />
24.4 Basit Monte Carlo Programları<br />
Bu kısımda, rastgele sayılar kullanılarak üç basit MC uygulaması verilmiştir.<br />
• Uygulama 1: Yazı-Tura Simülasyonu<br />
• Uygulama 2: Zar Simülasyonu<br />
• Uygulama 3: MC ile Pi sayısının hesabı<br />
Uygulama 1: Yazı-Tura Simülasyonu<br />
Hilesiz bir para atıldığında, yazı veya tura gelme olasılığı (P, probability) eşit ve kuramsal<br />
olarak P = 1/2 dir. Düşünün ki bir para n kez atılsın ve gelen turaları sayıp ve t ile gösterelim.<br />
Deney sayısı, n, arttıkça t/n oranı kararlı (sabit) kalmaya başlar. Bu durumda, olasılığın<br />
istatiksel tanımı şöyle yapılır:<br />
P(t) = t/n<br />
n sonsuza giderken P(t) değeri P = 1/2 değerine yaklaşır.<br />
Şimdi, [0, 1] aralığından rastgele seçilen sayıları kullanarak, para atma deneyini yapalım.<br />
Rastgele sayı üreteçleri sayıları eşit olasılıkla üretir. r bir rastgele sayı olsun. r < 0.5<br />
durumuna tura, r >= 0.5 durumuna da yazı diyelim. Bu şekilde, bir döngü kullanarak deney<br />
sayısına (n) göre, yazı-tura simulasyonu yapılabilir. Program 24.6, klavyeden girilen n'ye<br />
göre, P(t) ve 1 - P(t) olasılıklarını hesaplar.<br />
Program 24.6: Yazı-Tura Simulasyonu<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
/* 24prg06.c<br />
MC Yazı-Tura Simulasyonu */<br />
#include <br />
#include <br />
#include
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
ÇIKTI<br />
/* [0, 1] arası rastgele sayı gönderir */<br />
double rastgele(){<br />
double r = (double) rand()/RAND_MAX;<br />
return r;<br />
}<br />
int main()<br />
{<br />
int i, tura, yazi, n;<br />
double r, p;<br />
/* deney sayısı */<br />
printf("deney sayisini girin: ");<br />
scanf("%d",&n);<br />
/* rastgele sayı üretecini başlat */<br />
srand( time(NULL) );<br />
/* deneyleri başlat */<br />
for(tura=0, i=1; i
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
}<br />
ÇIKTI<br />
double r = (double) rand()/RAND_MAX;<br />
return r;<br />
int main()<br />
{<br />
int i, j, tura, yazi, n;<br />
double r, p;<br />
/* rastgele sayı üretecini başlat */<br />
srand( time(NULL) );<br />
for(j=1; j
olur. Neden?<br />
Program 24.8: Zar Simulasyonu<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
/* 24prg08.c: MC Zar Simulasyonu<br />
Atılan bir çift zarın toplamının yedi olma<br />
olasılığını hesaplar.<br />
Olasılık kuramına göre, birçift zarın<br />
toplamının 7 olma olasılığı<br />
aşağıdaki formülden hesaplanabilir:<br />
Ptoplam(7) = P(1,6) + P(2,5) + P(3,4) +<br />
P(4,3) + P(5,2) + P(6,1)<br />
Diğer taraftan:<br />
P(1,6) = P(2,5) = P(3,4) = P(4,3) = P(5,2)<br />
= P(6,1) = 1/36'dır.<br />
Buna göre:<br />
Ptoplam(7) = 6*(1/36) = 1/6 = 0.16666..<br />
dır. */<br />
#include <br />
#include <br />
#include <br />
#include <br />
/* [0, 1] arası rastgele sayı gönderir */<br />
double rastgele(){<br />
double r = (double) rand()/RAND_MAX;<br />
return r;<br />
}<br />
int main()<br />
{<br />
int i, j, n, zar1, zar2, yedi;<br />
double p;<br />
/* rastgele sayı üretecini başlat */<br />
srand( time(NULL) );<br />
for(j=1; j
43:<br />
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
50:<br />
51:<br />
52:<br />
53:<br />
54:<br />
p);<br />
}<br />
/* deneyleri başlat */<br />
for(yedi=0, i=1; i
olarak)<br />
şeklinde hesaplanabilir.<br />
Olayın canlandırılması adına, aşağıda nokta sayısının (n) farklı değerleri için oluşabilecek<br />
desenler gösterilmiştir.<br />
n = 10 nokta n = 100 nokta n = 200 nokta<br />
Program 24.9'da, MC yöntemi ile pi sayısının hesabı gösterilmiştir. Program ayrıca,<br />
hesaplanan pi ile math.h'de tanımlı sabit M_PI arasındaki hatanın yüzde olarak karşılığnı da<br />
ekranda gösterir. Program çıktısı incelendiğinde, hata n = 10 için yüzde 10, n = 1 milyar için<br />
yüzbinde 2 civarındadır.<br />
Program 24.9: MC ile Pi sayısının hesabı<br />
01:<br />
02:<br />
03:<br />
04:<br />
05:<br />
06:<br />
07:<br />
08:<br />
09:<br />
10:<br />
11:<br />
12:<br />
13:<br />
14:<br />
15:<br />
16:<br />
17:<br />
18:<br />
19:<br />
20:<br />
21:<br />
22:<br />
23:<br />
24:<br />
/* 24prg09.c:<br />
MC Yöntemi ile pi sayısının hesaplanması */<br />
#include <br />
#include <br />
#include <br />
#include <br />
/* [0, 1] arası rastgele sayı gönderir */<br />
double rastgele(){<br />
double r = (double) rand()/RAND_MAX;<br />
return r;<br />
}<br />
int main()<br />
{<br />
int i, j, n, m;<br />
double x, y, pi, hata;<br />
/* rastgele sayı üretecini başlat */<br />
srand( time(NULL) );<br />
for(j=1; j
25:<br />
26:<br />
27:<br />
28:<br />
29:<br />
30:<br />
31:<br />
32:<br />
33:<br />
34:<br />
35:<br />
36:<br />
37:<br />
38:<br />
39:<br />
40:<br />
41:<br />
42:<br />
43:<br />
44:<br />
45:<br />
46:<br />
47:<br />
48:<br />
49:<br />
ÇIKTI<br />
/* deney sayısı 10'un katları */<br />
n = pow(10, j);<br />
/* deneyleri başlat */<br />
for(m=0, i=1; i pi = 2.8000000 ,<br />
yuzde hata = %10.8732319<br />
100 : 78 --> pi = 3.1200000 ,<br />
yuzde hata = % 0.6873155<br />
1000 : 794 --> pi = 3.1760000 ,<br />
yuzde hata = % 1.0952199<br />
10000 : 7878 --> pi = 3.1512000 ,<br />
yuzde hata = % 0.3058113<br />
100000 : 78625 --> pi = 3.1450000 ,<br />
yuzde hata = % 0.1084592<br />
1000000 : 785728 --> pi = 3.1429120 ,<br />
yuzde hata = % 0.0419961<br />
10000000 : 7853164 --> pi = 3.1412656 ,<br />
yuzde hata = % 0.0104104<br />
100000000 : 78536996 --> pi = 3.1414798 ,<br />
yuzde hata = % 0.0035910<br />
1000000000 : 785380671 --> pi = 3.1415227 ,<br />
yuzde hata = % 0.0022272<br />
C / C++ Derleyicileri<br />
1. Dev-C++<br />
2. Salford (Silverfrost)<br />
3. GCC (GNU Compiler Collection)
4. Turbo C 2.01<br />
5. Eclipse IDE<br />
6. NetBeans IDE<br />
Dev-C++<br />
• Derleyicinin ilk üretildiği tarih: 1991-2009<br />
• Ekran Görüntüsü<br />
Salford (Silverfrost FTN95)<br />
• Derleyicinin üretildiği tarih: ?-2009
• Ekran Görüntüsü<br />
GCC (GNU Compiler Collection)<br />
• Derleyicinin üretildiği tarih: ?-2009<br />
• Ekran Görüntüsü
Turbo C<br />
• Derleyicinin üretildiği tarih: 1987-1988<br />
• Ekran Görüntüsü