You are on page 1of 404

indekiler

Blm 1
Giri ve Temel Kavramlar
1.1 1.2 Bir C Programnn Oluturulmas ................................................... 1-3 C Atomlar ...................................................................................... 1-5 Blm Sonu.................................................................................... 1-6

Blm 2
Tipler, Operatrler ve fadeler
2.1 2.2 2.3 2.4 2.5 Deiken simleri............................................................................ Veri Tipleri ve Boyutlar .................................................................. Sabitler ........................................................................................... Bildirimler ....................................................................................... Operatrler ..................................................................................... Aritmetik Operatrler................................................................... likisel ve Mantksal Operatrler................................................ Artrma ve Eksiltme Operatrleri................................................. Bit Operatrleri............................................................................ Atama Operatrleri ve fadeleri................................................... Koul fadeleri ................................................................................ Operatr ncelii ve leme Sras ................................................ Tip Dnmleri ............................................................................. Blm Sonu.................................................................................... 2-3 2-3 2-4 2-9 2-9 2-9 2-10 2-11 2-11 2-12 2-14 2-15 2-16 2-20

2.6 2.7 2.8

Blm 3
Kontrol Ak
3.1 3.2 3.3 3.4 3.5 Deyimler ve Bloklar ........................................................................ if-else, else-if ve switch .................................................................. Dngler: while, for ve do-while ..................................................... break ve continue........................................................................... goto ve etiketler.............................................................................. Blm Sonu.................................................................................... 3-3 3-3 3-6 3-7 3-7 3-11

Blm 4
Fonksiyonlar
4.1 Fonksiyon Tanm, Bildirimi, arma ve Deer Dndrme............................................................................ Fonksiyon Tanm ....................................................................... Fonksiyon Bildirimi ...................................................................... Fonksiyon arma ve Deer Dndrme ................................... Argmanlarn Aktarlmas: deer-ile-arma ve referans-ile-arma.................................................................... main fonksiyonu .......................................................................... Fonksiyon Argman olarak diziler.............................................. Fonksiyon Argman Fonksiyon ismi .......................................... 4-3 4-3 4-3 4-4 4-7 4-15 4-15 4-17

Fonksiyonlar
4.2 Deikenlerin Grnrlk Alan ve Varolma Sresi....................... Global ve Lokal Deikenler ....................................................... Blok Yaps Kullanlarak Grnrlk Alannn Kstlanmas ........ Grnrlk Alan ve Global Deiken Tanmnn Kaynak Dosyada bulunduu yer ................................................. Grnrlk Alan ve Varolma Sresinin Kontrolu ....................... extern bildirim .................................................................. static bildirim.................................................................... otomatik deikenler ....................................................... register deikenler ......................................................... typedef kullanm ............................................................. lk Deer Atama ............................................................................. C nilemcisi ................................................................................. C Programlarn ayr ayr Derleme ve Balama ............................. Blm Sonu.................................................................................... 4-18 4-19 4-21 4-25 4-26 4-26 4-29 4-29 4-33 4-34 4-35 4-44 4-50 4-56

4.3 4.4 4.5

Blm 5
Adres Deikenleri
5.1 5.2 5.3 5.4 5.5 5.6 5.7 Adres Deikeni Bildirimi ............................................................... Adres Deikenleri ve Diziler ......................................................... Adres deikenleri ve tek-boyutlu diziler..................................... Adres Deikenleri ve Dizgiler ....................................................... Adres Dizileri .................................................................................. ift Adres Deikeni....................................................................... Adres Deikenlerine Tip Dntrme Uygulanmas .................... void * tipi adres deikenleri ....................................................... Adres Deikenleri ve Fonksiyonlar............................................... Fonksiyon argman olarak adres deikenleri .......................... Fonksiyon argman olarak diziler .............................................. Adres deeri dndren fonksiyonlar ........................................... const deikenler ........................................................................ Fonksiyon argman olarak adres dizileri ................................... Fonksiyona iaret eden adres deikeni .................................... Bir fonksiyonun argman olarak bir baka fonksiyona aktarlmas .................................................................................. Fonksiyon tablosu ....................................................................... Komut satr argmanlar ............................................................ Deien Sayda Argman Alan Fonksiyonlar................................. Kendini aran Fonksiyonlar ........................................................ Blm Sonu.................................................................................... 5-3 5-17 5-22 5-37 5-43 5-50 5-51 5-53 5-60 5-62 5-64 5-70 5-71 5-75 5-82 5-84 5-89 5-93 5-101 5-111 5-114

5.8 5.9

Blm 6
Adres Deikenleri ve ok-Boyutlu Diziler
6.1 6.2 ok-Boyutlu Dizi Bildirimi ............................................................... 6-3 ok-Boyutlu Dizilerin Fonksiyonlara Aktarlmas ........................... 6-22 Blm Sonu.................................................................................... 6-31

Blm 7
Dinamik Bellek Ynetimi
7.1 Standart C'de Dinamik Bellek Kullanm ........................................ 2-b ve 3-b diziler iin dinamik bellek ayrlmas............................ Dizgilere iaret eden adres dizisi ve dinamik bellek kullanm ........................................................................... Yaplar ve Dinamik Bellek Kullanm .............................................. Blm Sonu.................................................................................... 7-3 7-8 7-19 7-21 7-26

7.2

Blm 8
Yap Deikenleri
8.1 8.2 8.3 Yap Deikeni Bildirimi ................................................................. Yap Dizisi ...................................................................................... Yaplar ve Adres Deikenleri........................................................ Yap deikenlerine iaret eden adres dizisi............................... Yap eleman olarak fonksiyona iaret eden adres deikeni........................................................................... Yap elemanlarnn offsetlerinin hesaplanmas .......................... Yap Deikenleri ve Fonksiyonlar ................................................. Union Deikeni ............................................................................. Bit-Alan.......................................................................................... Blm Sonu.................................................................................... 8-3 8-10 8-18 8-25 8-35 8-37 8-41 8-49 8-52 8-53

8.4 8.5 8.6

Blm 9
Giri/k lemleri
9.1 Standart Disk Giri/k lemleri ................................................. Bir disk dosyasnn oluturulmas, dosyaya yazma ve dosyann kapatlmas ............................................................. Bir disk dosyasndan okumak ..................................................... Text ve Binary Modlar ................................................................. Text ve Binary Format................................................................. Giri/k Hatalarnn lenmesi.................................................... Giri/k lemlerinde Komut Satr Argmanlarnn Kullanlmas.................................................................................... Rastgele Eriim .............................................................................. fgetpos ve fsetpos fonksiyonlar ................................................. sscanf ve sprintf fonksiyonlar..................................................... Blm Sonu.................................................................................... 9-3 9-5 9-10 9-11 9-22 9-28 9-34 9-40 9-48 9-50 9-52

9.2 9.3 9.4

1-1

BLM 1: Giri ve Temel Kavramlar


Bu blmde C programlama dilinin zelliklerine ksaca deinildikten sonra basit bir C program oluturulur. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

1-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

1-3

1.1 Bir C Programnn Oluturulmas


C programlama dili, Bell Laboratuarlarnda 1972 ylnda Dennis Ritchie tarafndan gelitirilmitir. C dili verimli, gl ve tanabilir bir programlama dilidir. Metin ilemci, veri taban, grafik program yada bilimsel almalarda kullanlan uygulama programlar, derleyiciler ve UNIX gibi iletim sistemleri gelitirmek iin kullanlan genel amal ve orta seviyeli bir dildir. Tanabilirlik (portability), ayn programn farkl donanmlarda ve iletim sistemleri altnda iletilebilirliini ifade eder. Bir dilin verimlilii (efficiency), hzl fakat fazla yer kaplamayan yazlmlar gelitirmeye olanak salad oranda artar. C programlama dili verimli, basit fakat gl yapsndan ve bu dilde gelitirilen uygulamalarn tanabilir olmasndan dolay programclar, mhendisler ve sistem programclar tarafndan tercih edilir ve yaygn olarak kullanlr. C dilinde pek ok ilem standart C ktphanesinde bulunan fonksiyonlar kullanlarak gerekletirilir; rnein giri/k ilemleri. C dili, zel ktphanelerin gelitirilerek programlarda kullanlabilmesine olanak salar. Programlarda, gerekli olduunda baz zel ilemler, yazlm firmalar tarafndan gelitirilmi ktphaneler kullanlarak gerekletirilebilir. Bir programlama dilinden bahsedilirken, hangi ortamda kullanld belirtilir. Bir programlama dilinin kullanld ortam donanm, iletim sistemi ve kaynak kodlarn (iletim sistemi altnda programlama dili ile oluturulan) altrlabilir kodlara evrilmesini salayan derleyici programdan oluur. Tanabilirlik zelliinden dolay C ile kodlanm programlar pek ok ortamda iletilebilir. Mevcut ortamda kullanlan C derleyicisinin yaps renildikten sonra dier ortamlarda da benzer yazlmlar kolaylkla gelitirilebilir. Kitapta yer alan rnek programlar aada grld gibi disket sembol ( ) ve bir rnek numaras ile balar. Metin iinde programa deinilirken genel olarak program ismi yerine rnek numaras kullanlr. Fakat rnek programlar diskette program ismi ile bulunur. Programlardaki ekran ktlar monitr sembol ve "kt" yazs sonras verilir (
kt). Ayrca eer program klavyeden bilgi okuyor ise girilen bilgiler klavye iareti Bilgi Girii).

ve "bilgi girii" yazs sonrasnda verilir (

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

1-4

Aada ekrana "C programlama dili" dizgisini yazan ve bir ka satrdan oluan basit bir C program verilmitir. Herhangi bir C programnn oluturulmas, bir editr (text editor) program kullanlarak kaynak kodun (source code) yazlmas ve bir dosyaya saklanmas ile balar. Bu dosya, C kaynak dosyas (source file) olarak adlandrlr.
rnek 1.1-1 c.c program. #include <stdio.h> int main(void) { printf( "C programlama dili\n" ); return 0; } kt C programlama dili

Kaynak dosya isminin izin verilen uzunluu iletim sistemine gre deiir. rnein DOS iletim sisteminde en fazla 8 karakterden oluur ve dosya isminde baz noktalama iaretleri bulunamaz. C kaynak dosyalar, .c uzantl dosyalardr. C kaynak dosyas yada dosyalar, altrlabilir program haline iki aamada getirilir:
l

Derleme (compilation): Bu aamada derleyici program, C kaynak dosyalarn object dosyalara evirir. Bir object dosyas (object-code file) binary kodlardan oluur, fakat henz altrlabilir durumda deildir. Object dosyalar DOS iletim sisteminde .obj uzantl, UNIX iletim sisteminde .o uzantl dosyalardr. Balama (linking): Bu aamada, linker olarak adlandrlan program (yada linkage editor), derleme srasnda oluturulan object dosyalarn standart ktphaneler (programlarda kullanlan standart ktphane fonksiyonlarna ait kodlar ieren (DOS iletim sisteminde .lib uzantl, UNIX iletim sisteminde .a dosyalar), programc tarafndan belirtilen dier object dosyalar ve ktphaneler ile birletirerek altrlabilir program dosyasn oluturur. Bu dosya (DOS iletim sisteminde .exe uzantl, UNIX iletim sisteminde ise .out uzantl yada uzantszdr), iletim sistemi altnda altrlmaya hazrdr.

Derleyiciler, derleme srasnda kaynak kod iinde herhangi bir yazm hatasna (syntax error) yada programlama hatasna rastladnda almasn durdurur ve ekrana hatay anlatan ve kaynak program iinde hangi satrda bulunduunu gsteren hata mesajn listeler. Baz hatalar yukarda anlatlan balama ilemi srasnda oluur ve balama hatas (linkage error) olarak adlandrlr. Bu durumda, linker program tarafndan ekrana
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

1-5

hata mesaj listelenecektir. Hatasz olarak derlenen ve balanan bir programn almas srasnda oluan hatalar ise alma zaman (run-time error) hatalardr. n

1.2 C Atomlar
Atom (token olarakta adlandrlr), programlama dili iin anlam olan tek bir karakter yada karakterler (boluk yada baz zel karakterlerle blnmemi) btndr. Bir C program atomlardan oluur. Derleyici almaya baladnda kaynak kodu ilk olarak atomlara ayrr. Bir program iinde 6 eit atom bulunur: isimler (identifiers), anahtar szckler (keywords), sabitler (constants), dizgi sabitleri (string literals), operatrler (operators) ve ayralar (separators). Bir isim, harf ve rakam dizisidir. C dilinde eitli tiplerde sabitler bulunur: tamsay sabitler, karakter sabitleri, kayan-noktal sabitler ve enum sabitleri. Dizgi sabiti (string literal yada string constant) ift trnaklar arasnda bulunan karakter dizisinden oluur ("..."). Ayralar, C dilinin noktalama iaretlerdir: , ; { } = ( ) : Operatrler ve dier C atomlar izleyen blmde ayrntl olarak incelenecektir. Aadaki isimler, C dilinde ayrlm szcklerdir ve program iinde deiken ismi olarak kullanlamaz (keywords): auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

Derleyici tarafndan program iindeki dz boluklar (blank space), yatay ve dey tab boluklar (HT ve VT), yeni-satr karakterleri (NL, newlines), form-feed karakterleri (FF) (bunlarn tamam boluk karakteri olarak adlandrlr: white space) ve aklama satrlar (/* ile balayan ve */ ile sonlanan) atom ayrac (token delimiter) olarak grlr. Kaynak kod iinde birbirini izleyen isimler, anahtar szckler ve sabitler bitiik yazlamazlar; atom ayrac ile birbirlerinden ayrlmaldrlar. Bunun dnda program iinde C atomlar arasnda istenildii kadar boluk karakteri yada aklama bulunabilir yada atomlar bitiik yazlabilir. Buna gre c.c program aadaki ekillerde yazlabilir: Her satrda bir atom bulunacak ekilde:
ATOM:
anahtar szck anahtar szck

#include <stdio.h> int main

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

1-6
ayra anahtar szck ayra ayra isim ayra dizgi sabiti ayra ayra anahtar szck sabit ayra ayra

( void ) { printf ( "C programlama dili\n" ) ; return 0 ; }

Tm atomlar ayn satrda bulunacak ekilde:


#include <stdio.h> intomain(void){printf("C programlama dili\n");returno0;}
NOT:

o iareti, atom ayrac bulunmas gereken ksmlar gstermek iin kullanlmtr.

Grld gibi iki anahtar szck (int ve main); bir anahtar szck ve sabit (return ve 0) arasnda mutlaka bir atom ayrac bulunmaldr (boluk karakteri yada aklama). Aadaki C deyiminde deiken isimleri ve operatrler arasnda atom ayrac bulunmas gerekmez:
c=a+b;

Her iki ekilde de program kodunun okunabilirlii olduka snrldr. C dili birden fazla satrdan oluan aklama satrlarna izin verir; /* ile balar ve */ ile sonlanr. ie bulunamazlar yada dizgi sabitlerinin iine yerletirilemezler. Aklama satrlar ve dzenli bir ekilde yerletirilen boluk karakterleri, program kodunun okunabilirliini (readibility) artrr ve program zerinde daha sonra yaplacak almalar kolaylatrr. Kitaptaki rneklerde, programlarn ksa olular ve metin iinde aklamalarn bulunduu gz nnde bulundurularak aklama satrlarna ok az yer verilmitir. Her iki programda da grld gibi # ile balayan nilemci komutlar tek bir satrda bulunabilir (satr devam ettirmek iin kullanlan \ ile blnmedike). nilemci komut satrnda bulunan atomlar FF yada VT ile ayrlamazlar. # ncesinde yada sonrasnda istenen miktarda dz boluk ve HT (yada aklama) bulunabilir. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-1

BLM 2 : Tipler, Operatrler ve fadeler


Bu blmde deikenler, sabitler, deikenlerin bildirilmesi, operatrler ve ifadeler anlatlacaktr. Bildirimler, programda kullanlacak deikenleri listeler, deikenlerin zelliklerini ve ilk deerlerini bildirir. Operatrler, deikenler ve sabitler zerinde yaplacak ilemleri belirtir. Programlarda operatrler ve operand'lardan (deiken, sabit, fonksiyon ars) oluan C ifadeleri ilenerek yeni deerler elde edilir. Bir program deyimi, ";" ile sonlanm bir ifadeden oluur. Bu blmde son olarak tip dnmleri anlatlacaktr. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-3

2.1 Deiken isimleri


Deiken, sembolik sabit ve fonksiyon isimleri (identifiers) harf, rakam ve alt-izgiden oluur. lk karakter bir harf olmaldr. Alt-izgi (underscore) karakteri "_", harf olarak ilem grr ve uzun deiken isimlerinde okunabilirlii artrmak iin kullanlabilir. Aadakiler geerli isim rnekleridir:
SecenekSayisi DIZI_BOYU Listele Sayi123

Bir isim boluk, virgl yada ( ) & $ # . ! \ ? gibi zel semboller ieremez. Ktphane rutinleri genel olarak alt-izgi ile balad iin program iinde kullanlan deiken isimlerini alt-izgi ile balatmak uygun olmaz. C dilinde kk ve byk harf ayrm yaplr; rnein Dizi ile dizi birbirinden farkldr. Deiken isimlerinin kk harflerle, sembolik sabit isimlerinin ise byk harflerle oluturulmas yaygn bir uygulamadr. Program iindeki d balanma zellii olmayan (internal) bir ismin 31 karakteri belirgindir. Yani 31 karakterden uzun isimlerin kullanlmas anlamszdr. D balanma zellii olan fonksiyon isimlerinin ve external deikenlerin ise 6 karakteri belirgindir ve bu isimlerde byk-kk harf ayrm yaplmayabilir. Anahtar szckler deiken ismi olarak kullanlamaz. n

2.2 Veri Tipleri ve Boyutlar


C dilindeki temel veri tipleri unlardr: char, int, float ve double. Tamsay tipler (integral types): char Karakter veri tipi (1- byte). C karakter tablosunda bulunan bir karakteri (daima pozitif) saklayabilir. Bu tipin snrlar (minimum ve maksimum; yazlan deerler dahil): unsigned char : 0 ve 255 signed char : -128 ve 127 Tamsay veri tipi (donanma bal olarak 2 yada 4 byte). Snrlar (minimum ve maksimum; yazlan deerler dahil): unsigned int : 0 ve 65535 (2-byte) signed int : -32768 ve 32767 (2-byte)

int

Bu tiplere signed yada unsigned anahtar szckleri eklenerek srasyla iaretli yada iaretsiz (pozitif yada 0) olduklar belirtilebilir. Bunlardan biri kullanlmadnda derleyiciye bal olarak tip iaretli yada iaretsiz kabul edilir. unsigned yada signed bulunan bildirimlerde int kullanlmayabilir; rnein unsigned i;.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-4

short ve long tip belirleyiciler bir tamsay tipin uzunluunu deitirir; "short int", bir ksa tamsaydr ve 16 bit'tir; "long int", bir uzun tamsaydr ve 32 bit'tir. Snrlar (minimum ve maksimum; yazlan deerler dahil): unsigned short : 0 ve 65535 signed short : -32768 ve 32767 unsigned long : 0 ve 4294967295 signed long: -2147483648 ve 2147483647 Bildirimlerde int kullanlmayabilir. rnein unsigned short int yerine unsigned short kullanlabilir. Ayrca tip belirleyiciler istenilen srada yerletirilebilir; rnein int short unsigned. Bilgisayarda gerel saylar (real numbers) yani kesirli ksm bulunan saylar temsil etmek iin kayan-nokta dzeni (floating-point notation) kullanlr. Kayan-nokta tipler (floating-point types) unlardr: Pozitif yada negatif olabilirler. Hassasiyet (precision), ondalk noktadan sonraki hane saysn belirtir. Aada grld gibi 3 ayr hassasiyet seviyesi vardr. float Tek-hassasiyetli kayan nokta (4-byte). Hassasiyet : en az 6 hane. double ift-hassasiyetli kayan nokta (8-byte). Hassasiyet : en az 10 hane. long double Geniletilmi hassasiyetli kayan nokta. Hassasiyet : en az 10 hane. Byte saylar ve snrlar donanma gre deiir. Standart balk dosyalar limits.h ve float.h'de snrlar iin sembolik sabitler bulunur. n

2.3 Sabitler
Tamsay sabitler, l yada L harfi eklenmedii zaman int deerlerdir; rnein 1234 deeri. Tamsay sabit sonuna l yada L harfi eklenerek bunun bir long deer olduu belirtilir; 123l yada 123L gibi. unsigned (iaretsiz) tamsay sabitlere, u yada U harfleri eklenir; unsigned long sabitlere ise ul yada UL harfleri eklenir. Tamsay sabitler onluk (decimal) yerine nne 0 yerletirilerek sekizlik (octal); nne 0x yada 0X yerletirilerek onaltlk (hexadecimal) say sistemlerinde gsterilebilirler; rnein onluk sabit 171, sekizlik sabit olarak 0253 yada onaltlk sabit olarak 0xAB veya 0xab eklinde gsterilebilir. Bu sabitlere de L yada U eklenebilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-5

Kayan-noktal sabitler ondalk nokta ierebilir (123.4); sl (exponent) olarak verilebilir (1e-2 yada 1E-2) yada her ikisi bir arada (1.23e-2) bulunabilir. f yada F harfleri eklenmi ise float aksi taktirde double deerlerdir. l ve L ekleri ise long double sabitler iin kullanlr. Trnaklar arasna yerletirilmi bir karakterden oluan karakter sabitleri tamsay deerlerdir; rnein 'a', 'X'. Karakter sabiti, bilgisayarn karakter tablosunda szkonusu karaktere karlk gelen saysal deeri verir. Karakter sabiti '0', ASCII karakter tablosunda (ASCII character set) 48 deerine karlk gelir. Bir programda bu karakteri temsil etmek iin saysal deer 48 yerine karakter sabiti '0' kullanm daha pratiktir. Karakter sabitleri dier tamsaylar gibi ilemlerde kullanlabilirler. Dizgi sabitleri (string constant, string literal) ift trnaklar arasnda bulunan sfr yada daha ok karakterden oluur; "deneme" yada bo dizgi "" gibi. Dizgi sabitleri izleyen blmlerde ayrntl olarak incelenecektir. Dizgi sabitleri ve karakter sabitleri escape dizileri ierebilirler. Escape dizileri, ters kesme karakteri \ ve bunu izleyen harf yada rakamlardan oluur; white-space (boluk karakterleri) yada grafiksel olarak temsil edilemeyen karakterleri temsil etmek ve baz zel anlam olan karakterlerin bu zel anlamn derleyiciden gizlemek iin kullanlr. Escape dizileri birden fazla karakter kullanlarak oluturulur fakat sadece bir karakteri temsil ederler. rnein printf fonksiyonu arsndaki dizgi sabiti, ekranda bir alt satra geilmesini salayan \n (newline) escape dizisini ierir. Escape dizileri: \a \b \f \n \r \t \v \\ \? \' \" bell backspace formfeed newline carriage return horizontal tab vertical tab \ karakteri ? karakteri ' karakteri " karakteri

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-6

ASCII karakterleri temsil etmek iin sekizlik yada onaltlk ASCII karakter kodlar ile oluturulan escape dizileri kullanlabilir: '\ooo' escape dizisinde ooo, 0'dan 7'ye kadar rakamlardan oluan sekizlik ASCII karakter kodudur (burada sekizlik saynn ilk rakam olarak 0 verilmesi gereksizdir). rnek olarak backspace iin '\010' yada '\10' kullanlabilir. '\xhhh' escape dizisinde hhh, 0'dan 9'a ve a'dan f'e (yada A'dan F'e) kadar rakamlardan oluan onaltlk ASCII karakter kodudur. rnek olarak backspace iin '\x08' yada '\x8' kullanlabilir. Escape dizileri dizgi sabitleri iinde yukardaki ekilde kullanldnda, hatalara sebep vermemek iin tm haneler doldurulmaldr. rnein derleyici "\x07Bell" dizgisini \x07B ({ karakteri) ve ell olarak yorumlar. Bunun yerine "\x007Bell" kullanlmaldr. '\0' karakter sabiti ('\000' yada '\x000'), ASCII karakter tablosunda saysal kodu sfr olan bo karakterdir (null character). Saysal kodu 48 olan '0' ile kartrlmamaldr. Karakter sabiti, tek karakter ieren dizgi sabiti ile kartrlmamaldr; rnein 'a' ve "a" ayn deildir. 'a' bir tamsaydr ve karakter tablosunda bir saysal deere (koda) eittir; "a" ise a karakteri ve dizgiyi sonlandran null karakterden ('\0') oluan bir karakter dizisidir. C dilinde enum anahtar kelimesi kullanlarak her biri bir tamsay sabite (enumeration constant) karlk gelen isimlerden oluan liste tanmlanabilir. Bir enum bildirimi eitli ekillerde yaplabilir. Aadaki deyimde, enum tipi etiket tanmlanr:
enum etiket { enum-listesi ... };

Tanmlanan enum tipi kullanlarak enum deikeni isim aadaki ekilde bildirilir:
enum etiket isim;

enum tipi ve enum deikeni bildirimi bir arada yaplabilir (seime bal kullanmlar keli parantezler arasnda verilmitir):
enum [etiket] { enum-listesi...} [isim];

Aada enum tipi olarak SAYI etiketi bildirilir:


enum SAYI { SIFIR, BIR, IKI, UC, DORT };

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-7

Listedeki her elemana aadaki ekilde ak olarak sabit deer atamas yaplabilir:
... eleman_ismi = sabit-ifade, ...

Deer atanmad durumda listedeki ilk elemann deeri 0 olur. Ayrca deer atanmam herhangi bir elemann deeri kendinden nceki elemann deerinin bir fazlasdr. Bu nedenle sabit listesindeki hi bir elemana ilk deer atama yaplmaz ise listedeki isimler sfrdan balayarak birer birer artan sral deerler alr. rnein SIFIR'n deeri 0, BIR'in deeri 1, IKI'nin deeri 2 gibi. Aadaki enum bildiriminde grld gibi ak atama yaplabildii iin listedeki sabit deerlerin sral olmas gerekmez:
enum LISTE { a = 12, b = 0, c = 5 };

enum tipi SAYI kullanlarak enum deikeni DEGER bildirilebilir:


enum SAYI DEGER;

enum tipi ve deikeni bildirimi ayn deyimde yaplabilir:


enum SAYI { SIFIR, BIR, IKI, UC, DORT } DEGER;

Eer ayn tipte baka deiken bildirilmeyecek ise yaplabilir:

enum bildirimi etiket olmadan

enum { SIFIR, BIR, IKI, UC, DORT } DEGER;

Herhangi bir enum deikeni bildirmeksizin isimlerle ifade edilen sabitlerden oluan enum listesi bildirilebilir:
enum { SIFIR, BIR, IKI, UC, DORT };

rnek 2.3-1 enum.c program. #include <stdio.h> enum SAYI { SIFIR, BIR, IKI, UC, DORT }; enum { OCAK = 1, SUBAT, MART, MAYIS = 5, HAZIRAN }; int main(void) { enum SAYI DEGER = SIFIR; int AY = OCAK; printf( "SIFIR : %d\n", DEGER ); DEGER = DORT; C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-8

rnek 2.3-1 devam


printf( "DORT : %d\n", DEGER ); printf( "OCAK : %d\n", AY ); AY = MART; printf( "MART : %d\n", AY ); AY = HAZIRAN; printf( "HAZIRAN : %d\n", AY ); return 0; } kt SIFIR : 0 DORT : 4 OCAK : 1 MART : 3 HAZIRAN : 6

rnek 2-3-1'de enum tipi SAYI ve SAYI tipinde DEGER deikeni bildirilir. Bildirim srasnda DEGER deikenine SIFIR deeri atanr. Ayrca int tipinde AY deikeni bildirilir ve ilk deer olarak enum sabiti OCAK atanr. Bir enum listesi sadece tamsay deerlerden oluur. Bu rnekte de grld gibi enum tipinde bir deiken, enum tipi ile tanmlanan deerlerden birini tar ve dolaysyla daima int tipindedir. Bundan baka bir enum listesinde bulunan sabit ismi, bir dierinde kullanlamaz. Fakat ayn kstlama listede yer alan sabit deerler iin szkonusu deildir. enum tipi, tamsay sabitler yerine anlaml isimler kullanlmasn salad iin programlarn okunabilirlii arttrr. Ayn ilem, bir grup #define komutu ile gerekletirilebilir. Fakat birbiri ile ilgili deerler tek bir listede topland iin enum kullanm daha pratiktir. C dilinde, veri tipi olarak mantksal doru ve yanl (Boolean TRUE ve FALSE) deerleri yoktur. Herhangi bir test ifadesi, 0 dnda herhangi bir pozitif yada negatif deer veriyor (non-zero value) ise koul doru kabul edilir. Eer 0 deeri veriyor ise koul yanltr. Doru yada yanl koulunu test etmek iin TRUE ve FALSE makrolar kullanlabilir:
#define TRUE 1 #define FALSE 0

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-9

Fakat bu deerler enum sabiti olarakta tanmlanabilir:


enum bool { FALSE, TRUE };

Burada FALSE sabitinin deeri 0, TRUE sabitinin deeri ise 1'dir. n

2.4 Bildirimler
Tm deikenler, program iinde kullanlmadan nce bildirim deyimleri ile bildirilmelidir. Bir bildirim, deikeninin tipini belirtir. Ayn deyimde ayn tipte birden fazla deiken bildirilebilir; yada her deikenin bildirimi ayr bir bildirim deyimi ile yaplabilir:
int a, b, c; char s, dizi [ 10 ]; yada int a; int b; int c; char s; char dizi [ 10 ];

Bir deikene bildirim deyiminde = ve bir ifade ile ilk deer atama yaplabilir:
char c = 'a'; int i = 9;

Bu bildirim deyimlerinde ilk deer olarak 'a' ve 9 kullanlr. Bildirim deyimlerinde eitli belirleyiciler (qualifier yada storage class specifier) kullanlabilir (const, volatile yada static, auto gibi). Bildirimler izleyen blmlerde ayrntl olarak incelenecektir. n

2.5 Operatrler Aritmetik operatrler


Aritmetik ilemlerde kullanlan ve iki operand alan (binary) aritmetik operatrler unlardr: +, -, *, / ve kalan operatr %.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-10

Aritmetik ifade:
operand i % j operatr operand

Tamsaylarla yaplan blme ileminde kesirli ksm atlr (truncated). float ve double operand'lara uygulanamayan % operatr i'nin j'ye blmnden kalan deeri verir.

likisel ve Mantksal Operatrler


Operand'lar karlatrmak iin kullanlan ilikisel operatrler ve anlamlar unlardr:
< > <= >= kktr byktr kktr yada eittir byktr yada eittir

Aadaki iki operatr yukardakilerden daha dk nceliklidir:


== != eittir eit deildir

likisel operatrler kullanlarak oluturulan ilikisel ifadeler, koul ifadeleri olarakta adlandrlr. Mantksal operatrler && (-ve- operatr) ve || (-veya- operatr) ile birletirilen ifadeler soldan-saa doru ilenir; sonucun doru yada yanl olduu saptanr saptanmaz ilem durur. C dilinde ilikisel ve mantksal ifadeler doru ve yanl sonular (boolean deer) vermez. likisel ve mantksal ifadelerin deerleri bir tamsaydr; 0 (yanl) yada 0 dnda bir deer (doru). Aadaki mantksal ifadede ilk olarak ifade1 ilenir; doru ise ifade2 ilenir ve bu ifade de doru ise ifade3 ilenir. fadelerden biri, rnein ifade1 yanl sonucunu verir ise mantksal ifadeden klr ve dierleri ilenmez:
ifade1 && ifade2 && ifade3

Bu zellik kullanlarak sfra blme hatas (divide-by-zero) aadaki ekilde nlenebilir:


d != 0 && n/d < 10

likisel ifade d != 0 ilk olarak ilenecek ve d'nin deeri 0 olduunda yanl sonucunu verecei iin n/d ilenmeden ifadenin tamamndan klacaktr. && operatr, || operatrnden daha yksek ncelie sahiptir. Ayrca her iki operatr de ilikisel

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-11

operatrlerden daha dk ncelie sahip olduu iin ilikisel operatrlerle oluturulan ifade1, ifade2 yada ifade3 dnda parantezler gereksizdir. Bir dier mantksal operatr, ! (-deil- operatr: unary negation operator) operatrdr; 0 dnda bir deere sahip operand'n deerini 0, deeri 0 olan operand'n deerini 1 yapar. Genel olarak test ifadelerinde kullanlr; rnein if (!dogru) ifadesi if (dogru == 0) yerine kullanlr.

Artrma ve Eksiltme Operatrleri


C dilinde deikenlerin deerlerinin artrlmas ve eksiltilmesi iin artrma (increment) ve eksiltme (decrement) operatrleri bulunur. Artrma operatr ++, operand'nn deerine 1 ekler; eksiltme operatr -- ise operand'nn deerinden 1 karr. Her iki operatr de, deikenden nce nek (prefix) yada deikenden sonra sonek (postfix) operatrler olarak kullanlabilir: ++i, i++, --i, i--, nek artrma: deikenin deeri artrldktan sonra kullanlr. sonek artrma: deikenin deeri kullanldktan sonra artrlr. nek eksiltme: deikenin deeri eksiltildikten sonra kullanlr. sonek eksiltme: deikenin deeri kullanldktan sonra eksiltilir.

--(a + b) eklinde bir ifade hataldr. nk ++ ve -- operatrleri sadece deikenlere uygulanr (lvalue). Baz uygulamalarda operatrlerin nek ve sonek kullanmlar farkl sonular verebilir.

Bit Operatrleri
C dilinde mantksal bit ilemleri iin yalnzca iaretli yada iaretsiz char, short, int, ve long operand'lara (integral types) uygulanabilen 6 operatr bulunur: & | ^ << >> ~ ve (bitwise AND) veya (bitwise OR) dlayan veya (bitwise exclusive-OR) sola bit kaydrma (shift left) saa bit kaydrma (shift right) deil yada 1'in tmlevi operatr (bit-negate yada bitwise complement)

Aada bu operatrler kullanlarak eitli bit ilemleri yaplr:


VE (AND)

rnek:
& 0 1 0 0 0 1 0 1

0101 0101 & 1111 0000 0101 0000

0x55 0xF0 0x50

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-12

VEYA (OR)

rnek:
| 0 1 0 0 1 1 1 1

0101 0101 | 1111 0000 1111 0101

0x55 0xF0 0xF5

dlayan - VEYA (EXCLUSIVE-OR)

rnek:
^ 0 1 0 0 1 1 1 0

0101 0101 ^ 1111 0000 1010 0000

0x55 0xF0 0xA0

DEL (NOT)
~ 0 1

1 0 /* /* /* /* /* 0101 0101 */ 1111 0000 */ 1010 1010 */ 1010 1010 */ 0000 0011 */

unsigned char a = 0x55; unsigned char b = 0xF0;


~a a << 1 b >> 6

AA AA 03

Atama Operatrleri ve ifadeleri


Aadaki ifade basit bir atama ifadesidir:
degisken = operand

Bu ifade, sonuna ; eklendiinde atama deyimi olur. Bu ifadede operand'n deeri degisken'e atanr. Eittir iareti =, C dilinde atama operatrdr (assignment operator). operand bir deiken, sabit bir deer yada bir baka geerli C ifadesi olabilir. Bir atama ifadesinin deeri sada bulunan operand ile ayndr; tipi ise solda bulunan operand ile ayndr. Buna gre yukardaki atama ifadesinin deeri degisken'e atanan deer (sada bulunan operand) ile ayndr; tipi ise degisken (solda bulunan operand) ile ayndr. rnein aadaki printf satr ekrana 9 deerini yazar:
printf( "%d\n", i = 9 );

Ayn ifadede birden fazla atama bulunabilir:


i=j=k=7

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-13

Bu ifadedeki tm atama operatrleri ayn operatr nceliine sahiptir. Bu durumda ifade, operatrlerin grup ilikisine gre ilenir. Atama operatrnn grup ilikisi (izleyen paragraflarda anlatlacak) sadan-sola doru olduu iin bu ifade aadaki srada ilenir:
k=7 j=k i=j

Bu ifadeler aadaki ifade ile ayn etkiye sahiptir:


i = ( j = (k = 7) )

fade ; ile sonlanr ise oluturulan atama deyiminde tm deikenlere 7 deeri atanr:
i = j = k = 7;

Bu atama ilemi aadaki 3 ayr atama ilemi ile ayn ii yapar:


k = 7; j = 7; i = 7;

Aadaki deyim, bir gizli atama deyimidir (embedded assignment):


( c = getchar( ) ) != EOF

getchar tarafndan dndrlen deer ilk olarak c'ye atanr; atanan deer ayn zamanda bu atama ifadesinin deeridir ve daha sonra EOF ile karlatrlr. Parantezler gereklidir nk = operatr != operatrnden daha dk ncelie sahiptir. Bu ifade bir while dngsnn test ifadesinde kullanlabilir.
i=i+9

ifadesi iki aamada ilenir: ilk olarak i + 9 ifadesinin deeri hesaplanr; hesaplanan deer i deikenine atanr. C dilinde, = operatrnn sanda ve solunda ayn deikenin bulunduu ifadeler tek bir atama operatr (+=) ile oluturulabilir:
i += 9

ki operand alan pek ok operatr'e (binary operators) karlk gelen atama operatr vardr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-14

Aadaki operatrler oluturulabilir:

kullanlarak,
+ * / %

operator=
<< >> &

eklinde atama operatrleri


^ |

Sonu olarak,
ifade1 operator= ifade2

ifadesi ve
ifade1 = (ifade1) operator (ifade2)

ifadesi birbirine etir. stteki ifadede ifade1 yalnzca bir kez ilenir. ifade2 dndaki parantezler mutlaka kullanlmaldr. rnein,
a *= b + 1

ifadesi,
a = a * (b + 1)

ifadesine etir; a = a * b + 1 ifadesine deil. n

2.6 Koul fadeleri


operand alan ?: operatr (ternary operator) ile koul ifadeleri (conditional expressions) oluturulabilir:
(ifade1) ? ifade2 : ifade3

lk olarak ifade1 ilenir. Eer sonu 0 dnda bir deer (non-zero value), yani doru ise ifade2 ilenir ve koul ifadesinin deeridir. Aksi taktirde koul ifadesinin deeri ifade3 olur. Ayn ilem aadaki if deyimi ile gerekletirilebilir:
if (ifade1) ifade2 else ifade3

Koul ifadesi, dier C ifadelerine izin verilen her yerde kullanlabilir. ifade2 ve ifade3 farkl tiplerde ise sonu tip dnm kurallarna gre belirlenir. ifade1 dndaki parantezler ?: operatrnn ncelii ok dk olduu iin kullanlmayabilir. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-15

2.7 Operatr ncelii ve leme Sras


Birden fazla operatr ieren ifadeler, parantezler bulunmuyor ise operatr ncelik srasna (precedence) gre ilenir. Ayn ncelie sahip operatrlerin bulunduu ifadeler ise operatrlerin grup zelliklerine (associativity) gre ilenir. ekil 2.7-1'de operatrlerin ncelik ve grup zellikleri listelenir. Bu tabloda ayn satrda bulunan operatrler eit ncelie sahiptir; aa doru operatr ncelii azalr. fadelerde parantezler kullanlarak ncelikler deitirilebilir. C dili &&, ||, ?:, ve virgl operatr ''," dnda bir operatrn operand'larnn hangi srada ileneceini belirtmez. Aadaki test ifadesinde ifadeler soldan-saa doru ilenir:
if ( (c = getchar()) == EOF || c == '\n' ) { ... }

Fakat aadaki ifadede arlardan hangisinin nce ilenecei belli deildir. Dolaysyla fonksiyonlarn i yapsna bal olarak a deikeninin deeri arlarn ileni srasna gre deiebilir:
a = fonk1( ) + fonk2( );

Bu gibi belirsiz durumlar baz teknikler kullanlarak nlenebilir; rnein bu ifadede arlarn dndrd deerler ara deikenlerde saklanarak belli bir ileni sras garanti edilebilir. Ayn ekilde fonksiyon argmanlarnn ileni sras da derleyiciye gre deiebilir:
fonk1( ++i, fonk2( i ) );

Bu ardaki belirsizlik aadaki ekilde nlenebilir:


++i; fonk1( i, fonk2( i ) );

Bir C ifadesinin ilenmesi srasnda ifadenin asl amac dnda oluan etkiler yan etki olarak adlandrlr. rnein aadaki atama deyiminin asl amac, i deikenine j deikeninin deerinin atamaktr. Yan etki ise atama sonras j deikeninin deerinin artmasdr:
i = j++;

Yan etkiler her zaman ak olmayabilir. Yan etkiler ieren ifadelerin ileni sras derleyiciye bal olarak deiebilir. rnein aadaki ifadede indeks deerinin i deikeninin ++ sonras deeri mi, yoksa ++ ncesi deeri mi olduu derleyiciye gre deiir:
dizi[ i ] = i++;

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-16

Bir dier rnek olarak aadaki printf ars verilebilir:


int i = 9; ... printf( "%d\n", i++ * i++ );
ekil 2.7-1 Operatr ncelik tablosu. Operatrler operatr ncelii aa doru azalr Fonksiyon arma, indeks, ok ve nokta operatrleri: ( ) [ ] -> . ! ~ ++ -- + - * & (tip) sizeof Aritmetik operatrler (iki operand alr): * / % +<< >> likisel operatrler: < <= > >= == != & ^ | && || ?: = += -= *= /= %= &= ^= |= <<= >>= Virgl operatr: , Tek operand alan (unary) +, - ve * operatrleri ayn operatrlerin ift operand alanlarndan (binary) daha yksek ncelie sahiptir. Grup likileri

soldan saa sadan sola soldan saa soldan saa soldan saa soldan saa

sadan sola sadan sola soldan saa

Sonu olarak, ifadelerin ileni srasna bal kodlar oluturulmamaldr. n

2.8 Tip Dnmleri


C dilinde tip dnmleri otomatik olarak (tip geniletme -promoting-, tip dengeleme balancing- yada atama srasnda -assigning-) yada program iinde tip dntrme operatr kullanlmas ile (type casting) gerekleir. Eer bir ifade de bulunan tamsay deer int, unsigned int, long yada unsigned long tipinde deil ise tipi geniletilir (tamsay deerin sizeof operatrnn operand' olarak bulunduu ifade dnda). Bu ilem otomatik olarak integral tiplere uyguland iin integral promotion olarak adlandrlr. Eer orjinal tipteki tm deerler bir int ile temsil edilebiliyor ise yeni tip int olur; aksi taktirde unsigned int olur.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-17

Bu ilem, iaretli yada iaretsiz char, short int, tamsay bit-alan yada enum tipler zerinde uygulanr. Kayan-nokta tiplere bu ilem uygulanmaz. rnein bir signed char deer int'e; unsigned short deer ise int yada unsigned int'e geniletilir. rnek 2.8-1'de eitli tamsay tip geniletme ilemleri yer alr. rnekte yer alan ilk if deyiminde,
c == ~0x5A

testi yaplr. Burada unsigned char tipinde c deikeninin deeri olan 0xA5, 0x00A5'e geniler. Ayrca yine 0x005A'ya genileyen KARAKTERSABIT'in deeri ~ operatr uygulandktan sonra 0xFFA5 olur. Dolaysyla test ifadesi yanl sonucunu verir ve if deyiminin else ksm alr. Bu sorun test ifadesinde tip dntrme operatr (izleyen paragraflarda anlatlacaktr) kullanlarak KARAKTERSABIT'in unsigned char'a dntrlmesi ile nlenebilir. zleyen if deyiminde 0xC0 deerine (1100 0000) 3 kez sola bit-kaydrma ilemi uygulanr. Fakat bu deer kaydrma ncesi int'e genilediinden dolay sonu 0 olmaz. Yine rnekte de grld gibi tip dntrme yaplarak bu sorun nlenebilir. Programda char tipinde k1, k2 ve k3 deikenleri bildirilir. Program, karakter tipinin 8bit olduu donanmda k2 iin ekrana -56 yazar (orjinal deer 200 yada 0xC8). Derleyici printf parametrelerine (format dizgisi hari) tip kontrol yapmaz ve k2'nin int'e genilediini saptayamaz. Bir char tip, derleyici tarafndan signed yada unsigned (iaretli yada iaretsiz) olarak yorumlanabilir. Bu donanmda signed olarak yorumlar ve signed char veriyi int'e iaret genilemesi (sign extension) ile geniletir; yani bo kalan yksek anlaml ilave bit pozisyonlarn orjinal iaretli char verinin iaret bit (en yksek anlaml bit) deeri olan 1 ile doldurur. Dolaysyla signed char 0xC8 deeri int'e 0xFFC8 olarak geniler (-56). Toplama ilemi 0064 + FFC8 = 002C eklinde olur ve 0x2C (yada 44) sonucunu verir. unsigned char'n int'e genilemesi bo kalan yksek anlaml bit pozisyonlarnn 0 ile doldurulmas ile olur. Programda unsigned char kullanldnda toplama sonucu elde edilen 300 deeri (0x012C) 1-byte alana smaz. Sonu 44 yada 2C olur. Burada daha ksa bir tipe dnm (demotion) gerekleir. signed tiplerin bu tip dnmlerinde sonu derleyiciye gre deiir. zleyen ilemde k1'in deeri 0x7C'dir (124). k1 + k1 ifadesinde her iki 0x7C deeri 0x007C deerine geniler ve toplamlar 0x00F8'dir. Tekrar dnm olmaz ve toplam deer ekranan yazlr. Fakat toplamn atand k2'nin deeri geniler; k2'nin (0xF8) yksek anlaml bit'i dnm ncesi 1 olduu iin ekrana yazlan deer 0xFFF8 olur. Bir operatr (+ yada * gibi iki operand alan -binary operator-) farkl tiplerde operand'larla ilem yapyor ise operand'lar belli baz dnm kurallarna gre ortak bir
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-18

veri tipine dntrlr (balancing). fadede tamsaylar bulunuyor ise integral promotion gerekleir. Bu ilem aada verilen ve tiplerin nceliinin sralamada ileriye doru artt listeye gre gerekleir:
int, unsigned int, long, unsigned long, float, double, long double

Buna gre eer operand'lardan herhangi biri long double ise dieri de bu tipe dntrlr; yada operand'lardan herhangi biri double ise dieri de bu tipe dntrlr; yada operand'lardan herhangi biri float ise dieri de bu tipe dntrlr; yada integral promotion uygulanr.
int i; long l; double d;

rnein yukarda bildirilen deikenlerle oluturulan ( ( i + l ) + d ) ifadesinde ilke olarak i'nin tipi long'a daha sonra da i + l ifadesinin tipi double'a evrilir. Atama ilemlerinde (atama operatrleri ile oluturulan) operand'lar farkl tiplerde ise tip dntrme gerekleir. Sadaki deer sonucun tipini belirleyen soldaki tipe dntrlr. Atama ileminde, bir aritmetik tip (tamsay ve kayan-nokta tipler) bir dier aritmetik tipe dnebilir. Dnmler operand'larn tiplerine bal olarak veri kaybna yol aabilir. Fonksiyon arsnda argmanlar aktarlrken atama ileminde olduu gibi tip dntrme gerekleebilir. Prototip bulunmuyor ise char ve short tipler int'e; float tipler double'a dntrlr. Tek operand alan (unary) tip dntrme operatr (cast operator) kullanlarak tip dnmleri zorlanabilir. Aadaki ifadede, ifade'nin tipi verilen tipe dntrlr. zleyen blmlerde ayrca adres deikenlerine tip dntrme uygulanmas ve void tipi adres deikenlerinin kullanm anlatlacaktr. n
(tip-ismi)ifade

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-19

rnek 2.8-1 tip.c program. #include <stdio.h>

#define KARAKTERSABIT 0x5A int main(void) { unsigned char c = 0xA5; unsigned char a = 0x40, b = 0xD0; char k1 = 100, /* 0x64 */ k2 = 200, /* 0xC8 */ k3 = k1 + k2; unsigned char uk1 = 100, /* 0x64 */ uk2 = 200, /* 0xC8 */ uk3 = uk1 + uk2; if ( c == ~KARAKTERSABIT ) ; else puts( "integral promotion" ); if ( c == (unsigned char)~KARAKTERSABIT ) puts( "OK !" ); else ; c = 0xC0; /* 1100 0000 */ if ( c << 3 ) puts( "c << 3 --> Sonuc 0 degildir" ); else ; if ( (unsigned char)(c << 3) ) ; else puts( "c << 3 --> Sonuc 0 " );
/* integral promotion: signed char --> int */

printf( "k1 : %d, k2 : %d, k3 : %d\n", k1, k2, k3 ); printf( "k1 : 0x%X, k2 : 0x%X, k3 : 0x%X\n", k1, k2, k3 );
/* integral promotion: unsigned char --> unsigned int */

printf( "uk1 : %u, uk2 : %u, uk3 : %u\n", uk1, uk2, uk3 ); printf( "uk1 : 0x%X, uk2 : 0x%X, uk3 : 0x%X\n", uk1, uk2, uk3 ); k1 = 124; /* 0x7C */ k2 = k1 + k1;

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

2-20

...rnek 2.8-1 devam


printf( "k1 : 0x%02X\n", k1 ); printf( "k1 + k1 : 0x%02X\n", k1 + k1 ); printf( "k2 : 0x%02X\n", k2 ); return 0; }
kt

integral promotion OK ! c << 3 --> Sonuc 0 degildir c << 3 --> Sonuc 0 k1 : 100, k2 : -56, k3 : 44 k1 : 0x64, k2 : 0xFFC8, k3 : 0x2C uk1 : 100, uk2 : 200, uk3 : 44 uk1 : 0x64, uk2 : 0xC8, uk3 : 0x2C k1 : 0x7C k1 + k1 : 0xF8 k2 : 0xFFF8

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-1

BLM 3: Kontrol Ak
Kontrol Ak (flow of control), program deyimlerinin altrlma srasn ifade eder. Program deyimleri, bu blmde anlatlacak olan kontrol ak deyimleri tarafndan herhangi bir ekilde deitirilmedii srece, birbirini izleyen srada altrlr (sequential flow of control). n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-3

3.1 Deyimler ve Bloklar


C dilinde deyimler ; ile sonlanr. Dolaysyla bir C ifadesine ; eklendiinde program deyimi (statement) oluturulmu olur. Aadakiler geerli C deyimleridir (expression statement):
a = 10; i = i + 2; puts( "deneme" );

Sadece ; ile oluturulan deyim, bo deyim (null statement) olarak adlandrlr ve hi bir ilem yapmaz. ounlukla aada grld gibi deyim blou bulunmayan dnglerin almas iin kullanlr:
... while (...) ; ... yada ... for (...;...;...) ; ...

Oklu parantezler { ve } kullanlarak bildirimler ve deyimler grup haline getirilir ve bileik deyim (compound statement) yada blok oluturulur:
{ ... bildirimler; deyimler; ... }

Bu blok, ekil olarak tek bir deyime eittir. Blou kapatan oklu parantezden sonra ; kullanlmaz. rnek olarak fonksiyon iindeki deyimleri snrlayan parantezler; if, else, while yada for sonrasnda birden fazla deyim bulunduunda blok oluturmak iin kullanlan parantezler verilebilir. n

3.2 if-else, else-if ve switch


if-else deyimi, bir yada daha fazla deyimin ancak belli bir koul salandnda altrlmas iin kullanlr:
if (ifade) deyim1 else deyim2

else ksm kullanlmayabilir. Test ifadesi ifade ilendikten sonra doru sonucunu verdiinde (yani 0 dnda bir deere sahip ise) deyim1 altrlr; eer yanl sonucunu
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-4

verir (ifadenin deeri 0'dr) ve else ksm var ise deyim2 altrlr. if deyimi ifade'nin saysal deerini kontrol ettii iin
if (ifade != 0) yerine if (ifade)

kullanlabilir. Test ifadeleri, ilikisel ve mantksal operatrler kullanlarak oluturulur. ie if deyimlerinde else ksmnn kullanlmamas karkla yol aabilir. Aadaki deyimde else ksm, kendine en yakn olan else'i bulunmayan if 'e aittir:
if ( ... ) if ( ... ) ...; else ...;

Eer en stteki if'e ait olmas istenirse, oklu parantezler kullanlmaldr:


if ( ... ) { if ( ... ) ...; } else ...;

Aadaki else deyimi, for blounda bulunan if'e aittir. Fakat program satrlarnn pozisyonu en stte yer alan if'e ait olduu izlenimini verir:
if ( ... ) for ( ... ) if ( ... ) { ...; } else ...;

ie if'lerde (nested-if) oklu parantezler kullanlarak olas hatalar nlenebilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-5

Aadaki if deyimlerinde birden fazla koul test edilir:


if (ifade) deyim else if (ifade) deyim else if (ifade) deyim
. . .

else if (ifade) deyim else deyim

ifadeler sral olarak ilenir ve herhangi bir ifade doru sonucunu verir ise ilgili bloktaki deyimler altrlr ve tm if-else zinciri sona erer. deyimler, bir deyimden yada parantezlerle snrl deyim grubundan oluabilir. Zincirin sonunda bulunan else ksm, nceki hi bir koul salanamaz ise altrlr (default case) ve iptal edilebilir. switch deyimi, ifade'nin tamsay sabit-ifade yada sabit deerlerden birine eit olup olmad test eder:
switch (ifade) { case sabit-ifade:
. . .

deyimler;

case sabit-ifade: default: }

deyimler; deyimler;

Herhangi bir case, ifadenin deerine eit ise ilgili deyimler altrlr; hi biri eit deil ise default ksmnda bulunan deyimler altrlr (if-else zincirinde bulunan son else ksm gibi). Tm case ifadeleri birbirinden farkl olmaldr. default ksm kullanlmayabilir. default ksmnn sonda bulunmas gerekmez. Programlarda if-else zincirleri yerine switch kullanlabilir. break ve return deyimleri kullanlarak switch bloundan hemen klabilir. Herhangi bir case iinde bulunan deyimler altrldktan sonra break deyimine rastlanmaz ise izleyen case'ler taranr. Ayn deyimleri altran farkl case'ler pepee sralanabilir. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-6

3.3 Dngler: while, for ve do-while


Aadaki while dngsnde, ifade ilenir; deeri 0 deilse deyimler altrlr ve ifade'nin tekrar ilenmesi ile dng devam eder:
while (ifade) deyim

ifade'nin deeri 0 oluncaya kadar dng devam eder. Aadaki for deyiminde yer alan 1. ve 3. ifadeler, atama yada fonksiyon ars; 2. ifade ise bir ilikisel ifadedir:
for (ifade1; ifade2; ifade3) deyim

ifade1 dng balangcnda ve sadece bir kez altrlr. ifade2 ise for dngsnn test ifadesidir ve ilendikten sonra 0 dnda bir deer veriyor ise deyimler altrlr. ifade3 ise deyimler altrldktan sonra altrlr. Dngnn herhangi bir ksm iptal edilebilir. for (;;) ; dngs, "sonsuz" dngdr. Bu dngden break yada return ile klr. Yukardaki for dngs yerine aadaki while dngs kullanlabilir:
ifade1; while (ifade2) { deyim ifade3; }

Bir C operatr olan virgl "," ounlukla for dnglerinde birden fazla ifadeyi bir arada yazmak iin kullanlr. Virgl operatr ile ayrlan ifadeler soldan saa ilenir; sonucun tipi ve deeri sa operand'n tipi ve deeridir. rnek olarak aadaki for dngs verilebilir:
for ( ifade1, ifade2; ...; ... ) ...;

while ve for dnglerinde test ifadesi stte bulunur. do-while dngsnde ise altta bulunur. Dolaysyla, dng blounda bulunan deyimler en az bir kez altrlm olur:
do deyim while (ifade);

nce deyimler altrlr daha sonra test ifadesi ilenir. Eer doru ise deyimler tekrar altrlr ve dng devam eder. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-7

3.4 break ve continue


Test ifadesi yanl sonucunu vermeden nce break deyimi kullanlarak for, while ve dowhile dnglerinden klabilir. Ayrca switch deyiminden k iin de kullanlabilir. Sadece dnglerde kullanlabilen continue deyimi ise dngnn bir sonraki tekrara atlamasn salar. Bu ilem while ve for dngsnde hemen test ksmna geilmesini, for dngsnde ise ifade3'n altrlmasn salar. n

3.5 goto ve etiketler


break deyimi, i ie dnglerde en iteki bloktan klmasn salar. Tm bloklardan kmak iin goto deyimi kullanlabilir:
for ( ... ) for ( ... ) { ... if ( ... ) goto etiket; } ... etiket: ...

etiket bir deiken ismi ile ayndr ve : ile sonlanr. goto ile ayn fonksiyon iinde herhangi bir deyime balanabilir. Bir etiketin grnrlk alan (scope) fonksiyonun tamamdr. Genel olarak goto kullanlarak yazlan kodlarn okunabilirlii azdr. Bu nedenle programlarda goto kullanm tercih edilmez. Bu blmde C dilinde kontrol akn deitiren deyimler anlatld. n

rnek 3.1-1 kontrol.c program. #include <stdio.h> int main(void) { int i = 0, j = 0; printf( "for girisi - i : %d\n", i ); for ( i = 0; i < 5; i++ ) printf( "%d", i ); printf( "\nfor cikisi - i : %d\n", i ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-8

...rnek 3.1-1 devam


/*
for girisi - i : 0 01234 for cikisi - i : 5

*/ i = 0; printf( "do-while girisi - i : %d\n", i ); do { printf( "%d", i ); i++; } while ( i < 5 ); printf( "\ndo-while cikisi - i : %d\n", i ); /*
do-while girisi - i : 0 01234 do-while cikisi - i : 5

*/ i = 0; printf( "do-while girisi - i : %d\n", i ); do printf( "%d", i ); while ( i++ < 5 ); printf( "\ndo-while cikisi - i : %d\n", i ); /*
do-while girisi - i : 0 012345 do-while cikisi - i : 6

*/ i = 0; printf( "while girisi - i : %d\n", i ); while ( i < 5 ) { printf( "%d", i ); i++; } printf( "\nwhile cikisi - i : %d\n", i ); /*
while girisi - i : 0 01234 while cikisi - i : 5

*/ i = 0; printf( "while girisi - i : %d\n", i ); while ( i++ < 5 ) printf( "%d", i ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-9

...rnek 3.1-1 devam


printf( "\nwhile cikisi - i : %d\n", i ); /*
while girisi - i : 0 12345 while cikisi - i : 6

*/ i = 0; printf( "sonsuz while girisi - i : %d\n", i ); while (1) { if ( i > 5 ) break; else printf( "%d", i ); i++; } printf( "\nsonsuz while cikisi - i : %d\n", i ); /*
sonsuz while girisi - i : 0 012345 sonsuz while cikisi - i : 6

*/ i = 0; printf( "sonsuz for girisi - i : %d\n", i ); for (;;) { if ( i > 5 ) break; else printf( "%d", i ); i++; } printf( "\nsonsuz for cikisi - i : %d\n", i ); /*
sonsuz for girisi - i : 0 012345 sonsuz for cikisi - i : 6

*/ i = 0; printf( "for-continue girisi - i : %d\n", i ); for ( i = 0; i < 5; i++ ) { if ( i == 2 ) continue; printf( "%d", i ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-10

...rnek 3.1-1 devam


} printf( "\nfor-continue cikisi - i : %d\n", i ); /*
for-continue girisi - i : 0 0134 for-continue cikisi - i : 5

*/ for ( i = 0, j = 0; i < 5; i++ ) for ( ; j < 5; j++ ) if ( (i * j) != 16 ) putchar( '.' ); else goto cikis; cikis: printf( "i : %d, j : %d\n", i, j ); /*
.....i : 5, j : 5

*/ printf( "switch -\n" ); for ( i = 0; i < 4; i++ ) switch (i) { case 0: case 1: printf ( "i < 2\n" ); break; case 2: printf ( "i : 2\n" ); break; default: printf ( "i : %d\n", i ); } /*
switch i<2 i<2 i:2 i:3

*/ printf( "if-else -\n" ); for ( i = 0; i < 4; i++ ) if ( i < 2 ) printf ( "i < 2\n" ); else if ( i == 2 ) printf ( "i : 2\n" ); else C PROGRAMLAMA DILI, 1997 Ismet Kocaman

3-11

...rnek 3.1-1 devam


printf ( "i : %d\n", i ); /*
if-else i<2 i<2 i:2 i:3

*/ return 0; } kt ktlar programda dng klarnda aklama satr olarak verilmitir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-1

BLM 4: Fonksiyonlar
Fonksiyonlarn kolaylkla oluturularak verimli bir ekilde kullanlabilmesi, C dilinin en nemli zelliklerinden biridir. Belirli bir ilevi yerine getiren ve tekrarlanan program paralar okunabilirlii arttrmak, deiiklik yaplmasn ve hata bulmay kolaylatrmak amacyla programn btnnden ayrlarak fonksiyon haline getirilebilir. Ayn amala, tekrarlanmayan fakat programn btnnden farkl ilevleri yerine getiren ksmlar da fonksiyon haline getirilebilir. Bylece tanmlanan fonksiyon gerekli olduka arlr ve aran bloktaki kod tekrar nlenmi olur. Tanmlanan fonksiyon sadece bir kez arlacak da olsa btnden ayrld iin program zerinde kontrol artar. Ayrca byk bir programn tamamn tek bir main blou iine yerletirmek iyi bir yol deildir. Programn esas ilevi ile ilgili olmayan ayrntlarn ana programdan ayrlmas kolaylk salar. Fonksiyonlar oluturularak ok kapsaml projeler kk paralara blnebilir. Daha nceden yazlarak fonksiyon haline getirilmi kodlar, bir baka programda ayn ileve ihtiya duyulduunda ilgili kodlar yeniden yazmaya gerek kalmadan kullanlabilir. C dilinde giri/k ilemlerini gerekletirmek iin deyimler bulunmaz. Bu ilemler, standart C ktphanesinde bulunan fonksiyonlar arlarak gerekletirilir. nceki blmlerde yer alan rnek programlarda standart C ktphanesinde bulunan giri/k fonksiyonlar (printf, scanf gibi) kullanld. C ktphanesi bir ok hazr fonksiyon ierir. Hazr ktphane fonksiyonlar kullanldnda program link ilemi srasnda bu fonksiyonlarn ktphanede bulunan tanmlar ile birletirilir. Bu blmde verilecektir. n fonksiyonlarn oluturulmasna ve kullanmna yer

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-3

4.1 Fonksiyon Tanm, Bildirimi, arma ve Deer Dndrme


Fonksiyon, belli bir ilevi yerine getiren ve genellikle kendini aran program satrna bir deer dndren deyimler grubudur.

Fonksiyon Tanm
Fonksiyon tanm aadaki gibi yaplr:
fonksiyon bal - tip fonksiyon_ismi( parametre bildirimleri )

{
fonksiyon blou -

diger bildirimler ve deyimler ... }

Tanm iki ksmdan oluur: fonksiyon bal ve fonksiyon blou. Fonksiyonun dndrecei deerin tipi, istenen tip belirleyici fonksiyon ismi ncesine yerletirilerek belirlenir. Dolaysyla balkta yer alan tip, fonksiyonun dndrecei deerin tipini belirtir. Eer hi bir tip belirleyici bulunmuyorsa fonksiyonun int tipinde deerler dndrecei kabul edilir. Hi bir deer dndrmeyen fonksiyonlar ise void tipi ile tanmlanr. Seilen fonksiyon ismi (fonksiyon_ismi), fonksiyonun ilevini aka belirtmelidir. Parantezler iinde virglle ayrlm olarak bildirilen deikenler, fonksiyon parametreleri olarak adlandrlr ve ar srasnda fonksiyonun almay bekledii verilerin saysn ve tipini belirtir. Fonksiyonun hi bir parametresi yoksa, yani fonksiyona hi bir deer aktarlmyor ise parantezler iinde void tip belirleyici kullanlr. Deer dndrmeyen ve parametresi olmayan bir fonksiyon tanm aadaki gibi yaplr:
void isim( void ) { ... }

Fonksiyon bildirimi
Fonksiyonlar da deikenler gibi bildirilebilir. Bildirim fonksiyonun ismini, dndrecei deerin tipini, ar ile aktarlan verilerin saysn ve tipini belirtir. Bu bildirim fonksiyon prototipi (yada ksaca prototip) olarak adlandrlr:
tip fonksiyon_ismi ( parametre tip listesi );

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-4

Bir programda tanmlanan her fonksiyon iin tekbir prototip bulunur. Prototipler, genel olarak kaynak programn balang noktasna yakn ve bildirdikleri fonksiyonun ilk kullanmndan nce yerletirilir. Bylece derleyiciye programdaki arlar kontrol etme imkan salanm olur. Prototipteki parantezler arasnda fonksiyon parametrelerinin virglle ayrlm tip listesi yer alr. Tipleri sralarken parametre isimleri de kullanlabilir; fonksiyon balnda yer alan parametre bildirimleri listesi prototipte de kullanlabilir. Bu uygulama okunabilirlii arttrr, fakat C dilinin bir kural deildir. Eer fonksiyonun hi bir parametresi yoksa prototipte de void veri tipi kullanlr:
tip isim( void );

Fonksiyon prototipinde parantezlerin ii bo braklrsa derleyici hibir argman kontrolu yapamaz. Eer fonksiyon hibir deer dndrmyor ise prototipte de tanmda olduu gibi void tip belirleyici kullanlmaldr. tip verilmediinde ise int tipi deerler dndrecei kabul edilir. rnek programlarda kullanlan hazr C ktphane fonksiyonlarnn prototipleri, ilgili balk dosyalarnda (header file yada include file) bulunur ve programa nilemci komutu #include kullanlarak alnr.

Fonksiyon arma ve deer dndrme


Yukarda anlatlan ekilde tanmlanan ve bildirilen bir fonksiyona eriim fonksiyon ars ile gerekleir. Fonksiyon oluturmak iin bloktan ayrlan program parasnn yerine fonksiyon ar satr yerletirilir. rnek programlarda sk sk standart C ktphanesinde bulunan hazr fonksiyonlar kullanld. Bunlardan biri de ekrana eitli formatlarda bilgi yazmak iin kullanlan printf fonksiyonudur. Programlarda printf fonksiyonuna eriim, gerekli olan noktaya bu fonksiyonun ars yerletirilerek gerekletirilir. Fonksiyonlar arasnda veri alverii, arma ve aran fonksiyona dnme srasnda gerekleir. arnn yer ald fonksiyon (bu ana program yani main fonksiyonu yada bir baka fonksiyon olabilir) aran fonksiyon olarak adlandrlr. ar ile eriilen fonksiyon ise arlan fonksiyon olarak adlandrlr. Programn almas srasnda ar satrna gelindiinde arlan fonksiyon blou iinde bulunan deyimler altrlr. Fonksiyonun almas bittiinde ise tekrar aran fonksiyona geri dnlr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-5

rneklerde grld gibi fonksiyonlar aran fonksiyondan deer alabilirler. Fonksiyona ar srasnda aktarlan herhangi bir deer argman olarak adlandrlr.
NOT:

Fonksiyon arsnda yer alan (fonksiyona aktarlan) sabit deerler yada deikenler argman, gerek argman yada gerek parametre olarak adlandrlr. Ayrca tanmda parantezler iinde bildirilen deikenler ise parametre, formal parametre yada formal argman olarak adlandrlr. Burada herhangi bir karklk olmamas iin arda yer alan deerler yada deikenler argman, tanmda bildirilen deikenler ise parametre olarak adlandrlr.

Aadaki satrda fonksiyon ismi ve bunu izleyen bir ift parantez kullanlarak hibir argman deeri almayan ve dndrd deer kullanlmayan (dndryor ise) fonk fonksiyonu arlr:
fonk( );

Bu en basit fonksiyon ar deyimidir. Eer fonksiyon argman deerleri bekliyor ise ar parantezler iine argmanlarn virglle ayrlm listesi verilerek yaplr:
fonk( argman listesi ... );

Argman listesi fonksiyon tanmndaki tip ve sayda deikenler, sabit deerler yada istenen tipte deerler veren ifadeler ierebilir. arda yer alan her bir argmana tanmdaki bir parametre karlk gelir; birebir eleme gerekleir. Eer argman tipleri ile parametre tipleri farkl ise argman tipleri, atama ileminde olduu gibi prototipteki karlk gelen parametre tiplerine evrilir. Aada argman deeri alan fonk fonksiyonu tanmlanr; main blounda yer alan ardaki argmanlarn her biri tanmdaki parametrelerden birine karlk gelir. Dolaysyla a parametresi 15 deerini, b parametresi 32 deerini ve c parametresi de 23 deerini alr. Bir fonksiyona argman olarak herhangi bir basit deiken, union yada yap deikeni, sabit bir deer, dizi yada fonksiyon aktarlabilir (union ve yap deikenleri, izleyen blmlerde ayrntl olarak anlatlacaktr ). aran fonksiyona deer dndrmek iin return deyimi kullanlr:
return ifade;

return deyimi hem fonksiyonun almasn sona erdirebilir (kontrol ar satrna geri dner), hem de aran deyime deer dndrebilir. Eer return deyiminde herhangi bir ifade bulunmuyor ise hibir deer dndrmez ve bulunduu satra gelindiinde sadece fonksiyonun almasn sona erdirerek, ar satrna dnlmesini salar. Bir fonksiyonda birden fazla return deyimi olabilir ve fonksiyon iinde herhangi bir yerde
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-6

bulunabilir. Fakat return deyimi ile sadece tek bir deer dndrebilir ve fonksiyonun her arlnda sadece bir return deyimi altrlr.
int fonk( int, int, int ); int main (void) { int i; argmanlar ...
main fonksiyonu tanm -

- fonksiyon bildirimi

i = fonk( 15, ... return 0; }

32,

23 );

- fonksiyon ars

int fonk( int a, int b, int c )


fonk fonksiyonu tanm -

- fonksiyon bal

{ int j; ... return j; }

parametreler

Fonksiyon hibir deer dndrmese de, kapan parantezine gelmeden nce herhangi bir koula bal olarak fonksiyonu durdurmak iin return deyimi kullanlabilir. Fakat fonksiyon hibir deer dndrmyor ise return deyimi kullanm zorunlu deildir. aran fonksiyon dndrlen deeri kullanmayabilir. Fakat baz durumlarda (zellikle fonksiyonun ilediini gsteren bir bilgi veya bir hata kodu dndren baz ktphane fonksiyonlarnda) kullanlmas gerekebilir. rnek olarak printf fonksiyonu ar satrna ekrana yazlan karakter saysn yada hata olumas durumunda negatif deer dndrr. Fakat rnek programlarda grld gibi dndrd deer kullanlmayabilir. Eer fonksiyon deer dndryor ise ve bu deer kullanlacak ise fonksiyon ars dndrlen tipteki bir deikenin yer ald bir atama deyimine yada dndrd deerin kullanld bir ifadeye yerletirilebilir. Bylece dndrlen deer uygun tipteki bir deikene atanm olur yada ifade iinde kullanlabilir. rnek olarak;
degisken = fonksiyon_ismi( arguman listesi ); return ifade; deyiminde yer alan ifade'nin (ifade herhangi bir deiken, deiken yada sabitlerden oluan aritmetik bir ifade olabilir) deerinin tipi ne olursa olsun, dndrlmeden nce fonksiyonun tipine evrilecektir. Fonksiyonda hibir return deyimi bulunmad zaman fonksiyon blounda yer alan deyimler altrldktan ve blou C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-7

kapatan paranteze (sa parantez: } ) gelindikten sonra yine ar satrna geri dnlr. Bylece kontrol aran fonksiyona gemi olur. Fakat eer fonksiyon kapan parantezine gelerek geri dnyorsa yada bir arda deer dndrd halde baka bir arda deer dndrmyorsa hatal alyor olabilir. Her iki durumda da, bu fonksiyon aran bloa anlamsz deerler dndrr. Bir fonksiyon sabit bir deer, union yada yap deikeni deeri veya herhangi bir adres deeri dndrebilir. Fakat bir baka fonksiyon yada dizi dndremez. Fonksiyon ars, program iinde iki ekilde bulunabilir: kendi bana bir program deyimi olarak yada herhangi bir ifadenin iinde, o ifadenin bir paras olarak. lk durumda, dndrlen deer kullanlmam olur. kinci durumda ise dndrlen deer ifade iinde kullanlacaktr. Ayrca ar, baka bir fonksiyon arsnda argman olarak da kullanlabilir. Bylece dndrlen deer bir baka fonksiyona aktarlm olur.

Argmanlarn aktarlmas: deer-ile-arma ve referans-ile-arma


Programda ar satrna gelindiinde arda yer alan her bir argmann deeri fonksiyondaki karlk gelen parametreye atanr. Bir baka deyile, her parametre karlk gelen argman deerinin kopyasn alr. Argman deerlerinin aktarlmas ile gerekleen bu ekildeki bir ar deer-ile-arma olarak adlandrlr. Deer-ilearma gerekleiyor ise fonksiyon parametre deerlerini deitirebilir, fakat aran blokta yer alan argman deerlerini etkileyemez. Argmanlar dizi ismi yada fonksiyon ismi olduunda karlk gelen parametreler adres deikenleridir (izleyen blmlerde ayrntl olarak anlatlacaktr). Bu durumda argmanlarn deerleri yerine adresleri aktarlr. Bu ekilde gerekleen fonksiyon ars referans-ile-arma olarak adlandrlr ve aran bloktaki argman deerlerine eriim mmkn olur. Argman deerlerinin aktarlmas, aktarlan deerlere eriim ve aran bloa deer dndrme ilemleri iin gerekli olan kodlar, derleyici tarafndan oluturularak aran ve arlan fonksiyonlara yerletirilir. Fonksiyon parametreleri ve fonksiyon blou iinde bildirilen deikenler ar ile bloa girildiinde otomatik olarak oluturulur ve bloktan kldnda yok olurlar. Bu nedenle fonksiyon balnda bildirilen parametreler ve fonksiyon blou iinde bildirilen deikenler, o fonksiyonun lokal (local: yerel) deikenleridir ve sadece o fonksiyon blou iinden eriilebilirler (main ve dier fonksiyonlar eriemez). Parametre deerleri deitiinde aran fonksiyondaki deerler etkilenmez dolaysyla parametreler blok iinde herhangi bir lokal deiken gibi kullanlabilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-8

C dilinde, tm bloklarn dnda tanmlanan deikenler global (genel) deikenler olarak adlandrlr ve varlklarn lokal deikenlerin aksine programn almas boyunca sabit bellek adreslerinde srdrrler. Bu deikenlere program iinde yer alan tm fonksiyonlardan eriilebilir. Fonksiyon arlar srasnda deerlerini koruduklar iin fonksiyonlar arasnda veri tanmasnda kullanlabilir. Fakat yukarda da belirtildii gibi verilerin argmanlar aracl ile aktarlmas, hem fonksiyondan kldnda bu deikenler yok oldu iin bellek tasarrufu salar, hem de argman deerleri zerindeki ilemler bu deerlerin kopyalar zerinde gerekletirildii iin aran bloktaki deerleri etkilemez. Bu nedenlerden dolay fonksiyonlara veri aktarlmasnda sabit bellek adreslerinde bulunan global deikenlerin kullanlmas tercih edilmez. Global deikenlerin kullanm daha sonra ayrntl olarak anlatlacaktr. Baz derleyiciler argman deerlerinin mikroilemcinin register birimlerine yerletirilmesini salar. rnek 4.1-1de yer alan program, Fahrenhayt olarak girilen scaklk deerini Santigrat'a evirir. Ekrandan 33.8 deeri girildiinde program 1.0 deerini verir. main fonksiyonu tanm programda grld gibi balk ve fonksiyon bloundan oluur. Programda, scaklk evirme ilemi aadaki forml kullanlarak yaplr:
t_c = ( t_f - 32.0 ) / 1.8

rnek 4.1-1 fonk1.c program. #include <stdio.h> main fonksiyonu bal - int main(void) { float t_c, t_f; printf("Fahrenhayt : "); scanf("%f", &t_f ); main fonksiyonu blou t_c = ( t_f - 32.0 ) / 1.8; printf("Santi. : %.1f\n", t_c); return 0; } Bilgi Girii Fahrenhayt : 33.8 kt Santi. : 1.0

Formln bulunduu ksm fonksiyon haline getirilerek main bloundan ayrlabilir. Bu durumda evirme ileminin yapld satra, bu ilemi gerekletiren fonksiyonun ars
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-9

yerletirilecektir. Fonksiyon ars, fonksiyon isminden sonra parantezler iinde aktarlmak istenen argmanlarn verilmesi ile gerekleir. Fonksiyonun kendine aktarlan Fahrenhayt deerini formle gre Santigrat leine evirerek ar satrna geri dndrmesi ve dndrlen deerin de t_c deikenine atanmas gerekir. Buna gre bir float argman deeri alan ve aran bloa bir float deer dndren SantiGrat fonksiyonu fahr parametresi ile tanmlanabilir:
SantiGrat fonksiyonu bal - float SantiGrat( float fahr ) { SantiGrat fonksiyonu blou } float c; c = ( fahr - 32.0 ) / 1.8; return c;

Fonksiyon balnda fahr parametresi bildirilir. Fonksiyon tanmnn oklu parantezler arasnda kalan ve fonksiyon blou olarak adlandrlan ksmnda ise float tipindeki c deikeni bildirilir. rnek 4.1-2'de main blou iinde Fahrenhayt deerleri iin bildirilen t_f deikeni ve Santigrat deerleri iin bildirilen t_c deikeni, main fonksiyonunun lokal deikenleridir. Ayrca SantiGrat tanmnda bildirilen fahr ve c deikenleri de bu fonksiyonun lokal deikenleridir ve main bloundan eriilemezler. Fonksiyon argmanlar deerleri ile aktarlr; yani arlan fonksiyon arda yer alan her argmann deerinin kendine ait geici bir kopyasn alr. Dolaysyla fonksiyon, aran bloktaki esas argmanlara eriemez. SantiGrat fonksiyonu, arda argman olarak yer alan t_f argmanna eriemez. Sadece bu argmann deeri fahr parametresine ilk deer olarak atanr. Bylece aran blokta kullanlan deiken isimleri, arlan blokta da deiken ismi olarak kullanlabilir. Ayrca farkl bloklarda ayn isimlerin kullanlmasndan doabilecek hatal eriimler nlenmi olur.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-10

rnek 4.1-2 fonk2.c program.


nilemci komutu - #include <stdio.h>

SantiGrat fonksiyonu bildirimi, prototipi - float SantiGrat( float fahr ); int main(void) {
lokal deiken bildirimleri -

float t_c, t_f; printf("Fahrenhayt : "); scanf("%f", &t_f ); t_c = SantiGrat( t_f ); printf("Santi. : %f\n", t_c); return 0; } float SantiGrat( float fahr ) {

printf fonksiyonu ars scanf fonksiyonu ars SantiGrat fonksiyonu ars printf fonksiyonu ars -

lokal deiken bildirimleri -

float c; c = ( fahr - 32.0 ) / 1.8; return c; }

aran bloa deer dndrme -

Bilgi Girii Fahrenhayt : 33.8 kt Santi. : 1.0

SantiGrat tanmnda, return c; deyimi ile return anahtar szc kullanlarak main fonksiyonundaki ar satrna SantiGrat fonksiyonunun lokal deikeni c'nin deeri dndrlr. main bloundan SantiGrat fonksiyonuna yaplan ar, bir float argman deeri aktarr. Programdaki main fonksiyonu tanm standart ktphane fonksiyonlar olan printf ve scanf arlarn ierir. Bu fonksiyonlarn prototiplerinin bulunduu balk dosyas stdio.h, #include nilemci komutu kullanlarak program iine alnr. Bu fonksiyonlarn nceden derlenmi tanmlar link ilemi srasnda program ile birletirilir. SantiGrat fonksiyonu t_f argman ile arlr. SantiGrat fonksiyonunun dndrd deer ise t_c deikenine atanr.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-11

Programdaki prototip aadaki ekilde de yazlabilir:


float SantiGrat( float );

Bu bildirim ile yine fonksiyonun bir float deer almay bekledii ve sonu olarak bir float deer dndrecei belirtilir. zetle; SantiGrat fonksiyonu prototipi:
dndrlen deerin tipi isim tip listesi

float SantiGrat( float );

SantiGrat fonksiyonu bal:


dndrlen deerin tipi isim parametre bildirimleri

float SantiGrat( float fahr )

SantiGrat fonksiyonu ars:


lokal deiken isim argman

t_c = SantiGrat( t_f );

Program, SantiGrat fonksiyonu ars printf fonksiyonu arsna argman olarak kullanlarak yazlabilir. printf fonksiyonu ars iki argman aktarr; format dizgisi ve SantiGrat arsnn dndrd float deer:
printf("Santi. : %f\n", SantiGrat( t_f ) );

Ayrca forml return deyimine yerletirilebilir. Bylece daha ksa bir program elde edilir:
float SantiGrat( float fahr ) { return ( fahr - 32.0 ) / 1.8; }

Bu programda yer alan forml, fonksiyon oluturmak iin pek uygun deildir. Bu ilem, #define nilemci komutu ile basit bir makro tanmlayarak gerekletirilebilir:
#define SantiGrat( fahr ) (fahr - 32.0) / 1.8

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-12

Fonksiyon tanmlar, program iinde herhangi bir srada bulunabilir. Program almasn main blou ile balatr ve bu bloun kapan parantezinde sona erdirir. Bu nedenle main fonksiyonu genel olarak en bata yer alr ve dier fonksiyon tanmlar main blou sonrasna yerletirilir. Programn okunabilirliini arttran bu uygulama, C dilinin kurallarndan biri deildir. Bir programda herhangi bir fonksiyon tanmland yerden nce arlyor ise mutlaka aran blok ncesinde bildirimi yaplmaldr. Aksi taktirde program satrndaki ilk kullanm (ar srasnda) ile bildirilmi olur ve int tipi deerler dndrecei kabul edilir. Programda hata olumamas iin bu fonksiyonun tanmnda dndrd deerin tipi olarak int verilmi yada hibir tip belirtilmemi olmaldr (tip belirtilmedii iin int tipi deerler dndrecei varsaylr). Aadaki program satrlarnda fonk fonksiyonu tanm arnn yer ald main fonksiyonu sonrasna yerletirilmitir:
int main(void) { double x; x = fonk(...); ... } double fonk(...) { ... }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-13

Prototip bulunmad iin main blounda yer alan ilk ar ile int tipi deerler dndrecei kabul edilerek bildirilmi olur. Fakat tanmda double deerler dndrecei belirtilir. Bu durumda hata oluur. Aadaki ekilde grld gibi fonksiyon tanm main ncesine yerletirilerek (1.program) yada main ncesinde bildirimi yaplarak (2.program) bu hata nlenebilir. Fakat derleyicinin arlar kontrolne olanak salad iin prototip kullanm tercih edilir:
1.program /* fonk tanm */ 2.program /* prototip */

double fonk(...) { ... }


/* main tanm */

double fonk(...);
/* main tanm */

yada

int main(void) { double x; x = fonk(...); ... }

int main(void) { double x; x = fonk(...); ... }


/* fonk tanm */

double fonk(...) { ... }

rnek 4.1-2'de SantiGrat fonksiyonu tanm bu fonksiyonu aran main bloundan sonra yerletirilmitir. Bu nedenle bildirimi main bloundan nce yaplr. Bylece derleyici fonksiyon prototipinde verilen bilgileri kullanarak bu fonksiyona yaplan her arda tip kontrol (aktarlan argmanlarn ve dndrlen deerin tipi) yapar ve argman saysn kontrol eder. Aada iki int parametreye sahip ve yine int tipi deerler dndren fonk fonksiyonu tanmlanr. fonk fonksiyonu main blou iinde iki double deer ile arlr ve dndrd deer bir double deikene atanr:
#include <stdio.h> int main(void) { double Toplam, a = 1, b = 2; Toplam = fonk( a, b ); printf("Toplam : %1.1f\n", Toplam ); return 0; } int fonk( int x, int y ) { return x+y; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-14

fonk fonksiyonu tanm arnn yer ald main fonksiyonu sonrasnda yer alr ve main ncesinde prototipi bulunmaz. Derleyici ar satrna geldiinde fonk fonksiyonu henz bildirilmemi olduu iin int tipi deerler dndrecei kabul edilir. Ayrca argman ve parametre tipleri uymad halde gerekli tip evirmeleri yapamaz. Bu nedenle veri kayb olur ve ekrana 0.0 deeri yazlr. Bu durum aadaki grld gibi main fonksiyonu ncesinde fonk fonksiyonu bildirilerek nlenebilir. Bylece derleyici prototipte verilen bilgileri kullanarak gerekli tip evirmeleri gerekletirir ve ekrana 3.0 deeri yazlr:
#include <stdio.h> int fonk( int, int ); int main(void) { double Toplam, a = 1, b = 2; Toplam = fonk( a, b ); printf("Toplam : %1.1f\n", Toplam ); return 0; } int fonk( int x, int y ) { return x+y; }

Bir fonksiyon ayn program iinde yer alan dier tm fonksiyonlardan arlabilir. Ayrca kendini aran C fonksiyonu (main hari) tanmlanabilir. C dilinde, fonksiyonlar birbirlerini arabilirler, fakat bir fonksiyon baka bir fonksiyon iinde tanmlanamaz. Aadaki fonk1 ve fonk2 fonksiyonlar main tarafndan arlabilir ve ayrca birbirlerini de arabilirler. Fakat main fonksiyonunu aramazlar:
... int main(void) { ... } fonk1( ) { ... } fonk2( ) { ... }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-15

main fonksiyonu:
rneklerde de grld gibi her C program en az bir fonksiyon ierir ve bu fonksiyon main olarak adlandrlr. main bir anahtar szck deildir ve programn baka bir yerinde kullanlamaz. Ayrca her C programnda sadece tek bir main fonksiyonu bulunabilir. Btn altrlabilir program deyimleri main yada bir baka fonksiyonun iinde yer alr. main, int tipi deerler dndren bir fonksiyon olarak komut satr bilgilerinin program iinde kullanlmasn salayan parametreler ile tanmlanr. Program altnda main fonksiyonunun bu parametrelerine, komut satrna girilen bilgiler aktarlr:
int main( int argc, char **argv ) { ... return 0; }

Komut satr argmanlarnn kullanlmad durumlarda parametre bildirimleri yerine void kullanlr. main fonksiyonu bir baka fonksiyon tarafndan arlamaz ve bu nedenle aran fonksiyona deer dndrmesi szkonusu olamaz. Fakat main fonksiyonu almasn sona erdirdiinde, iletim sistemine durum ifadesi iin return deyimi ile bir tamsay deer dndrebilir. Bu deer program iindeki hata kontrol kodlarna bal olarak dzenlenir ve genel olarak normal bir k ifade etmek iin 0 (sfr), hatal bir k ifade etmek iin ise sfr hari bir tamsay olarak seilir. letim sisteminde bulunan ve dndrlen deere eriebilen bir toplu ilem komutu kullanlarak programn hatasz alp almad saptanabilecei gibi baka komut gruplar da altrlabilir. return deyimi yerine standart C ktphanesinde bulunan exit fonksiyonu kullanlarak programdan klabilir.

Fonksiyon Argman Olarak Diziler


Bir dizi, ayn veri tipindeki bir grup deikenden oluur. Bu deikenlerin her biri dizi eleman olarak adlandrlr. Dizi elemanlar bellekte birbirini izleyen eit byklkte alanlarda bulunur. Elemanlara eriim ortak bir deiken ismi yani dizi ismi kullanlarak gerekletirilir. Aada tip tipinde n elemandan oluan dizi dizisi bildirilir:
tip dizi [ n ];

Her dizi elemannn bir indeks numaras vardr. Dizinin balang elemannn indeks numaras 0'dr. Dizinin son elemannn indeks numaras ise n - 1'dir. Dizi elemanlarna
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-16

dizi_ismi[ indeks_no ] ifadesi ile eriilir. Dizi elemanlarna deer atama izleyen blmlerde anlatlaca gibi bildirim srasnda yada program iinde dizi_ismi [ indeks_no ] = deger; atama deyimi ile yaplabilir. deger, tip tipinde deer dndren bir ifade, sabit yada deiken olabilir. Keli parantezler ([ ]) indeks operatrdr. Diziler izleyen blmlerde ayrntl olarak anlatlacaktr. C dilinde dizi ismi (yukardaki bildirimdeki dizi), dizinin balang elemannn bellek adresini veren sabittir. Bu nedenle, dizi ismi bir fonksiyon arsnda argman olarak yer aldnda dizi elemanlarnn deerleri yerine dizinin balang adresi aktarlr (referansile-arma). arlan fonksiyon dizinin bellek adresini bildii iin aran bloktaki elemanlarn deerlerini deitirebilir. Aadaki rnekte argman olarak int tipi elemanlardan oluan bir dizi ve bu dizinin eleman says olarak yine int tipi bir deer bekleyen Dizix2 fonksiyonu tanmlanr. main blou iinde bildirilen ve ilk deer atamas yaplan 5 elemanl tamsay dizi dizisi (dizi dizisinin tipi int[5]'dir), bu fonksiyona argman olarak aktarlr.

rnek 4.1-3 fonkdizi.c program. #include <stdio.h> #define DiziBoy(s) sizeof s / sizeof s[0] void Dizix2( int[ ], int ); int main(void) { int dizi[ 5 ] = { 1, 2, 3, 4, 5 }; int i;
/* cagri oncesi dizinin ekrana listelenmesi */

for ( i = 0; i < DiziBoy( dizi ) ; i++ ) printf("dizi [%d] : %d\n", i, dizi [ i ] );


/* fonksiyon cagrisi */

Dizix2( dizi, DiziBoy(dizi) );


/* cagri sonrasi dizinin ekrana listelenmesi */

for ( i = 0; i < DiziBoy(dizi) ; i++ ) printf("dizi [%d] : %d\n", i, dizi [ i ] ); return 0; } void Dizix2( int dizi[ ], int Boy ) { int n; for ( n = 0; n < Boy; n++ ) dizi [ n ] = dizi [ n ] * 2; } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-17

...rnek 4.1-3 devam


kt dizi [ 0 ] dizi [ 1 ] dizi [ 2 ] dizi [ 3 ] dizi [ 4 ] dizi [ 0 ] dizi [ 1 ] dizi [ 2 ] dizi [ 3 ] dizi [ 4 ] : : : : : : : : : : 1 2 3 4 5 2 4 6 8 10

Fonksiyon arsnda ilk argman olarak dizi ismi dizi ve ikinci argman olarakta dizinin eleman saysn veren DiziBoy(dizi) makrosu yer alr. ndeksi olmayan dizi ismi (dizi), dizinin balang elemannn adresini veren adres sabiti olduu iin aktarlan deer de yine balang elemannn bellek adresidir ve bu adres deerinin kopyas fonksiyon tanmnda bildirilen adres deikenine (yine ayn isimdeki fonksiyon parametresi dizi ) atanr. Bylece Dizix2 fonksiyonu, dizinin aran bloktaki deerlerine eriebilir. Programda dizinin elemanlarnn deerleri, Dizix2 fonksiyonu arsndan nce ve sonra listelenir. Dizix2 fonksiyonu iinde elemanlarn deerleri 2 ile arplr ve tekrar diziye yerletirilir. ktda da grld gibi ar sonras elemanlarn deerleri deimitir. rnekte main blounda bildirilen dizi bir sabit, Dizix2 bloundan bildirilen dizi ise bir adres deikenidir. Fonksiyon parametresi olarak bildirilen bir dizi iin bellek alan ayrlmaz. Bunun yerine aktarlan adres deerini alabilecek bir adres deikeni oluturulur. Bu nedenle fonksiyon parametresi bir tek-boyutlu dizi olduunda, tanm ve prototipteki parametre bildirimlerinde keli parantezler arasnda dizinin eleman saysnn verilmesi gereksizdir. Parametre iki boyutlu bir dizi olduunda ise ikinci boyuttaki eleman says verilmeyebilir. Fakat blok iinde bildirilen bir dizi iin boyutlar bellidir ve derleme srasnda bellek alan ayrlr. Sonu olarak bir fonksiyona ar ile bir dizinin tamamnn aktarlmas mmkn deildir. Ancak dizinin herhangi bir elemannn deeri yada adresi aktarlabilir.

Fonksiyon Argman olarak Fonksiyon smi


C dilinde bir fonksiyonun ismi, o fonksiyonun adresini verir. Dolaysyla bir fonksiyon ismi baka bir fonksiyon arsnda argman olarak yer aldnda aktarlan deer bu fonksiyonun adresidir. Aadaki rnekte argman olarak fonksiyon ismi f2 kullanlarak, f1 fonksiyonu arlr. f1 fonksiyonu tanmnda bildirilen p parametresi, hibir argman deeri almayan ve hibir deer dndrmeyen fonksiyona iaret eden adres deikenidir ve ar ile f2
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-18

fonksiyonunun adresini alr (fonksiyona iaret eden adres deikeni, izleyen konularda anlatlmtr):
/* * fonkadr.c */ #include <stdio.h> void f1( void(*)(void) ); void f2( void ); int main( void) { f1( f2 ); /* arguman olarak fonksiyon ismi */ return 0; }
/* p parametresi : fonksiyona isaret eden adres degiskeni */

void f1( void (*p)(void) ) { (*p)( ); } void f2( void ) { printf("f2 ...\n"); } kt: f2 ...

Fonksiyonlara her eit verinin adresi aktarlabilecei iin argmanlar dizi ismi yada fonksiyon ismi olmad durumlarda da, aran bloktaki argman deerlerine eriim yada verimli ve hzl programlar oluturmak amacyla referans-ile-arma gerekletirilebilir. rnein bir yap deikeninin kopyas yerine bellek adresi aktarlabilir. zellikle argman olarak byk bir yap aktarlmak istendiinde, tm yapnn kopyas yerine adresi aktarlarak snrl stack alan daha az kullanlabilir. referans-ile-arma, daha sonraki blmlerde ayrntl olarak incelenecektir.

4.2 Deikenlerin Grnrlk Alan ve Varolma Sresi


Bir deikenin program iindeki kullanmna etki eden iki nemli zellii, o deikenin grnrlk alan (scope yada visibility) ve varolma sresi'dir (lifetime yada duration). Bir deikenin grnrlk alan, program iinde deikenin deerine eriilebilen alandr. Varolma sresi ise o deikenin program iinde var olduu ve deerini koruduu sredir. C programlar deiken ve fonksiyon tanmlarndan oluur. Grnrlk alan ve varolma sresi, deiken tanmnn veya bildiriminin fonksiyon blou iinde yada dnda
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-19

bulunuyor olmasna gre belirlenir. Bu nedenle fonksiyonlar, deikenlerin grnrlk alan ve varolma sresi zerinde en nemli etkiye sahiptirler.

Global ve Lokal Deikenler


Bir deikene, bulunduu dosya iinde her yerden ve baka dosyalardan eriilebilmesi global grnrlk olarak; fonksiyonlarn dnda tanmlanan deikenler de bu ekilde eriilebildikleri iin global deikenler (global variable. global:genel) olarak adlandrlr. Bu deikenler tm bloklarn dnda bulunduu iin harici deikenler (external) olarak da adlandrlrlar. Daha nce de belirtildii gibi fonksiyonlar birbiri iinde tanmlanamazlar ve fonksiyonlara eriim doal olarak global seviyede gerekleir. Dolaysyla uygun ekilde tanmlanan ve bildirimi yaplan bir fonksiyon, bulunduu dosya iindeki tm bloklardan ve dier dosyalardan arlabilir. Fonksiyon parametreleri ve fonksiyon blou iinde bildirilen deikenler, lokal deikenler (local variable. local:yerel yada lokal) olarak adlandrlr. nk bu deikenlere eriim sadece bildirildikleri blok iinde mmkndr (lokal grnrlk). Blok iinde eriilebildikleri iin dahili deikenler (internal) olarak da adlandrlrlar. Aadaki rnekte main blou iinde lokal deiken i bildirilir. Bu deiken main blou dnda tanmszdr ve eriim sadece main fonksiyonunu snrlayan parantezler iinde mmkndr. Dolaysyla i deikenine, fonk fonksiyonu tarafndan yaplan eriim baarsz olur. Sonu olarak program derlenemez ve derleyici hata verir:
#include <stdio.h> void fonk( void ); int main(void) {
/* lokal degisken bildirimi */

int i = 9; fonk(); return 0; } void fonk( void ) { printf("i : %d\n", i ); }

i deikenine fonk blou iinde eriim ancak bu deiken global seviyede bildirildiinde gerekleebilir. rnek 4.2-1'de bu amala main ve fonk fonksiyonlarnn dnda ve ncesinde, global deiken i tanmlanr. Bylece her iki fonksiyon da ayn deikene eriebilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-20

rnek 4.2-1 global1.c program. #include <stdio.h> void fonk( void ); int i; int main(void) { i = 9; fonk( ); return 0; } void fonk( void ) { printf("i : %d\n", i ); }
/* global degisken tanimi */

... rnek 4.2-1 devam


kt i:9

Global deikenlere, programdaki tm fonksiyonlardan ve hatta birden fazla dosyadan oluan programlarda dier dosyalardan da eriilebilir. Dolaysyla deikenler global seviyede bildirildiinde, hatal bir eriim deikenin deerini deitirebilir. C dilinin en nemli zelliklerinden biri, programlarn fonksiyonlar oluturularak paralara (modllere) blnebilmesi ve oluturulan fonksiyonlarn ihtiya duyulduka tekrar kullanlabilmesi, dolaysyla modler programlamann ok kolay uygulanabilmesidir. Global grnrlk, fonksiyonlar arasnda ok sayda veri balants olumasna sebep olabilir. Sonu olarak, fonksiyonlar arasnda veri transferi global deikenler aracl ile yapldnda fonksiyonlarn tekrar kullanlabilirlii azalr. Tm bu nedenlerden dolay global deikenlerin kullanm tercih edilmez ve veriler argmanlar aracl ile aktarlr. Fakat ok sayda verinin aktarld uygulamalarda, uzun argman listeleri yerine global deikenlerin kullanm daha pratik olacaktr. Aada i deikeninin deeri fonk fonksiyonuna argman olarak aktarlr. Bylece, bu deikenin deeri fonk blou iinde kullanlabilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-21

Bu program da yine ayn kty verir:


/* * lokal.c programi. */ #include <stdio.h> void fonk( int ); int main(void) { int i = 9; fonk( i ); return 0; } void fonk( int i ) { printf("i : %d\n", i ); }

Bu programda fonk fonksiyonu balnda bildirilen i parametresi ile main blou iinde bildirilen i deikeni ilgisizdir. Her ikisi de iinde bulunduu bloun lokal deikenidir. Fakat okunabilirlii arttrmak amacyla parametre bildiriminde farkl isimler kullanlmaldr. fonk blou iinde bildirilecek olan dier bir i deikeni de, main blounda bildirilen ayn isimdeki deiken ile ilgisiz olur ve sadece fonk iinde eriilebilir.

Blok Yaps kullanlarak Grnrlk Alannn Kstlanmas


Fonksiyonlar birbirleri iinde tanmlanamazlar fakat bir fonksiyon blou iinde baka bloklar yer alabilir. Oklu parantezlerle snrlanm bildirimler ve deyimler, deyim blou yada program blou olarak adlandrlr. Deiken bildirimi iermeyen ve sadece deyimlerden oluan bir blok ise, bileik deyim olarak adlandrlr. Deikenlerin grnrlk alanlar, eitli ekillerde kstlanabilir. Herhangi bir program blou iinde bildirilen deikene sadece o blok iinde eriilebilir. Oklu parantezlerin her ifti, iinde bildirilen deikenlerin Grnrlk Alann kstlar. Aadaki rnekte, main fonksiyonu iinde bulunan blokta i deikeni bildirilir ve ilk deer atamas yaplr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-22

rnek 4.2-2 blok1.c programi. #include <stdio.h> int main(void) { /* lokal degisken bildirimi */ int i = 9; printf("dis blok, i : %d\n", i ); { /* lokal degisken bildirimi */ int i; i = 20; printf("ic blok, i : %d\n", i ); } printf("dis blok, i : %d\n", i ); return 0; } kt dis blok, i : 9 ic blok, i : 20 dis blok, i : 9

ktda da grld gibi, ikinci blou balatan sol parantez sonras bildirilen yeni i deikeni, d bloktaki ayn isimde bildirilen i deikeni ile ilgisizdir ve grnrlk alan blou sona erdiren sa parantez ile snrldr. Blok yaps kullanlarak grnrlk alannn kstlanmasnn baz avantajlar vardr: zellikle byk programlarda, deikenin bildirimi ile ilk kullanm arasndaki mesafe uzun olduunda, bu iki nokta arasnda gidip gelmek gleir. Fakat deiken ilk kullanld yere yakn bildirildiinde, aradaki mesafe ksaltlm olaca iin program kodunun okunabilirlii artar.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-23

Aadaki if deyiminde, i deikenine test ifadesi gerekletii taktirde ihtiya olacaktr. Bylece, test ifadesi gereklemez ise bu deiken iin bellek alan ayrlmam olur:
... if (...) { int i; ... } ...

Ayrca i deikeni, programda kullanld yerden nce grlmedii iin yine program kodunun okunabilirlii artar. Yukardaki rnekte, blok yaps kullanlarak lokal deikenlerin grnrlk alan kstland. Blok yaps, global deikenlere de uygulanabilir. rnek 4.2-3'de, tamsay a ve b global deikenleri bildirilir ve bu deikenlere ilk deer olarak srasyla 10 ve 20 deerleri atanr:
rnek 4.2-3 blok2.c program. #include <stdio.h> void fonk( double ); int a = 10; int b = 20;
/* global degisken */ /* global degisken */

int main(void) { fonk( 9.0 ); printf("main, a : %d, b : %d\n", a, b ); return 0; } void fonk( double a ) /* lokal parametre */ { /* lokal degisken */ double b = 3.0; { int a = 30; printf( "fonk, ic blok a : %d\n", a ); } printf( "fonk, a : %1.1f, b : %1.1f\n", a, b ); } kt fonk, ic blok a : 30 fonk, a : 9.0, b : 3.0 main, a : 10, b : 20 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-24

Programda tanmlanan fonk fonksiyonu blounda, ayn deiken isimleri kullanlarak double tipinde a parametresi ve yine double tipinde b deikeni bildirilir. Ayrca fonk fonksiyonu iinde oluturulan bir baka blokta, tamsay a deikeni bildirilir. Bu deikenler fonk fonksiyonunun lokal deikenleridir ve hi biri blok dnda bulunan global tamsay deikenler ile ilgili deildir. Fonksiyon parametrelerine, grnrlk alanlar fonksiyonun en d blounda bildirilen deikenlerinki ile ayn olduundan dolay ayn isimde deiken bildirimleri ieren i bloklar hari fonksiyon iinde her yerden eriilebilir (sadece goto etiketi'nin grnrlk alan fonksiyon blounun tamamdr). Bu nedenle fonk iinde bulunan blokta bildirilen tamsay a deikeni, bu blok iinde double parametre a'nn deerine eriimi engeller. Programda ilk olarak fonk fonksiyonu arlr ve argman olarak 9.0 deeri aktarlr. Aktarlan bu deer, a parametresine atanr. double tipindeki b deikeninin bildirimini izleyen blok iinde tamsay deiken a bildirilir. Dolaysyla bu blok iinde double tipindeki a parametresinin deerine erimek mmkn deildir. Sonu olarak, blok iinde yer alan printf fonksiyonu ktda da grld gibi ekrana tamsay a deikeninin deerini yazar (30). Blok knda bulunan printf fonksiyonu ise ekrana iki deer yazar; a parametresinin ar ile argman olarak aktarlan deeri (9.0) ve b deikeninin bildirimde ilk deer olarak atanan double deeri (3.0). a ve b global deikenleri main blou iinde grnr (eriilebilir) olduklar iin fonk ars tamamlandktan sonra izleyen satrdaki printf fonksiyonu ile deerleri ekrana yazlr. Blok iinde bildirilen deikenler ve fonksiyon parametreleri, ayn isimli fonksiyonlar da gizler. rnek olarak main blou iinde bildirilen bir fonk deikeni, fonk fonksiyonuna eriimi engeller ve main iinde bu ismin tm kullanmlar fonk deikenine eriim anlamna gelir. Ayn ekilde fonk parametresi ile tanmlanan bir fonksiyon iinde ayn isimde bir lokal deiken bildirildiinde bu ismin kullanm fonk deikenine eriim anlamna gelir. Global deikenlerin grnrlk alannn, blok yaps kullanlarak kstlanmas okunabilirlii azaltt iin hatalara sebep olabilir. Fakat baz durumlarda tercih edilen bir yoldur. rneklerde sadece basit deikenler (tek bir veri elemanna sahip deikenler) kullanld. Fakat grnrlk kurallar tm dier deiken tipleri (diziler, union ve yap deikenleri) iin de geerlidir. Okunabilirlii arttrmak iin prototipteki parantezler arasnda verilen parametre tip listesinde, parametre isimlerinin de kullanlabilecei belirtildi. Bu isimlerin grnrlk alan, prototipi sona erdiren parantez ile sonlanr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-25

Yukardaki rnekte yer alan fonk fonksiyonu prototipi, parametre ismi kullanlarak aadaki ekilde yazlabilir:
void fonk( double a );

Burada yer alan a ismi, sadece parantezler arasnda grnr (eriilebilir) olduu iin programn baka yerinde kullanlabilecei gibi prototipte de a yerine herhangi bir isim kullanlabilir:
void fonk( double DEGISKEN );

Grnrlk Alan ve Global Deiken Tanmnn Kaynak Dosyada Bulunduu Yer


Yukarda deiken bildiriminin fonksiyon blou (yada herhangi bir blok) iinde yada dnda bulunmasnn grnrlk alann etkiledii anlatld. Tm bloklarn dnda bulunan global bir deikenin, kaynak dosya iinde tanmland yer de, grnrlk alann etkiler. nk derleyici, kaynak dosyay bandan balayarak satr satr okur. Aadaki programda, tamsay i deikeni global seviyede tanmlanr. Fakat tanm i deikenine ilk eriimin (fonk fonksiyonu arsnda argman olarak) yapld main fonksiyonu tanmndan sonra yerletirilir. Derleyici kaynak dosyay satr satr okuyarak i deikeninin kullanld noktaya ular. i deikeni bu noktada henz bildirilmemi olduu iin derleyici tarafndan tanmlanmad kabul edilir; ve i deikeni bildirildii yerden nce kullanldndan dolay derleyici hata verir. Sonu olarak kaynak dosyada bir global deiken'e eriim ancak bildirildii yerden sonra tanmlanan fonksiyonlar iinden mmkndr. Derleyici kaynak dosyay satr satr okuduu iin, bu kural lokal deikenler iin de geerlidir. Bir lokal deiken, blok iinde sadece bildirildii nokta ile blok kapan parantezi arasnda eriilebilir.
#include <stdio.h> void fonk( int ); int main(void) { fonk( i ); return 0; } int i = 10; /* global degisken */ void fonk( int j ) { printf("i : %d\n", j ); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-26

Grnrlk Alannn ve Varolma Sresinin Kontrolu


Deikenlerin bellekte nasl saklandklar, grnrlk alanna ve varolma sresine etki eder. Deikenler bellekte iki ekilde saklanrlar: otomatik ve static olarak. Otomatik olarak saklanan deikenler herhangi bir blok iinde bulunurlar ve bu bloa girildiinde oluturulur, bloktan kldnda ise otomatik olarak yok olurlar. Static olarak saklanan deikenler ise herhangi bir blok iinde yada dnda bulunabilirler. Bu deikenler deerlerini programn almas boyunca ve iinde bulunduklar blok yada fonksiyona giri ve klarda muhafaza ederler. C dilinde, deiken bildiriminin nne yerletirilerek, derleyiciye deikenin bellekte nasl saklanacan ve grnrlk alann bildiren eitli saklama snf belirleyiciler (storage class specifiers) bulunur. Bu belirleyiciler unlardr: auto, static, extern, register ve typedef.. Her bildirimde en fazla bir belirleyici bulunabilir.

extern bildirim :
Bir global deiken, ayn kaynak dosya iinde tanmland yerden nce kullanlacak ise, mutlaka kullanld yerden nce bir extern bildirim yaplmaldr. extern bildirim, normal bildirimin nne extern anahtar kelimesi yerletirilerek yaplr. Bu yol ile yukardaki rnekteki eriim problemi zlebilir:
rnek 4.2-4 extern.c program. #include <stdio.h> void fonk( int ); int main(void) { extern int i; fonk( i ); return 0; } int i = 10;
/* global degisken */

/* extern bildirim

*/

void fonk( int j ) { printf("i : %d\n", j ); } kt i : 10

rnek 4.2-4'de yaplan extern bildirim, main blou iinde bulunduu iin sadece bu fonksiyon iinde geerlidir. i deikeni program iinde yine tanmland yerden nce ve baka bir fonksiyonda kullanlacak ise bu fonksiyon blou iinde extern bildirim gereklidir. Fakat tanmland yerden nce kullanld tm fonksiyonlar iine extern

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-27

bildirim yerletirmek yerine tm bloklarn dnda ve ncesinde bir extern bildirim yapmak en pratik yoldur. Yukarda bir global deikenin, ayn kaynak dosyada tanmland yerden nce kullanlabilmesi iin extern bildirimin gerektii belirtildi. Kaynak program birden fazla dosyadan oluabilir ve global deikene tanmland dosyadan farkl bir dosyada eriim gerekebilir (yani bir dosyada bulunan fonksiyonun dier dosyadaki herhangi bir deikene eriimi gerekebilir). Bu durumda da yine global deikene eriilen dier dosyada extern bildirim gerekir. Bir global deikenin bildirimi ve tanm ayn ey deildir. Bildirim ile deikenin zellikleri (tipi, boyutlar gibi) ifade edilir ve bu deikenin baka bir yerde tanmlandn belirtilir. Tanm ise ayn zamanda bir bildirimdir; deiken iin bellek alan ayrlmasn ve bu alana ilk deer atama yaplabilmesini salar. Kaynak program oluturan btn dosyalar arasnda global deikenin yalnzca bir tanm olmaldr; program oluturan dier dosyalarda bu deikene erimek iin extern bildirimler bulunabilir. Yukardaki rnek programda grld gibi tanmn bulunduu dosyada da extern bildirimler bulunabilir. Kaynak dosyada extern anahtar kelimesi bulunmayan ve ilk deer atama yaplmayan deiken bildirimleri, geici tanm (tentative definition) olarak adlandrlr. Yine extern kullanlmadan ilk deer atama yaplan bir bildirim ise gerek tanmdr. Eer kaynak dosyada bir deikene ilk deer atama yaplan bir gerek tanm bulunmuyor ise tm geici tanmlar ilk deer olarak 0 (adres deikenleri iin ilk deer olarak bo adres deeri -null pointer- ) ile o deikenin tanm olarak kabul edilir. Eer gerek tanm bulunuyor ise geici tanm, bildirim olarak ele alnr:
/* gecici tanm */

int i; ... int main(void) { ... printf( "i : %d\n", i ); }


/* gercek tanm */

int i = 3;

rnek 4.2-5'de yer alan program, iki ayr kaynak dosyadan oluur. Bu rnekte, birden fazla kaynak dosyadan oluan bir programdaki eriim kurallar gsterilir. Basit programlar genellikle tek bir kaynak dosyaya yerletirilir. Fakat karmak ve kapsaml projeler birden fazla kaynak dosyaya blnr. lk dosyada,
int i = 10, j = 20;

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-28

satrnda i ve j global deikenleri tanmlanr ve ilk deer atamalar yaplr. Bu tanm ile bellekte her iki deiken iin bellek alan ayrlr. Ayrca bu tanm, birinci dosyada bulunduu satrdan itibaren her iki deikenin de bildirimi olarak i grr. kinci dosyada ise fonk fonksiyonu blounda, i ve j deikenlerinin
extern int i, j;

satr ile extern bildirimleri yaplr. Bu satr ile deikenler iin bellek alan ayrlmaz, fakat ikinci dosyada bulunduu noktadan blok sonuna kadar (nk blok iinde bulunur) i ve j'nin tamsay deikenler olduunu ve baka bir yerde tanmland ifade edilir. Tanm yeri, bulunulan grnrlk alan d yada bir baka dosya olabilir. Bylece bu deikenlerin bir baka dosyada tanmland belirtilir ve dolaysyla fonk fonksiyonu dier dosyadaki i ve j deikenlerine eriebilir.
rnek 4.2-5 Birden fazla kaynak dosyadan oluan (iki-dosyal) program. /* * dosyaa.c */ #include <stdio.h>
/* global degisken tanimlari */

/* * dosyab.c */ #include <stdio.h> void fonk(void) {


/* extern bildirimler */

int i = 10, j = 20; extern void fonk( void ); int main(void) { fonk(); return 0; } kt i : 10, j : 20

extern int i, j; printf( "i : %d, j : %d\n", i, j ); }

Programda ayrca ikinci dosyada tanmlanan fonk fonksiyonu, birinci dosya iinde bulunan main fonksiyonu tarafndan arlr. Eriimin gereklemesi iin, ilk dosyadaki main bloundan nce fonk fonksiyonunun extern bildirimi yaplr. Ancak C dilinde deikenlerin aksine fonksiyonlar daima kendiliinden global olduu iin birinci dosyadaki fonksiyon bildiriminde, extern anahtar kelimesinin kullanm gereksizdir. extern anahtar kelimesinin kullanm fonksiyonun baka bir dosyada tanmlandn aka belirtir ve bylece okunabilirlii arttrr. fonk fonksiyonu baka bir kaynak dosyada tanmlanm olsa dahi main tarafndan arlabilir. Fonksiyonlar normal olarak, birden fazla kaynak dosyadan oluan programlarda her yerden eriilebilir. kinci dosyadaki extern bildirim, fonk blou iinde yer alr. Bu durumda bildirim sadece bu blok sonuna kadar geerli olur. Tm bloklarn dnda ve kaynak dosyann banda yer
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-29

alan extern bildirim ise, ayn kaynak dosyada bulunduu satrdan sonra tanmlanan tm fonksiyonlar iinde geerlidir.

static deikenler :
Baz durumlarda birden fazla kaynak dosyadan oluan programlarda global bir deikenin sadece tanmland kaynak dosyada grnr (eriilebilir) olmas istenebilir. Bu i bildirimde tip ncesine static anahtar kelimesi yerletirilerek gerekletirilir. Bu ekilde bildirilen bir deiken static external (global) deiken olarak adlandrlr ve sadece bulunduu kaynak dosyada, tanmland satr sonrasnda eriilebilir. static anahtar kelimesi, eriimi kstlamak iin fonksiyon bildirimlerine de uygulanabilir. Bu ekilde bildirilen bir fonksiyon static fonksiyon olarak adlandrlr ve sadece tanmland dosya iinde arlabilir. rnek 4.2-5'de ikinci dosyada tanmlanan fonk fonksiyonunun balk ksmnda tip ncesine static eklenirse, ilk dosyadan eriim mmkn olmayacaktr. Linker hata verir ve program derlenemez:
static void fonk(void) { ... }

Fonksiyonun tanmland dosyada prototipi bulunmuyor ise static anahtar kelimesi fonksiyon tanmna yerletirilmelidir (balkta, tip belirleyici ncesine). static anahtar kelimesi bir fonksiyonun hem prototipinde hem de tanmnda yer alabilir. Fakat static bildirimi yaplan bir fonksiyonun tanmnda da static belirleyici kullanlmas gerekmez. static belirleyici, fonksiyon ismini programn dier dosyalarndan gizler. Bylece ayn isim dier dosyalarda baka bir fonksiyon iin kullanlabilir. rnein ticari fonksiyon ktphaneleri oluturulurken ktphanedeki btn fonksiyonlar static olarak tanmlanr. Bu yolla kullancnn kendi oluturduu fonksiyonlarla isim benzerliinden doabilecek aksaklklar nlenmi olur. Fonksiyon ismine, tanmda sadece static belirleyici; prototipte ise extern ve static belirleyiciler uygulanabilir.

otomatik deikenler :
Bir deikenin kullanmna etki eden dier nemli zellii, programn almas srasnda var olduu ve deerini koruduu sredir. Herhangi bir blok iinde (fonksiyon blou yada program blou) bildirilen lokal deiken, bloa girildii yada fonksiyon arld zaman oluturulur ve blok sonuna ulaldnda yada fonksiyondan kldnda yok olur. Dolaysyla, "lokal" kelimesi bu deikenin grnrlk alann ifade eder.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-30

auto belirleyici kullanlarak bildirilen bir lokal deiken, fonksiyonla yada girilen blok ile birlikte otomatik olarak gelir ve gider (otomatik varolma sresi). Bu nedenle otomatik deiken olarak da adlandrlr. Fakat bildirimlerde auto kullanlmas zorunlu deildir. nk fonksiyonlar iinde extern ve static belirleyici olmadan bildirilen tm deikenler, kendiliinden otomatik olaca iin bildirimde auto anahtar kelimesinin kullanm sadece program kodunun okunabilirliini arttrr. Fonksiyon parametreleri de lokal deikenlerdir ve dolaysyla otomatik olarak saklanrlar. Otomatik deikenlerin baz avantajlar vardr: bellek tasarrufu salarlar (fonksiyon almasn bitirdiinde kaybolduklar iin, ihtiya olmadnda bellek harcamazlar). otomatik deikenler, programn iletim zaman srasnda oluturulduu iin altrlabilir program kodunun boyutlarn yada bellekte kaplayaca alan arttrmazlar. fonksiyon arlar arasnda deerleri muhafaza edilmedii iin, nceki arlardan kalma artk deerlerin bir sonraki arda kullanlmas gibi bir sorun yoktur. rnek programlarda pek ok otomatik deiken bildirildi. Aadaki fonksiyonda tamsay i ve j deikenlerinin her ikisi de otomatik deikenlerdir:
void fonk( void ) { int i; auto int j; }

/* otomatik degisken i */ /* otomatik degisken j */

Yukarda da belirtildii gibi otomatik deikenlerin varolma sresi blok ile snrldr. Ve sadece blok iinde bildirildikleri satrdan blok sonuna kadar geerlidirler (grnrlk alan). Global deikenler, programn almas boyunca fonksiyon arlar arasnda deerlerini muhafaza ederler (global varolma sresi) ve tanmlandklar satrdan program sonuna kadar ve dier dosyalardan yaplan eriimlere izin verirler. Geni grnrlk alan ve uzun varolma sresine sahiptirler (static bellek alannda olarak saklanrlar). Bu nedenle birbirlerini armayan ve baz verileri paylamak durumunda olan fonksiyonlar arasnda veri tanmasnda kullanlabilirler. Dolaysyla argmanlar ile veri aktarmna ve return ile deer dndrlmesine alternatif olarak kullanlabilir. ok sayda veri paylalyor ise, uzun argman listeleri kullanmna gerek kalmaz. Bu nedenlerden dolay, lokal fonksiyon parametreleri yerine global deikenler kullanlr. Ayrca baz durumlarda referans-ile-arma yerine, global veri kullanm tercih edilebilir (rnein, global dizi kullanm).
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-31

nceki blmde de anlatld gibi global deikenlere static anahtar kelimesi uygulanarak grnrlk alanlar bulunduklar kaynak dosya ile snrlanabilir (external static deikenler). static belirleyici blok iinde bildirilen lokal deikenlere de uygulanabilir. Blok iinde static olarak bildirilen deikenler (internal static deikenler), otomatik deikenlerde olduu gibi yine bildirildikleri blok iinde grnrler. Fakat otomatik deikenlerin aksine bulunduklar bloa her giri ve kta yada fonksiyonun her arlnda gidip gelmek yerine daima var olur. Dolaysyla static anahtar kelimesi bir lokal deikene uygulandnda, bu deikenin grnrlk alan yerine varolma sresini etkiler. Sonu olarak, herhangi bir blok iinde static olarak bildirilen bir deiken, bu blok ile snrl grnrlk alanna sahiptir ve programn almas boyunca srekli olarak bellekte tutulur. Aadaki programda, static belirleyici kullanlarak fonksiyon arlar arasnda deerini koruyan lokal deiken Deger bildirilir:
rnek 4.2-6 static.c program. #include <stdio.h> #define #define ILK_DEGER IKINCI_DEGER 10 20

void fonk( int ); int main(void) { printf("ilk cagri ..." ); fonk( ILK_DEGER ); printf("ikinci cagri ..."); fonk( IKINCI_DEGER ); return 0; } void fonk( int i ) { static int Deger; if ( i == ILK_DEGER ) Deger = 0; Deger = Deger + i; printf(" Deger : %d\n", Deger ); } kt ilk cagri ... Deger : 10 ikinci cagri ... Deger : 30

Programda, Deger deikeni arlar arasnda deerini koruduu iin ikinci arda ekrana 30 deeri yazlr. nk ikinci arda aktarlan 20 deeri nceki ardan kalan
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-32

10 deeri ile toplanr. Grld gibi static bildirim, Deger deikeninin varolma sresini arttrr. Fakat Deger deikenine eriim, sadece fonk fonksiyonu iinde mmkndr; grnm alan deimez. Program, fonksiyon iinde bildirilen lokal deikenler (otomatik deikenler) iin stack alann kullanr Fonksiyon almasn bitirinceye kadar bu deikenler stack alannda kalr. Dolaysyla fonksiyonun lokal deikenleri iin ok fazla stack alan gerekiyor ise yada stack alannda pek ok veri alan olumasna sebep olan ok sayda i ie ar yaplm ise (kendi kendini pek ok kez aran fonksiyonlarda olduu gibi), program stack alan dna taabilir (stack overflow). Bu durum iletim zaman hatasna sebep olur. rnein ok sayda elemana sahip bir otomatik dizi, bu tamaya sebep olabilir. Aada bildirilen s dizisi, 1 byte byklnde 5000 elemana sahiptir ve iletim zaman srasnda stack tamas hatasna sebep olabilir:
void fonk(void) { ... char s [ 5000 ]; ... }

Bildirimde static anahtar kelimesi kullanlarak derleyicinin lokal deikenler iin stack alann kullanmamas salanabilir. s dizisi static olarak bildirildiinde, bu dizinin elemanlar stack yerine bellekteki static veri alanna yerletirilir. Bylece stack'ta dier lokal deikenler iin kullanlabilecek alan miktar artm olur.
void fonk(void) { ... static char s [ 5000 ]; ... }

Baz derleyiciler, program iin daha geni stack alan ayrlmasn salayan seeneklere sahiptir. static veriler kullanlrken daha nce belirtilen noktalar dikkate alnmaldr. Veriler static (kalc) olarak saklandnda, arlar arasnda deerlerini korurlar. Dolaysyla fonksiyonun her arlnda ayn deerlere eriilir. Bir deiken bildiriminde, varolma sresi ve grnrlk alann ifade eden en fazla bir belirleyici bulunabilir. Herhangi biri bulunmad durumda fonksiyon iinde bildirilen deikenler (btn deiken tipleri dahil) iin auto; yine herhangi bir fonksiyon iinde bildirilen fonksiyonlar iin ise, extern belirleyici kabul edilir. Tm fonksiyonlarn dnda bildirilen deikenler iin extern kabul edilir. Tm fonksiyonlarn dnda bildirilen fonksiyonlar ise global varoma srelidir ve programn tm dosyalarndan grnrler.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-33

Aadaki rnekte, f1 ve f2 fonksiyonlarnn prototipleri main fonksiyonu iine yerletirilmitir. Dolaysyla bildirimler main blou iinde geerli olur. Bu durumda f1 fonksiyonu f2 fonksiyonunu ardnda hata oluur. nk f2 fonksiyonu tanm f1 blou sonrasnda yer alr. Fakat bildirimler main dna karldnda bu sorun nlenir.
#include <stdio.h> int main(void) { void fonk1( void ); void fonk2( void ); fonk1(); fonk2(); return 0; } void fonk1(void) { /* bu cagri hata olusturur */ fonk2(); puts( "fonk1 ..." ); } void fonk2(void) { puts("fonk2 ..."); }

register deikenler :
Yukardaki satrlarda auto, static ve extern belirleyiciler anlatld. register ise bir dier belirleyicidir. Bir otomatik deikenin yada fonksiyon parametresinin bildiriminde, tip ncesine yerletirilen register anahtar kelimesi, deikenin mikro-ilemcinin register birimlerinde saklanacan ifade eder. Fakat bu kullanmda, baz kstlamalar szkonusudur. Donanma bal olarak, register belirleyici sadece char, short ve int tamsay tipler (signed yada unsigned) ve adres deikeni tipleri ile kullanlabilir. Ayrca sadece tek elemanl veriler mikro-ilemcinin register birimlerine yerletirilebilir. Diziler, yap deikenleri gibi birden fazla elemandan oluan veri gruplar, register birimlerine yerletirilemeyecek kadar byktr. Donanma bal olarak, sadece belli sayda register birimi kullanlabilir ve bu saydan fazla register kullanm sz konusu olduunda, kalan deikenler derleyici tarafndan register bildirim dikkate alnmadan adreslenebilir bellek alanlarna yerletirilir. Register birimleri adreslenebilir olmad iin & operatr kullanlarak, register ile bildirilmi bir deikenin adresi alnamaz. Bu kural, derleyicinin deikenleri register birimlerine yerletirip yerletirmediine baklmakszn geerlidir. Dolaysyla scanf fonksiyonu kullanlarak, bir register deikene deer alnamaz.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-34

Aadaki satrda, i ve j register deikenleri bildirilir:


register int i, j;

Yukardaki bildirimde register anahtar kelimesi kullanlarak, int tipi i ve j deikenlerinin mikro-ilemcinin register birimlerinde saklanmasnn istendii ifade edilir. register bildirimde, tip belirleyici kullanlmadnda, veri tipi olarak int kabul edilir.

typedef :
C dilinde typedef anahtar kelimesi kullanlarak mevcut veri tipleri iin yeni isimler tanmlanabilir. Program kodunun okunabilirliini arttran, yaygn bir uygulamadr. Aadaki bildirim ile int tip belirleyicisi yerine kullanlabilecek TAMSAYI ismi tanmlanr:
typedef int TAMSAYI;

Grld gibi typedef bildirimi, normal bildirim ncesine typedef anahtar kelimesi yerletirilerek gerekletirilir. Bylece deiken bildirimi, tip ismi bildirimi olur ve bildirimde yer alan isim, veri tipi ismi haline gelir. typedef bildirimi, yeni bir veri tipi oluturmaz. Sadece mevcut bir veri tipi iin yeni bir isim tanmlanmasn salar. Pratik ve yaygn kullanmna rnek olarak, birden fazla veri elemanndan oluan tipler iin (diziler ve yap deikenleri gibi) ksa ve tanmlayc isimler oluturulmas verilebilir (rnek 7.2-1, rnek 8.3-3, rnek 8.3-4, rnek 8.3-5, rnek 9.4-3). typedef ile tanmlanan yeni isimler, byk harflerle yazlarak okunabilirlik arttrlabilir. typedef bildirimi, tanabilirlik problemlerinin daha kolay zlebilmesini salar. Donanma bal veri tipleri iin typedef bildirimleri kullanlr ise program farkl bir evreye tandnda, sadece typedef bildirimlerini deitirmek yeterli olacaktr. typedef kullanm, nilemci komutu #define kullanmna benzer. Fakat derleyici tarafndan ilem grd iin typedef ile daha kapsaml deitirmeler yaplabilir. typedef, dier belirleyicilerde olduu gibi verilerin bellekte nasl saklanacana etki etmemekle birlikte, bildirimde bulunduu yer dolaysyla ayn ekilde yorumlanr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-35

4.3 lk Deger Atama


lk deer atama, herhangi bir deikene (bu aada grld gibi bir basit deiken, dizi deikeni, yada daha sonraki blmlerde ayrntl olarak anlatlan union yada yap deikeni olabilir) balang deerinin bildirim srasnda atanmasdr. Bu ilem, normal atama ile ayn deildir ve baz kurallar vardr.
bildirim deyimi int i = 120; ilk deer

Bir deikenin bildirimi srasnda bellek alan ayrlyor ise bu bildirim ile deiken tanmlanm olur. Otomatik deikenlerin bildirimleri, ayn zamanda bellek alan ayrlmasn salad iin bu deikenlerin tanmdr. Bir otomatik basit deikene yada bir register deikene, tanmland srada ilk deer atama ilemi yaplabilir. Bunun iin deiken bildirim deyiminde bir sabit deere, nceden tanmlanm deikene, fonksiyon arsna yada bunlarla oluturulan herhangi bir geerli ifadeye eitlenebilir. Daha nce de anlatld gibi auto ve register belirleyiciler ile bildirilen deikenler, otomatik varolma srelidir. Programn almas srasnda bu deikenler bulunduklar fonksiyon blouna yada program blouna her normal girite (goto ile sapmadan gerekleen) tekrar oluturulur ve eer var ise ilk deer atama ilemleri (bu i iin gerekli komutlarn altrlmas ile) yaplr. Dolaysyla otomatik deikenlerin nceki fonksiyon arlarnda yada program blou girilerinde aldklar deerleri korumalar szkonusu deildir. lk deer atama yaplmadnda auto ve register deikenlerin balang deerleri belirsizdir. Bir otomatik deikene ilk deer atama ile daha sonra yaplacak olan atama ilemi bildirim srasnda yaplarak ilemler ksaltlm olur. Fakat, ilk deer atama ilemi deikenin kullanm noktasndan uzakta yapld iin ilk deerlerin grlmesi zor olabilir. Bu nedenle okunabilirlii arttrmak amacyla ak olarak atama yaplmas (herhangi bir atama deyiminde) tercih edilir. Fonksiyon parametreleri de otomatik olarak saklanrlar, fakat bu deikenlere ilk deer atama yaplamaz. Ayrca global olarak bildirilemezler. Ancak parametrenin kendisi aada grld gibi ilk deer atama ileminde kullanlabilir:
int fonk( int m ) { ... int i = m + 1; ... }
/* parametre m */

/* ilk deger atama */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-36

Yukardaki ilem, bir atama deyimi ile de gerekletirilebilir:


int fonk( int m ) /* parametre m */ { ... int i; ... /* atama deyimi */ i = m + 1; ... }

Global ve static deikenlere de ilk deer atama yaplabilir. Fakat atanan ilk deer otomatik deikenlerin aksine, bir sabit yada nceden bildirilmi global yada static verinin bellek adresine bir tamsay sabitin eklendii yada karld ifade olabilir. lk deer atama yaplmadnda ise balang deerleri 0 olur.
rnek 4.3-1 ilkdeg1.c program. #include <stdio.h>
/* global degiskenler */

int a = 0; int b; int main(void) {


/* auto degiskenler */

char c = 'c'; int i = 3; int j; long l, n, m = 5L; long k = m * 10L * 2L;


/* internal static degiskenler */

static s1 = 9; static s2;


/* register degiskenler */

register r1 = i * 2; register r2;


/* atama deyimi */

l = n = 3L; printf( "global degiskenler : \n a : %d, b : %d\n", a, b ); printf( "otomatik degiskenler : \n"); printf( "c : %c, i : %d, j : %d, l : %ld, n : %ld, m : %ld, k : %ld \n", c, i, j, l, n, m, k ); printf( "static degiskenler : \n s1 : %d, s2 : %d \n", s1, s2 ); printf( "register degiskenler : \n r1 : %d, r2 : %d\n", r1, r2 ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-37

rnek 4.3-1 devam


kt
global degiskenler :

a : 0, b : 0
otomatik degiskenler :

c : c, i : 3, j : 235, l : 3, n : 3, m : 5, k : 100
static degiskenler :

s1 : 9, s2 : 0
register degiskenler :

r1 : 6, r2 : 916

Programda aada aklanan bildirim ve ilk deer atama ilemleri yer alr: otomatik deikenler : Programda c, i, j, l, n, m ve k otomatik deikenleri bildirilir. c, i, m ve k deikenlerine, bildirim srasnda ilk deer atama yaplr. lk deer atama ileminde, her bir deer sadece tek bir deikene atanr. Dolaysyla,
long l, n, m = 5L;

bildirim deyimindeki 5L deeri, sadece m deikenine atanr. Okunabilirlii arttrmak amacyla, her bir bildirim deyiminde sadece tek bir ilk deer atamann yaplmas uygun olur. l ve n deikenlerine, aadaki deyim ile 3L deeri atanr:
l = n = 3L;

Bu ilem, ilk deer atama ile bildirim srasnda aadaki ekilde de yaplabilir:
long l = 3L, n = 3L, m = 5L;

lk deer atama yaplmayan j deikeninin deeri, daha sonra da hibir deer atanmad iin belirsizdir ve o anda bellekte bulunan anlamsz deerler ekrana yazlr. global deikenler : Global a deikenine ilk deer olarak 0 atanr. Global b deikenine ilk deer atama yaplmad halde balang deeri 0 olur. b deikenine de ilk deer atama yaplarak, global bildirimler aadaki ekilde dzenlenebilir:
int a = 0, b = 0;

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-38

static deikenler : Tamsay s1 deikenine ilk deer olarak 9 deeri atanr. Tamsay s2 deikenine ise ilk deer atama yaplmaz. Fakat ktda grld gibi ilk deer atama yaplmayan tamsay static deiken s2'nin balang deeri 0 olur. register deikenler : int tipi register deiken r1'e, bildirim deyiminde i * 2 ifadesi eitlenerek ilk deer atama yaplr. int tipi register deiken r2'nin deeri ise ilk deer atama yaplmad iin belirsizdir. Static varolma sreli deikenler (global ve static olarak bildirilen), program balamadan nce oluturulur ve ilk deer atama ilemleri sadece bir kez yaplr. Dolaysyla bu deikenler arlar arasnda deerlerini korurlar (ayn durum kendini aran fonksiyon blou iinde tanmlanan static deikenler iinde geerlidir). rnek 4.3-2'de bildirilen j deikeni, ktda grld gibi arlar arasnda deerini korur.
rnek 4.3-2 ilkdeg2.c program. #include <stdio.h> int fonk( void ); int main(void) { int i; for ( i = 0; i < 5; i++ ) printf("%d\n", fonk() ); return 0; } int fonk(void) { static int j = 0; /* blok ici static bildirim */ return j++; } kt 0 1 2 3 4

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-39

Diziler ve yap deikenleri birden fazla veri elemanna sahiptir (izleyen blmlerde anlatlacaktr). Bir diziye yada yap deikenine (otomatik yada static) ilk deer atama, bildirim srasnda virgl ile ayrlm ve oklu parentezlerle snrlanm sabitlerden oluan ilk deer listesi ile yaplabilir. Dizinin boyutlar verilmediinde derleyici ilk deerleri sayarak eleman saysn hesaplar. Fakat bildirimde keli parantezler iinde eleman says verildiinde belirtilen saydan daha az ilk deer varsa, kalan elemanlarn ilk deerleri 0 olur. Daha ok sayda ilk deer var ise derleyici hata mesaj verir. Bir otomatik deikene ilk deer atama tek bir ifade ile yaplyor ise bu ifade sabit ifade olmayabilir. Bir otomatik diziye ilk deer atama yaplmadnda elemanlarn deerleri belirsiz olur. lk deer atama yaplmayan global yada static bir dizinin elemanlarnn deerleri ise 0 olur. Ayn kurallar bir union iin de geerlidir, fakat bir union deikenine ilk deer atama sadece ilk elemannn tipinde bir sabit deer ile yaplabilir. Aada, tek boyutlu otomatik GUN dizisi bildirilir ve parantezlerle snrl 12 sabit deer ile ilk deer atama yaplr. Atanan deerler, aylardaki gn saylardr:
int GUN[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

GUN dizisinde olduu gibi dizinin boyutlar verilmediinde derleyici ilk deerleri sayarak eleman saysn hesaplar. Bu durumda, GUN dizisi 12 elemanl bir dizi olacaktr. Fakat bildirimde keli parantezler iinde eleman says verildiinde belirtilen saydan daha az ilk deer varsa kalan elemanlarn ilk deerleri belirsiz olur. Daha ok sayda ilk deer var ise derleyici hata mesaj verir. Bir yapy yada diziyi oluturan veri grubunun herhangi bir eleman, bir baka veri grubu oluturabilir (alt-veri grubu). Herhangi bir yap yada dizi deikenine uygulanan ilk deer atama kurallar, bu alt-veri gruplar iin de geerlidir. Yani, alt-veri grubu elemanlarna ilk deer atama, yine oklu parantezlerle snrlanm ve virgllerle ayrlm sabit deerler ile yaplr. Eleman saysndan fazla ilk deer var ise bu hata oluturur. Altveri grubunun ilk deerleri parantezlerle snrlanmam ise gerekli sayda ilk deer kullanlr ve kalan deerlerle ana grubun izleyen elemanlarna ilk deer atama yaplr. rnek 4.3-3'de iki boyutlu tamsay b dizisi bildirilir ve tmyle parantezlerle snrl sabit deerler ile ilk deer atama yaplr:
int b[4][3] = { { 1, 2, 3 }, /* b[0][0..2] */ { 4, 5, 6 }, /* b[1][0..2] */ { 7, 8, 9 }, /* b[2][0..2] */ };

b dizisi, 4 elemandan oluur ve her eleman 3 elemanl bir dizidir. b dizisinin ilk eleman olan b[0] dizisine 1, 2, ve 3 iki deerleri atanr; yani alt-veri grubu olan b[0][0], b[0][1]
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-40

ve b[0][2] elemanlarna). zleyen elemanlar ise b[1] ve b[2] dizisine ilk deer olarak atanr. Fakat b[3] dizisi iin deer kalmadndan dolay elemanlara 0 deeri atanr. Bu bildirim ve ilk deer atama aadaki ekilde de yaplabilir:
int c[4][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Fakat bu durumda ilk deer atama farkl yorumlanr. nk sol parantez ile balayan ilk deer listesi, c[0] iin deil, c dizisi iindir. lk deer kullanlr, izleyen deerler er er c[1] ve c[2] iin kullanlr. Aadaki bildirim ise d dizisinin ilk kolonuna ilk deer atama yapar (d[0][0], d[1][0], d[2][0] ve d[3][0] elemanlarna) :
int d[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } }; rnek 4.3-3 ilkdiz1.c program. #include <stdio.h> int main(void) { int i, j; int a[ ] = { 1, 2, 3 }; int b[ 4 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, }; int c[ 4 ][ 3 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int d[ 4 ][ 3 ] = { { 1 }, { 2 }, { 3 }, { 4 } }; for ( i = 0; i < sizeof (a) / sizeof (a[0]); i++ ) printf("a[%d] : %d\n", i, a[ i ] ); for ( i = 0; i < 4; i++ ) for ( j = 0; j < 3; j++ ) printf("b[%d][%d] : %d\n", i, j, b[ i ][ j ] ); for ( i = 0; i < 4; i++ ) for ( j = 0; j < 3; j++ ) printf("c[%d][%d] : %d\n", i, j, c[ i ][ j ] ); for ( i = 0; i < 4; i++ ) for ( j = 0; j < 3; j++ ) printf("d[%d][%d] : %d\n", i, j, d[ i ][ j ] ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-41

...rnek 4.3-3 devam


kt a[0] : 1 a[1] : 2 a[2] : 3 b[0][0] : 1 b[0][1] : 2 b[0][2] : 3 b[1][0] : 4 b[1][1] : 5 b[1][2] : 6 b[2][0] : 7 b[2][1] : 8 b[2][2] : 9 b[3][0] : 0 b[3][1] : 0 b[3][2] : 0 c[0][0] : 1 c[0][1] : 2 c[0][2] : 3 c[1][0] : 4 c[1][1] : 5 c[1][2] : 6 c[2][0] : 7 c[2][1] : 8 c[2][2] : 9 c[3][0] : 0 c[3][1] : 0 c[3][2] : 0 d[0][0] : 1 d[0][1] : 0 d[0][2] : 0 d[1][0] : 2 d[1][1] : 0 d[1][2] : 0 d[2][0] : 3 d[2][1] : 0 d[2][2] : 0 d[3][0] : 4 d[3][1] : 0 d[3][2] : 0

rnek 4.3-4'de global dizi i, otomatik dizi j ve static dizi s bildirilir ve ilk deer atamalar yaplr. lk deer atamada, herhangi bir deerin tekrarlandn belirtmek iin bir yol yoktur. Ayrca sadece belli elemanlara ilk deer atamakta mmkn deildir. lk deer atama yaplmadnda, global i ve static s dizisinin elemanlarnn deerleri 0 olur. Fakat otomatik j dizisinin elemanlarnn deerleri belirsiz olur. j dizisinin elemanlarnn deerleri bir dng ve atama deyimi ile 0 yaplabilir:
... int j[ 3 ]; ... for ( indeks = 0; indeks < 3; indeks++ ) j[ indeks ] = 0; ...

rnek 4.3-4 ilkdiz2.c program. #include <stdio.h> int i[ ] = { 0, 1, 2, 3 }; int main(void) { int indeks; int j[ ] = { 4, 5, 6 }; static int s[ ] = { 7, 8, 9 }; for ( indeks = 0; indeks < sizeof (i) / sizeof (i[0]); indeks++ ) printf(" i[%d] : %d\n", indeks, i[ indeks ] ); for ( indeks = 0; indeks < sizeof (j) / sizeof (j[0]); indeks++ ) printf(" j[%d] : %d\n", indeks, j[ indeks ] ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-42

...rnek 4.3-4 devam


for ( indeks = 0; indeks < sizeof (s) / sizeof (s[0]); indeks++ ) printf(" s[%d] : %d\n", indeks, s[ indeks ] ); return 0; } kt i[0] :0 i[1] :1 i[2] :2 i[3] :3 j[0] :4 j[1] :5 j[2] :6 s[0] :7 s[1] :8 s[2] :9

Eer bir global deikenin bildiriminde ilk deer atama yaplyor ise bu bildirim ile tanmlanm olur. Bir global deikenin sadece tek bir tanm bulunabilir. Bir extern bildirim, bildirilen deikenin zelliklerinin baka bir yerde tanmlanarak bu deiken iin bellek alan ayrldn ifade eder. Global dizilere ilk deer atama, sadece tanmda olur. Tanmda dizi boyutlar belirtilmelidir (ilk deer atama var ise ve boyutlar verilmezse derleyici tarafndan deerler saylarak hesaplanr); fakat dizinin extern bildiriminde boyutlarn verilmesi seime baldr. Aada rnek olarak, SAYI dizisi verilir:
1. dosya : ... #define ELEMAN 5 ...
/* global dizi tanimi */

2. dosya : ...
/* extern bildirim */

extern int SAYI [ ]; ...

int SAYI [ ELEMAN ]; ...

Global bir deikenin sadece bir tanm olur. lk deer atama yaplan bir bildirim o deikenin tanmdr. Yani herhangi bir extern bildirimde ilk deer atama giriimi, ikinci bir tanm oluturma giriimi olacaktr. Ayrca extern bildirimde deiken iin (basit deiken, dizi yada yap deikeni) bellek alan ayrlmaz. Bu nedenlerden dolay extern bildirimlerde ilk deer atama yaplamaz. enum tipi bir deikene listedeki sabit deerlerden biri ilk deer olarak atanabilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-43

Karakter dizilerine, dizgi sabitleri (string literal) ilk deer olarak atanabilir. Aada karakter dizisi s bildirilir ve ilk deer atama yaplr:
char s [ ] = "abc";

Derleyici, "abc" dizgisinde bulunan karakterleri sayarak dizgi uzunluunu bulur ve ona gre bellek dzenlemesi yapar. Bu nedenle ilk deer atama yaplyor ise keli parantezler arasnda eleman says belirtmek gerekmez. Aadaki deyimlerde s1 ve s2 karakter dizileri tanmlanr:
char s1[ ] = "abc"; char s2[ ] = { 'a', 'b', 'c', '\0' };

s1 dizisine ilk deer olarak "abc" karakter dizgisi atanr. Dizgi sabitleri, bellekte karakter dizisi olarak saklanrlar. Dizgi sonunun belirlenmesi iin derleyici tarafndan otomatik olarak her dizgi sonuna bo-karakter (NUL veya karakter sabiti olarak '\0') eklenir. Bu nedenle derleyici tarafndan saptanan dizgi uzunluu, karakter saysnn bir fazlasdr. sizeof s1 / sizeof s1[0] ifadesi ile bulunan s1 dizisinin eleman says, "abc" dizgisinin karakter saysndan bir fazladr (yani 4). Dolaysyla ilk deer atama yaplrken keli parantezler arasnda eleman says veriliyor ise bo-karakter iin ilave yer ayrlmaldr. Ayrca dizgideki karakter says (bo-karakter hari), parantezler arasnda verilen eleman saysn gememelidir. rnek olarak, aada bildirilen c dizisinin eleman says kullanlacak dizgi boyunun bir fazlas olarak verilmitir:
... #define DIZGI_BOYU 20 ... char s[ DIZGI_BOYU+1 ];

s1 dizisi, eleman says belirtilerek aadaki gibi bildirilebilir:


char s1[ 4 ] = "abc";

lk deer atama, karakter sabitlerinden oluan ilk deer listesi ile de yaplabilir. Fakat bu durumda, derleyici tarafndan karakter dizisi sonuna bo-karakter eklenmeyecei iin bu i ak olarak yaplmaldr:
char s2 [ ] = { 'a', 'b', 'c', '\0' };

yada
char s2 [ 4 ] = { 'a', 'b', 'c', '\0' };

rnek 4.3-6'da sadece bo karakterlerden oluan s1 ve s2 dizisi bildirilir. Fakat ktda da grld gibi strlen fonksiyonu her iki dizinin eleman says iin 0 deerini

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-44

dndrr. Eleman saylar sizeof operatr kullanlarak hesaplandnda s1 dizisi iin 1, s2 dizisi iin ise 2 bulunur.
rnek 4.3-5 bosdizgi.c program. #include <stdio.h> #include <string.h> int main(void) { char s1 [ ] = ""; char s2 [ ] = "\0"; printf("eleman sayisi, s1 : %d \n", sizeof s1 / sizeof s1[0] ); printf("eleman sayisi, s2 : %d \n", sizeof s2 / sizeof s2[0] ); printf("strlen(s1) : %d, strlen(s2) : %d\n", strlen(s1), strlen(s2) ); return 0; } kt eleman sayisi, s1 : 1 eleman sayisi, s2 : 2 strlen(s1) : 0, strlen(s2) : 0

4.4 C nilemcisi
C derleyicisi, kaynak dosyalar ilk olarak aslnda C dilinin paras olmayan baz zel komutlar iin tarar. # iareti ile balayan bu zel komutlar (directives), derleme ileminin nileme olarak adlandrlan ilk admnda, C nilemcisi (C preprocessor) tarafndan ilenir. nilemci komutlar unlardr: kaynak dosya iine balk dosyalarnn alnmas iin kullanlan #include; sembolik sabitler ve makro tanmlamak iin kullanlan #define ve kaynak dosya iinde baz satrlarn derleyici tarafndan belli koullara bal olarak grlmesini salayan #if, #endif, #elif ve #else ve daha nce tanmlanm bir makro ismini iptal eden #undef komutlardr.

#include komutu
Kaynak dosya iinde bulunan her,
#include <dosya>

yada
#include "dosya"

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-45

satr, nilemci tarafndan balk dosyas dosya'nn metni ile deitirilir. Balk dosyalar (include files yada header files) sk sk kullanlan #define satrlarn yada extern bildirimleri ierir ve bunlarn tekrar yazlmasn nlemek amacyla kaynak metin iine #include nilemci komutu yerletirilerek alnrlar. #include satrlar kaynak metin iinde ierdikleri bilgilerin kullanmndan nce herhangi bir yerde bulunabilirler. Fakat genel olarak balk dosyas isminden de anlalaca gibi kaynak metnin ilk satrlar #include satrlardr. #include ile kaynak metin iine alnan bir dosya baka #include satrlar ierebilir. Standart ktphane fonksiyonlarnn prototiplerini ve baz standart makrolar ieren balk dosyalar sistem balk dosyalar yada standart balk dosyalar olarak adlandrlr. rneklerin ilk satrnda #include komutuyla, kullanlan ktphane fonksiyonlarnn prototiplerini ve makrolar ieren standart giri/k balk dosyas stdio.h'nin programlar iine alnmas saland. Dosya ismi, al parantezler (< ve >) ile snrlanm ise dosya dosyas sistem balk dosyalarnn bulunduu yer olarak belirlenen fihristte (sistem include fihristi) aranr. Bu i iin derleyiciler genel olarak iletim ortamndaki bir deikene (environment variable) atanan fihrist yolu bilgisini kullanr. Aadaki #include satrndaki x.h balk dosyas, sistem balk dosyalarnn bulunduu fihristteki sys alt-fihristinde aranr (DOS iletim sisteminde fihrist ayrac ters kesme iaretidir. Ayrca baz dier iletim sistemlerinde, dosya isimlerinde byk-kk harf ayrm yapld dikkate alnmaldr):
#include <sys\x.h>

Dosya ismi, ift trnaklar arasnda bulunuyor ise dosya dosyas bulunulan fihristte aranr; dosya ismi, bulunulan fihriste gre (relative path) yada kk fihristine gre (full path) verilen fihrist yolu bilgisini ierebilir. rnek olarak aadaki include satrlar verilebilir;
#include "..\baslik.h"

yada
#include "c:\derle\hata.msg"

#include kullanm bir programn tm kaynak dosyalarnn ayn tanm ve bildirimleri iermesini salar. Balk dosyasnda deiiklik yapldktan sonra bu dosyay alan tm kaynak dosyalar tekrar derlenmelidir. Balk dosyalar genel olarak .h uzantldr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-46

#define komutu
Bu komut kullanlarak program yazmada kolaylk salayan sembolik sabitler ve makrolar tanmlanabilir. #define kullanlarak sembolik sabit tanm aadaki ekilde yaplr:
#define isim degistirilecek_metin

#define komutu, sabit ismi isim ve degistirilecek_metin boluk yada tab ile ayrlr. isim bir deiken ismi ile ayndr; degistirilecek_metin ise herhangi bir metin olabilir. Kaynak metin iinde #define satrn izleyen tm satrlardaki isim'ler, degistirilecek_metin ile deitirilir. Bir #define satr daha nceden tanmlanm isimleri ierebilir. Aadaki satrda, 5 deeri yerine kullanlmak zere SATIRSAYI sembolik sabiti tanmlanr:
#define SATIRSAYI 5

Sabit saylar yerine #define ile tanmlanan sembolik sabitler kullanlarak program kodunun daha kolay anlalr olmas salanabilir. rnein yukarda tanmlanan sembolik sabit SATIRSAYI kullanlarak aadaki for dngs oluturulabilir:
for ( satir = 0; satir < SATIRSAYI; satir++ ) ...

Bu dngde satir deikeninin son deerinin satr says snr olduu aka bellidir. Ayrca satr saysnda deiiklik yaplmas gerektiinde, bu deiikliin tm program yerine sadece #define satrnda yaplmas yeterli olacaktr. Makro satr ok uzun ise \ ile izleyen satrdan devam edilebilir:
#define UZUNDIZGI "Bu bir denemedir" \

\ karakteri ile satr sonunu iaretleyen NL (newline) karakteri gizlenir ve bu satrn tek bir satr olarak ilem grmesi salanr. ok uzun makrolar bu yolla birka satra blnebilir. Deitirme ilemi ift trnaklar ile snrl dizgilerde gereklemez. rnein tanmlanan bir abc ismi iin aadaki puts deyiminde herhangi bir ilem yaplmaz:
puts( "abc" );

Program iinde bulunan bir abcd dizgisinde de herhangi bir ilem yaplmaz. Bu ilemin gereklemesi iin program metni iinde boluk karakterleri ile snrl abc ismi aranr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-47

#define kullanlarak argman kabul eden makrolar tanmlanabilir. rnein iki argmanndan byk olan argmann deerini dndren Maksimum makrosu aadaki gibi tanmlanabilir (makro ismi ile sol parantez arasnda boluk bulunmamaldr):
#define Maksimum( x, y ) ((x) > (y) ? (x) : (y))

Maksimum makrosu kullanld program satrnda nilemci tarafndan aldnda, x ve y argmanlarnn yerini programda girilen argmanlar alr. Bu makro ayn ilevi yerine getiren bir fonksiyondan farkl olarak, argmanlarn her ikisinin de ayn tipte olmas koulu ile farkl tiplerde argmanlar ile arlabilir. Argman olarak verilen ifadelerin iki kez ilendii dikkate alnacak olursa, ++ yada -- gibi operatrlerle oluturulan ifadeler argman olarak kullanlmamaldr. Ayrca ifadelerin ileni srasnn nemli olabilecei dikkate alnarak ilave parantezler ile ncelikler kontrol edilmelidir. rnein aadaki SayiKare makrosu hataldr:
#define SayiKare(x) x*x

Bu makro i + 3 gibi bir ifade ile arldnda hata oluur. Bu makro, hatasz almas iin ilave parantezler kullanlarak aadaki ekilde tanmlanmaldr:
#define SayiKare(x) (x) * (x)

degistirilecek_metin iinde argman isminden nce bulunan # iareti, argmann makro almnda ift trnaklar arasna yerletirilmesini salar.
#define Print( x ) printf( #x " : %d\n", x )

Yukardaki Print makrosu i argman ile arldnda alm aadaki gibi olur:
printf( "i" " : %d\n", i ); yada printf( "i : %d\n", i );

nilemci operatr ##, makro alm srasnda argmanlar birletirir. Aadaki makro den, ve eme argmanlar ile arldnda deneme ismini verir:
#define Ekle( a, b ) a ## b

Programlarda makrolarn kullanm ok kolaylk salar. Standart balk dosyalarnda pek ok makro tanm bulunur.

#if komutu
Koul deyimleri kullanlarak nileme kontrol edilebilir. Bylece derleme srasnda belli koullara bal olarak belli program satrlarnn seilerek programa dahil edilmesi

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-48

salanabilir. Bu amala nilemci komutlar #if, #endif, #else ve #elif ile oluturulan deyimler kullanlr:
#if ifade1 ... #elif ifade2 ... #elif ifadex ... #else ... #endif

Burada ifade1, ..., ifadex sabit tamsay ifadelerdir ve ilendikten sonra herhangi biri sfr harici bir deer veriyor ise izleyen #elif (else-if), #else yada son olarak deyimi kapatan #endif satrna kadar olan satrlar programa dahil edilir. #if komutunda kullanlan ve nilemci operatr defined ile oluturulan defined isim ifadesinin deeri, eer isim tanml ise 1'dir; aksi taktirde 0'dr. Bu operatr defined yada !defined olarak kullanlabilir:
#if !defined isim ... #endif

yada
#if defined isim ... #endif

#if defined isim satr yerine #ifdef isim; #if !defined isim satr yerine ise #ifndef isim kullanlabilir. Aadaki satrlarda nilemci komutlarnn kullanm rneklenmitir:
rnek 4.4-1 onisle.c program. #include <stdio.h> #include <ctype.h> #define #define #define #define MODUL1 MODUL2 MODUL3 MODUL4 1 2 3 4 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-49

...rnek 4.4-1 kt devam


#define PROG MODUL3

#if !defined DENEME #define DIZGI1 "DENEME tanimli degil" #endif #define DENEME #if defined DENEME #define DIZGI2 "DENEME tanimlidir" #endif PROG #define #elif PROG #define #elif PROG #define #else #define #endif #if == MODUL1 ISIM "MODUL1" == MODUL2 ISIM "MODUL2" == MODUL3 ISIM "MODUL3" ISIM "MODUL4"

int main(void) { puts( DIZGI1 ); puts( DIZGI2 ); puts( ISIM ); printf( "L : %s\n", islower( 'L' ) ? "buyuk harf" : "kucuk harf" ); /* islower makrosu */ #undef islower printf( "L : %s\n", islower( 'L' ) ? "buyuk harf" : "kucuk harf" ); /* islower fonksiyonu */ return 0; } kt DENEME tanimli degil DENEME tanimlidir MODUL3 L : kucuk harf L : kucuk harf

#undef komutu
Standart C ktphane fonksiyonlarnn bildirimleri balk dosyalarnda bulunur. Standart balk dosyalarnda bu fonksiyonlardan bazlar ayn zamanda yine ayn isimde makrolar olarak tanmlanmlardr. Bu makrolar kullanldklar satrlarda nilemci tarafndan aldklarnda fonksiyon arsndan daha hzl alan C ifadelerine dnrler ve fonksiyon ismini gizlerler. Fakat makrolar programlarda hata giderme ve izleme
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-50

ilemleri yaplrken sorun olabilir. Makro karl yerine fonksiyonun kendisini kullanmak iin #undef nilemci komutu kullanlarak standart balk dosyasndaki makro tanm iptal edilebilir.

4.5 C Programlarn ayr ayr Derleme ve Balama


Herhangi bir C programnn oluturulmas, bir editr program kullanlarak kaynak kodun yazlmas ve bir dosyaya saklanmas ile balar. Bu dosya, C kaynak dosyas olarak adlandrlr. Bir programn farkl ksmlar, farkl kaynak dosyalara yerletirilebilir ve bu dosyalarn herbiri ayr ayr derlenebilir. C programlar fonksiyon haline getirilebilecek ksm kalmayncaya kadar blnebilir. Tek bir kaynak dosyada yer alan program, birka kaynak dosyaya blmenin baz avantajlar vardr. Programn herhangi bir paras zerinde yaplan hata dzeltme yada deiiklik sonras derleme, programn sadece ilgili ksmnda yaplabilir. Bu yolla zellikle byk programlar zerinde alrken zaman kazanlm olur. Ayrca zerindeki tm almalarn tamamland fonksiyonlar, dierleri zerindeki almalar devam ederken tekrar tekrar derlemek gerekmez. C kaynak dosyas yada dosyalar, altrlabilir program haline iki aamada getirilir: Derleme (compilation): Bu aamada derleyici program, C kaynak dosyalarn object dosyalara evirir. Bir object dosyas (object-code file) binary kodlardan oluur, fakat henz altrlabilir durumda deildir. C kaynak dosyalar, .c uzantl dosyalardr. Object dosyalar ise, DOS iletim sisteminde .obj uzantl, UNIX iletim sisteminde .o uzantl dosyalardr. Balama (linking): Bu aamada, linker olarak adlandrlan program (yada linkage editor), derleme srasnda oluturulan object dosyalarn standart ktphaneler (programlarda kullanlan standart ktphane fonksiyonlarna ait kodlar ieren .lib uzantl dosyalar), programc tarafndan belirtilen dier object dosyalar ve ktphaneler ile birletirerek altrlabilir program dosyasn oluturur. Bu dosya (DOS iletim sisteminde .exe uzantl, UNIX iletim sisteminde ise .out uzantl yada uzantszdr), iletim sistemi altnda altrlmaya hazrdr. Yukarda da belirtildii gibi bir C programn oluturan fonksiyonlarn ve external deikenlerin ayn anda derlenmesi gerekmez. Programn kaynak kodu birka dosyaya yerletirilebilir, ayrca bu dosyalar daha nce derlenmi ktphane fonksiyonlar ile balanabilirler. Fakat bu ilemlerin hatasz gereklemesi dosyalar arasnda paylalan verilerin bildirimlerinin uygun ekilde dzenlenmesine baldr. Bunu salamak iin balk dosyalar kullanlr. Fonksiyon prototipleri, sembolik sabitler (#define ile tanmlanan) ve paylalan verilere ait bildirimler .h uzantl bir balk dosyasna yerletirilir. Bu dosya ihtiya duyulan kaynak dosyalar iine #include nilemci komutu kullanlarak dahil edilir. Her kaynak dosyann sadece ihtiya duyduu bilgilere erimesi iin ayr bir balk dosyas oluturulabilir. Fakat bu pratik bir yol deildir. Genellikle
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-51

belli bir program byklne kadar ihtiya duyulan tm bilgileri ieren tek bir balk dosyasnn bulunmas daha pratiktir. Fakat kapsaml projelerde pek ok balk dosyas bulunabilir. Herhangi bir kaynak dosya (modl) iinde bir external deiken yada fonksiyona, bildirildii noktadan dosya sonuna kadar her yerde eriilebilir. Fakat external deikene, tanm ncesinde eriim gerekiyor ise yada bu deiken kullanld dosyadan farkl bir kaynak dosyada tanmlanm ise extern bildirim gereklidir. extern bildirimler link programna bilgi verir. Ayn kural fonksiyonlar iin geerli olmadndan dolay herhangi bir kaynak dosyada tanmlanan bir fonksiyona, extern bildirim olmadan dier kaynak dosyalardan eriilebilir. Burada bir deikenin bildirimi ve tanm arasndaki fark nemlidir. Bildirim deikenin ismini, tipini ve dier zelliklerini belirtir. Tanm ise bildirimi de ierir ve ayn zamanda derleyici yada linker tarafndan deiken iin bellekte yer ayrlmasn salar. Tanmlar belirtilen veriler iin gerekte bellek alan ayrlmasn salar; bildirimler ise derleyiciye baka bir yerde tanmlanm verinin zellikleri hakknda bilgi vermek iin oluturulur. ANSI standardnda kaynak program oluturan tm modller arasnda bir external deikenin sadece tek bir tanm bulunabilir; tanm ieren dosyada ve dier dosyalarda extern bildirimler bulunabilir. Bu durum bir global (external) deikenin biri hari tm bildirimlerinin nne extern yerletirilerek gerekletirilebilir. Fakat her zaman bu kadar basit olmayabilir. Birden fazla modlden oluan programlar genellikle ok sayda veriyi paylar ve bazlar extern ieren ve bazlar iermeyen bildirimlerin ayr listelerini ayr modllerde bulundurmak kolay deildir. Tercih edilen yol yukarda bahsedildii gibi tm verilerin tekbir .h dosyasnda bulundurulmasdr. Fakat ANSI standardnda belirtildii gibi eer bildirimler/tanmlar ayr ayr dosyalarda farkl yazlmak durumunda ise tek bir balk dosyas kullanlamaz. Bu durumda tek bir balk dosyas kullanm mmkn olmayabilir. Fakat bunun pratik bir zm vardr. Aadaki satrlar verilerin sadece ana modlde tanmlanm olmasn ve dier modllerde de extern olarak bildirilmi olmasn garanti eder.
.h dosyas ... #ifdef ANA_MODUL #define EXTERN #else #define EXTERN extern #endif ... EXTERN bildirimler... ...

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-52

dosya1.c ... #define ANA_MODUL ... EXTERN bildirimler... ...

Sembolik sabit kullanlarak kritik bildirimler iin extern anahtar kelimesinin kullanm kontrol edilir. Eer dosyada ANA_MODUL tanm var ise o zaman programn ana modl derleniyor demektir ve sembolik sabit EXTERN hi bir ey anlamna gelmez. Aksi taktirde EXTERN, extern olarak tanmlanr ve bulunduu satrlar ise external verilerin bildirimi olarak i grr. Ana modl derleniyor iken tanmlarn oluturulmasn salamak iin balk dosyasnn dahil edildii satr ncesine #define ANA_MODUL yerletirilir. Programn dier modlleri bu tanm iermez. Tanm ve bildirim ayrm konusunda derleyiciler farkllk gsterebilir. Baz linker programlar (balayclar) bir programn kaynak dosyalar arasnda ayn veri elemanlarnn birden fazla tanmnn bulunmasna izin verirler. Fakat birden fazla ilk deer atama bulunamaz, aksi taktirde link srasnda hata oluur. Bu durum, tek bir .h dosyas kullanmna izin verdii iin gelitirme ilemini basitletirse de, programn tanabilirliini azaltr. Dosyalar ayr ayr derlendii iin bir fonksiyonun gerek adresi ile ar arasndaki iliki ve global verilere eriim, altrlabilir program kodunun oluturulmas srasnda linker tarafndan kurulan balar (link) ile gerekleir. Linker bu ii yaparken derleme srasnda object dosyalar iine yerletirilen bilgileri kullanr. Sonu olarak balama (linking), farkl fonksiyonlar yada farkl kaynak dosyalar iinde ayn deiken isminin kullanm ile ayn bellek alanna eriimin gereklemesini salar. Bir modl, bir baka modlde tanmlanm bir isme eriebiliyor ise bu iliki, d eriim (external reference) olarak adlandrlr. D eriimler linker tarafndan oluturulur. Bir ismin (deiken yada fonksiyon ismi) ba zellii, bu ismin programn hangi ksmlarnda kullanlabileceine, dolaysyla link programnn bu isim zerinde yapaca ilemlere karar verir. Bir deiken isminin balanma zellii, nceki blmlerde anlatld gibi baz anahtar kelimelerle yada program iinde bulunduu yer ile belirlenebilir. Bir isim, i yada d balanma zelliine (internal yada external linkage) sahip olabilir veya hibir balanma zellii bulunmayabilir (no linkage). altrlabilir program oluturmak zere derlenip balanma ilemi yaplm bir grup kaynak dosya iinde, d balanma zelliine sahip bir deiken isminin kullanm, ortak bir bellek alanna eriimi gerekletirir. Programn farkl modllerinde bulunan ayn isimli deikenler, ayn bellek
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-53

alannda bulunurlar. Dolaysyla farkl dosyalarda bu deikenlerin kullanm ayn veriye eriim anlamndadr. Tek bir kaynak dosya iinde, i balanma zelliine sahip bir deiken isminin kullanm da ayn ekilde ortak bir bellek alanna eriim anlamna gelir. Bir deiken ismi, bu iki balanma zelliinden herhangi birine sahip olmayabilir (no linkage). Bu durumda sadece tanmland blok iinden eriim mmkndr. Bir programdaki balanma zellii olmayan isimler, blok eriimli (blok ile snrl grnrlk alan) fakat extern ile bildirilmeyen isimlerdir (fonksiyon parametreleri, fonksiyon ve deiken isimleri hari herey; goto etiketi, yap etiketi, yap eleman ismi, typedef ismi, yada enum sabiti). Global deikenler ve fonksiyonlar (tm bloklarn dnda ve static anahtar kelimesi olmadan bildirilen), programdaki tm kaynak modllerden eriilebildikleri iin (grnrlk alanlar programn tamamdr; program scope) kendiliinden d balanma zelliine sahiptirler. Bir global deiken yada fonksiyon, static anahtar kelimesi ile bildirildiinde bulunduu dosya ile snrl grnrlk alanna (file scope) sahip olduu iin i balanma zelliine sahiptir. Fakat static anahtar kelimesinin, blok ii ve d kullanmna dikkat etmek gerekir. nk blok ile snrl grnrlk alanna (block scope) sahip bir deikene static uygulandnda, sadece varolma sresi etkilenir ve static sreli olur. Tm bloklarn dnda bulunan (file scope) bir deikene uygulandnda ise bu deikenin balanma zellii deierek d balanmadan i balanmaya dnr. Aadaki rnekte yer alan iki ayr kaynak dosyada, farkl ba tipleri gsterilir. Bu iki dosya, tek bir altrlabilir program oluturur. Derleme ve birletirme ilemleri, iletim ortamna gre deiir.
rnek 4.5-1 bagla1.c ve bagla2.c program.
/* * bagla1.c */

#include <stdio.h> static void fa( int ); int main( void ) { extern void fa( int ); /* internal linkage */ extern void fb( void ); /* external linkage */ fa( 123 ); fb( ); return 0; } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-54

...rnek 4.5-1 devam


int i = 13; static void fa( int i ) { for (;;) { double i = 12.0; printf("%f\n", i ); goto fa_son; } fa_son: printf("%d\n", i ); }
/* * bagla2.c */ /* external linkage */ /* internal linkage */

/* no linkage

*/

/* no linkage

*/

#include <stdio.h> extern int i; static int j = 45; void fb( void ) { printf("%d\n", i ); printf("%d\n", j ); } kt 12.000000 123 13 45
/* external linkage /* internal linkage /* external linkage */ */ */

fa fonksiyonu, static ile bildirildii iin sadece 1. kaynak dosya iinde eriilebilir. Bu nedenle i balanma zelliine sahiptir. lk dosyada tanmlanan i deikeni, static olarak bildirilmedii iin d balanma zelliine sahiptir ve ikinci dosyada ayn isimle extern kullanlarak bildirilen bir deiken buradaki deere eriebilir. fa iinde bildirilen double i deikeninin balanma zellii yoktur nk blok iinde ve extern olmadan bildirilmitir. kinci dosyada, static belirleyici ile bildirilmedii iin fb fonksiyonu d balanma zelliine sahiptir. Dolaysyla ilk kaynak dosyadan arma mmkn olur. kinci dosyada bulunan j deikeni static ile bildirildii iin i balanma zelliine sahiptir ve dier dosyalardan eriim mmkn deildir.
extern void fa( int ); /* internal linkage */ extern void fb( void ); /* external linkage */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-55

Yukardaki extern bildirimler, dosya iinde grnrle sahip ve tm bloklarn dnda tanmlanm (file scope) bir isim ile balant yapmak anlamna gelir. main iindeki fa fonksiyonu bildirimi ayn dosyadaki ayn isimli fonksiyon ile balanr ve bylece i ba oluturur. main bloundaki extern bildirimler ncesinde fa iin static bildirim yaplmaldr nk derleyici bunun d balanma zelliine sahip olduklarn kabul edebilir ve ayn dosyada daha sonra bulunan gerek fonksiyon tanmlar ile uyumaz. Derleyici fb'nin d balanma zelliine sahip olduunu kabul eder. Aadaki satrlarda bir ka kaynak dosyadan oluan bir programda, veri paylam iin dosya iinde tm bloklarn dnda bulunan eitli bildirim ve tanmlar incelenmitir:
Dosya1: int a = 1; Dosya2: extern int a;

a deikeni dosyalar arasnda paylalr ve ilk deeri 1'dir. Dosya1: extern int a; ... int a; Dosya2: extern int a;

a deikeni dosyalar arasnda paylalr ve ilk deer olarak 0 tar. Dosya1: int a; Dosya2: int a;

Hatal tanm. (baz derleyiciler izin verir) Dosya1: int a = 1; Dosya2: int a = 2;

Linker hata verir. ki kez tanmlama giriimi. Dosya1: static int a = 1; Dosya2: int a = 2; Dosya3: extern int a;

Dosya1'de bulunan a deikeni dier dosyalarda bulunan deikenler ile ilgisizdir. Dosya2 ve Dosya3 ilk deeri 2 olan a deikenini paylar. Dosya1: Dosya2: Dosya3: static int a = 1; int a = 2; extern int a; extern int a; Yukardaki bildirim/tanmlar ile ayndr. Dosya1: extern int a; Dosya2: extern int a;

Hata. a deikeni tanmlanmamtr.

Standart C ktphanesi standart giriten okuyan (klavye) ve standart ka yazan (ekran) pek ok hazr fonksiyon ve makro tanm ierir. Kitaptaki rnek programlarda klavyeden girilen bilgileri formatl olarak almak iin standart ktphane fonksiyonu scanf
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

4-56

kullanld. Ayrca eitli bilgileri ekrana formatl olarak listelemek iin yine standart ktphane fonksiyonu printf kullanld. C ktphanesinde karakter giri/k ilemleri iin getchar ve putchar makrolar bulunur. Bu makro ve fonksiyonlarn kullanmna Blm 9'da yer verilmitir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-1

BLM 5: Adres Deikenleri


Adres deikenleri (pointer variable yada ksaca pointer) C dilinin gl olduu konulardan biridir. Adres deikenleri kullanlarak verimli ve ksa C programlar oluturulabilir. C dilinde adres deikenleri ve diziler birbirleri ile ok yakn ilikilidir. Bu blmde adres deikenlerinin bildirimi ve programlarda kullanm anlatlacaktr. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-3

5.1 Adres Deikeni Bildirimi


Deiken bildirimleri ieren bir program derlendiinde, bellekte deikenlerin her biri iin bildirimde yer alan tipte verileri saklayabilecek byklkte ayr bir alan ayrlr. Ayrca bellekte ayrlan her alann (dolaysyla deikenin) bir bellek adresi vardr. Programda deikene atanan deerler bu adres kullanlarak eriilebilen bellek alannda saklanr. ekil 5.1-1'de, bildirilen deiken iin bellekte ayrlan alanlar sembolik olarak gsterilir:
ekil 5.1-1 c, i, ve n deikenlerinin sembolik bellek grnm.

: c: :

Bellek 1 byte

Program :

: i: : : n:
4 byte 2 byte

...
char c; short i; long n;

...

ekil 5.1-1'deki kutularn her biri 1 byte bellek alann temsil eder. Buna gre char tipindeki c deikeni iin 1 byte bellek alan ayrlmtr. Bu deikene 1 byte byklnde deerler atanabilir. Ayn ekilde, short tipindeki i ve long tipindeki n deikenleri iin srasyla 2 ve 4 byte bellek alanlar ayrlmtr. Sembolik olarak gsterilen bu bellek alanlarnn her birinin ayr bir bellek adresi vardr. C dilinde, bellekte tutulan deerlerin bellek adreslerini almak iin adres operatr (address operator) & kullanlr. Adres operatr bir unary operatr olduu iin tek operand kabul eder ve herhangi bir deerin atanabilecei ve verilerin saklanabilecei bellek alanna, dolaysyla bellek adresine sahip deikenlere ve dizi elemanlarna uygulanabilir (ayrca izleyen blmlerde anlatlacak olan yap deikenlerine de uygulanabilir). Bellekte tutulmadklarndan ve dolaysyla bellek adresleri bulunmadndan sabit deerlere, register deikenlere ve C operatrleri ile oluturulan ifadelere uygulanamaz.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-4

NOT: Nesne, lvalue ve rvalue C programlar, programc tarafndan tanmlanan ve programn almas srasnda var olan nesneler (deikenler, diziler, sabitler gibi) ierir. Programda bulunan bildirimler ve deyimler aracl ile bu nesneler oluturulur ve ilenir. Bir nesne (data object yada object) deerlerin saklanabilecei ve daha sonra alnabilecei bir bellek alandr. Nesnenin zellikleri (attributes: nceki blmlerde anlatlan saklama snf ve tipi) saklayabilecei deerlerin saysn, tipini ve bellek dzenini belirtir. Nesnenin ierdii deer (data value) say, karakter yada bir baka nesnenin adresi olabilir ve bir bit grubu (ikili say sisteminde) ile temsil edilir. Bir nesne tek bir deer (scalar; rnek olarak bir basit deiken) yada deer grubu (aggregate; rnek olarak dizi ve yap deikeni) ierebilir. Sonu olarak, bir nesne bilgisayar belleindeki bir bilgi saklama alan; deer ise belli bir bit grubudur. Bir deiken (variable), programc tarafndan tanmlanan ve isimlendirilen bir nesnedir. Deikenin deeri programda var olduu sre ierisinde atama ilemi ile deitirilebilir. Deiken, nesnenin zel bir eklidir ve dolaysyla bir deiken iin deikenin deeri (rvalue), deikenin yeri (lvalue), deikenin ismi (identifier) yada deikenin tipi terimleri kullanlabilir. lvalue (left value), bir atama deyiminin solunda kalan ifade yada isimdir ve bir nesneye eriir. Deikenler, dizi elemanlar ve adres deikenleri lvalue'dr. &, ++ ve -- operatrleri ancak lvalue ifadelere uygulanabilir. rvalue (right value) ise bir atama deyiminin sanda bulunan ifadedir ve deeri atama deyiminin solundaki lvalue ile eriilen nesneye atanr. Bir rvalue ifadesi herhangi bir nesne eriimi salamayabilir. Dizi ismi, fonksiyon, sabit ve lvalue olan her ifade bir rvalue'dr. Aada tamsaylara iaret eden p adres deikeni, tamsay deiken i ve tamsay deerlerden oluan a dizisi ile oluturulan deyimler kullanlarak lvalue ve rvalue ifadeler rneklenir:

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-5

lvalue ifadeler

rvalue ifadeler

*p = 10; i = *p; *( a + 3 ) = 22; p = &a[5]; a[5] = 7;


lvalue

+ p; +

Adres operatr'nn genel kullanm ekilleri aada verilmitir:


&degisken_ismi

yada
&dizi_ismi[ indeks ]

dizi_ismi[indeks] ifadesi, herhangi bir dizinin tamsay indeks ile belirlenen elemandr. Bellek adresleri donanma bal olarak 2 yada 4 byte byklnde deerlerdir. Adres operatr (&) kullanlarak yukardaki ekilde alnan adres deeri, 2 yada 4 byte byklnde adres deerlerini saklayabilecek adres deikenine (gsterge deikeni yada ksaca gsterge olarakta adlandrlr) atanabilir. Adres deikenleri, tadklar adres deerlerinin kullanlmasna ve bu deerler zerinde ilemler yaplabilmesine olanak salar. Aadakiler, adres operatr ile oluturulabilecek geerli C deyimleridir:
pi = &i; adrDizi = &Dizi[10];

lk deyimde daha nce uygun bir veri tipi ile bildirilmi i deikeninin adres operatr kullanlarak alnan bellek adresi, adres deikeni pi'ye atanr. kinci deyimde ise Dizi dizisinin 10 no.'lu elemannn (11. eleman) adresi, adrDizi adres deikenine atanmtr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-6

rnek 5.1-1'de adres operatr kullanlarak Dizi dizisinin elemanlarnn bellek adresleri listelenir:
rnek 5.1-1 adresop1.c program. #include <stdio.h> int main(void) { int Dizi[ ] = { 0, 1, 2 }; int i; for ( i = 0; i < 3; i++ ) printf("Dizi[%d] icin bellek adresi : %u\n", i, &Dizi[ i ] ); return 0; } kt Dizi[0] icin bellek adresi : 3458 Dizi[1] icin bellek adresi : 3460 Dizi[2] icin bellek adresi : 3462

Aada adres operatr'nn hatal kullanmlar rneklenmitir. Bu deyimler, derleme srasnda hataya sebep verir ve program derlenemez:
/* adres operatr register saklama snfna sahip deikenlere uygulanamaz. */ register short i; short *pi; pi = &i; pi = &( i + 5 ); pi = &++i; pi = &4; /* ifadelerin adresi alnamaz. /* ifadelerin adresi alnamaz. /* adres operatr sabitlere uygulamaz. */ */ */

rnek 5.1-2'de kullanlan ve bundan sonra da programlarda ok sk olarak kullanlacak olan sizeof operatr, ifade'nin bykln byte olarak dndrr. Dndrd deer standart C ktphanesinde iaretsiz tamsay olarak tanmlanm olan size_t tipindedir ve bu tip kullanlarak bildirilen bir deikene atanabilir:
size_t i; i = sizeof ifade;

ifade, bir deiken ismi (basit deikenin, adres deikeninin, dizinin yada yapnn ismi) yada (tip-belirleyici) eklinde oluturulan bir tip-evirme (type-cast) ifadesidir. Dizi ismine uygulandnda dizinin tamamnn byte olarak bykln; dizgi sabitine yada deikenine uygulandnda ise toplam bykl dizgi sonunu iaretleyen '\0' karakteri de dahil olmak zere verir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-7
NOT:

sizeof operatr (unary operator : yani tek operand alr), daha sonraki blmlerde anlatlacak olan yap tipine yada yap deikeni ismine uygulandnda dndrd byte says gerek byte (donanma ve derleyiciye bal olarak bellek dzeni gerei yap iinde bulunabilecek boluklarn da (padding bytes) dahil edildii) miktardr. sizeof bir derleme-zaman operatrdr (compile-time operator). Dizi boyutlar derleme srasnda belli olduu iin, sizeof kullanlarak dizinin eleman says derleme srasnda saptanabilir. sizeof operatr dizgi uzunluunu '\0' dahil olmak zere verir. Standart C ktphanesinde yer alan strlen fonksiyonu ise s dizgisinde bulunan karakterlerin saysn dizgi sonunu iaretleyen '\0' karakteri hari olmak zere verir: size_t strlen( const char *s ); /* string.h */

Aadaki programda sizeof operatrnn eitli uygulamalarna yer verilmitir: /* * sizeof.c programi. */ #include <stdio.h> #include <string.h> #define DiziBoy(s) (sizeof s / sizeof s[0]) int main(void) { long n; int j[] = { 0, 1, 2 }; static int jj[ DiziBoy(j) ]; char *s = "1234"; char t[] = "1234"; size_t ELSAYI = sizeof j / sizeof j[0]; sizeof n, sizeof j, sizeof jj printf( "-sizeof- s : %u byte, t : %u byte\n", sizeof s, sizeof t printf( "-strlen- s : %u karakter, t : %u karakter\n", strlen(s), strlen(t) printf( "char : %u, int : %u, long : %u byte \n", sizeof (char), sizeof (int), sizeof (long) printf( "j dizisinin eleman sayisi : %u \n", ELSAYI ); printf( "jj dizisinin eleman sayisi : %u \n", DiziBoy( jj ) ); printf( "j dizisi int[3] tipindedir : %u byte\n", sizeof (int[3]) ); ELSAYI = sizeof t / sizeof t[0]; printf( "-sizeof- t dizisinin eleman sayisi : %u \n", ELSAYI ); printf( "sizeof 2L : %u byte, sizeof 2 : %u byte\n", sizeof 2L, sizeof 2 ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman printf( "n : %u byte, j : %u byte, jj : %u byte\n", ); ); ); );

5-8

sizeof.c devam printf( "sizeof \"1234\" : %u byte\n", printf( "strlen(\"1234\") : %u karakter\n", return 0; } kt n : 4 byte, j : 6 byte, jj : 6 byte -sizeof- s : 2 byte, t : 5 byte -strlen- s : 4 karakter, t : 4 karakter char : 1, int : 2, long : 4 byte j dizisinin eleman sayisi : 3 jj dizisinin eleman sayisi : 3 j dizisi int[3] tipindedir : 6 byte -sizeof- t dizisinin eleman sayisi : 5 sizeof 2L : 4 byte, sizeof 2 : 2 byte sizeof "1234" : 5 byte strlen("1234") : 4 karakter sizeof "1234" ); strlen("1234") );

rnek 5.1-2 adresop2.c program. #include <stdio.h> int main(void) { long n = 10; printf( "n degiskeni : %u byte, bellek adresi : %u\n", sizeof ( n ), &n ); printf( "adres degeri : %u byte.\n", sizeof ( &n ) ); return 0; } kt n degiskeni : 4 byte, bellek adresi : 3492 adres degeri : 2 byte.

ktda grld gibi, long tipinde tanmlanan n deikeni iin 4 byte bellek alan ayrlmtr. Bu alann adresi (&n), 2 byte byklnde bir tamsaydr (3492). Bu nedenle programn derlendii ve altrld ortamda adres deikenleri 2 byte byklndedir (farkl bir donanmda 4 byte olabilir).

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-9

ekil 5.1-2 n deikeninin sembolik bellek grnm.


n deikeninin bellek adresi

: n:
3492

Bellek

10

4 byte

n deikeninin deeri

Bir deikenin deerine, deikenin bellek adresi kullanlarak eriilebilir. Adresler zerinde aritmetik ilemler yapmak mmkndr. C dilinde, bu uygulamalar gerekletirebilmek iin adres deikenleri kullanlr. rnek 5.1-3'de, long *p; deyimi ile p adres deikeni bildirilir. Program derlendiinde long tipindeki n ve k tamsay deikenleri iin herbiri 4 byte byklnde, srasyla 3518 ve 3522 adresli bellek alanlar ayrlr.
rnek 5.1-3 adresop3.c program. #include <stdio.h> int main(void) { long n; long k; long *p; n = 1650; p = &n; k = *p; printf( "adresler: &n : %u, &k : %u\n", &n, &k ); printf( "degerler: p : %u, *p : %ld, n : %ld, k : %ld\n", p, *p, n, k ); printf( "p : %u, n : %u, k : %u byte\n", sizeof p, sizeof n, sizeof k ); return 0; } kt adresler: &n : 3518, &k : 3522 degerler: p : 3518, *p : 1650, n p : 2, n : 4, k : 4 byte : 1650, k : 1650

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-10

Adres deikeni bildirim deyimi,


long *p;

ile p adres deikeni iin 2 byte byklnde bellek alan ayrlr. Bildirim deyiminde long veri tipi yer ald halde p adres deikeni iin 4 byte yerine 2 byte bellek alan ayrlmtr. n = 1650; atama deyimi ile n deikeni iin ayrlm olan bellek alanna 1650 deeri yerletirilir. zleyen satrda bulunan p = &n; deyimi ile n deikeninin adres operatr kullanlarak alnan bellek adresi (3518) p adres deikenine atanarak, p adres deikeninin n deikenine iaret etmesi salanr (ekil 5.1-3). Bylece p adres deikeni kullanlarak n deikeninin bellek alanna eriilebilir. Adres deikeni bildirim deyiminde kullanlan * iaretinin, k = *p; atama deyiminde de kullanld grlyor. Bu satrda p adres deikeninin iaret ettii bellek alannda bulunan deer alnarak (yani n deikeninin deeri olan 1650), k deikeninin bellek alanna kopyalanr. ktda da grld gibi, her iki deikenin de (n ve k) bu atama ilemi sonras deeri 1650 olur.
ekil 5.1-3 p adres deikeni.

*p

n:

3518 p

1650
4-byte

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-11

rnek programda, * operatrnn iki ayr kullanm yer alr:


long *p; bildirim deyiminde,

* operatr bildirim deyimlerinde adres deikeninin tipinin bir parasdr. Adres deikeni bildirim deyimi iki ekilde yorumlanabilir: p adres deikeninin indirek deeri bir long tamsaydr (1); p adres deikeni long * tipindedir (2):
long + *p
* operatr adres deikeninin indirek deerini verdii iin ( k = *p; atama deyiminde olduu gibi), *p ifadesi ile alnan deer long tamsaydr.

(1)

long * p ; long * + p
k = *p; atama deyiminde,
(2) p adres deikeni long * tipindedir. Yani long tamsay deikenlere iaret eder.

* operatr, C operatrleri ile oluturulan ifadelerde adres deikenine uygulanarak iaret edilen bellek alanndaki deere eriilir. Dolaysyla adres deikeninin indirek deerini verir. n deikeni, p adres deikeninin iaret ettii (gsterdii) deiken olarak adlandrlr. nk p'nin tad deer (3518) n deikeninin bellek adresidir. n deikeninin deeri olan 1650, adres deikeninin indirek deeri olarak adlandrlr. n deikeninin deerine indirek olarak eriim iin kullanlan *p ifadesinde yer alan * iareti de, indirek deer operatr (indirection yada dereferencing operator) olarak adlandrlr. ekil 5.1-4'de deikenlerin sembolik bellek grnmleri verilmitir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-12

ekil 5.1-4 p adres deikeni, n deikenine iaret eder.

: n : 3518
1650

Bellek

4 byte

k : 3522
1650

: : p:
3518

: ! Deikenlerin bellekteki bulunularnn sembolik olarak gsterildii ekillerde, deikenler bellekte bitiik olarak gsterilir (rnek olarak n ve k deikenleri). Fakat donanmn bellek dzenlemesinin bir gerei olarak (alignment) deikenler bellekte her zaman pepee bulunmayabilir.

Adres deikenleri iaret edecekleri deikenlerin tiplerine bal olarak herhangi bir temel tip ile bildirilebilir. Fakat adres deikeni bildirim deyiminde yer alan veri tipi (* iareti karldnda elde edilen temel veri tipi), adres deikeninin iaret edecei deikenin tipi ile ayn olmaldr. Bylece adres deikeninin hangi tipteki deikenlerin bellek adresini tayaca belirlenmi olur. Tipler farkl olduunda, derleme srasnda hata oluur.
NOT: ndirek deer operatr tek operand alr (unary operator) ve ift operand alan arpma operatr * (binary operator) ile kartrlmamaldr. zellikle, i *= j; gibi deyimler yanltc olabilir.

rnek 5.1-4'de int * tipinde pi adres deikeni, long * tipinde pl adres deikeni ve double * tipinde px adres deikeni bildirilir. Programda adres deikenlerinin tiplerine sizeof operatr uygulanarak byte saylar listelenir. ktda da grld gibi, bellekte i ve l deikenleri iin farkl byklklerde alanlar ayrlm olmasna ramen bu deikenlere iaret eden adres deikenleri iin ayn byklkte bellek alanlar ayrlmtr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-13

Bir bilgisayardaki btn adres deikenleri ayn byklktedirler (donanmna bal olarak 2 yada 4 byte). Sonu olarak adres deikeninin bellek alan bykl ve dzeni, iaret ettii deikenin tipine deil donanma baldr. Dikkat edilecek olursa ayrlan bellek alan int tipi deikenler iin ayrlan bellek alan ile ayn byklktedir.
ekil 5.1-5 Adres deikeni bildirim deyimi.
tip Adres deikeninin indirek deerinin tipi. Adres deikeninin hangi tipte deikenlere iaret edeceini belirtir. tip * Adres deikeninin tipidir ve adres deikeni iin ayrlan bellek alannn bykln etkilemez. *adres_degiskeni Bu ifade adres deikeninin indirek deerini verir.

tip * adres_degiskeni

adres_degiskeni Deiken ismi oluturma kurallarna uygun olarak verilen adres deikeni ismi. fadelerde adres deikeninin indirek deerinin bulunduu (iaret edilen) bellek adresini verir.

Programlarda grld gibi bir adres deikeni de bellekte saklanr ve dolaysyla deer atanabilecek bellek alanna ve bir bellek adresine sahiptir (lvalue). Bu nedenle adres deikenleri ile ++ ve -- operatrleri kullanlabilir ve hatta bir adres deikenine iaret eden adres deikeni bildirilebilir (bu konu izleyen blmlerde anlatlacaktr). Ayrca * operatr ile oluturulan *adres_degiskeni ifadesine de deer atanabilir (lvalue); ++ ve -- operatrleri uygulanabilir.
NOT: rnek programlarda adres deerleri ekrana listelenirken printf format dizgisinde %u format belirleyici kullanld. %u format belirleyici printf fonksiyonunun argman olan deerin, iaretsiz (-u-nsigned) tamsay tip olarak ilem grmesini salar. Bu durumda adres deerleri ekrana ondalk formatta yazlr. Fakat bir bellek adresi iaretsiz tamsay tipinde deildir; kendine zg bir tiptir. Bu programlarn oluturulduu donanmda bellek adresi ile bir int deer ayn byte byklnde olmasna karn, bir baka donanmda byte saylar eit olmayabilir. Sonu olarak adres deeri bir tamsay deildir ve bu deer kullanlarak belirli baz adres ilemleri yaplabilir. printf fonksiyonu adres deerlerinin derleyiciye bal formatta (genel olarak onaltlk saylar olarak) temsil edilebilmesi iin %p format belirleyicisine sahiptir. Fakat programlarda adres aritmetiinin anlalabilir olmas iin asnda ounlukla %u kullanlmtr. C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-14

rnek 5.1.4'deki *pi = 42; atama deyiminde adres deikeninin indirek deerinin (yani i deikeninin deeri) bulunduu bellek alanna *pi ifadesi ile eriilerek 42 deeri atanr. Programda ayrca pi = &j; atama deyimi ile j deikeni iin ayrlan bellek alannn adresi pi adres deikenine atanr. Bylece pi'nin, j deikenine iaret etmesi salanr. Bu durumda pi'nin indirek deeri 40 olur.
rnek 5.1-4 adresop4.c program. #include <stdio.h> int main(void) { int i = 10, j = 40, *pi; long l = 10, *pl; double x = 1.0, *px; pi = &i; pl = &l; px = &x; printf( "int : %u, long : %u, double : %u\n", sizeof (int), sizeof (long), sizeof (double) ); printf( "int * : %u, long * : %u, double * : %u\n", sizeof (int*), sizeof (long*), sizeof (double*) ); printf( "&i : %u, &j : %u\n", &i, &j ); printf( "i : %d, j : %d, pi : %u, *pi : %d\n", i, j, pi, *pi ); i = 89; printf( "i : %d, j : %d, pi : %u, *pi : %d\n", i, j, pi, *pi ); *pi = 42; printf( "i : %d, j : %d, pi : %u, *pi : %d\n", i, j, pi, *pi ); pi = &j; printf( "i : %d, j : %d, pi : %u, *pi : %d\n", i, j, pi, *pi ); return 0; } kt int : 2, long : 4, double int * : 2, long * : 2, double * : 2 &i : 4362, &j : 4360 i : 10, j : 40, pi : 4362, *pi : i : 89, j : 40, pi : 4362, *pi : i : 42, j : 40, pi : 4362, *pi : i : 42, j : 40, pi : 4360, *pi : :8 10 89 42 40 /* sizeof i */ /* sizeof l */ /* sizeof x */ /* sizeof pi */ /* sizeof pl */ /* sizeof px */

ekil 5.1-6'da programda tanmlanan deikenlerin yaplan ilemler sonrasndaki sembolik bellek grnmleri verilmitir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-15

rnek 5.1-4'de grld gibi ayn temel veri tipine sahip olduklarnda, birka deiken ayn satrda virglle ayrlm olarak bildirilebilir:
short short short long long double double i; j; *pi; l; *pl; x; *px; short i, j, *pi; long l, *pl; double x, *px;

Yukardaki bildirim deyimlerinde yer alan deikenlerin tipleri yledir: i ve j deikenlerinin tipi, short; pi adres deikeninin tipi, short *; l deikeninin tipi, long; pl adres deikeninin tipi, long *; x deikeninin tipi, double ve px adres deikeninin tipi, double *. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-16

ekil 5.1-6 rnek 5.1-4'de yer alan adres deikeni ilemleri sonrasnda sembolik bellek grnmleri.
... int i = 10, j = 40, *pi; ... pi = &i; ...
Bellek Program satrlar: Program satrlar:

... i = 89; ...


Bellek

:
40 10

:
4360 4362 40 89

j: i:

4360 4362

j: i:

: : pi :
4362

: : pi :
4362

:
Program satrlar: Program satrlar:

:
... pi = &j; ...

... *pi = 42; ...


Bellek

:
40 42

Bellek

:
4360 4362 40 42

j: i:

4360 4362

j: i:

: : pi :
4362

: : pi :
4360

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-17

5.2 Adres Deikenleri ve Diziler


rnek 5.2-1'de, 3 elemanl Dizi dizisi tanmlanr. Bu program derlendiinde bellekte, int verileri saklayabilecek sral 3 alan ayrlr. Ayrlan alanlarn herbiri 2 byte byklndedir. ktda da grld gibi, her dizi elemannn bir bellek adresi vardr. Ayrlan bellek alanlar sral olduu iin bu alanlara ait bellek adresleri de sral olacaktr. Dizi dizisinin elemanlarna, bu adresler kullanlarak eriilebilir.

rnek 5.2-1 dizi1.c program. #include <stdio.h> int main(void) { int Dizi[ ] = { 0, 1, 2 }; int i; for ( i = 0; i < 3 ; i++ ) printf(" Dizi[%d] : %d, bellek adresi : %u \n", i, Dizi[ i ], &Dizi[ i ] ); return 0; } kt Dizi[0] : 0, bellek adresi : 3462 Dizi[1] : 1, bellek adresi : 3464 Dizi[2] : 2, bellek adresi : 3466

ekil 5.2-1'de grld gibi Dizi dizisinin eleman numaras (indeksi) birer birer artarken (0, 1, 2), elemanlarn & operatr ile alnan bellek adresleri ikier ikier artar (3462, 3464, 3466).
ekil 5.2-1 int[3] tipindeki Dizi dizisinin sembolik bellek grnm.

:
Dizi[0] : 3462 Dizi[1] : 3464 Dizi[2] : 3466
0 1 2

Bellek 2 byte

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-18

Fakat rnek 5.2-2'de olduu gibi Dizi dizisi long temel veri tipi ile bildirildiinde, sral adres deerleri arasndaki fark 4 olur.
rnek 5.2-2 dizi2.c program. #include <stdio.h> int main(void) { long Dizi[ ] = { 0, 1, 2 }; int i; for ( i = 0; i < 3 ; i++ ) printf(" Dizi[%d] : %ld, bellek adresi : %u \n", i, Dizi[ i ], &Dizi[ i ] ); return 0; } kt Dizi[0] : 0, bellek adresi : 3456 Dizi[1] : 1, bellek adresi : 3460 Dizi[2] : 2, bellek adresi : 3464 NOT: Adres deerleri donanma gre deiebilir!

Bu durumda, sembolik bellek grnm aadaki gibi olacaktr.


ekil 5.2-2 long[3] tipindeki Dizi dizisinin sembolik bellek grnm.

:
Dizi[0] : 3456 0

Bellek

4 byte

Dizi[1] : 3460 1 Dizi[2] : 3464 2

Her iki rnekte de grld gibi dizinin indeksi birer birer artarken, karlk gelen elemanlara ait bellek adresleri de dizinin bildirildii temel veri tipi ( sizeof(tip) ) boyutlarnda artar. Dizinin indeksi ve bellek adresleri arasndaki bu iliki kullanlarak balang elemannn adresi bilindiinde dizinin dier elemanlarna eriilebilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-19

Buna gre int elemanlardan oluan Dizi dizisinin birinci eleman ( Dizi[1] ), balang elemann ( Dizi[0] ) bulunduu 2 byte ( sizeof Dizi[0] byklndeki ) bellek alann izleyen 2 byte'lk bellek alannda bulunacaktr. Balang elemannn adresi (&Dizi[0] ifadesi ile alnan) 3462 olduuna gre, birinci elemann adresini elde etmek iin balang elemannn adresinden itibaren 1 dizi eleman alan kadar bellek alan atlamak gerekir ve bu nedenle 3462 deerine 1*sizeof (int) yani 2 byte eklenir. Bylece 3464 deeri elde edilir. Ayn ekilde dizinin ikinci eleman ( Dizi[2] ), balang elemann izleyen 2 bellek alan sonrasnda bulunduundan bu elemann bellek adresi 3462 deerine 2*sizeof (int) eklenerek elde edilebilir ( 3462+4 = 3466 ). Yada dizinin ikinci eleman, birinci eleman izleyen bellek alannda bulunduundan 3464 + 1*sizeof (int) ifadesi de ayn sonucu ( 3466 ) verecektir. Bylece dizi elemanlarnn adresleri, balang adresine atlanacak alan says ile sizeof (tip) arpm eklenerek elde edilebilir:
balang adresi + i * sizeof( tip )

Bu ifadede i deikeni atlanacak alan saysn (dizinin indeks deikeni) belirten tamsay, tip ise dizinin bildirim deyiminde yer alan temel veri tipidir. long Dizi[3] dizisi iin uygulandnda, birinci elemann adresi 3456 deerine 1*sizeof (long); ikinci elemann adresi ise 3456 deerine 2*sizeof (long) eklenerek bulunabilir:
balang elemannn ( Dizi[0] ) bellek adresi : birinci elemann ( Dizi[1] ) bellek adresi : ikinci elemann ( Dizi[2] ) bellek adresi : 3456 3456 + 1 * 4 = 3460 3456 + 2 * 4 = 3464

Bilinen aritmetik kurallar uygulanarak adres deerleri yada adres deikenleri ile ilemler yaplrken, yukardaki
balang adresi + i * sizeof( tip )

ifadesi kullanlabilir. Fakat C dilinde adres deerleri veya adres deikenleri ieren ifadelerle yaplan ilemler adres aritmetiine gre yorumlanr. Adres aritmetiine gre herhangi bir adres deerine yada adres deikenine bir tamsay deerin eklendii ifadede, tamsay deer direk olarak toplanmaz. Tamsay deer, adres deerinin ait olduu alann yada bir baka deyile adres deikeninin indirek deerinin byte says ile leklendirildikten sonra ileme girer. Yani belli bir lek faktr ile arplr. Bu leklendirme C tarafndan otomatik olarak yaplr. Aadaki programda adres aritmetiini rneklemek iin char *, int * ve double * tipindeki bo adres deerlerine (NULL) tamsay 1 deeri eklenmitir. ktda da grld gibi char, int ve double tipi verilerin bellek adresleri iin lek faktrleri srasyla 1, 2 ve 8'dir (bu deerler donanma bal olarak deiebilir).
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-20

rnek 5.2-3 arit1.c program. #include <stdio.h> int main(void) { printf( "sizeof (char) : %u\n" "sizeof (int) : %u\n" "sizeof (double) : %u\n", sizeof (char), sizeof (int), sizeof (double) ); printf( "(char *)0 + 1 : %u\n" "(int *)0 + 1 : %u\n" "(double *)0 + 1 : %u\n", (char *)0 + 1, (int *)0 + 1, (double *)0 + 1 );

return 0; } kt sizeof(char) : 1 sizeof(int) : 2 sizeof(double) : 8 (char *)0 (int *)0 (double *)0 +1 : 1 +1 : 2 +1 : 8

Dizi dizisinin her bir eleman, birbirini izleyen eit byklkteki bellek alanlarna yerletirilmi ayn temel veri tipindeki sral deikenlerdir. Dolaysyla sral dizi elemanlar iin bellekte ayrlan eit byklkteki alanlarn adresleri zerinde ilemler yaplrken, dizideki herhangi bir elemann bellek adresine tamsay 1 deeri eklendiinde bir sonraki elemann bellek adresi elde edilir. nk adres aritmetiine gre toplama ileminden nce 1 deeri tek bir dizi eleman iin ayrlan bellek alannn byte says ( sizeof (tip) ifadesinin dndrd deer, yani bildirimde yer alan temel veri tipinin byte olarak bykl ) ile leklendirilir. Bu nedenle bir dizinin balang elemannn adresini kullanarak dier elemanlarn bellek adreslerini veren,
balang adresi + i * sizeof( tip )

ifadesi yerine,
balang adresi + i

kullanlmaldr. i'nin deeri (indeks deikeni) balang adresine eklenmeden nce, C dilinin yukarda anlatlan zelliinden (adres aritmetii) dolay bellek adresinin ait olduu bellek alannn byte says ile arplm olacaktr. Dolaysyla adres aritmetii kullanlarak rnek 5.2-1'de yer alan printf satr aadaki ekilde yazlabilir:
printf(" Dizi[%d] : %d, bellek adresi : %u \n", i, Dizi[ i ], &Dizi[ 0 ] + i ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-21

Program derlenerek altrldnda, yine ayn kt elde edilir. Dizi elemanlarna iaret eden adres deikeni kullanlarak, dizi elemanlarnn bellek adresleri zerinde aritmetik ilemler kolaylkla yaplabilir. Adres deikenleri de bellekte saklanrlar (lvalue). Bu nedenle adres deikenleri iin ayrlan bellek alanlarna rneklerde grld gibi deer atanabilir. Ayrca dier deikenlerde olduu gibi adres deikenlerine de artrma (++) ve eksiltme (--) operatrleri uygulanabilir. Adres deikenine tamsay 1 eklemek, indirek deerinin byte byklndeki bir alan sonrasnn bellek adresini verir. Eklenen tamsay 2 olduunda ise bulunulan bellek adresini izleyen ve her biri indirek deerin byte byklnde olan iki bellek alan sonrasnn adres deeri elde edilir. rnek 5.2-4'de yer alan programn ktsnda grld gibi bildirilen adres deikenlerine 1 deeri, adres deikeninin indirek deerinin byte says ile arplarak eklenir.

rnek 5.2-4 arit2.c program. #include <stdio.h> int main(void) { short i, *pi; long l, *pl; double x, *px; pi = &i; pl = &l; px = &x; printf( "short i : %u byte, pi : %u, pi + 1 : %u\n", printf( "long l : %u byte, pl : %u, pl + 1 : %u\n", printf("&i : %d, &i + 1 : %d \n", &i, &i + 1 ); printf("&l : %d, &l + 1 : %d \n", &l, &l + 1 ); printf("&x : %d, &x + 1 : %d \n", &x, &x + 1 ); return 0; } kt short i : 2 byte, long l : 4 byte, double x : 8 byte, pi : 3614, pl : 3608, px : 3618, pi + 1 : 3616 pl + 1 : 3612 px + 1 : 3626 sizeof( i ), sizeof( l ), pi, pi + 1 pl, pl + 1 ); );

printf( "double x : %u byte, px : %u, px + 1 : %u\n", sizeof( x ), px, px + 1 );

&i: 3614, &i + 1 : 3616 &l: 3608, &l + 1 : 3612 &x : 3618, &x + 1 : 3626

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-22

Programda 1 says i, l, ve x deikenlerinin adres operatr (&) kullanlarak alnan adres bellek adresleri ile toplanmadan nce otomatik olarak ilemde yer alan deikenin veri tipinin byte says ile arplmtr.

Adres Deikenleri ve Tek-Boyutlu Diziler


rnek 5.2-5'de Dizi dizisinin elemanlarna adres deikeni kullanlarak eriilir. Programda Dizi dizisinin balang elemannn bellek adresi pDizi adres deikenine atanr. Daha sonra for blounda yer alan printf arsnda, pDizi'nin tad adres deerine her evrimde dizinin bir sonraki elemannn numaras eklenir. lem adres deerleri zerinde yapld iin, i'nin deeri toplama ilemine girmeden nce indirek deerin byte says ile arplarak leklendirilir.
rnek 5.2-5 dizi3.c program. #include <stdio.h> int main(void) { int Dizi[ ] = { 0, 1, 2 }, i; int *pDizi; pDizi = &Dizi[0]; for ( i = 0; i < 3 ; i++ ) printf(" *(pDizi + %d) : %d, bellek adresi pDizi + %d : %u \n", i, *( pDizi + i ), i, pDizi + i ); return 0; } kt *(pDizi + 0) : 0, bellek adresi pDizi + 0 : 3476 *(pDizi + 1) : 1, bellek adresi pDizi + 1 : 3478 *(pDizi + 2) : 2, bellek adresi pDizi + 2 : 3480

Programda toplama ileminden sonra atama yaplmad iin, pDizi'nin tad adres deeri program boyunca deimez ve dizinin balang elemannn adresidir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-23

ekil 5.2-3 int[3] tipindeki Dizi dizisi ve int * tipindeki pDizi adres deikeninin sembolik bellek grnm.
pDizi
3476

:
0 1 2

Bellek

Dizi[0] Dizi[1] Dizi[2]

pDizi+1 pDizi+2

3478 3480

: :
3476 pDizi

for dngs ve printf deyimi aadaki ekilde oluturulabilir:


for ( i = 0; i++ < 3 ; pDizi++ ) /* yada for ( i = 0; i < 3 ; i++, pDizi++ ) */ printf("*pDizi : %d, bellek adresi pDizi : %u \n", *pDizi, pDizi );

Yine ayn kt elde edilir. Fakat pDizi++ ifadesi (pDizi = pDizi + 1 ifadesi ile ayndr) ile artrm sonunda elde edilen adres deeri pDizi adres deikenine atand iin, program sonunda pDizi'nin deeri dizinin balang elemannn adresi olmayacaktr. zet olarak;
l

Dizi bildirim deyimi ieren bir program derlendiinde, bellekte dizinin eleman says kadar ve her biri bildirimde yer alan veri tipi ile belirtilen byte byklnde ( sizeof(tip) ) sral bellek alanlar ayrlr. Bellek alanlar sral olduu iin, adresleri de sral olacaktr. Dizinin indeksi (eleman numaras) birer birer artarken, her indekse karlk gelen elemann bellek adresi de dizi bildirim deyiminde yer alan veri tipinin byte says kadar artar. Adres deeri yada adres deikeni ile bir tamsay deerin topland ifadede, tamsay deer adresin ait olduu alann byte says ile arplarak ileme girer.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-24
l

C dilinin yukarda anlatlan zellii (adres aritmetii) btn adres deerleri iin geerli olduundan, dizi elemanlarnn bellek adresleri zerinde yaplan ilemler de bu ekilde yorumlanr. Dolaysyla bir dizinin balang adresine herhangi bir elemann numarasn eklemek, o dizi elemannn bellek adresini verecektir. Herhangi bir adres deerine tamsay 1 deeri eklendiinde elde edilen sonu, bu adres deeri ile dizinin temel veri tipinin byte saysnn toplamna eittir. Adres deikenleri ile yaplan ilemlerde, iaret edilen verinin boyutlar daima yaplan ilemin sonucunu etkiler.

Aada adres deikenleri ile yaplabilecek ilemler sralanmtr :


l

Adres deikeninin deeri, ++ ve -- operatrleri ile artrlabilir yada eksiltilebilir. rnek olarak, eer pc adres deikeni bellekteki herhangi bir char verinin bulunduu bellek alanna iaret ediyorsa, pc++ ifadesi ile izleyen char alana iaret edecektir. Fakat bu ilemlerin tek bir veri elemanna iaret eden adres deikeni (basit adres deikeni) zerinde yaplmas anlamszdr. Bu ilemlerin eer adres deikeni bir dizi elemanna iaret ediyorsa (dizi adres deikeni) sral elemanlara eriim amacyla yaplmas anlamldr. Dizi elemanlarna eriim adres deikeni aracl ile yaplrken, C dili tarafndan dizi snrlarnn dna tama kontrol edilmez (ayn durum, indeks kullanlarak eriim salanrken de geerlidir). Tama durumunda istenmedii halde bitiik alanlardaki veriler bozulabilecei iin, adres ilemleri dikkatli yaplmaldr.

Adres deikenine dizi snrlar iinde kalarak bir tamsay deer eklenebilir yada karlabilir. Fakat bu ilem float yada double deerler ile yaplamaz. rnek : p += 2; Bu ilemler adres aritmetiine gre yorumlanr. Adres deikeni p herhangi bir dizinin elemanlarna iaret ediyorsa, p + i ifadesi (i bir tamsay deikendir) p deikeninin iaret ettii veriyi izleyen i'inci verinin adresini verir. Bu ilem, indirek deerin veri tipi ( sizeof (*p) ) C tarafndan otomatik olarak dikkate alndndan, btn adres deerleri ve adres deikenlerine uygulanabilir.

Adres deikenine 0 (sfr) deeri atanabilir. C derleyicisi, 0 deerini bellek adresi olarak kullanmaz. Dolaysyla 0 deeri adres deikenine atanarak zel bir durum bildirilebilir. Bo adres deikeni (null-pointer) deeri olarak 0 deeri, stdio.h, stdlib.h, stddef.h, locale.h, string.h ve time.h balk dosyalarnda NULL makrosu ile tanmlanmtr. Adres deikenine adres deerleri yada adres deerleri dndren ifadeler de atanabilir. Adres deikeni, programlarda herhangi bir tamsay deiken gibi kullanlamayaca gibi herhangi bir tamsay deer de adres deikenine atanamaz.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-25
l

Adres deikeni ayn tipte adres deeri bekleyen bir fonksiyona argman olarak aktarlabilir.

Ayn tipteki adres deikenleri arasnda aadaki ilemler yaplabilir. Fakat bu ilemler ancak adres deikenleri ayn dizinin elemanlarna iaret ediyor ise anlamldr:
l

Bir adres deikeninin deeri ayn tipte bir baka adres deikenine atanabilir. rnek : p1 = p2; yada p2 = p1;

ki adres deikeni arasnda toplama, arpma ve blme ilemleri yaplamaz.

ki adres deikeni birbirinden karlabilir. rnek : p2 - p1 lemin sonucu stddef.h'de tanmlanm bulunan ptrdiff_t tipindedir ve adres deikenleri arasndaki farkn, indirek deerin byte saysna blnmesiyle elde edilir. Bu leklendirme, yine C derleyicisi tarafndan otomatik olarak gerekletirilir. Dolaysyla ayn dizinin farkl elemanlarna iaret eden iki adres deikeni birbirinden karldnda, aradaki eleman says elde edilir. Aadaki program parasnda ptrdiff_t tipinde bildirilen n deikeni kullanlarak, iki adres deikeni arasndaki fark tanabilir ekilde saklanr. Ayrca fark deeri long tipine evrilerek tanabilir ekilde ekrana listelenir:
... ptrdiff_t n; ... n = ( p + 1 ) - p; ... printf( "n : %ld\n", (long)n ); ...

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-26

Adres deikeni ile bir baka adres deeri, adres deeri dndren bir ifade yada dier bir adres deikeni karlatrlabilir. rnek : p1 < p2 Bu ifade, p1 adres deikeni dizinin p2'den nceki herhangi bir elemanna iaret ediyorsa dorudur. Aadaki testlerin tm, ayn dizinin elemanlarna ait adres deerlerine yada ayn dizinin elemanlarna iaret eden adres deikenlerine uygulanabilir: <=, >=, <, >, !=, == Adres deikeni ve NULL deeri (0 deeri) arasnda, == ve != karlatrmas yaplabilir: rnek : p == NULL (yada p == 0) ve p != NULL (yada p != 0) Ayn dizinin elemanlarna iaret eden iki adres deikeninin fark, bir tamsay deer ile yada 0 ile karlatrlabilir: rnek : p1 - p2 < 0, p1 - p2 < 0 yada p1 - p2 = = 0 rnek 6.2-5'de atama deyimi,
pDizi = &Dizi[0];

ile Dizi dizisinin balang elemannn adresi pDizi adres deikenine atanr ve pDizi zerinde adres aritmetii uygulanarak dizi elemanlarna eriim salanr. Programda adres deikeni pDizi yerine dizi ismi Dizi kullanldnda da yine ayn kt elde edilir. nk C dilinde dizi ismi, dizinin balang elemannn bellek adresini veren sabittir (constant pointer). Adres deikeni olmad iin, dizi ismine herhangi bir adres deeri atanamaz, ++ yada -- operatrleri uygulanamaz. Aada, 3 elemanl m dizisi ve tamsay deiken n bildirilir:
... int m[3], n; ...

Dizi ismine m = &n deyimi ile n deikeninin bellek adresi atanamaz. Ayrca &m, m++ yada m-- ifadeleri geersizdir. Ancak dizi ismine * operatr uygulanarak verdii sabit adres deeri kullanlabilir ( *m, *(m+1) gibi ... ).
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-27

rnek 5.2-6 dizi4.c program. #include <stdio.h> #define DiziBoy(s) sizeof (s) / sizeof (s[0]) int main(void) { int Dizi[ ] = { 0, 1, 2 }, i; int *pDizi = Dizi; puts( "dizi elemanlarinin adresleri" ); for ( i = 0; i < DiziBoy(Dizi); i++ ) printf( "&Dizi[%d] : %u, &Dizi[0] + %d : %u, Dizi + %d : %u\n", i, &Dizi[i], i, &Dizi[0] + i, i, Dizi + i ); puts( "dizi elemanlarinin degerleri" ); for ( i = 0; i < DiziBoy(Dizi); i++ ) printf( "Dizi[%d] : %d, *(Dizi + %d) : %d\n", puts( "dizi elemanlarinin adresleri" ); for ( i = 0; i < DiziBoy(Dizi); i++ ) printf( "pDizi + %d : %u\n", i, pDizi + i ); puts( "dizi elemanlarinin degerleri" ); for ( i = 0; i < DiziBoy(Dizi); i++ ) printf( "pDizi[%d] : %d, *(pDizi + %d) : %d\n", i, pDizi[i], i, *(pDizi + i) ); puts( "pDizi = Dizi + 1 deyimi sonrasi degerler"); pDizi = Dizi + 1; printf("Dizi : %u, pDizi : %u, *pDizi : %d\n", Dizi, pDizi, *pDizi ); printf("pDizi - Dizi : %ld\n", (long)(pDizi - Dizi) ); puts( "pDizi++ deyimi sonrasi degerler" ); pDizi++; printf("Dizi : %u, Dizi + 2 : %u, pDizi : %u, *pDizi : %d\n", Dizi, Dizi + 2, pDizi, *pDizi ); printf( "%s\n", printf( "%s\n", return 0; } kt dizi elemanlarinin adresleri &Dizi[0] : 3910, &Dizi[0] + 0 : 3910, Dizi + 0 : 3910 &Dizi[1] : 3912, &Dizi[0] + 1 : 3912, Dizi + 1 : 3912 &Dizi[2] : 3914, &Dizi[0] + 2 : 3914, Dizi + 2 : 3914 C PROGRAMLAMA DILI, 1997 Ismet Kocaman (pDizi > Dizi) ? "pDizi > Dizi" : "pDizi < Dizi" );

i, Dizi[i], i, *(Dizi + i) );

(pDizi == Dizi + 2) ? "pDizi == Dizi + 2" : "pDizi != Dizi + 2" );

5-28

rnek 5.2-6 kt devam


dizi elemanlarinin degerleri Dizi[0] : 0, *(Dizi + 0) : 0 Dizi[1] : 1, *(Dizi + 1) : 1 Dizi[2] : 2, *(Dizi + 2) : 2 dizi elemanlarinin adresleri pDizi + 0 : 3910 pDizi + 1 : 3912 pDizi + 2 : 3914 dizi elemanlarinin degerleri pDizi[0] : 0, *(pDizi + 0) : 0 pDizi[1] : 1, *(pDizi + 1) : 1 pDizi[2] : 2, *(pDizi + 2) : 2 pDizi = Dizi + 1 deyimi sonrasi degerler Dizi : 3910, pDizi : 3912, *pDizi : 1 pDizi - Dizi : 1 pDizi++ deyimi sonrasi degerler Dizi : 3910, Dizi + 2 : 3914, pDizi : 3914, *pDizi : 2 pDizi > Dizi pDizi == Dizi + 2

&Dizi[0] ve dizi ismi Dizi, her ikisi de ayn adres deerini verir (3476). Dolaysyla bu adresteki deeri dndren Dizi[0] ve *Dizi ifadeleri de ayn sonucu verecektir. Fakat dizi ismine bir tamsaynn eklendii ifadeler adres aritmetiine gre yorumlandndan, dizi ismi kullanlarak;
Dizi + i

ifadesi ile dier dizi elemanlarnn bellek adreslerine,


*(Dizi+i)

ifadesi ile de bu adreslerdeki verilere eriilebilir. Bildirim deyimi ile 3 elemanl Dizi dizisi ( Dizi[0], Dizi[1], Dizi[2] ) bildirilir. Bu dizi bildirim deyiminde yer alan Dizi, int[3] tipindedir. int[3] ifadesinden indeks ([3] yada [eleman_says]) karldnda elde edilen ise bildirimde kullanlan temel veri tipidir. rnek 6.2-6'da adres deikenine dier deikenlerde olduu gibi bildirim srasnda ilk deer atama yaplr. int *pDizi = Dizi deyimi ile bildirilen pDizi adres deikenine ayn deyimde ilk deer atamas yaplarak Dizi dizisinin balangcna iaret etmesi salanr. Bildirim deyiminde Dizi yerine rnek 6.2-5'de olduu gibi &Dizi[0] kullanlabilir. rnek programda ilk olarak dizi ismi ile oluturulan ifadeler kullanlarak dizi elemanlarnn bellek adresleri listelenir. Dizi ismi, dizinin balang adresini veren sabit
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-29

olduu iin Dizi + i ifadeleri adres aritmetiine gre yorumlanr. Ayn ekilde dizinin balang elemanna bir tamsaynn eklendii &Dizi[0] + i ifadeleri de adres aritmetiine gre yorumlanr. Dizi elemanlarnn deerleri ise yine dizi ismi ile oluturulan bu ifadelere indirek deer operatr uygulanarak listelenir. rnek programda daha sonra adres deikeni kullanlarak dizi elemanlarnn adresleri ve deerleri listelenir. Adres deikeni de yine ifadelerde dizi ismi gibi bulunur fakat adres deikeni bir lvalue, dizi ismi ise deitirilemeyen bir lvalue'dr (non-modifiable lvalue ). Daha sonra pDizi = Dizi + 1 deyimi ile dizinin birinci elemannn bellek adresi adres deikenine atanr. pDizi adres deikeni, dizinin birinci elemanna iaret ettii iin *pDizi ifadesi 1 deerini dndrr. Dizi'nin deeri olan balang adresinin (3910), pDizi'nin deeri 3912'den karld ilem adres aritmetiine gre yorumlanr ve iki adres deeri arasndaki fark otomatik olarak dizi bildiriminde yer alan temel veri tipinin (int) boyutlarna blnr. Bu nedenle pDizi - Dizi ilemi 1 deerini dndrr. ptrdiff_t tipindeki bu deer ekrana listelenirken tanabilir olmas iin long tipine evrilir.
ekil 5.2-4 int[3] tipindeki Dizi dizisi ve int * tipindeki pDizi adres deikeninin program sonundaki sembolik bellek grnm.

:
3910 3912 3914

Bellek

0 1 2

Dizi[0] Dizi[1] Dizi[2]

: :
3914 pDizi

: NOT: Adres deerleri rnek 5.2-5 ile ayn deildir.

pDizi++ ifadesi ile adres deikeninin tad adres deerine tamsay 1 eklenir. Fakat yine adres aritmetiine gre tamsay 1 ileme girmeden nce pDizi'nin indirek deerinin byte says ile arpldndan elde edilen sonu 3914 (ikinci elemann adresi) olacaktr. Dolaysyla *pDizi ifadesi 2 deerini dndrr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-30

Dizi ismi Dizi'nin verdii adres deeri (3910), dizinin ikinci elemanna iaret eden pDizi'nin deerinden (3914) kktr. Bylece pDizi > Dizi testi doru olaca iin printf fonksiyonu ekrana "pDizi > Dizi" dizgisini yazar. Programda son olarak pDizi = = Dizi + 2 testi yaplr. pDizi adres deikeni dizinin ikinci elemannn adresini tadndan, test doru sonucunu verir ve ekrana "pDizi == Dizi + 2" dizgisi yazlr. Bu programda dizi ismi ve adres deikeni ile oluturulan ifadeler kullanlarak yaplan ilemler rneklendi. ekil 5.2-4'de programn sonunda Dizi dizisinin ve pDizi adres deikeninin sembolik bellek grnmleri yer alr. Sonu olarak Dizi dizisinin elemanlarnn bellek adreslerini veren &Dizi[ i ] ifadesi, Dizi + i ifadesi ile; bu elemanlarn deerlerini veren Dizi[ i ] ifadesi ise *(Dizi + i) ifadesi ile ayndr. Grld gibi dizi elemanlarnn adreslerine ve bu adreslerde bulunan deerlere dizi ismi kullanlarak kolaylkla eriilebilir. C dilinde adres deikenleri indeks operatr ([ ]) ile kullanlabilir. Bylece oluturulan pDizi[i] ifadesi ile *(pDizi + i) ifadesi ayndr (tamsay indeks i, dizinin herhangi bir elemannn numarasdr) ve her ikisi de pDizi + i adresindeki deeri verir. ndeks operatr ve indirek deer operatr, hem dizi ismine hem de adres deikenine uygulanabilir. Bu durumda dizi ismi Dizi ve adres deikeni pDizi ile aadaki ifadeler oluturulabilir: Dizi[ i ] yada *( Dizi + i ) ifadeleri Dizi + i adresindeki deeri, ve pDizi[ i ] yada *(pDizi + i) ifadeleri de, pDizi + i adresindeki deeri verir. Derleyici tarafndan dizi ismi ve indeks operatr ile oluturulan bir ifade, dizinin balang elemanna iaret eden adres deeri ve offset ifadesine dntrlr (sizeof ve & operatrnn operand' olan ifadeler ve bir char tipi dizinin dizgi sabiti ile ilk deer atamasnn yapld uygulama hari). Dolaysyla aada adres deeri ve indeks operatr ile oluturulan indeks ifadesi (array notation yada subscript notation) ile adres deeri ve offset ile oluturulan adres-offset ifadesi (pointer notation) birbiri ile ayndr :
indeks ifadesi : Dizi[ i ] adres-offset ifadesi : * ( Dizi + i )

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-31

Bu ifadeler dizi ismi yerine adres deikeni kullanlarak oluturulabilir.


indeks ifadesi : pDizi[ i ] adres-offset ifadesi : * ( pDizi + i )

Ok iareti bu ifadelerin ayn olduunu belirtir. Fakat bir adres sabiti olan dizi ismi ile oluturulan ifadeler, adres deikeni kullanlarak oluturulan ifadelerle ayn deildir. Derleyici bu iki grup ifade iin farkl kodlar oluturur (Ancak izleyen blmlerde de anlatlaca gibi, argman olarak dizi alan bir fonksiyonun parametre listesinde bildirilen dizi ismi, adres deikenidir. nk aktarlan adres deeridir). Bu ifadeler, ok-boyutlu diziler iin de oluturulabilir:
indeks ifadesi : Dizi2b[ i ][ j ] * ( Dizi2b[ i ] + j ) adres-offset ifadesi : * ( *(Dizi2b + i ) + j )

Dizi indeksleme ilemi yukarda da grld gibi aslnda adres aritmetiidir ve deime zellii vardr. Dolaysyla aadaki ifadeler birbirine etir (deime zelliinden dolay):
Dizi[ i ] *( Dizi + i ) * ( i + Dizi ) i [ Dizi ]

i [ Dizi ] ifadesinin gerekli olduu hi bir uygulama yoktur. Burada yalnzca dizi indeksleme ileminin deime zellii olduunu gstermek amacyla oluturulmutur. rnek programda aadaki makro kullanlarak dizinin eleman says bulunur:
#define DiziBoy(s) sizeof (s) / sizeof (s[0])

Bir dizi ismine sizeof operatr uygulandnda, dizinin toplam byte bykln verir. Dizinin tek bir elemannn byte says veren sizeof s[0] ifadesinde 0 yerine dizi snrlar iinde kalan bir baka indeks deeri kullanlabilir. Fakat her dizinin 0. eleman mutlaka bulunaca iin, indeks deeri olarak 0 kullanm ifadeyi daha anlalr hale getirir. Dizi ismine negatif indeks uygulanabilir. Bylece dizinin balang elemanndan nceki ayn byklkteki bellek alanlarna eriilebilir. Bu uygulama derleme srasnda hata oluturmayabilir, fakat dizi snrlar dna kmak C dilinin kurallarna uymaz. Ayn ekilde diziye iaret eden adres deikenine de negatif indeks uygulanabilir. Bu durumda iaret edilen dizi elemanndan bir nceki elemana eriilir. rnek 5.2-7'de int tipinde i deikeni, int * tipinde pDizi ve piDizi adres deikenleri, int[5] tipinde iDizi dizisi bildirilir. Programda ayrca double * tipinde pdDizi adres deikeni bildirilir ve double[2] tipinde dDizi dizisi tanmlanr.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-32

rnek 5.2-7 dizi5.c program. #include <stdio.h> #define DiziBoy(s) sizeof(s)/sizeof(s[0]) int main(void) { int i = 0, *pDizi; int *piDizi; double *pdDizi; int iDizi[ 5 ]; double dDizi [ ] = { 4.5, 5.4 }; piDizi = &i; pdDizi = dDizi; for ( i = 0, pDizi = iDizi; i < DiziBoy(iDizi); i++, pDizi++ ) *pDizi = i; pDizi = iDizi; ++pdDizi; ++*pDizi; *pdDizi += (double)*pDizi; piDizi = pDizi; *piDizi *= 2; if ( *piDizi == *(iDizi + 2) ) *piDizi = (int)*(pdDizi - 1); for ( i = 0, pDizi = iDizi; i < 5; i++, pDizi++) printf("iDizi[%d]: %d\n", i, *pDizi ); pDizi = iDizi; printf("dDizi[0]: %.1f, dDizi[1]: %.1f\n", dDizi[0], dDizi[1] ); return 0; } kt iDizi[0]: 4 iDizi[1]: 1 iDizi[2]: 2 iDizi[3]: 3 iDizi[4]: 4 dDizi[0]: 4.5, dDizi[1]: 7.4

Atama deyimi piDizi = &i ile adres deikeninin i deikenine; pdDizi = dDizi ile de pdDizi adres deikeninin dDizi dizisinin balang elemanna iaret etmesi salanr. for dngsnde, adres deikeni pDizi kullanlarak iDizi dizisinin elemanlarna karlk gelen eleman numaralar deer olarak atanr. Dng knda tad deer deien
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-33

pDizi adres deikenine, pDizi = iDizi ile tekrar iDizi dizisinin balang elemannn adresi atanr. ++pdDizi deyimi ile adres deikeninin dizinin ilk elemanna iaret etmesi salanr. ++*pDizi deyimi kullanlarak iDizi'nin balang elemannn deerine tamsay 1 eklenir. *pdDizi += (double)*pDizi deyiminde, iDizi[0]'n deeri (yani *pDizi) tip deitirme uygulanarak dDizi dizisinin ilk elemannn deeri ile toplanr ve elde edilen sonu yine dDizi dizisinin ilk elemanna atanr: *pdDizi = *pdDizi + (double)*pDizi; piDizi = pDizi deyimi, her iki adres deikeninin de ayn veriye iaret etmesini salar (yani iDizi dizisinin balang eleman). piDizi adres deikeni kullanlarak, iDizi dizisinin balang elemannn deeri tamsay 2 ile arplr. Elde edilen sonu yine balang elemanna atandktan sonra dizinin ikinci elemannn deeri ile karlatrlr. Bu test doru sonucu vereceinden koul salanr ve *piDizi = (int)*(pdDizi - 1) deyimi altrlr. Bylece tip deitirme yaplarak dDizi dizisinin balang elemannn deeri iDizi dizisinin balang elemanna atanr. Programn sonunda, pDizi adres deikeni kullanlarak iDizi dizisinin elemanlarna eriilir ve for dngs ile deerleri ekrana listelenir. for dngs sonrasnda pDizi = iDizi atama deyimi ile adres deikeninin yine dizi balangcna iaret etmesi salanr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-34

ekil 5.2-5'de rnek programda tanmlanan adres deikenlerinin ve dizilerin program sonundaki bellek dzenleri sembolik olarak gsterilir.
ekil 5.2-5 Program sonunda piDizi ve pDizi adres deikenleri iDizi dizisine; pdDizi adres deikeni ise dDizi dizisinin birinci elemanna iaret eder.
Bellek

:
... piDizi

:
... pdDizi

: :
... ... ...

: :
iDizi[0] iDizi[1] iDizi[2] iDizi[3] iDizi[4]
... ...

4 1 2 3 4

dDizi[0]

4.5

dDizi[1]

: :
... pDizi 7.4

: :

Yukardaki rnek programda grld gibi, ++ ve -- operatrleri adres deikenlerine n-ek (prefix operator) ve son-ek (postfix operator) operatrler olarak uygulanabilir. Operatr ncelik kurallarna gre eer bir ifadede birden fazla operatr bulunuyor ise, operatrler ncelik srasna (operatr ncelik tablosunda belirtilen) gre uygulanr. Operatrler ayn ncelie sahip ise, grup zelliklerine (associativity) gre ilenirler. Buna gre operatr ncelik tablosunda (operator precedence table) ayn srada bulunan ++ ve * operatrlerinin grup zellikleri sadan sola doru olduu iin, ifadelerdeki gruplandrma da sadan sola doru yaplr. Dolaysyla *++p ifadesinde adres deikenine sadan sola doru ilk olarak ++ operatr balanr. p adres deikeninin tad deer artrldktan sonra * operatr ile indirek deeri alnr.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-35

Aadaki programda arttrma ve indirek deer operatrlerinin adres deikenine bir arada uygulanmas rneklenmitir.
rnek 5.2-8 adr.c program. #include <stdio.h> int main(void) { int dizi[ ] = { 99, 88, 77, 66, 55 }; int *p = dizi; int i = 0; printf( "p : %u, *p : %d, i : %d\n", p, *p, i ); puts( "i = *p++" ); i = *p++; printf( "p : %u, *p : %d, i : %d\n\n", p, *p, i ); printf( "p : %u, *p : %d, i : %d\n", p, *p, i ); puts( "i = *++p" ); i = *++p; printf( "p : %u, *p : %d, i : %d\n\n", p, *p, i ); printf( "p : %u, *p : %d, i : %d\n", i = ++*p; printf( "p : %u, *p : %d, i : %d\n\n", printf( "p : %u, *p : %d, i : %d\n", i = (*p)++; printf( "p : %u, *p : %d, i : %d\n\n", p, *p, i ); puts( "i = ++*p" ); p, *p, i ); p, *p, i ); puts( "i = (*p)++" ); p, *p, i );

for ( i = 0; i < sizeof dizi / sizeof dizi[0]; i++ ) { dizi [ i ] = i; printf( "%d, ", dizi [ i ] ); } putchar( '\n' ); p = &dizi[ 2 ]; *( p + 1 ) = 9; p[-2] = 7; dizi[ *p++ ] = *( dizi + dizi[ 1 ] ) + 2; *(p + 1 ) = 5; dizi[ *p - 8 ] = 8; for ( i = 0; i < sizeof dizi / sizeof dizi[0]; i++ ) printf( "%d, ", dizi [ i ] ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-36

... rnek 5.2-8 devam


kt p : 3660, *p : 99, i : 0 i = *p++ p : 3662, *p : 88, i : 99 p : 3662, *p : 88, i : 99 i = *++p p : 3664, *p : 77, i : 77 p : 3664, *p : 77, i : 77 i = ++*p p : 3664, *p : 78, i : 78 p : 3664, *p : 78, i : 78 i = (*p)++ p : 3664, *p : 79, i : 78 0, 1, 2, 3, 4, 7, 8, 3, 9, 5,

rnek 5.2-8'de arttrma ( ++ ) ve indirek deer operatrlerinin ( * ) p adres deikenine bir arada uygulanmas ile oluturulan ifadelerde (ekil 5.2-6'da 1. satr), operatrlerin ileme girme sras ok ynnde yani sadan sola doru gerekleir. nk bu operatrler ayn ncelie sahiptir ve bir arada bulunduklar ifadelerde grup zellikleri sadan sola dorudur. 2. satrda ise ayn ilemler operatr etkisinin ak olarak belirtilmesi iin parantezler kullanlarak gerekletirilir. 3. satrda ise ifadelerin daha anlalr olmas iin arttrma ilemi ve indirek deerin i deikenine atanmas iki ayr deyimde yaplr. 4. satrda ise ilk ifadede yer alan ilem, arttrma operatr yerine toplama operatr kullanlarak gerekletirilir. Programda son olarak, for dngsnde dizi elemanlarna 0, 1, 2, 3 ve 4 deerleri atanr. p = &dizi[ 2 ] atama deyiminde dizinin 2. elemannn bellek adresi p adres deikenine atanr. Dolaysyla p+1 ifadesi dizinin 3. elemanna iaret eder. *(p + 1) = 9 deyimi ile bu elemana 9 deeri atanr. p[-2] = 7 deyiminde p adres deikenin iaret ettii dizi elemannn (2. eleman) 2 eleman ncesinde bulunan dizi elemanna (dizinin 0. eleman) 7 deeri atanr. dizi[1]'in deeri 1 olduu iin *(dizi + dizi[1]) ifadesi *(dizi + 1) olur ve dizinin 1.elemannn deerini verir (yani tamsay 1). Sonu olarak oluan dizi[ *p++ ] = 1 + 2 ifadesi, p adres deikeni dizinin 2. elemanna iaret ettii iin dizi[ 2 ] = 3 atama deyimidir. Bylece deeri artrlan p adres deikeni dizinin 3. elemanna iaret eder ve *(p + 1) = 5 deyimi ile dizinin 4. elemanna 5 deeri atanr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-37

Dizinin 3. elemannn deeri 9 olduu iin dizi[ *p - 8 ] = 8 atama deyimi ile dizinin 1. elemanna 8 deeri atanr. Dizi elemanlarnn deerleri ktda da grld gibi, srasyla 7, 8, 3, 9, 5 olur.
ekil 5.2-6 ++ ve * operatrleri ile oluturulan ifadelerin ilenmesi.
sadan sola sadan sola sadan sola sadan sola

(1)

i = *p++;

i = *++p;

i = ++*p;

i = (*p)++;

(2)

i = *(p++);

i = *(++p);

i = ++(*p);

i = *p; *p = *p + 1;

(3)

i = *p; p++;

++p; i = *p;

*p = *p + 1; i = *p;

(4)

i = *p; p = p + 1;

p = p + 1; i = *p;

5.3 Adres Deikenleri ve Dizgiler


Bir dizgi sabiti yada ksaca dizgi (string constant, character string yada string literal) ift trnaklar arasna yerletirilen sfr yada daha fazla karakterden oluur. rnein "12345abc" bir dizgi sabitidir. ift trnaklar yalnzca dizgiyi snrlamak iin kullanlr ve dizginin bir paras deildir. ki ift trnaktan oluan ve hibir karakter iermeyen dizgi bo dizgi olarak adlandrlr ( "" ). Karakter sabitlerinde kullanlan escape dizinleri (\n, \t, \007 gibi) dizgiler iinde de kullanlabilir. Dizgi iinde yer alan \" karakterleri tek bir ift trna ifade eder. Derleme srasnda pepee verilen dizgi sabitleri birbirine eklenir. rnein ekrana abcd karakterlerini yazan bir printf ars iki ekilde de olabilir:
printf( "ab" "cd\n" );

yada
printf( "abcd\n" );

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-38

Dizgiler bellekte ASCII kodu 0 olan bo karakter (null character: \0 yada karakter sabiti olarak '\0') ile sonlanm karakter dizileri olarak saklanrlar. Dolaysyla bir karakter dizisine ilk deer atama parantezlerle snrl ve virglle ayrlm karakter sabitleri listesi yerine dizgi sabiti kullanlarak yaplabilir:
char s[ ] = { 'a', 'b', 'c', '\0' };

yerine
char s[ ] = "abc";

kullanlabilir. kinci bildirimde dizgi sabitindeki karakterler s dizisinin elemanlarna atanr ve dizgi sonuna C tarafndan otomatik olarak bo karakter yerletirilir. Derleyici dizi uzunluuna '\0' karakterini de dahil eder. Dizgiler zerinde ilemler yaplrken bu karakter kullanlarak dizgi sonu belirlenebilir. Bildirimde dizi boyutlar verildiinde, dizgi sabitindeki karakter says dizinin eleman saysn gememelidir ('\0' hari). Herhangi bir dizgi sabiti karakter dizisi tipindedir ve deeri dizginin bellekte bulunduu alann balang adresidir (karakter dizisinin balang elemannn bellek adresi). Bir programda dizgi sabitinde bulunan karakterlere eriim, balang elemanna iaret eden adres deeri kullanlarak gerekletirilir. Dizgi sabitleri rnek programlarda ounlukla printf fonksiyonu argman olarak kullanld. Dolaysyla bir dizgiyi argman olarak alan printf fonksiyonu karakter dizisi balangcna iaret eden adres deeri alr. Bu nedenle indeks yada adres-offset ifadeleri kullanlarak gerekletirilen dizi ilemleri, dizgilerle de yaplabilir. Blm 5'de yer alan sizeof.c programnda (sayfa 5-5) char tipi verilere iaret eden s adres deikeni ve t karakter dizisi bildirilir ve "1234" dizgisi ile ilk deer atamalar yaplr. lk deerleri ayn olsa dahi bu iki bildirim birbirinden olduka farkldr. ktda da grld gibi sizeof operatr s iin 2 byte, t iin ise 5 byte deerini dndrr. nk s bir dizgi sabitine iaret eden adres deikenidir. lk deer olarak bildirimde bir karakter dizisinin adresi atanmtr. s adres deikeninin deeri bir baka dizgiye iaret edecek ekilde deitirilebilir. t ise bellekte 5 karakterlik alana sahip bir karakter dizisidir. erdii karakterler deitirilebilir fakat t daima ayn bellek alanna iaret eder (dizi ismi balangc adresini veren sabittir):
s: t:
'1' '2' '3' '1' '4' '2' '\0' '3' '4' '\0'

s adres deikenine deer atama ayr bir deyimde de yaplabilir:


char *s; s = "1234";

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-39

Dizginin balang adresini ald iin printf( "1234" ) ars yerine s adres deikeninin yada t dizisinin argman olarak aktarld aadaki printf arlar da ekrana yine "1234" dizgisini yazar:
printf( s ); yada printf( t );

Aadaki rnek programda a ve b karakter dizileri tanmlanr. lk deer atama iki ekilde de yaplabilir. Programda ayrca dizgi sabiti ile oluturulan ve C programlarnda pek rastlanmayan eitli ifadeler yer alr: dizgi sabitine indirek deer operatr uygulanarak dizginin ilk karakteri alnr; dizgi sabitine indeks uygulanarak bir karaktere eriilir ve adres aritmetiinin deime zelliinden faydalanlarak dizgideki bir karaktere eriilir. Bu ilem sonucu ekrana 023 karakterleri listelenir. ktda da grld gibi, her iki printf arsnda da ayn dizgi sabiti ("a") yer ald halde bellek adresleri farkldr. Dizgi sabiti "a", karakter sabiti 'a' ile kartrlmamaldr. 'a' bir karakter sabitidir ve ifadelerde a karakterinin ASCII kodunu veren tamsaydr. "a" ise a karakteri ve '\0'den oluan karakter dizisidir.
rnek 5.3-1 karak.c program. #include <stdio.h> #include <string.h> int main(void) { char a[ ] = "1234"; char b[ ] = { '1', '2', '3', '4', '\0' }; printf( "sizeof a : %u, sizeof b : %u\n", sizeof a, sizeof b ); printf( "strlen(a) : %u, strlen(b) : %u\n", strlen(a), strlen(b) ); printf( "%p\n", "a" ); printf( "%p\n", "a" ); putchar( *"0" ); putchar( "012345"[2] ); putchar( *(3+"012345") ); return 0; } kt sizeof a : 5, sizeof b : 5 strlen(a) : 4, strlen(b) : 4 0083 0089 023

rnek 5.3-2'de karakter dizisi s bildirilir ve elemanlarna ilk deer olarak "01234ab" dizgi sabitinde bulunan karakterler atanr. s dizisinin son eleman dizgi sonunu
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-40

iaretleyen '\0' karakteridir. Daha sonra char tipi verilere iaret eden ps adres deikeni bildirilir. Adres deikenine ilk deer olarak karakter dizisinin balang elemannn bellek adresi atanr. Bylece adres deikeni kullanlarak tm dizi elemanlarna eriilebilir.
rnek 5.3-2 dizgi.c program. #include <stdio.h> #include <string.h> #define NL '\n' int main(void) { char s[ ] = "01234ab"; char *ps = s; int i, BOY = strlen( s ); putchar( *ps++ ); putchar( *(ps++) ); putchar( (*ps)++ ); putchar( *++ps ); putchar( *(++ps) ); putchar( ++*ps ); putchar( ++(*ps) ); putchar( NL );
/* /* /* /* /* /* /* /* putchar( *ps ); ps++; yukaridaki deyim ile ayni */ */

putchar( *ps ); *ps = *ps + 1; */ ++ps; putchar( *ps ); */ yukaridaki deyim ile ayni */ *ps = *ps + 1; putchar( *ps ); */ yukaridaki deyim ile ayni */ 0123456 */

ps = s; while ( ps < s + BOY ) putchar( *ps++ ); putchar( NL ); /* 01336ab */ ps = s + BOY - 1; while ( ps >= s ) putchar( *ps-- ); putchar( NL ); /* ba63310 */ for ( ps = s, i = 0; i < BOY; i++ ) putchar( ps[i] ); putchar( NL ); /* 01336ab */ for ( ps = s + BOY - 1, i = 0; i < BOY; i++ ) putchar( ps[-i] ); putchar( NL ); /* ba63310 */ ps = s; while ( *ps ) /* while ( *ps != '\0' ) */ putchar( *ps++ ); putchar( NL ); /* 01336ab */ i = 0; C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-41

rnek 5.3-2 devam


ps = s; while ( ps[i] ) /* while ( ps[i] != '\0' ) */ putchar( ps[i++] ); putchar( NL ); /* 01336ab */ return 0; } kt 0123456 01336ab ba63310 01336ab ba63310 01336ab 01336ab

Programda yer alan iki while dngsnn test ifadesinde dizgi sonu, bo karakter kontrolu yaplarak belirlenir. Test ifadeleri koul salandnda (test doru olduunda) 0 harici bir deer, koul salanmadnda (test yanl olduunda) ise 0 deerini dndrr. Bu nedenle while dnglerinin test ifadelerinde *ps != '\0' ve ps[ i ] != '\0' yerine, sadece *ps ve ps[ i ] ifadeleri kullanlmtr. nk dizgi sonuna gelindiinde *ps ve ps[ i ] ifadelerinin deeri bo karakter ( 0 ) olacaktr; yani != '\0' koulunun yanl olmas durumunda dndrecei deer. Programda yer alan ilk putchar deyim grubu ekrana 0123456 karakterlerini yazar. Her putchar deyiminin ak formu, ayn satrda aklama satr olarak verilmitir. Grld gibi, ilk iki deyimde ps adres deikeninin iaret ettii karakter ekrana yazlr ve ps adres deikeninin deeri artrlarak bir sonraki karaktere iaret etmesi salanr. zleyen deyimde ise iaret edilen karakter (2) ekrana yazlr ve bu karakterin ASCII kod deeri bir artrlr. Bylece karakter dizisinin ikinci eleman 3 karakteri olur. Bundan sonra ps adres deikeninin deeri yine artrlr ve iaret edilen karakter (3) ekrana listelenir. lem izleyen deyimde bir kez daha tekrarlanarak ekrana 4 karakteri yazlr. Son iki deyimde, 4 karakterinin ASCII kod deeri iki kez artrlr ve elde edilen deerler ayn alana yazldktan sonra ekrana listelenir. Sonu olarak 4 karakterinin bulunduu bellek alannda bu iki deyim sonras 6 karakteri bulunur. Dizginin son iki karakterine eriim gereklemez. Programda adres deikeni ile oluturulan deyimler kullanlarak, s karakter dizisinin elemanlarnn deerleri ekrana listelenir (*ps++, *ps--, ps[i], ps[-i], ps[i++] ).

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-42

Karakter dizisinin elemanlarnn deerleri dizi ismi ile oluturulan s[i] yada *(s+i) ifadeleri kullanlarakta listelenebilirdi:
... i = 0; while ( s[ i ] ) putchar( s[i++] ); ...

yada
... i = 0; while ( *(s + i) ) { putchar( *(s + i) ); i++; } ...

Fakat burada ama dizgiye iaret eden adres deikeni kullanmn rneklemektir. s karakter dizisinin elemanlar char tipinde veriler, yani 1 byte byklnde sral bellek alanlarnda saklanan ASCII kodlardr ve sembolik bellek grnmleri aadaki gibi olur:
ekil 5.3-1 char *ps = s; deyimi sonras s karakter dizisinin ve ps adres deikeninin sembolik bellek grnm.

:
s[0] s[1] s[2] s[3] s[4] s[5] s[6] s[7] '0' '1' '2' '3' '4' 'a' 'b' '\0'

Bellek

: :
ps &s[0]

Standart C Ktphanesi dizgi giri/k ilemleri iin, dizgileri bir btn olarak yada karakter-karakter ileyen eitli fonksiyonlar ierir (gets, puts, getchar, putchar, scanf ve printf gibi). Ayrca C ktphanesinde dizgiler ve karakterler zerinde ilemler yapan
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-43

eitli fonksiyon ve makrolar bulunur (strcat, strchr, strcmp, strcpy, strlen, isalpha, isupper, islower, isdigit, toupper, tolower gibi). zleyen blmde, elemanlar dizgilere iaret eden char * tipi adres deikenleri olan adres dizileri anlatlacaktr.

5.4 Adres Dizileri


C dilinde elemanlar adres deerleri saklayabilecek diziler bildirilebilir. Byle bir dizi adres dizisi olarak adlandrlr ve bu dizinin sral bellek adreslerinde bulunan her eleman iin, donanma bal olarak tek bir adres deeri tayabilecek byklkte bellek alan ayrlr. Adres dizisinin elemanlar birbirini izleyen bellek adreslerinde bulunan ve tadklar deerlere adres dizisi ismi ve indeks operatr ile oluturulan ifadelerle eriilen adres deikenleridir. Fakat bu adres deikenlerinin tad adres deerleri sral olmayabilir. Aadaki bildirim deyimi ile char tipi verilere iaret eden 4 adres deikeninden oluan AdrDizi adres dizisi bildirilir:
char *AdrDizi [ 4 ];

Bu bildirim deyimi, indeks operatr ncelik listesinde indirek deer operatr ncesinde bulunduu iin adres dizisi deikeni (AdrDizi [...]) ile eriilen her dizi elemannn tipinin char * olduunu ifade eder. Bir baka deyile AdrDizi, char * tipindeki 4 veriden oluan dizi; yani char*[4] tipindedir. sizeof (char*[4]) yada sizeof (AdrDizi) ifadeleri dizinin toplam bellek alannn byte olarak bykln verecektir.
rnek 5.4-1 adrdizgi.c program. #include <stdio.h> #include <stdlib.h> #include <string.h> #define NL '\n' int main(void) { int i, j; char *AdrDizgi [ ] = { "a", "bcd987", "123", NULL }; printf( "sizeof AdrDizgi : %u, sizeof *AdrDizgi : %u\n" "sizeof **AdrDizgi : %u\n" "sizeof AdrDizgi[0] : %u, sizeof AdrDizgi[0][0] : %u\n", sizeof AdrDizgi, sizeof *AdrDizgi, sizeof **AdrDizgi, sizeof AdrDizgi[0], sizeof AdrDizgi[0][0] );

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-44

...rnek 5.4-1 devam


printf( "AdrDizgi : %p, *AdrDizgi : %p\n" "**AdrDizgi : %u\n" "AdrDizgi[0] : %p, AdrDizgi[0][0] : %u\n", AdrDizgi, *AdrDizgi, **AdrDizgi, AdrDizgi[0], AdrDizgi[0][0] ); for ( i = 0; i < sizeof AdrDizgi/ sizeof AdrDizgi[0] - 1; i++ ) printf( "AdrDizgi [ %d ] : %p, *AdrDizgi [ %d ] : %c, " "AdrDizgi[ %d ] dizgisi : %s\n", i, AdrDizgi[ i ], i, *AdrDizgi[ i ], i, AdrDizgi[ i ] );
/* * Adres dizisini sonlandiran NULL adres degeri test edilerek * dizgilerin listelenmesi: * while ( AdrDizgi[ i ] != NULL ) */

i = 0; while ( AdrDizgi[ i ] ) puts( AdrDizgi[ i++ ] );


/* * Adres dizisini sonlandiran NULL adres degeri ve her dizgi icinde * dizgileri sonlandiran '\0' (null character) test edilerek * dizgilerde bulunan karakterlerin listelenmesi: * while ( AdrDizgi[ i ] != NULL ) * ... * * */ while ( AdrDizgi[ i ][ j ] != '\0' ) ...

i = 0; while ( AdrDizgi[ i ] ) { j = 0; while ( AdrDizgi[ i ][ j ] ) putchar( AdrDizgi[ i ][ j++ ] );


/* * while ( ... ) * { * putchar( *(*(AdrDizgi + i ) + j) ); * j++; * } */

putchar( NL ); i++; } i = 0; while ( AdrDizgi[ i ] ) { printf( "AdrDizgi[ %d ] dizgisi %u karakter. \n", i, strlen( *(AdrDizgi + i ) ) );
/* i, strlen( AdrDizgi[ i ] ) ); */

i++; } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-45

...rnek 5.4-1 devam


puts( printf( " " Adres Karakter ASCII kod" ------- ---------- ------------" ); );

for ( i = 0; i < sizeof AdrDizgi/ sizeof AdrDizgi[0] - 1; i++ ) { putchar( NL ); j = 0; do { printf( "AdrDizgi [ %d ][ %d ] : %p %c %d\n", i, j, &AdrDizgi [ i ][ j ], AdrDizgi [ i ][ j ], AdrDizgi [ i ][ j ] ); } while ( AdrDizgi [ i ][ j++ ] ); } return 0; } kt sizeof AdrDizgi : 8, sizeof *AdrDizgi :2 sizeof **AdrDizgi :1 sizeof AdrDizgi[0] : 2, sizeof AdrDizgi [ 0 ][ 0 ] : 1

AdrDizgi : 0F3C, *AdrDizgi : 0042 **AdrDizgi : 97 AdrDizgi[ 0 ] : 0042, AdrDizgi [ 0 ][ 0 ] : 97 AdrDizgi [ 0 ] : 0042, *AdrDizgi [ 0 ] AdrDizgi [ 1 ] : 0044, *AdrDizgi [ 1 ] AdrDizgi [ 2 ] : 004B, *AdrDizgi [ 2 ] a bcd987 123 a bcd987 123 AdrDizgi [ 0 ] dizgisi 1 karakter. AdrDizgi [ 1 ] dizgisi 6 karakter. AdrDizgi [ 2 ] dizgisi 3 karakter. Adres ------AdrDizgi [ 0 ][ 0 ] : 0042 AdrDizgi [ 0 ][ 1 ] : 0043 AdrDizgi [ 1 ][ 0 ] : 0044 AdrDizgi [ 1 ][ 1 ] : 0045 Karakter ASCII kod ---------- -----------a 97 0 b c 98 99 : a, AdrDizgi [ 0 ] dizgisi : a : b, AdrDizgi [ 1 ] dizgisi : bcd987 : 1, AdrDizgi [ 2 ] dizgisi : 123

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-46

...rnek 5.4-1 kt devam


AdrDizgi [ 1 ][ 2 ] AdrDizgi [ 1 ][ 3 ] AdrDizgi [ 1 ][ 4 ] AdrDizgi [ 1 ][ 5 ] AdrDizgi [ 1 ][ 6 ] AdrDizgi [ 2 ][ 0 ] AdrDizgi [ 2 ][ 1 ] AdrDizgi [ 2 ][ 2 ] AdrDizgi [ 2 ][ 3 ] : : : : : : : : : 0046 0047 0048 0049 004A 004B 004C 004D 004E d 9 8 7 1 2 3 100 57 56 55 0 49 50 51 0

C dilinde dizgilerden oluan dizi, iki ekilde oluturulabilir: iki-boyutlu karakter dizisi (izleyen blmlerde anlatlacaktr) yada adres dizisi olarak: 2-b karakter dizisi:
char s [ ] [ 7 ] = { "a", "bcd987", "123" };

adres dizisi:
char *m [ ] = { "a", "bcd987", "123" };

yada
char *m [ 3 ]; m [ 0 ] = "a"; m [ 1 ] = "bcd987"; m [ 2 ] = "123";

s dizisi bildirimi ile, herbiri 7 karakter uzunluunda (dizgi sonunu iaretleyen '\0' dahil) 3 karakter dizisi iin bellek alan ayrlr. Dizgiler ayrlan bellek alannn tamamn kullanmayabilir ( "a" ve "123" dizgilerinde olduu gibi). Bildirimde verilmeyen s dizisinin 1.boyut deeri, ilk deer listesinde bulunan dizgi saysna gre derleyici tarafndan saptanabilir. 2.boyut deeri ise en uzun dizgiye gre belirlenmitir. Bylece dizgiler bellekte 2-b dizinin satrlar olarak saklanrlar:
s[0]: s[1]: s[2]:
s dizisi 'a' '\0' 'b' 'c' '1' '2' ... 'd' '3' ... '9' '\0' ... '8' ... ... '7' ... ... '\0' ...

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-47

Burada s[ i ], dizinin i. satr olan dizginin balang adresini veren sabittir. Adres dizisi bildirimi ile bellekte 3 adet char * tipinde adres deikeni iin ve ayrca 1+1, 6+1 ve 3+1 karakter uzunluunda (+1 karakter '\0' iindir) ayr karakter dizisi iin bellek alan ayrlr. Adres dizisinin eleman olan her adres deikeni bir dizgiye iaret eder:
adres dizisi

m[0]: m[1]: m[2]:

dizgiler 'a' '\0' 'b' '1' 'c' '2' 'd' '3' '9' '\0' '8' '7' '\0'

kinci uygulama ile farkl uzunluklarda dizgilerden oluan dizi (ragged array) oluturulabilir. Komut satr argmanlar bu ekilde bir dizidir. Bu uygulama daha verimlidir. Fakat izleyen blmlerde anlatlacak olan dinamik bellek alan kullanm sz konusu olduunda, gerekli bellek alan ayrma ileminin ayr ayr her dizgi iin yaplmas gerekir. Her iki uygulamada, bir dizgideki herhangi bir karaktere erien ifade indeks operatrleri kullanlarak ayn ekilde oluturulur: s[1][2] yada m[1][2] gibi. Bu iki ifade birbirinin ayn deildir ve sz konusu karaktere eriimi farkl ekilde gerekletirirler. rnek 5.4-1'de char tipi verilere iaret eden 4 adet adres deikeninden oluan AdrDizgi adres dizisi tanmlanr. lk deer listesinde yer alan son deer bo adres deeridir (NULL). Dolaysyla AdrDizgi[ 3 ] adres deikeni hibir dizgiye iaret etmez. Bu deer adres dizisi sonunu belirlemek iin kullanlr. Dizi ismi AdrDizgi, adres dizisinin balang adresini veren adres sabitidir. Bir ifadede AdrDizgi, ift adres sabitine dnr. Yani AdrDizgi'nin deeri, adres dizisinin ilk elemannn (ilk dizginin balangcna iaret eden) bellek adresidir. Adres dizisinin ilk eleman ilk dizginin balangcna iaret ettii iin, AdrDizgi'ye iki kez * operatr uygulandnda, a karakterine eriilir:
adres sabiti: AdrDizgi :
&AdrDizgi[0]

adres dizisi: AdrDizgi[0]: &AdrDizgi[0][0] AdrDizgi[1]: &AdrDizgi[1][0] AdrDizgi[2]: &AdrDizgi[2][0] AdrDizgi[3]:

dizgiler: 'a' 'b' '1' '\0' 'c' '2' 'd' '3' '9' '\0' '8' '7' '\0'

rnek programda, AdrDizgi adres dizisine bildirim srasnda ilk deer atama yaplarak farkl uzunlukta 3 dizginin balang elemanlarnn bellek adresleri atanr. Adres dizisinin elemanlarnn adreslerini &AdrDizgi[i] yada AdrDizgi+i ifadeleri verir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-48

ktda grld gibi, AdrDizgi[...][...] ifadesi ile dizgilerin eleman olan 1-byte byklnde char verilere eriilir. AdrDizgi[0][0]'n deeri, ilk dizginin balang eleman olan a karakterinin ASCII kodu olan 97 deeridir. nk AdrDizgi[0] ilk dizginin balang adresini veren adres deikenidir (bu donanmda 2-byte) ve indirek deer operatr uygulandnda iaret ettii bellek alannda bulunan char deeri verir. Programda dizgileri ve karakterleri listelemek iin eitli dngler yer alr. sizeof(AdrDizgi) ifadesi adres dizisinin toplam bellek alan bykl olan 8-byte deerini; sizeof(AdrDizgi[0]) ise dizinin eleman olan bir adres deikeninin bellek alan bykl olan 2-byte deerini verir. Dolaysyla
sizeof AdrDizgi / sizeof AdrDizgi[0]

ifadesi de dizinin eleman saysn verir ve dnglerin bir ksmnda NULL testi yaplmadan adres dizisindeki eleman saysnn saptanmasn salar. Aadaki rnek programda, double tipinde verilere iaret eden 5 adres deikeninden (AdrDizi[0], AdrDizi[1], AdrDizi[2], AdrDizi[3] ve AdrDizi[4]) oluan adres dizisi bildirilir. for dngsnde adres dizisinin elemanlarna double dizi ddizi'nin elemanlarnn sral bellek adresleri atanr. Bylece ddizi'nin elemanlarna programda grld gibi adres dizisi kullanlarak eriilebilir.
rnek 5.4-2 adrd.c program. #include <stdio.h> #define ELSayi(dizi) sizeof dizi / sizeof dizi[0] int main(void) { int i; double ddizi[ ] = { 3.5, 7.9, 1.2, 5.3, 4.4 }, *AdrDizi[ ELSayi(ddizi) ]; for ( i = 0; i < ELSayi(ddizi); i++ ) *( AdrDizi + i ) = ddizi + i; /* AdrDizi[ i ] = &ddizi[ i ]; */ for ( i = 0; i < ELSayi(ddizi); i++ ) printf( "ddizi[%d] : %1.1f, *AdrDizi[%d] : %1.1f\n", i, ddizi[ i ], i, *AdrDizi[ i ] );
/* * printf( "ddizi[%d] : %1.1f, *AdrDizi[%d] : %1.1f\n", i, *(ddizi+i), i, **(AdrDizi+i) ); */

return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-49

...rnek 5.4-2 devam


kt ddizi[ 0 ] ddizi[ 1 ] ddizi[ 2 ] ddizi[ 3 ] ddizi[ 4 ] : : : : : 3.5, *AdrDizi[ 0 ] : 7.9, *AdrDizi[ 1 ] : 1.2, *AdrDizi[ 2 ] : 5.3, *AdrDizi[ 3 ] : 4.4, *AdrDizi[ 4 ] : 3.5 7.9 1.2 5.3 4.4

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-50

5.5 ift Adres Deikeni


Bir adres deikeni bir baka adres deikenine iaret edecek ekilde bildirilebilir. Aadaki rnekte yer alan double **ppd = &pd deyimi, double * tipindeki pd adres deikenine iaret eden ppd adres deikenini bildirilir:
rnek 5.5-1 ciftadr.c program. #include <stdio.h> int main(void) { double d = 9.3, *pd = &d, **ppd = &pd;
/* * * * * * * */ double d = 9.3; double *pd; double **ppd; ... pd = &d; ppd = &pd;

printf( "d : %1.1f, *pd : %1.1f, **ppd : %1.1f\n", d, *pd, **ppd ); printf( "&d : %p, pd : %p, *ppd : %p\n", &d, pd, *ppd ); printf( "&pd : %p, ppd : %p\n", &pd, ppd ); return 0; } kt d : 9.3 &d : 1090 *pd : 9.3 **ppd : 9.3 pd : 1090 *ppd : 1090 &pd : 1098 ppd : 1098

ppd adres deikeni, indirek deere (9.3) eriim iki seviyede gerekletii iin ift adres deikeni (double pointer) olarak adlandrlr. ktda da grld gibi ppd ifadesi, pd adres deikeninin bellek adresini; *ppd ise d deikeninin bellek adresini verir. ppd adres deikeni, indirek deer operatr iki kez uygulandnda d deikeninin deerini verir (**ppd).
ppd: pd: d:

&pd

&d

9,3

ndirek eriimin iki seviyeden fazla olduu uygulamalar ok azdr. ift adres deikenleri izleyen blmlerde de anlatlaca gibi genel olarak adres dizileri fonksiyonlara argman olarak aktarlrken, komut satr argmanlar kullanlrken, bir fonksiyonun aran bloktaki adres deikeninin deerini deitirmesi istendiinde yada dinamik bellek alan ayran fonksiyonlar kullanlrken gereklidir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-51

5.6 Adres Deikenlerine Tip Dntrme Uygulanmas


C dilinde herhangi bir ifadeye, tip dntrme operatr uygulanarak tip dntrme yaplabilir. Bylece derleyicinin bu ifadeyi farkl bir veri tipinde grmesi salanabilir:
(tip-ismi) ifade

Tip dntrme ilemi, adres deikenlerine yada adres deeri veren ifadelere de uygulanabilir. Bu yolla adres deikeninin yada adres deeri veren ifadenin deeri bildirildiinden farkl bir tipte verinin adresi olarak ilem grebilir. Aadaki rnek programda, 1-byte char verilerden oluan cDizi dizisinin balangcna iaret eden char * tipindeki Adrc adres deikenine tip dntrme uygulanarak bu donanmda 2-byte olan int verilere iaret etmesi salanr. Tip dntrme ileminin uyguland adres deikeni 2-byte verilere iaret ettii iin tad adres deerine tamsay 1'in eklendii ifade adres aritmetiine gre yorumlanr ve cDizi'nin 2. elemannn bellek adresi elde edilir (&cDizi[2]). Elde edilen adres deeri yine bir int veriye iaret eder. Bu adres deeri tekrar tip dntrme uygulanarak char * tipine dntrlr ve ayn tipteki Adrc adres deikenine atanr. Adrc adres deikenine indirek deer operatr uygulandnda cDizi[2]'nin deeri olan 0xC3 elde edilir. Bu ilemde,
Adrc = (char *)( (int *)Adrc + 1);

ifadesi yerine,
( (int *)Adrc )++;

ifadesi kullanlamaz. nk tip dntrme operatr bir bellek alannda bulunan bit deerlerinin farkl tipte grlmesini ve buna gre ilenmesini salamaz; ancak atama yaplamayan bir rvalue (atama ileminde sada bulunan deer) oluturur. Artrma operatr ++ ise lvalue gerektirir. Programda ayrca Adrc+2 adresinde bulunan tamsay deer listelenir. Bunun iin dizinin balangc adresine tamsay 2 deerinin eklendii ve dizinin 2.elemannn char * tipindeki bellek adresini veren Adrc+2 ifadesine yine tip dntrme 2-byte bellek alanna iaret etmesi salanr. Elde edilen adres deerine * operatr uygulanarak bu alanda bulunan deer unsigned int olarak Tams deikenine atanr. C derleyicisi tip dntrme ileminden dolay Adrc+2 ifadesinin dndrd adres deerini unsigned int tipi verinin bellek adresi olarak grr ve atama deyimi ile bu adresteki 2-byte deeri (0xD4C3) Tams deikenine atar.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-52

Bu ilem aadaki deyimler kullanlarak gerekletirilebilir:


unsigned *pi; ... pi = (unsigned *)&cDizi[0]; Tams = *( pi + 1 );

/* /*

pi = (unsigned *)cDizi; Tams = pi[1];

*/ */

rnek 5.6-1 adrcevir.c program. #include <stdio.h> #define ELSayi(dizi) sizeof dizi / sizeof dizi[0] int main(void) { unsigned char cDizi [ ] = { 0xA1, 0xB2, 0xC3, 0xD4 }, *Adrc = cDizi; unsigned Tams, i; printf( "cDizi dizisi %u byte.\n", sizeof cDizi ); for( i = 0; i < ELSayi( cDizi ); i++ ) printf( "%u.byte : 0x%02X\n", i+1, *(Adrc+i) ); Adrc = (char *)( (int *)Adrc + 1 ); printf( "*Adrc : 0x%02X\n", *Adrc ); Adrc = cDizi; Tams = *(unsigned *)(Adrc + 2); printf( "Tams : 0x%04X\n", Tams ); return 0; } kt cDizi dizisi 4 byte. 1.byte: 0xA1 2.byte: 0xB2 3.byte: 0xC3 4.byte: 0xD4 *Adrc : 0xC3 Tams : 0xD4C3

Tek operand alan (unary) tip dntrme operatr (type cast operator yada type conversion operator) ve adres operatrleri (* ve &) ayn operatr nceliine sahiptir. Grup ilikileri sadan sola doru olduu iin ifade iinde bir arada bulunduklarnda sadan sola doru alrlar.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-53

void * tipi adres deikenleri


void tip belirleyici nceki blmlerde deer dndrmeyen yada argman almayan fonksiyonlar tanmlanrken kullanld. C dilinde, void * tipinde bildirilen bir adres deikeni hibir veriye iaret etmez; indirek deerinin alnmas anlamszdr. Ancak void * tipinde bir adres deikeninin deeri herhangi bir tipteki adres deikenine tip dntrme yaplmadan atanabilir. Herhangi bir tipteki adres deikeninin deeri de void * tipinde bir adres deikenine yine tip dntrme yaplmadan atanabilir. Baz uygulamalarda void * tipi adres deikenleri kullanlr. rnein izleyen blmlerde anlatlacak olan dinamik bellek ynetimi iin kullanlan baz standart C ktphane fonksiyonlar void * tipinde adres deeri dndrr. Bylece ayrlan bellek alanna eriim belli bir veri tipi ile snrlandrlmad iin dndrlen adres deeri herhangi bir tipteki adres deikenine atanarak istenen ekilde eriim gerekletirilebilir (baz programlarda okunabilirlii artrmak iin zaman zaman dndrlen void * tipi adrese tip dntrme yaplr). Pek ok standart C ktphane fonksiyonu da argman olarak void * adres deeri alr. zleyen blmlerde bir bellek blounu bir baka adrese byte-byte kopyalamak zere tanmlanan BlokKopya fonksiyonu da argman olarak void * tipi adres deeri alan fonksiyon rneidir. Aadaki programda void * tipi adres deikenleri kullanlarak bir tamsaynn byte deerleri listelenir:
rnek 5.6-2 void.c program. #include <stdio.h> int main(void) { int i = 0xABCD, ByteSayi; char c = 'A', *pc; void *pv; pv = &c; pc = pv; printf("c : %c\n", *pc ); pv = &i; printf( "i : 0x%04X, &i : %p\n", i, &i ); for ( ByteSayi = 0; ByteSayi < sizeof i; ByteSayi++ ) printf( "%p adresinde bulunan byte : 0x%02X\n", (char *)pv + ByteSayi, *( (char *)pv + ByteSayi ) & 0xFF ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-54

...rnek 5.6-2 devam


kt c:A i : 0xABCD, &i : 0DA2 0DA2 adresinde bulunan byte : 0xCD 0DA3 adresinde bulunan byte : 0xAB

Bir adres deikenine farkl tipte bir verinin adresi atanrken tip dntrme ilemi uygulanarak derleyiciye bilgi verilir. Aksi taktirde derleyici uyar mesaj verir. Programda grld gibi tip dntrme ilemi void * adres deikenlerine atama yaplrken yada void * adres deikeninin deeri bir baka adres deikenine atanrken gerekmez. kt incelendiinde programn derlendii donanmda, deikenin en dk anlaml (Least Significant) byte deeri dk bellek adresinde saklanr (yani 0xCD byte' 0DA2 adresinde bulunur). Bu bellek dzeni little-endian olarak adlandrlr. nk bellekte yukar doru giderken (artan bellek adresi ynne doru) verinin en dk anlaml byte deeri nce bulunur. Baz donanmlar big-endian dzenini kullanr. Bu dzenlerden hangisinin kullanld bit deerleri zerinde ilemler yaplrken nem kazanr.
NOT: Bilgisayar bellei byte'lara blnmtr. Her byte, 8 bit'ten oluur (1 yada 0 olmak zere iki deerin saklanabilecei en kk bellek birimi 1 bit -binary digitbyklndedir). Veriler bilgisayar belleinde bit'lerden oluan ikili saylar (binary number) olarak saklanr (rnek programlarda bellekte saklanan deerler sembolik bellek grnmlerinin kolay anlalr olabilmesi iin ondalk saylar olarak gsterildi). Kullanlan iki ayr fiziksel bellek organizasyon ekli vardr: little-endian ve big-endian. Bunlar bilgisayarn bir ikili saydaki bit'leri nasl organize ettii ile ilgilidir. Little-endian dzeninde, birden fazla byte ieren bir ikili saynn least significant byte' dk bellek adresine yerletirilir. Dolaysyla, most significant byte yksek bellek adresinde saklanr. Bu farkllk bit ilemleri yaplan programlarda ve ikili tamsaylar disk dosyasna yazan programlarda tanabilirliini nler. Ayrca iki farkl donanm arasnda veri tanmas szkonusu olduunda byte sras nem kazanr. Binary dosya giri/k fonksiyonlar fread ve fwrite saylar ikili formatta yazarken yada okurken donanmn endian dzenine gre okur (bu programn yazld donanmda byte sras little-endian yani sadan sola doru olduu iin rnek 5.62'de low-byte deeri high-byte ncesinde bulunur). endian.c programnda, onaltlk saylarn bit kaydrma ilemi (>>) yaplarak ikili say sistemindeki karlklar listelenmitir. Programda ayrca unsigned int ve unsigned long int tamsay deikenlerin bellek adresleri tip dntrme (typecasting) uygulanarak char tipi verilere iaret eden adres deikenine atanr ve C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-55 srasyla bu deikenler iin bellekte ayrlan 2-byte ve 4-byte (bu donanmda) bellek alanlarna byte-byte eriilerek bu alanlarda bulunan deerler listelenir. kt incelendiinde programn oluturulduu donanmn bellek dzeninin little-endian olduu anlalr. /* * */ endian.c programi.

#include <stdio.h> void ListBit( unsigned long Sayi, size_t BitSayi ); int main(void) { unsigned int unsigned long unsigned char

i = 0xABCD, ByteSayi; n = 0xAB12CD34; *pc = (char *)&i;

printf( "i : 0x%04X, &i : %p, ", i, &i ); ListBit( i, sizeof(i) * 8 ); puts( "Adres: Deger: Hex,(Binary)\n------ -------------------"); for ( ByteSayi = 0; ByteSayi < sizeof i; ByteSayi++ ) { printf("%p 0x%02X,", pc + ByteSayi, *(pc + ByteSayi) ); ListBit( *(pc + ByteSayi), sizeof(char) * 8 ); } pc = (char *)&n; printf( "\nn : 0x%08lX, &n : %p, ", n, &n ); ListBit( n, sizeof(n) * 8 ); puts( "Adres: Deger: Hex,(Binary)\n------ -------------------"); for ( ByteSayi = 0; ByteSayi < sizeof n; ByteSayi++ ) { printf("%p 0x%02X,", pc + ByteSayi, *(pc + ByteSayi) ); ListBit( *(pc + ByteSayi), sizeof(char) * 8 ); } return 0; } void ListBit(unsigned long Sayi, size_t BitSayi) { putchar( '(' ); while ( BitSayi-- > 0 ) putchar( '0' + (char)((Sayi >> BitSayi) & 0x01) ); puts( ")" ); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-56

...endian.c devam
kt i : 0xABCD, &i : 0E10, (1010101111001101) Adres: Deger: Hex,(Binary) 0E10 0xCD, (11001101) 0E11 0xAB, (10101011)

n : 0xAB12CD34, &n : 0E0A, (10101011000100101100110100110100) Adres: Deger: Hex,(Binary) 0E0A 0x34, (00110100) 0E0B 0xCD, (11001101) 0E0C 0x12, (00010010) 0E0D 0xAB, (10101011) Little-endian ve big-endian donanmlarda bir word iindeki byte organizasyonunu gstermek iin aadaki ekiller hazrlanmtr. Programn oluturulduu donanmda word bykl (word size) 2 bytetr. Onaltlk (hexadecimal) 0xABCD saysnn ikili say sisteminde (binary) gsterilmesi ve byte sras:
most significant bit (en yksek anlaml bit) A
15 14 13 12 11 10

B
9 8 7 6

least significant bit (en dk anlaml bit) C D


5 4 3 2 1 0 bit numaras

High byte AB

Low byte CD
1 byte

big-endian artan bellek adresi

little-endian

... 0E11 0E10

...
LSB MSB

CD AB
...

0E11 0E10

AB CD
...

MSB LSB

Word

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-57

unsigned int tamsay 0xABCD : big-endian 0E10 0E11

little-endian 0E10 0E11

AB
MSB

CD
LSB

CD
LSB

AB
MSB

Bellek Adresi Byte Deeri Byte Sras

soldan saa

sadan sola

0xABCD

0xABCD

0xAB12CD34 saysnn byte sras:


unsigned long tamsay 0xAB12CD34 : big-endian 0E0A 0E0B 0E0C

0E0D

AB

12

CD

34

MSB LSB Big-endian: bir word iindeki en dk bellek adresinde MSB bulunur.

little-endian 0E0A 0E0B

0E0C

0E0D

34

CD

12

AB

LSB MSB Little-endian: bir word iindeki en dk bellek adresinde LSB bulunur.

ekillerde de grld gibi byte sras yledir: Little-endian'da artan bellek adresi ynnde ilk olarak LSB (Least Significant Byte) bulunur ( en sadaki byte: little-end ). Big-endian'da ise ilk olarak MSB (Most Significant Byte) bulunur. Standart binary giri/k fonksiyonlar fread ve fwrite donanmn endian srasna gre okur ve yazar. Yukardaki rnek programn ve rnek 9.1-7'nin ktlar incelendiinde bu programlarn oluturulduu donanmn little-endian dzenini kulland anlalr. Byte verilerde bu ekilde bir sralama sz konusu deildir. Aadaki program bit-alanlar (Blm 8) konusundan sonra incelenebilir. Programda tarih bilgileri tek bir int deikende saklanr: 0-99 arasnda Yil deeri iin en fazla 7 bit; 1-12 arasnda ay deeri iin en fazla 4 bit ve 1-31 aras gn deeri iin en fazla 5 bit gereklidir. Toplam olarak 16 bit yani bu programn oluturulduu donanmda bir int deeri saklayabilecek bir tamsay deiken bu i iin yeterli olacaktr. Tarih bilgisini oluturan 16 bit'i bir int'e yerletirmek iin bit ilemleri gereklidir. 31-12-99 tarihi iin bit dizilii MSB solda bulunmak zere onaltlk say sisteminde C79F deerine eittir. Fakat bu deerin bellekte bulunu sras donanmn endian srasna gre deiecektir. Aadaki rnekte olduu gibi bu i iin bit-kaydrma ilemleri yerine bit-alan yaps kullanldnda donanmn ayrntlar ile uramak gerekmez. Fakat bir tamsayy bit-alan yaps olarak ileyebilmek iin tamsay deikenin bellek adresi, tip dntrme uygulanarak struct GunAyYil tipi bit-alan yapsna iaret eden adres C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-58 deerine dntrlr. Daha sonra ok operatr kullanlarak bit-alanlarna eriilir ve deerler yerletirilir. Bylece belli bir bit sralan esas alnarak gerekletirilen bit-kaydrma ve maskeleme ilemlerine gerek kalmaz. rnek programda her iki uygulamaya da yer verilmitir.
Yil : 99 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1
Yil << 9

YIL :
0

Ay : 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0
Ay << 5

AY :
0 0

GUN :
0 0 0 0 0 0 0 0 0 0 0 1

Gun : 31 1 1 1 1

Bit-OR

Bit-OR

TARIH1 :
1 1 C 0 0 0 1 7 1 1 1 0 9 0 1 1 1 F 1 1

/* bits.c programi. * */ #include <stdio.h> /* maksimum Gun 31 #define BitGUN 5 /* maksimum Ay 12 #define BitAY 4 /* maksimum Yil 99 #define BitYIL 7 /* Toplam 16 bit (2-byte) : 11111 : : 1100 1100011 */ */ */ */

: 1111111001100011

#define TarihBitKay(Gun,Ay,Yil) \ (Yil << (BitGUN+BitAY)) | (Ay << BitGUN) | Gun void ListBit( unsigned long Sayi, size_t BitSayi ); struct GunAyYil { unsigned Gun: BitGUN, Ay : BitAY, Yil: BitYIL; C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-59 ... bits.c devam }; int main(void) { unsigned int Tarih1, Tarih2, Gun = 31, Ay = 12, Yil = 99; struct GunAyYil *pT = (struct GunAyYil *)&Tarih2; Tarih1 pT->Gun pT->Ay pT->Yil = = = = TarihBitKay( Gun, Ay, Yil ); Gun; Ay; Yil;

printf( "Tarih1 : %04X, ", Tarih1 ); ListBit( Tarih1, sizeof(Tarih1) * 8 ); printf( "Tarih2 : %04X, ", Tarih2 ); ListBit( Tarih2, sizeof(Tarih2) * 8 ); printf( "Tarih2 - Gun %02d, Ay %02d, Yil 19%02d\n", pT->Gun, pT->Ay, pT->Yil ); printf("Tarih2 - Gun %02d, ", pT->Gun ); ListBit( pT->Gun, BitGUN ); printf("Tarih2 - Ay %02d, ", pT->Ay ); ListBit( pT->Ay , BitAY ); printf("Tarih2 - Yil %02d, ", pT->Yil ); ListBit( pT->Yil, BitYIL ); return 0; } void ListBit( unsigned long Sayi, size_t BitSayi ) { putchar( '(' ); while ( BitSayi-- > 0 ) printf( "%1d", (Sayi >> BitSayi) & 0x01 ); puts( ")" ); } kt Tarih1 : C79F, (1100011110011111) Tarih2 : C79F, (1100011110011111) Tarih2 - Gun 31, Ay 12, Yil 1999 Tarih2 - Gun 31, (11111) Tarih2 - Ay 12, (1100) Tarih2 - Yil 99, (1100011) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-60 Aadaki rutin kullanlarak donanmn hangi endian dzenini kulland anlalabilir: ... short int WORD = 0x0001; ... /* low-byte sifir degil ise : little-endian */ printf("%s\n", *((char *)&WORD) ? "little-endian" : "big-endian" ); ...

5.7 Adres Deikenleri ve Fonksiyonlar


rnek 5.7-1'de tamsay i ve j deikenleri tadklar deerlerin deitirilmesi iin DegerDeg fonksiyonuna argman olarak aktarlr.
rnek 5.7-1 degaktar.c program. #include <stdio.h> void DegerDeg( int, int ); int main(void) { int i = 10, j = 20; printf("i : %d, j : %d\n", i, j ); DegerDeg( i, j ); printf("i : %d, j : %d\n", i, j ); return 0; } void DegerDeg( int a, int b ) { int t; t a b } kt i : 10, j : 20 i : 10, j : 20 = a; = b; = t;

DegerDeg fonksiyonu ars ile i ve j deikenlerinin bellek alanlarnda saklanan deerlerin kopyalar, DegerDeg fonksiyonunun lokal deikenlerine deer olarak atanr. Yani i deikeninin deeri a parametresine, j deikeninin deeri ise b parametresine aktarlr. DegerDeg blou iinde sadece bu lokal kopyalar deitirilir. Bu nedenle ktda da grld gibi deitirme ilemi sadece DegerDeg fonksiyonu iinde
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-61

gerekleir ve aran blokta yer alan i ve j deikenlerinin deerleri ayn kalr. DegerDeg fonksiyonu main fonksiyonunun lokal deikenleri olan tamsay i ve j deikenlerinin bellek alanlarna eriemez ve dolaysyla bu deikenlerin bellek alanlarnda saklanan deerlerini de deitiremez. Bu ekilde gerekleen bir fonksiyon ars, ar srasnda yalnzca argman deerleri aktarld iin deer-ile-arma (call-by-value) olarak adlandrlr. DegerDeg fonksiyonu aran bloktaki i ve j deikenlerine ancak bu deikenlerin bellek adreslerini bildii taktirde eriilebilir. Dolaysyla deer-ile-arma yoluyla eriemeyecektir. C dilinde fonksiyonlara adres deerleri aktarlabilir. Fakat fonksiyon adres deerleri alabilecek ekilde tanmlanmal ve bildirimi de (prototip) buna gre yaplmaldr. Adres deerleri aktarlmak istendiinde, tanmda bildirilen parametreler adres deikenleri olmaldr ve fonksiyon bildiriminde de karlk gelen adres deikeni tipleri listelenmelidir. Fonksiyonlara her eit bellek adresi aktarlabilir; bir basit deikenin, bir dizinin, adres dizisinin, yap deikeninin ve hatta bir baka fonksiyonun bellek adresi. Bu yolla sadece basit deikenlere deil dier tiplere de eriilebilir. Argman olarak adres deeri alan bir fonksiyonun arsnda aadakilerden herhangi biri argman olarak bulunabilir:
l l l

sabit adres deeri, adres deeri dndren bir ifade, adres deikeni (basit deikene, fonksiyona, yap deikenine yada bir diziye iaret eden)

arda yer alan argman, fonksiyon tanmnda parametre olarak bildirilen adres deikeninin tipinde olmaldr. Fonksiyon ars, arda argman olarak adres deerleri yer aldnda referans-ile-arma olarak adlandrlr. nk ar ile argmanlarn bellek alanlarna eriim iin gerekli olan referans adres bilgisi aktarlr. Dizi ismi, dizinin balang adresini veren sabittir. arda yer alan argman herhangi bir dizi ismi olduunda aktarlan deer balang elemannn bellek adresi olacandan dolay otomatik olarak referans-ile-arma gerekleir. Bir fonksiyon aran bloa return deyimi ile sadece tekbir deer dndrr. Fakat baz uygulamalarda birden fazla deer dndrmek gerekebilir. Byle bir uygulamada da yine adres deikenleri kullanlr. Ayrca bir fonksiyon adres deeri dndrecek ekilde tanmlanabilir. Byle bir fonksiyon adres deeri olarak herhangi bir durumu ifade etmek iin bo adres deikeni deeri de (NULL) dndrebilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-62

Fonksiyon argman olarak adres deikenleri


rnek 5.7-1'deki deer deitirme ilemi rnek 5.7-2'de olduu gibi DegerDeg fonksiyonuna adres deerleri aktarlarak gerekletirilebilir:
rnek 5.7-2 refakt1.c program. #include <stdio.h> void DegerDeg( int *, int * ); int main(void) { int i = 10, j = 20; printf("i : %d, j : %d\n", i, j ); DegerDeg( &i, &j ); printf("i : %d, j : %d\n", i, j ); return 0; } void DegerDeg( int *adr1, int *adr2 ) { int t; t = *adr1; *adr1 = *adr2; *adr2 = t; } kt i : 10, j : 20 i : 20, j : 10

Programda grld gibi DegerDeg fonksiyonu bellek adresleri alabilecek ekilde tanmlanr; int * tipinde iki adres deikeni olan adr1 ve adr2 parametreleri bildirilir. Fonksiyon prototipi de buna gre dzenlenir ve DegerDeg fonksiyonunun int tipinde deikenlere iaret eden iki adres deeri bekledii bildirilir. ar satrnda argman olarak &i ve &j ifadeleri kullanlarak i ve j deikenlerinin bellek adresleri sabit adres deerleri olarak aktarlr. Bu ilem izleyen rnekte grld gibi adres deikenleri kullanlarakta yaplabilir. Her iki uygulamada da argmanlar ayn eit veriyi aktarr: aran bloktaki lokal deikenlerin bellek adresleri. Dolaysyla, adres deerlerinin hangi yolla aktarld DegerDeg fonksiyonunu etkilemez. DegerDeg fonksiyonu altnda int * tipinde iki lokal adres deikeni oluturur (adr1 ve adr2). Aktarlan adresler bu adres deikenlerine atanr. ardaki argmanlar ve tanmdaki parametreler birebir eletii iin, i deikeninin adresi adr1 adres deikenine, j deikeninin adresi ise adr2 adres deikenine atanr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-63

rnek 5.7-3 refakt2.c program. #include <stdio.h> void DegerDeg( int *adr1, int *adr2 ); int main(void) { int i = 10, j = 20; int *pi = &i, *pj = &j; printf("i : %d, j : %d\n", *pi, *pj ); DegerDeg( pi, pj ); printf("i : %d, j : %d\n", i, j ); return 0; } void DegerDeg( int *adr1, int *adr2 ) { int t; t = *adr1; *adr1 = *adr2; *adr2 = t; } kt i : 10, j : 20 i : 20, j : 10

Fonksiyon iinde deer deitirme srasnda geici olarak kullanm iin bellek alan oluturmak amacyla, int tipinde t deikeni bildirilir. ndirek deer operatr (*) ile elde edilen deerler, t deikeni aracl ile deitirilir. Bu ilem direk olarak i ve j deikenlerinin bellek alanlar zerinde yaplr. Bylece main fonksiyonunun lokal deikenlerine indirek olarak eriilir ve deerleri deitirilir. rnek 5.7-3'de yer alan fonksiyon prototipinde, okunabilirlii arttrmak iin tanmda yer alan parametre isimleri de kullanlmtr. Her iki rnekte de fonksiyon, aran bloa deer dndrmeyecek ekilde tanmlanmtr ve fonksiyon blounda return deyimi bulunmaz. Fonksiyonun ar satrna hibir deer dndrmediini belirtmek iin tanm ve prototipte void tip belirleyici kullanlmtr. Fakat ilem, iki deiken zerinde ve adres deerleri kullanlarak yapld iin birden fazla deer dndrlm gibi gerekleir. Fonksiyonun adres deeri dndrmesi istendiinde, void tip belirleyici yerine istenen adres deikeni tipi kullanlr ve fonksiyonun dndrd adres deeri de aran blokta ayn tip belirleyici ile bildirilmi olan bir adres deikenine atanr.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-64

Fonksiyon argman olarak diziler


nceki blmlerde de belirtildii gibi dizi ismi, balang elemannn bellek adresini veren sabittir. Bu nedenle fonksiyon arlrken kullanlan argmanlar dizi ismi olduunda aktarlan deerler bellek adresleridir (referans-ile-arma); bu argmanlara karlk gelen ve fonksiyon tanmnda bildirilen parametreler ise adres deikenleridir. Fonksiyona aktarlan dizi herhangi bir tipte olabilir. Fonksiyonlara argman olarak dizgi sabitleri de aktarlabilir. C dilinde ift trnaklar arasna yerletirilen karakterlerle oluturulan bir dizgi sabiti, karakter dizisi olarak bellekte tutulur. Bir dizgi sabitinin deeri, bellekte sakland alann balang adresidir. Bu nedenle bir fonksiyona herhangi bir dizgi sabiti argman olarak verildiinde aktarlan deer bir adres deeridir; yani bellekte bulunan bir karakter dizisinin balang elemannn adresi. arlan fonksiyonun tanmnda bildirilen ve bu argmana karlk gelen parametre ise char tipi verilere iaret eden bir adres deikenidir. rnek 5.7-4'de argman olarak aktarlan dizgi sabitinin uzunluunu dndren DizgiBoy fonksiyonu tanmlanr. Standart C ktphanesinde bulunan strlen fonksiyonu da ayn ii yapar.
rnek 5.7-4 dizgiboy.c program. #include <stdio.h> unsigned DizgiBoy( char[ ] ); int main(void) { char *p = "123"; char s[ ] = "123"; printf( "123 dizgisi : %u\n", DizgiBoy ( p ) ); printf( "s karakter dizisi : %u\n", DizgiBoy ( s ) ); printf( "123 dizgisi : %u\n", DizgiBoy ( "123" ) ); return 0; } unsigned DizgiBoy( char m[ ] ) { unsigned i; for ( i = 0 ; m[ i ] != '\0' ; i++ ) ; return i; } kt 123 dizgisi : 3 s karakter dizisi : 3 123 dizgisi : 3 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-65

Programda DizgiBoy fonksiyonuna argman olarak p adres deikeni, karakter dizisi ismi s ve dizgi sabiti "123" aktarlr. lk deer olarak bildirimde p adres deikenine "123" dizgi sabitinin bellek adresi atand iin, arda argman olarak yer aldnda DizgiBoy fonksiyonuna yine bu dizginin balang adresi aktarlm olur. Programda bildirilen s karakter dizisi char tipi verilerden oluur. Dizi ismi s, arda argman olarak kullanldnda fonksiyona karakter dizisinin balang eleman olan char verinin bellek adresi aktarlm olur. Son arda argman olarak kullanlan "123" dizgi sabitinin deeri de yine bellekte bulunduu alann balang adresi olduu iin her arda da DizgiBoy fonksiyonuna adres deerleri aktarlm olur. Aktarlan adres deerleri, DizgiBoy fonksiyonu balnda bildirilen m adres deikenine atanr. m bir adres deikeni olduuna gre bildirimi,
char m [ ];

yerine
char *m;

eklinde yaplabilir. Ayrca fonksiyon prototipi de aadaki ekilde yazlabilir:


unsigned DizgiBoy ( char * );

Fakat bildirim indeks operatr ([ ]) kullanlarak yapldnda, aktarlan adres deerinin bir diziye ait olduu aka belirtilmi olur. Sonu olarak bir dizi fonksiyona argman olarak aktarlrken, fonksiyon tanmnda bildirilen parametre adres deikenidir ve her iki ekilde de bildirilebilir: adres deikeni olarak yada eleman says verilmeden keli bo parantezlerle. Aktarlan deer dizinin tek bir elemanna iaret eden adres deeri olduu iin tanmda dizi boyutunun verilmesi anlamszdr (zleyen blmlerde anlatlaca gibi, ok-boyutlu diziler aktarlrken ilk boyuttaki eleman says verilmeyebilir. Fakat izleyen boyut deerleri verilmelidir). Bu durum yalnzca fonksiyon tanmnda bildirilen parametreler iin geerlidir. rnein aadaki a dizisi bildirimleri birbirinden farkldr:
dosya 1: char a [ 5 ]; dosya 2: extern char *a;

Dosya 1'deki bildirim 5 char veri iin bellek alan ayrr. Dosya 2'deki bildirim ise ilk deer atamas yaplmam (hibir bellek alanna iaret etmeyen) bir adres deikeni bildirimidir. Dolaysyla extern eriimin gereklemesi iin bu iki bildirimin ayn ekilde yaplmas gerekir:
dosya 1: char a [ 5 ]; dosya 2: extern char a [ ];

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-66

Adres deikenlerine indeks operatr uygulanabilir. Bu nedenle for dngs iinde dizgi elemanlarna eriim m[ i ] ifadesi ile gerekletirilir. Dng iinde indeks deikeni i'nin deeri, m[ i ] ifadesi ile dizgi sonunu belirten '\0' karakterine (bo karakter) eriilinceye kadar arttrlr. ndeks deikeninin ald son deer dizgi uzunluunu verir. m bir adres deikeni olduu iin for dngs yerine aadaki while dngs kullanlabilir:
... i = 0; while ( *m++ ) i++; ...

DizgiBoy fonksiyonu dizgilerin uzunluunu '\0' karakteri hari olarak ekrana yazar. rnek 5.7-5'deki programn ktsnda da grld gibi sizeof operatr kullanldnda, s ve "123" karakter dizilerinin uzunluu dizgi sonunda yer alan '\0' karakteri de dahil olmak zere verilir. p ise bu donanmda 2 byte bellek alanna sahip bir adres deikenidir.
rnek 5.7-5 size.c program. #include <stdio.h> int main(void) { char *p = "123"; char s[ ] = "123"; printf( "p adres degiskeni : %u byte\n", sizeof ( p ) ); printf( "s karakter dizisi : %u byte\n", sizeof ( s ) ); printf( "123 dizgisi : %u byte\n", sizeof ( "123" ) ); return 0; } kt p adres degiskeni : 2 byte s karakter dizisi : 4 byte 123 dizgisi : 4 byte

imdiye kadar verilen tm rnek programlar da ekran kts almak iin printf fonksiyonu kullanld. printf fonksiyonu ilk argman olarak bir dizgi alr; izleyen argmanlar hakknda bilgi ieren bir format dizgisi. rnek 5.7-4'de printf fonksiyonunda ikinci argman olarak DizgiBoy fonksiyonu ars yer ald. Bylece bu fonksiyonun dndrd unsigned deer, printf fonksiyonuna aktarlr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-67

Bu ilem aadaki ekilde de gerekletirilebilir: "123" dizgisi iin:


... char *p = "abc"; unsigned j; ... j = DizgiBoy( p ); printf( "%s dizgisi : %u karakter \n", p, j ); ...

Bildirim deyimi,
char *p = "123";

ile yaplan atama ilemi dizgi kopyalama deildir. Burada "123" dizgi sabitinin bellek adresi, p adres deikenine deer olarak atanr. C dilinde bir dizginin tamamn tek bir birim olarak ele alarak ileyen operatrler yoktur. Dizgiler zerinde yaplan dizgi kopyalama, dizgi karlatrma veya belli bir karakteri aramak amacyla dizgi tarama gibi ilemler standart ktphanede yer alan fonksiyonlar ve adres aritmetii kullanlarak yaplabilir. zleyen paragraflarda dizgiler zerinde bu ilemleri gerekletiren ve argman olarak dizgilerin bellek adreslerini alan birka fonksiyon tanmlanr. rnek 5.7-6'da DizgiKopyala fonksiyonu tanmlanr. Bu fonksiyon argman olarak char tipi verilere iaret eden iki adres deeri bekler. Fonksiyon arsnda argman olarak karakter dizisi isimleri s1 ve s2 kullanlr. Bylece fonksiyona dizilerin balang elemanlarnn bellek adresleri aktarlr. Fonksiyona aktarlan adres deerleri, p1 ve p2 adres deikenlerine atanr. DizgiKopyala fonksiyonu bu adresleri kullanarak "abc" ve "123" dizgilerine eriebilir. while dngsnde yer alan p1[ i ] = p2[ i ] deyiminde, p2[ i ] ifadesi ile eriilen elemann deeri p1 karakter dizisinin karlk gelen pozisyonuna atanr. Bu ilem p2 dizisinin her eleman ile son eleman olan '\0' karakterine eriilinceye kadar tekrarlanr. Elemanlara eriim, atama sonras artrlan dizi indeks deikeni i kullanlarak gerekletirilir. Dizgi sonunu saptamak iin while dngsnn test ifadesinde gizli atama (embedded assignment) uygulanarak bo karakter (null karakteri : '\0') kontrolu yaplr:
( p1[ i ] = p2[ i ] ) != '\0'

Test ifadesinde ilk olarak p2[ i ] ifadesi ile elde edilen deer, p1[ i ] ile eriilen elemana atanr ve daha sonra bu deer '\0' ile karlatrlr. Eer eit deilse dng devam eder. Eit ise p2 dizisinin son elemanna eriilmitir ve dngden klr. Atama deyimi dndaki parantezler gereklidir nk atama operatr (=) dier operatrlerden dk nceliklidir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-68

rnek 5.7-6 dizgikop.c program. #include <stdio.h> void DizgiKopyala( char[ ], char[ ] ); int main(void) { char s1[ ] = "abc"; char s2[ ] = "123"; printf("s1 : %s, s2 : %s\n", s1, s2 ); DizgiKopyala( s1, s2 ); printf("s1 : %s, s2 : %s\n", s1, s2 ); return 0; } void DizgiKopyala( char p1[ ], char p2[ ] ) { int i = 0; while ( (p1[ i ] = p2[ i ]) != '\0' ) i++; } kt s1 : abc, s2 : 123 s1 : 123, s2 : 123

Fonksiyon iinde elemanlar p1 = p2 atama ilemi ile kopyalamak mmkn deildir. Bu ilem sadece p2'nin tad adres deerini p1'e kopyalar. Ayrca bu ilemin main blounda yer alan karakter dizileri zerinde hibir etkisi yoktur. rnek 5.7-6'da p1 ve p2 adres deikenlerinin tad adres deerleri kopyalama ncesi ve sonras ayn kalr. Yalnzca p2 ile indirek olarak eriilen bellek alanlarndaki deerler (s2 dizisinin elemanlarnn deerleri), p1 ile eriilen alanlara (s1 dizisinin bellek alan) kopyalanr. rnek 5.7-6'da adres deikeni p1 ve p2 parametreleri, dizi bildiriminde olduu gibi indeks operatr kullanlarak bildirildi. DizgiKopyala fonksiyonu * operatr kullanlarak aadaki ekilde de yazlabilir:
void DizgiKopyala( char *p1, char *p2 ) { while ( (*p1 = *p2) != '\0' ) { p1++; p2++; } } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-69

++ ilemi, atama deyimi iinde yaplabilir. Ayrca while dngs test ifadesinde dizgi sonunu saptamak iin yaplan bo karakter kontrolu gereksizdir. nk dizgi sonuna eriildiinde *p2++ ifadesi, != '\0' testi ile ayn deeri verir (bo karakter deeri olan 0, koul salanamadnda karlatrma ileminin dndrd yanl deeri ile ayndr) ve dngden klr. Sonu olarak DizgiKopyala aadaki ekilde de yazlabilir:
void DizgiKopyala( char *p1, char *p2 ) { while ( *p1++ = *p2++ ) ; }

*p2++ ifadesi, p2'nin deeri artrlmadan nce iaret ettii karakteri verir. p1'in tad adres deeri ise bu karakter p1 ile eriilen alana kopyalandktan sonra artrlr. Aadaki programda iki dizgiyi birbiri ile karlatran DizgiKarsi fonksiyonu tanmlanr:
rnek 5.7-7 dizgikar.c program. #include <stdio.h> int DizgiKarsi( char*, char* ); int main(void) { char s1 [ ] = "abcdf"; char s2 [ ] = "12345"; char s3 [ ] = "abcdf"; printf( "s1 : %s, s2 : %s\n", s1, s2 ); printf( "%s ve %s, %s\n", s1, s2, ( DizgiKarsi( s1, s2 ) == 0 ? "esit" : "esit degil") ); printf( "s1 : %s, s3 : %s\n", s1, s3 ); printf( "%s ve %s, %s\n", s1, s3, ( DizgiKarsi( s1, s3 ) == 0 ? "esit" : "esit degil") ); return 0; } int DizgiKarsi( char *p1, char *p2 ) { for ( ; *p1 == *p2; p1++, p2++ ) ; return( *p1 ? *p1 - *p2 : 0 ); } kt s1 : abcdf, s2 : 12345 abcdf ve 12345, esit degil s1 : abcdf, s3 : abcdf abcdf ve abcdf, esit

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-70

DizgiKarsi fonksiyonu argman olarak karlatrlacak dizgilerin bellek adreslerini bekler. Programda argman olarak karakter dizisi isimleri kullanlmtr. Fakat fonksiyon dizgi sabitleri kullanlarak aadaki ekilde de arlabilir:
... DizgiKarsi ( "abcdf", "12345" ); ... DizgiKarsi ( "abcdf", "abcdf" ); ...

Aktarlan adres deerleri p1 ve p2 adres deikenlerine atanr. Her iki deikenin de tadklar adres deerleri birer birer arttrlr ve indirek deerler karlatrlr. Karakterlerin eit olmad ilk durumda dngden klr. Eer tm karakterler birebir eitse, for dngs dizi sonuna gelindiinde '\0' karakterini saptar ve dngden klr. return deyimi iinde kullanlan ? operatrnn test ifadesinde, *p1'in deeri kontrol edilir. Dizi sonuna gelinmise *p1'in deeri '\0' olaca iin 0 deeri dndrlr. Eer dizi sonuna gelmeden nce dngden klm ise *p1 ifadesi null olmayan herhangi bir deere sahip olaca iin *p1 - *p2 ifadesinin deeri dndrlecektir. *p1-*p2 ifadesi, p1'in iaret ettii karakter ASCII karakter tablosunda p2'nin iaret ettii karakterden nce yer alyorsa negatif tamsay deer, aksi taktirde pozitif tamsay deer verir. DizgiKarsi fonksiyonundaki parametre bildirimleri yaplabilir. indeks operatr kullanlarakta

Adres deeri dndren fonksiyonlar


Bir fonksiyon adres deeri dndrecek ekilde tanmlanabilir. rnek 5.7-8'de tanmlanan BlokKopyala fonksiyonu, ikinci parametre ile belirtilen bellek blounun son parametre ile belirtilen sayda byte'n, ilk parametre ile belirtilen bellek adresine kopyalar ve yine ilk parametre ile belirtilen bellek adresini dndrr.
rnek 5.7-8 blokkopy.c program. #include <stdio.h> void *BlokKopyala( void *hDizgi, const void *kDizgi, size_t ByteSayi ); int main(void) { char dizgi[ ] = "abcdefg"; printf("dizgi : %s\n", dizgi ); BlokKopyala( dizgi, "123", 3 ); printf("dizgi : %s\n", dizgi ); puts( (char *)BlokKopyala( dizgi, "xyz", 3 ) ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-71

rnek 5.7-8 devam


void *BlokKopyala( void *hDizgi, const void *kDizgi, size_t ByteSayi ) { char *h = hDizgi; const char *k = kDizgi; while ( ByteSayi-- ) *h++ = *k++; return hDizgi; } kt dizgi : abcdefg dizgi : 123defg xyzdefg

rnek programda char tipi veriler kopyalanr. Fonksiyon void * tipi adres deeri dndrr; ayrca parametre listesinde de void * tipi adres deikenleri bildirildii iin fonksiyonun kullanm belli bir adres tipi ile snrl deildir. Dolaysyla farkl tiplerde veriler saklayan bellek bloklar ayn fonksiyon kullanlarak kopyalanabilir.

const deikenler
Bir deiken bildiriminde kullanlan const anahtar szc (type qualifier), deikenin deerinin deitirilmesini nler. Deikenin ancak bildirim srasnda ilk deer atama ile verilen deerini programn herhangi bir yerinde direk yada indirek (adres deikeni aracl ile) deitirme giriimi derleyici hatas oluturur:
const int ci = 90; ci = 90; /* Hata */

Fonksiyonlar const olarak bildirilemezler. const anahtar szc dizilere, yap deikenlerine, union'lara, bit-alanlarna yada bunlarn elemanlarna uygulanabilir. Bir bildirimde const anahtar szc deiken isminden nce herhangi bir yerde bulunabilir. Fakat bir bildirimde saklama snf belirleyicinin (storage class specifier) ilk nce yazlmas okunabilirlik asndan tercih edilir:
static const int ci = 90;

const, adres deikenlerine de uygulanabilir. Pek ok standart ktphane fonksiyonu bildiriminde olduu gibi, BlokKopyala fonksiyonunun adres deikeni kDizgi parametresi bildiriminde de const anahtar szc kullanlmtr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-72

const anahtar szc (type qualifier) derleyiciye arlan fonksiyonun adresi aktarlan bellek alannda bulunan deerleri deitiremeyeceini bildirir. Bylece kaynak dizgiyi deitirme giriimi, derleme srasnda hata oluturacandan dolay dizgi korunmu olur. Atama ilemindeki tip uyumu ile argman aktarmadaki tip uyumunun ayn olduu dnlecek olursa bu korumann gereklemesi iin aktarlan adres deerinin const veriye ait olmas gerekmez. Dolaysyla const olmayan bir deikenin adresi, bir const'a iaret eden adres deikenine atanabilir. Yukardaki rnekte kDizgi parametresine const olmayan adres deeri aktarlr. Fakat fonksiyon iinde kDizgi ile eriilen alanlardaki deerleri deitirme giriimi derleme hatas oluturacaktr. Ayn ekilde rnek 5.7-2'deki DegerDeg fonksiyonu const adres deikeni parametrelerle tanmlanp bildirilebilir ve const olmayan deiken adresleri ile arlabilir. Fakat yine derleme hatas oluur. nk fonksiyon iinde indirek olarak bu deerler deitirilmek istenir. const olmayan bir adres deikenine bir const deikenin adresi atanamaz. Bildirimde tip belirleyici bulunmad zaman int kabul edilir:
const ci = 20; /* const int ci = 20 */

Aadaki bildirimlerde eitli const kullanmlar rneklenir:


int i = 10; int *pi; const int ci = 20; const int *pci = &ci;

/* /* /*

const int bildirimi const int'e isaret eden adres degiskeni bildirimi bildirim srasnda const olmayan degisken adresi atanabilir. Tersi gecerli degildir !

*/ */

yada
const int *pci = &i; */

zleyen ekilde de grld gibi pci adres deikeni bildirim srasnda ilk deer olarak adresi atanan bir const int deere (ci) iaret eder. pci'nin tad adres deeri deitirilebilir. Fakat sadece bir baka const int deikenin bellek adresi atanabilir. pci adres deikeninin indirek deeri deitirilemez.
pci = &ci; pci = &i; i = *pci; *pci = 99; pi = &ci; pi = pci; /* /* /* /* Hata ! */

Hata ! */ Hata ! */ Hata ! const olmayan adres deikenine const adres degeri atanamaz */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-73

pci :
const int adresi

ci :
const int deer: 20

i:
int deer: 10

Aada tad adres deeri deitirilemeyen const adres deikeni cpi bildirilir. Ancak cpi, const olmayan bir tamsayya iaret eder. cpi'nin indirek deeri deitirilebilir.
int i = 10; int *pi = &i; int *const cpi = &i;

/* /*

int'e isaret eden const adres degiskeni bildirimi

*/

yada
int *const cpi = pi;
cpi :
int adresi

const adres degiskenine const olmayan adres degeri atanabilir. Tersi gecerli degildir ! */
i:
int deer: 10

*cpi = 10; i = *cpi; cpi = &i;

/*

Hata !

*/

Aada const int'e iaret eden const adres deikeni cpci bildirilir.
const ci = 20; const int *const cpci = &ci;
cpci :
const int adresi

/* /*

const int bildirimi const int'e isaret eden const adres degiskeni bildirimi
ci :
const int deer: 20

*/ */

cpci'nin tad adres deeri ve indirek deeri deitirilemez:


*cpci = 10; cpci = &ci; /* /* Hata ! Hata ! */ */

const'a iaret eden adres deikeni bildirimlerinde, const anahtar szc * ncesinde herhangi bir yerde; const adres deikeni bildirimlerinde ise * sonrasnda bulunur. C dilinde bildirimlerde kullanlan bir dier anahtar szck volatile'dir (type qualifier). Derleyiciye bildirilen deikenin deerinin programn kontrol tesinde faktrler tarafndan deitirilebileceini bildirir. Derleyici sz konusu deiken zerinde optimizasyon yapmaz.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-74

rnek 5.7-9'de bir dizgiyi belli bir karakter iin tarayan ve bulunduu ilk pozisyonun adresini dndren DizgiTarama fonksiyonu tanmlanr.
rnek 5.7-9 dizgitar.c program. #include <stdio.h> char *DizgiTarama( char *, char ); int main(void) { char dizgi[ ] = "abcdefg"; char c = 'e', *pdizgi; pdizgi = DizgiTarama( dizgi, c ); if ( pdizgi != NULL ) printf(" %c, %s dizgisi icinde %d. karakterdir.\n", c, dizgi, (pdizgi-dizgi)+1 ); else printf(" %s dizgisi icinde, %c karakteri bulunamadi.\n", dizgi, c ); printf( "Bu bir %s\n", DizgiTarama( "Bu bir denemedir", 'd' ) ); return 0; } char *DizgiTarama( char *pDizgi, char c ) { while ( *pDizgi != '\0' && *pDizgi != c ) ++pDizgi; return ( *pDizgi == c ? pDizgi : NULL ); } kt e, abcdefg dizgisi icinde 5. karakterdir. Bu bir denemedir

Program "abcdefg" dizgisi iinde e karakterini bulur ve kanc karakter olduunu ekrana yazar. DizgiTarama fonksiyonu char tipi verilere iaret eden adres deeri dndrecek ekilde tanmlanm ve prototipi de buna gre dzenlenmitir. Fonksiyon aranlan karaktere ilk kez rastladnda, bu karakteri saklayan elemann bellek adresini dndrr. printf fonksiyonu, format dizgisinde yer alan %s format belirleyiciye karlk gelen argman olarak dizgi adresi bekler. Programdaki son printf arsnda ekrana ilk olarak "Bu bir " dizgisi yazlr. Bundan sonra printf fonksiyonu %s'e karlk gelen argman olarak DizgiTarama fonksiyonu tarafndan dndrlen "Bu bir denemedir" dizgisindeki d karakterinin bellek adresini alr; ve dizgiyi bu pozisyondan itibaren ekrana yazar. nceki blmlerde fonksiyonlarn bir durumu ifade etmek iin adres deeri olarak 0 deerini dndrebilecei ve 0 deerinin adres deikenlerine atanabilecei belirtilmiti.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-75

DizgiTarama fonksiyonu da verilen karakterin dizgi iinde bulunamadn bildirmek iin 0 adres deeri (NULL, yani bo adres deikeni deeri) dndrr. Fonksiyon prototipi ve tanm, indeks operatr kullanlarak hazrlanabilir: Prototip:
char *DizgiTarama( char[ ], char);

Tanm:
char *DizgiTarama( char pDizgi[], char c ) { int i; i = 0; while ( pDizgi[ i ] != '\0' && pDizgi[ i ] != c ) ++i; return ( pDizgi[ i ] == c ? &pDizgi[ i ] : NULL ); }

Fonksiyonda karakter bulunamadnda dndrlen deer olarak NULL ismi yerine (char *)0 yada sadece 0 deeri kullanlabilir.

Fonksiyon Argman olarak Adres Dizileri


rnek 5.7-10'da, 5 double veriden oluan d dizisi bildirilir. Programda elemanlar kkten bye doru sralanr ve dizi bu sralamaya gre yeniden dzenlenir. ktda dizi elemanlarnn sralama ncesi ve sonras deerleri listelenir. Sralama ilemi dizi elemanlar zerinde yapld iin ktda da grld gibi elemanlarn sralama sonras yerleimi farkl olacaktr. Fakat baz uygulamalarda, dizi elemanlarnn yerleiminin bozulmamas gerekebilir. Bu rnekte, sadece 5 elemanl bir dizi kullanld. Eleman says arttka, 8-byte bellek alan kaplayan double verilerin sralama ilemi olduka yavalar.
rnek 5.7-10 adrf10.c program. #include <stdio.h> int main(void) { double d[ ] = { 3.0, 1.9, 2.8, 5.7, 4.6 }; int i, j, ELSayi = sizeof d / sizeof d[0]; double t;
/* elemanlarin listelenmesi */

for( i = 0; i < ELSayi; i++ ) printf("d[%d] : %1.1f \n", i, d[ i ] );


/* elemanlarin siralanmasi */

for( i = 0; i < ELSayi - 1; i++ ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-76

rnek 5.7-10 devam


for( j = i + 1 ; j < ELSayi; j++ ) if ( d[ i ] > d[ j ] ) { t = d[ j ]; d[ j ] = d[ i ]; d[ i ] = t; }
/* siralama sonrasi elemanlarin listelenmesi */

printf("\n"); for( i = 0; i < ELSayi; i++ ) printf("d[%d] : %1.1f \n", i, d[ i ] ); return 0; } kt d[ 0 ] d[ 1 ] d[ 2 ] d[ 3 ] d[ 4 ] d[ 0 ] d[ 1 ] d[ 2 ] d[ 3 ] d[ 4 ] : : : : : : : : : : 3.0 1.9 2.8 5.7 4.6 1.9 2.8 3.0 4.6 5.7

rnek 5.4-2'de adres dizisi AdrDizi kullanlarak 5 double veriden oluan ddizi dizisinin elemanlarna eriilir. rnek 5.7-10'daki sralama ilemi, rnek 5.7-11'de grld gibi double d dizisine iaret eden adres dizisi kullanlarak gerekletirilebilir. Bu amala double verilere iaret eden pd adres dizisi bildirilir. Programda elemanlarn indirek olarak eriilen deerleri kullanlarak pd adres dizisinde saklanan bellek adresleri sralanr. Sralanan deerler 2-byte bellek alannda saklanan bellek adresleri olduu iin sralama ilemi ok daha hzl gerekleir. pd adres dizisinin tad adres deerleri sralamaya gre yeniden dzenlenir ve bylece d dizisinin sralama ilemi ncesi dizilii de bozulmam olur.
rnek 5.7-11 adrf11.c program. #include <stdio.h> #define ELSayi 5 int main(void) { double d[ ] = { 3.0, 1.9, 2.8, 5.7, 4.6 }; double *pd[ ELSayi ]; C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-77

rnek 5.7-11 devam


double *t; int i, j;
/* adres dizisine deger atama ve elemanlarin listelenmesi */

for( i = 0; i < ELSayi; i++ ) { pd[ i ] = &d[ i ]; printf("pd[%d] : %p, *pd[%d] : %1.1f, d[%d] : %1.1f \n", i, pd[ i ], i, *pd[ i ], i, d[ i ] ); }
/* elemanlarin degerlerine gore bellek adreslerinin siralanmasi */

for( i = 0; i < ELSayi - 1 ; i++ ) for( j = i + 1 ; j < ELSayi; j++ ) if ( *pd[ i ] > *pd[ j ] ) { t = pd[ j ]; pd[ j ] = pd[ i ]; pd[ i ] = t; }
/* degerlerin listelenmesi */

printf("\n"); for( i = 0; i < ELSayi; i++ ) printf("pd[%d] : %p, *pd[%d] : %1.1f, d[%d] : %1.1f \n", i, pd[ i ], i, *pd[ i ], i, d[ i ] ); return 0; } kt pd[0] pd[1] pd[2] pd[3] pd[4] pd[0] pd[1] pd[2] pd[3] pd[4] : : : : : : : : : : 1074, *pd[0] : 3.0, d[0] : 3.0 107C, *pd[1] : 1.9, d[1] : 1.9 1084, *pd[2] : 2.8, d[2] : 2.8 108C, *pd[3] : 5.7, d[3] : 5.7 1094, *pd[4] : 4.6, d[4] : 4.6 107C, *pd[0] : 1.9, d[0] : 3.0 1084, *pd[1] : 2.8, d[1] : 1.9 1074, *pd[2] : 3.0, d[2] : 2.8 1094, *pd[3] : 4.6, d[3] : 5.7 108C, *pd[4] : 5.7, d[4] : 4.6

ktda grld gibi ilem adres deerleri zerinde yapld iin pd adres dizisinin tad bellek adreslerinin sralama sonras dizilii farkl olacaktr. Fakat d dizisinin eleman yerleimi ayn kalr. Programdaki listeleme ve sralama ilemleri fonksiyon haline getirilerek main bloundan ayrlabilir. rnek 5.7-12'de listeleme ve sralama ilemleri iin listele ve sirala fonksiyonlar tanmlanmtr. Bu program da yine ayn kty verir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-78

Bu programda yer alan fonksiyon prototipleri okunabilirlii arttrmak iin parametre isimleri kullanlarak aadaki gibi yazlabilir:
/* fonksiyon bildirimleri */

void sirala( int ELSayi, double *p[ ] ); void listele( int ELSayi, double *p[ ], double dd[ ] );

Yukardaki prototiplerde de grld gibi listele ve sirala fonksiyonlar argman olarak adres dizisine iaret eden adres deeri almay bekler. Her iki fonksiyona da adres deeri (adres dizisi adresi) aktarma ilemi, ar satrlarnda argman olarak adres dizisi ismi pd kullanlarak gerekletirilir:
listele( BOY, pd, d ); ... sirala( BOY, pd );

Argman pd ile alnan adres deeri, fonksiyonlarn kendi lokal adres deikeni olan p adres deikenine (her iki fonksiyonda da, adres deikeni iin ayn parametre ismi kullanlabilir) atanr. Bylece fonksiyonlar p adres deikeni aracl ile aran bloktaki adres dizisine ve indirek olarakta d dizisine eriebilir ve bu diziler zerinde ilemler yapabilir. listele ve sirala fonksiyonlarnn parametre bildiriminde indeks operatr ([ ]) yer ald halde,
double *p[ ]

bildiriminde yer alan p, sabit deil bir adres deikenidir. Ayn ekilde,
double dd[ ]

bildiriminde yer alan dd, bir adres deikenidir. nceki blmlerde indeksi olmayan dizi isminin (arda argman olarak yer alan dizi isimleri pd ve d gibi) bir adres deikeni olmad, fakat dizinin balang elemannn adresini veren sabit olduu belirtildi. Dolaysyla dizi ismine (double dizi ismi d yada adres dizisi ismi pd gibi) atama yapmak, ++ yada -- operatrleri uygulamak mmkn deildir. Herhangi bir dizi ismi bir fonksiyona argman olarak aktarldnda, fonksiyon argman deeri olarak dizi isminin verdii balang adresini alr ve bu adres deerini, kendi lokal adres deikenine (sadece fonksiyon blou iinden eriilebilen) atar. Bu adres deikenine baka bir adres deeri atanabilir; tad adres deeri deitirilebilir; ++ yada -- operatrleri uygulanabilir. Fonksiyona adres dizisi aktarldnda ise alnan adres deeri bir baka adres deikeninin (adres dizisinin balang eleman) adresi olduu iin fonksiyon tanmnda bildirilen lokal adres deikeni ift adres deikeni'dir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-79

Bu nedenle prototipler ve parametre bildirimleri aadaki gibi yazlabilir: Bildirimler:


/* fonksiyon bildirimleri */

void sirala( int, double ** ); void listele( int, double **, double [ ] );

yada
/* fonksiyon bildirimleri */

void sirala( int ELSayi, double **p ); void listele( int ELSayi, double **p, double dd[ ] );

Parametre bildirimleri:
void sirala( int ELSayi, double **p ) { ... } void listele( int ELSayi, double **p, double dd[] ) { ... }

Ayrca dd dizisi iin prototip ve tanmlarda indeks operatr kullanlarak yaplan,


double dd[ ]

bildirimi yerine,
double *dd

bildirimi kullanlabilir. Fakat prototip ve parametre bildirimlerinde indeks operatr ([ ]) kullanlmas, adres deikeninin bir dizinin balangcna iaret ettiini aka belirtir.
rnek 5.7-12 adrf12.c program. #include <stdio.h> #define BOY 5 void sirala( int, double *[ ] ); void listele( int, double *[ ], double [ ] );

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-80

rnek 5.7-12 devam


int main(void) { int n; double d[ ] = { 3.0, 1.9, 2.8, 5.7, 4.6 }; double *pd[BOY]; for( n = 0; n < BOY ; n++ ) pd[ n ] = &d[ n ]; listele( BOY, pd, d ); sirala( BOY, pd ); printf("\n"); listele( BOY, pd, d ); return 0; } void sirala( int ELSayi, double *p[ ] ) { int i, j; double *t; for( i = 0; i < ELSayi - 1 ; i++ ) for( j = i + 1 ; j < ELSayi; j++ ) if ( *p[ i ] > *p[ j ] ) { t = p[ j ]; p[ j ] = p[ i ]; p[ i ] = t; } } void listele( int ELSayi, double *p[ ], double dd[ ] ) { int l; for( l = 0; l < ELSayi; l++) printf("pd[%d] : %p, *pd[%d] : %1.1f, d[%d] : %1.1f \n", l, p[ l ], l, *p[ l ], l, dd[ l ] ); } kt rnek 5.7-11 ile ayn.

rnek 5.7-12'de diziler zerinde ilemler indeks operatr kullanlarak yapld. Bu ilemler rnek 5.7-13'de olduu gibi adres aritmetii uygulanarak gerekletirilebilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-81

Bu amala pd adres dizisine d dizisinin elemanlarnn bellek adreslerini atayan,


pd[ n ] = &d[ n ];

deyimi yerine,
*( pd+i ) = d + i;

deyimi kullanlabilir.
rnek 5.7-13 adrf13.c program. #include <stdio.h> #define BOY 5 void sirala( int, double ** ); void listele( int, double **, double [ ]); int main(void) { int i; double d[ ] = { 3.0, 1.9, 2.8, 5.7, 4.6 }; double *pd[BOY]; for( i = 0; i < BOY ; i++ ) *( pd+i ) = d + i; listele( BOY, pd, d ); sirala( BOY, pd ); printf("\n"); listele( BOY, pd, d ); return 0; } void sirala( int ELSayi, double **p ) { int i, j; double *t; for( i = 0; i < ELSayi - 1 ; i++ ) for( j = i + 1 ; j < ELSayi ; j++ ) if ( **(p+i) > **(p+j) ) { t = *( p + j ); *( p + j ) = *( p + i ); *( p + i ) = t; } }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-82

...rnek 5.7-13 devam


void listele( int ELSayi, double **p, double dd[ ]) { int l; for( l = 0; l < ELSayi; l++) printf("pd[%d] : %p, *pd[%d] : %1.1f, d[%d] : %1.1f \n", l, *( p + l ), l, **( p + l ), l, dd[ l ] ); } kt rnek 5.7-11 ile ayn.

rnek 5.7-13'de listele fonksiyonunda yer alan *( p + l ) ifadesi adres deeri, **( p + l ) ifadesi ise bu adreste bulunan deeri verir. p parametresi ift adres deikeni olduundan indirek deere eriim iin * operatr iki kez uygulanmaldr. Ayn ekilde sirala fonksiyonundaki ilemler de adres aritmetii kullanlarak gerekletirilebilir. rnek programlarda adres dizisi kullanlarak double verilerden oluan bir dizi zerinde sralama ilemleri yapld. Dizgiler ve yaplar gibi bellekte ok yer kaplayan verilerin sralama ilemlerinin bu verilere iaret eden adres dizileri zerinde yaplmas olduka verimlidir.

Fonksiyona iaret eden adres deikeni


Bir fonksiyon deiken deildir fakat fonksiyona iaret eden adres deikeni bildirilebilir. Herhangi bir fonksiyonun adresi bu adres deikenine atanabilir; argman olarak fonksiyonlara aktarlabilir yada adres dizilerine yerletirilebilir. Ayrca bir fonksiyon baka bir fonksiyonun adresini dndrebilir. Fonksiyona iaret eden bir adres deikeni aadaki ekilde bildirilir:
tip (*adr) (parametre tip listesi);

Bu bildirimde tip, adr adres deikeninin iaret ettii fonksiyonun dndrecei deerin tipidir. *adr ifadesi dnda bulunan parantezler kullanlmadnda, operatr nceliinden dolay bu bildirim ile adres deeri dndren bir fonksiyon bildirilmi olur (bildirilen adr, tip tipinde verilere iaret eden adres deeri dndren fonksiyon olur). nk * operatr adr yerine tip ile birleir. Bildirimin sonunda bulunan ve parantezlerle snrlanm parametre tip listesi, adres deikeninin bir fonksiyona iaret ettiini belirtir. Bu bildirimde adr, tip tipinde deerler dndren fonksiyona iaret eden adres deikeni; *adr ise fonksiyonun kendisidir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-83

rnek programda,
int (*adr_fonk) (const char *);

bildirim deyimi ile int deer dndren ve bir const char * tipinde argman alan fonksiyona iaret eden adr_fonk adres deikeni bildirilir. Bu adres deikenine const char * tipi argman alan bir fonksiyonun adresi atanabilir. *adr_fonk ifadesinin dnda bulunan parantezler kullanlmadnda,
int *adr_fonk (const char *);

bildirim deyimi ile bir int verinin adresini dndren adr_fonk fonksiyonu bildirilmi olur.
rnek 5.7-14 adrfonk1.c program. #include <stdio.h> int main(void) { int (*adr_fonk) (const char *); adr_fonk = puts; (*adr_fonk)("abc"); return 0; } kt abc

Programda,
adr_fonk = puts;

atama deyimi ile adres deikenine puts fonksiyonun adresi atanr. nk yukardaki atama deyiminde olduu gibi bir ifadede fonksiyon ismi (puts), yine ayn fonksiyona iaret eden adres deerine dnr. Bu nedenle yukardaki atama deyiminde puts ncesinde & operatr gerekli deildir. Standart ktphane fonksiyonu puts, argman olarak aktarlan dizgiyi ekrana yazar ve durum gsteren bir int deer dndrr. Fonksiyon ismi yukardaki atama deyiminde parantezler olmadan kullanlr nk bu bir fonksiyon ars deildir. Dolaysyla fonksiyon arma operatr ( () ) kullanlmaz. ar satr,
(*adr_fonk) ("abc");

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-84

ile puts fonksiyonuna adres deikeni aracl ile indirek olarak eriilir ve ekrana abc dizgisi yazlr. Fonksiyona iaret eden adres deikeni ile gerekletirilen arda * operatr kullanlmayabilir. Dolaysyla ar aadaki ekilde gerekletirilebilir:
adr_fonk("abc");

Bir fonksiyonun argman olarak bir baka fonksiyona aktarlmas


Bir fonksiyon ismi, bir baka fonksiyon arsnda argman olarak kullanldnda aktarlan deer bu fonksiyonun adresidir. Bu uygulamaya rnek olarak, son argman fonksiyona iaret eden adres deikeni olan qsort fonksiyonu gsterilebilir:
void qsort ( void *baslangic, size_t el_sayi, size_t byte, int (*Adr)( const void *adr1, const void *adr2 ) ); /* stdlib.h */

Standart ktphane sralama fonksiyonu qsort, herbiri byte byklnde el_sayi elemandan oluan ve bellek adresi baslangic olan eleman ile balayan diziyi sralar. Dizinin iki elemann birbiri ile karlatrmak iin adresi Adr olan karlatrma fonksiyonunu arr. Argman olarak karlatrlan iki elemann adresini alan bu fonksiyon indirek olarak eriilen deerler arasndaki ilikiye gre negatif (deger1 < deger2), 0 (deger1 == deger2) yada pozitif (deger1 > deger2) bir deer dndrmelidir. qsort fonksiyonu her tipte dizi ile alabilir. Ancak dizi tipine gre ayn prototipe sahip fakat i yaps farkl karlatrma fonksiyonlar gelitirilmelidir. rnein aadaki fonksiyon bir tamsay dizinin elemanlarn karlatrmak iin kullanlabilir:
int IntKarsi( const void *i, const void *j ) /* tamsayi dizi */ { if ( *(int*)i < *(int*)j ) return -1; else if ( *(int*)i == *(int*)j ) return 0; else return 1; }

Sonu olarak fonksiyon adresi alacak ekilde tanmlanm herhangi bir fonksiyon bir dierini indirek olarak adres deikeni aracl ile arabilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-85

rnek 5.7-15 qsort.c program (Ornek 5.7-11). #include <stdio.h> #include <stdlib.h> #include <string.h> #define BOY 5 void List( int, double *[ ], double [ ] ); int dAdrKarsi( const void *adr1, const void *adr2 ); int DoubleKarsi( const void *adr1, const void *adr2 ); int DizgiKarsi( const void *adr1, const void *adr2 ); int main(void) { int n; double d[ ] = { 3.0, 1.9, 2.8, 5.7, 4.6 }, *pd[ BOY ]; char *Adr[ ] = { "defgabc", "cdefgab", "bcdefga", "abcdefg" }; for( n = 0; n < BOY ; n++ ) pd[ n ] = &d[ n ]; List( BOY, pd, d ); puts( "adres dizisi sirala" ); qsort( pd, BOY, sizeof (double*), dAdrKarsi ); List( BOY, pd, d ); puts( "double dizi sirala" ); qsort( d, BOY, sizeof (double), DoubleKarsi ); List( BOY, pd, d ); puts( "adres dizisi sirala" ); qsort( Adr, sizeof Adr / sizeof Adr[0], sizeof Adr[0], DizgiKarsi ); for ( n = 0; n < sizeof Adr / sizeof Adr[0]; n++ ) puts( Adr[ n ] ); return 0; } void List( int ELSayi, double *p[ ], double dd[ ]) { int i; putchar( '\n' ); for( i = 0; i < ELSayi; i++) printf("*pd[%d] : %1.1f, d[%d] : %1.1f \n", i, *p[ i ], i, dd[ i ] ); putchar( '\n' ); } int dAdrKarsi( const void *adr1, const void *adr2 ) { const double d1 = **(double **)adr1; const double d2 = **(double **)adr2; if ( d1 < d2 ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-86

...rnek 5.7-15 devam


return -1; else if ( d1 == d2 ) return 0; else return 1;
}

int DoubleKarsi( const void *adr1, const void *adr2 ) { const double d1 = *(double *)adr1; const double d2 = *(double *)adr2; if ( d1 < d2 ) return -1; else if ( d1 == d2 ) return 0; else return 1; } int DizgiKarsi( const void *adr1, const void *adr2 ) { const char *s1 = *(char **)adr1; const char *s2 = *(char **)adr2; return strcmp( s1, s2 ); } kt *pd[0] : 3.0, d[0] : 3.0 *pd[1] : 1.9, d[1] : 1.9 *pd[2] : 2.8, d[2] : 2.8 *pd[3] : 5.7, d[3] : 5.7 *pd[4] : 4.6, d[4] : 4.6 adres dizisi sirala *pd[0] : 1.9, d[0] : 3.0 *pd[1] : 2.8, d[1] : 1.9 *pd[2] : 3.0, d[2] : 2.8 *pd[3] : 4.6, d[3] : 5.7 *pd[4] : 5.7, d[4] : 4.6 double dizi sirala *pd[0] : 2.8, d[0] : 1.9 *pd[1] : 3.0, d[1] : 2.8 *pd[2] : 1.9, d[2] : 3.0 *pd[3] : 5.7, d[3] : 4.6 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-87

...rnek 5.7-15 devam


*pd[4] : 4.6, d[4] : 5.7 adres dizisi sirala abcdefg bcdefga cdefgab defgabc

rnek 5.7-16'da argman olarak int tipi deerler dndren bir fonksiyona iaret eden adres deikeni bekleyen Liste fonksiyonu tanmlanmtr. Fonksiyon bildirimi okunabilirlii arttrmak iin parametre ismi kullanlarak aadaki gibi yazlabilir:
void Liste( int (*adr_fonk)( const char *s ) );

rnek 5.7-16 adrfonk2.c program. #include <stdio.h> void Liste( int (*)(const char *) ); int main(void) { Liste( puts ); return 0; } void Liste( int (*adr_fonk)(const char *) ) { adr_fonk("abc"); } kt abc

Liste fonksiyonu balnda adr_fonk parametresinin int tipi deerler dndren ve bir char * argmana sahip fonksiyona iaret eden adres deikeni olduu bildirilir. Liste fonksiyonu aktarlan fonksiyon adresini lokal adres deikeni adr_fonk'a atar. Bu adres deikeni ile indirek olarak puts fonksiyonuna eriir ve abc dizgisini ekrana yazar. Bildirimde Liste fonksiyonunun argman olarak fonksiyona iaret eden adres deikeni bekledii belirtildii iin arda & operatr kullanm gereksizdir. rnek programlarda adres dizisi kullanlarak double veriler sraland. Sralama ve listeleme ilemleri argman olarak adres dizisi alan fonksiyonlarla gerekletirildi. rnek

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-88

5.7-17'de listeleme ilemi sirala fonksiyonu iinde yaplr. sirala fonksiyonu argman olarak fonksiyon adresi alacak ekilde tanmlanr.
rnek 5.7-17 adrfonk3.c program. #include <stdio.h> #define BOY 5 void sirala( int, double **, void (*)( int, double ** ) ); void listele( int, double ** ); int main(void) { int i; double d[ ] = { 3.0, 1.9, 2.8, 5.7, 4.6 }; double *pd[ BOY ]; void (*adr_fonk)( int, double **, void (*)(int, double **) ); for( i = 0; i < BOY ; i++ ) *( pd + i ) = d + i; adr_fonk = sirala; (*adr_fonk)( BOY, pd, listele ); return 0; } void sirala( int ELSayi, double **ps, void (*adr_list)( int, double ** ) ) { int i, j; double *t; for( i = 0; i < ELSayi - 1 ; i++ ) for( j = i + 1 ; j < ELSayi ; j++ ) if ( **( ps + i ) > **( ps + j ) ) { t = *( ps + j ); *( ps + j ) = *( ps + i ); *( ps + i ) = t; } (*adr_list)( ELSayi, ps ); } void listele( int ELSayi, double **pl ) { int l; for( l = 0; l < ELSayi; l++) printf("eleman %d - %1.1f \n", l + 1, **( pl + l ) ); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-89

...rnek 5.7-17 devam


kt eleman 1 - 1.9 eleman 2 - 2.8 eleman 3 - 3.0 eleman 4 - 4.6 eleman 5 - 5.7

Aadaki fonksiyon prototipi, sirala fonksiyonunun argman olarak bir int deer, bir ift adres deeri ve bir fonksiyon adresi (int ve double ** tipi iki argman alan ve hi bir deer dndrmeyen) beklediini belirtir: Prototip :
void sirala( int, double **, void (*)( int, double ** ) );

Fonksiyon balnda ise aktarlan fonksiyon adresinin atanaca adr_list parametresi (sirala fonksiyonunun lokal adres deikeni ) bildirilir: Fonksiyon bal:
void sirala( int ELSayi, double **ps, void (*adr_list)(int, double **) )

main blou iinde bildirilen adr_fonk adres deikeni, sirala fonksiyonuna eriim iin kullanlr. adr_fonk adres deikeni ile indirek olarak eriilen sirala fonksiyonu, ar satr,
(*adr_fonk)( BOY, pd, listele );

ile listele fonksiyonunun nc argman olarak aktarlan ve kendi lokal adres deikeni adr_list'e atanan adresini alr ve bu yolla eritii listele fonksiyonunu kullanarak sralanm deerleri ekrana yazar.

Fonksiyon Tablosu
nceki blmlerde dizgilere ve double verilere iaret eden adres dizileri bildirildi. Adres dizisi, ayn tipte elemanlardan oluan her eit veri grubunun bellek adreslerini tayabilir. Elemanlar ayn prototipe sahip fonksiyonlarn adresini saklayan adres dizisi fonksiyon tablosu olarak adlandrlr. Dizi elemanlarnn hepsi ayn tipte olduu iin iaret edilen fonksiyonlar da ayn tipte deerler dndrmeli ve ayn parametre listesine sahip olmaldr. Fonksiyon tablosu aadaki ekilde bildirilir:
tip (*tablo_ismi [ n ]) (parametre-tip-listesi);

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-90

Bu bildirimde tip, fonksiyonlarn dndrd deerin tipi; tablo_ismi, C dilinin kurallarna uygun olarak belirlenen fonksiyon tablosu ismi; n, tabloda yer alan fonksiyon says; parametre-tip-listesi ise fonksiyonlarn virgl ile ayrlm olarak verilen parametre tiplerinin listesidir. Bildirim srasnda ilk deer atama yaplabilir:
tip (*tablo_ismi [ ] ) (parametre-tip-listesi) = { adres_1, ... , adres_n };

Programlarda belli bir koula gre yaplan fonksiyon arlar, if ve switch deyimleri yerine fonksiyon tablosundan yine seime bal olarak belirlenen dizi indeksi ile elde edilen fonksiyon adresi kullanlarak gerekletirilebilir. Tablo kullanlarak fonksiyon arlmas aadaki ekilde olur:
(*tablo_ismi [ indeks ] ) (aktarlan-argumanlarin-listesi);

Eer fonksiyon herhangi bir deer dndryor ise bu deer ar ifadesi uygun ekilde bildirilmi bir deikene atanarak alnabilir. rnek 5.7-18'de ayr fonksiyon tanmlanr: menu, giris ve liste fonksiyonlar. Adres deikeni aracl ile eriilen menu fonksiyonu, basit bir menu listeler ve ekrandan ald seenek numarasn dndrr. Ana programda switch deyimi kullanlarak seime gre giris yada liste fonksiyonlar arlr. rnek 5.7-19'da switch deyimi kullanlmadan yine menu fonksiyonunun dndrd seenek numarasna gre giris yada liste fonksiyonlar arlr. Bu amala fonk_t adres dizisi bildirilir ve ilk deer olarak giris ve liste fonksiyonlarnn bellek adresleri atanr. Deer atama yaplrken, nceki rnekler de olduu gibi fonksiyon isimleri & operatr olmadan kullanlr. Kullanm kolayl amacyla fonksiyonlara eriim iin kullanlan ifadeler iin #define n-ilemci komutu ile sembolik isimler tanmlanmtr. Programda adres dizisinin 0 indeksli balang eleman kullanlmamtr. Ayrca bu elemana atanan 0 deeri, atama ncesi tip evirme uygulanarak fonksiyon tipine evrilir. Sonu olarak main blou iki satrdan oluan bir program haline gelir. ok sayda fonksiyon ieren programlarda fonksiyon tablosu kullanm olduka pratiktir.
rnek 5.7-18 fonktab1.c program. #include <stdio.h> int menu(void) { int secim; while ( 1 ) { printf( "Secenekler \n" "---------------- \n" "1-Giris \n" "2-Liste \n" C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-91

...rnek 5.7-18 devam


"3-Cikis "Seciminiz : scanf("%d", &secim ); \n" " );

if ( secim < 1 || secim > 3 ) printf("\t\t hatali giris ...\n"); else break; } /* while */ return secim; } void giris(void) { printf("\t\t giris ...\n"); } void liste(void) { printf("\t\t liste ...\n"); } int main(void) { int i, (*adr_menu)(void) = menu; while ( (i = (*adr_menu)( ) ) != 3 ) switch( i ) { case 1: giris(); break; case 2: liste(); break; default: break; } return 0; } kt Secenekler 1 - Giris 2 - Liste 3 - Cikis Seciminiz : 1 giris ... Secenekler 1 - Giris C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-92

...rnek 5.7-18 kt devam


2 - Liste 3 - Cikis Seciminiz : 2 liste ... Secenekler 1 - Giris 2 - Liste 3 - Cikis Seciminiz : 3

Aadaki program da yine ayn kty verir.


rnek 5.7-19 fonktab2.c program. #include <stdio.h> int menu(void) { int secim; while ( 1 ) { printf( "Secenekler \n" "---------------- \n" "1-Giris \n" "2-Liste \n" "3-Cikis \n" "Seciminiz : " ); scanf("%d", &secim ); if ( secim < 1 || secim > 3 ) printf("\t\t hatali giris ...\n"); else break; } /* while */ return secim; } void giris(void) { printf("\t\t giris ...\n"); } void liste(void) { printf("\t\t liste ...\n"); }
/* giris fonksiyonu tanimi */

/* liste fonksiyonu tanimi */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-93

...rnek 5.7-19 devam


void (*fonk_t [ ] )(void) = { (void (*)())0, giris, liste }; int i, (*adr_menu)(void) = menu; #define FONK (*fonk_t[ i ]) #define MENU (*adr_menu) int main(void) { while ( (i = MENU( ) ) != 3 ) FONK( ); return 0; } kt rnek 5.7-18 ile ayn kt.
/* fonksiyon tablosu tanimi */

/* global degisken i ve adr_menu bildirimi */ /* fonksiyon cagrilari icin isim tanimlanmasi */

Komut Satr Argmanlar


nceki blmlerde yer alan programlarda, main fonksiyonu parametresiz olarak tanmland. Komut satrna boluk ile ayrlm olarak komut isminden sonra girilen ve komut satr argmanlar olarak adlandrlan bilgilerin program iinde kullanlabilmesi iin main fonksiyonu iki parametre ile tanmlanr. Program almaya baladnda komut satrna girilen bu bilgiler iletim sistemi tarafndan main fonksiyonunun parametrelerine deer olarak aktarlr. rnek 5.7-20'de main fonksiyonu argc (argument count) ve argv (argument vector) parametreleri ile tanmlanmtr. argc ve argv parametreleri aracl ile komut satr argmanlarna program iinden eriilebilir. Yaygn olarak kullanlan argc ve argv isimleri yerine baka isimler de kullanlabilir.
rnek 5.7-20 arg1.c program. #include <stdio.h> #include <string.h> int main( int argc, char **argv ) /* char *argv[ ] */ { int i; printf("argc : %d\n", argc ); for ( i = 0; i <= argc; i++ ) printf("argv[%d] : %12s, %2u karakter\n", i, argv[ i ], strlen( argv[i] ) ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-94

...rnek 5.7-20 devam


Bilgi Girii Komut satiri (DOS): C:\>arg arg1 arg2 <enter> kt argc argv[0] argv[1] argv[2] argv[3 : 3 : C:\ARG.EXE, : arg1, : arg2, : (null), 10 karakter 4 karakter 4 karakter 0 karakter
komutun bulunduu

NOT: Program DOS ortamnda derlenmitir. Dolaysyla farkl ortamlarda argv[0], fihrist bilgisini iermeyebilir (rnein UNIX'te).

main fonksiyonun ilk parametresi olan int tipindeki argc deikeni dizgilerin saysn (bu rnekte; 3) verir. kinci parametre argv ise dizgilerin adres dizisine iaret eden ift adres deikenidir. Dolaysyla bildirimi char **argv eklinde yaplabilir. Fakat [ ] kullanm, adres deikeninin bir diziye iaret ettiini ak olarak belirttii iin tercih edilebilir. Adres dizisi argv'nin elemanlar char * tipindeki adres deikenleridir ve karakter dizgilerine iaret ederler. rnek programda adres dizisi "C:\ARG.EXE", "arg1" ve "arg2" dizgilerinin balang elemanlarnn bellek adresleri ve son eleman olarakta bo adres deerinden (NULL) oluur.
argv: C:\ ARG.EXE \ 0 arg1\ 0 arg2\ 0 0

Yukardaki rnekte komut satrna iki argman girilmitir: arg1 ve arg2 dizgileri. argv[1] ve argv[2] adres deikenleri ile eriilen bu argmanlar, '\0' ile sonlanm karakter dizgileridir. Adres dizisinin balang eleman argv[0], iletim sistemine bal olarak src ismini, programn ve bulunduu fihristin ismini ierir (DOS altnda). argv[ argc ] ise NULL deer tayan bo adres deikenidir ve hibir veriye iaret etmez. Bo adres deeri, adres dizisinin sonunu iaretler. Programlar iinde genellikle argv[0] ve argv[argc] kullanlmaz. Komut isminden sonra hi bir argman girilmediinde argc'nin deeri 1'dir. Sonu olarak adres dizisinin argv[1] ifadesi ile eriilen ikinci dizgisi, komut satrna program isminden sonra girilen ilk argmandr. Son argmana ise argv[argc-1] ifadesi ile eriilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-95

Komut satr argmanlarna eriim tekniklerini gstermek iin arg2.c ve arg3.c programlarnda eitli while ve for dnglerine yer verilmitir. Blm 9'da bu teknikler kullanlarak program iine komut satrndan eitli seeneklerin alnmas ile ilgili rneklere yer verilmitir.
rnek 5.7-21 arg2.c program. #include <stdio.h> #include <string.h> int main( int argc, char **argv ) {
/* * */ av ve ac degiskenleri, parametrelerin ilk degerlerinin korunmasi icindir.

int i, ac = argc; char **av = argv; char *p; puts( "while - 1" );
/* * dizgilerin listelenmesi : * *argv her artirimdan sonra dizgilerin baslangic adreslerini ve son olarakta donguden * cikilmasini saglayan bos adres degerini (NULL) verir. */

while ( *++argv ) puts( *argv ); puts( "while - 2" );


/* * * * */ while dongusunde *++argv ifadesi, dizgilerin baslangic elemanlarinin bellek adreslerini verir. Bu adresler kullanilarak erisilen dizgi boyunca ilerlenerek karakterler listelenebilir. Yukaridaki dongu argv'nin degerini degistirdigi icin orijinal deger gereklidir. */

argv = av; while ( *++argv ) /* while ( *++argv != NULL ) { printf( "argv[...] --> %u\n", argv[0] ); for ( p = argv[0]; *p; p++ )
/* * asagidaki for donguleri de kullanilabilir: * for ( p = argv[0]; *p != '\0'; p++ ) * yada * for ( p = argv[0]; *p++; ) */

printf( "\t%u adresindeki karakter --> %c\n", p, *p ); putchar( '\n' ); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-96

rnek 5.7-21 devam


puts( "while - 3" ); argv = av; while ( *++argv ) { printf( "argv[...] --> %u\n", argv[0] ); for ( i = 0; *(argv[0]+i); i++ ) {
/* * */ for ( i = 0; argv[0][i]; i++ )

printf( "\t%u adresindeki karakter --> ", argv[0] + i ); putchar( *(argv[0] + i) ); putchar( '\n' );
/* * putchar( argv[0][i] ); */

} putchar( '\n' ); } puts( "for - 1" );


/* argv + i yada &argv[ i ] ifadeleri adres dizisinin elemanlarinin bellek adreslerini; * *(argv + i), &argv[ i ][ 0 ] yada argv[ i ] ifadeleri ise dizgilerin baslangic elemanlarinin * bellek adreslerini (yani adres dizisinin elemanlarinin degerlerini) verir: */

argv = av; for ( i = 0; i <= argc; i++ ) printf( "%s dizgisi %u karakter\n", *(argv + i), strlen( argv[i] ) ); puts( "for - 2" );
/* * * * * * * */ argv, adres dizisinin baslangic elemanina (&argv[0]) isaret eden cift adres degiskenidir. Dolayisiyla argv+i yerine ++argv ifadesi ile argv'nin adres dizisinin bir sonraki elemanina isaret etmesi saglanir. Fakat argv+i kullanildiginda argv'nin orijinal degeri degismez. argv adres degiskenine ++ isleminden sonra * operatoru uygulandiginda isaret ettigi adres dizisi elemaninin degerini (dizginin baslangic adresi) verecektir.

for ( i = 0; i <= argc; i++, argv++ ) { printf( "%s dizgisi %u karakter\n", *argv, strlen( *argv ) );
/* * for dongusu yerine buraya yerlestirilebilir: * argv++; */

} puts( "while - 5" ); argv = av; while ( --argc > 0 ) puts( *++argv ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-97

...rnek 5.7-21 devam


puts( "while - 6" ); argv = av; argc = ac; while ( --argc > 0 ) {
/* * * * * * * * */ *++argv ifadesi karakter dizilerinin (dizgilerin) baslangic adreslerini verdigine gore baslangic elemanina erisim icin **++argv yerine (*++argv)[0] ifadesi kullanilabilir. Yani **++argv == *(*++argv + 0) == (*++argv)[0] Indeks operatoru ([]), oncelik listesinde indirek deger operatorunden (*) once bulunur. Dolayisiyla ifadenin *++(argv[0]) seklinde yorumlanmasini onlemek icin parantezler kullanilir. ++ uygulanmadigi zaman asagidaki ifadeler aynidir: **argv, (*argv)[i], *(argv[i]) yada *argv[i]

putchar( (*++argv)[0] ); putchar( '\n' ); } puts( "while - 7" ); argv = av; argc = ac; while ( --argc > 0 ) {
/* * argv cift adres degiskenidir. Iki kez * uygulandiginda isaret ettigi dizginin baslangic * elemani olan char veriyi verir. */

putchar( **++argv ); putchar( '\n' ); } puts( "while - 4" );


/* * adres dizisinin elemanlari olan argv[i] adres degiskenlerinin tasidigi adres degerlerini * degistirdigi icin bu uygulama program sonuna yerlestirilmistir. */

argv = av; /* != NULL */ while ( *++argv ) { while ( *argv[0] ) /* != '\0' */ {


/* * komut satirina girilen arguman dizgilerde bulunan karakterlerin listelenmesi. */

putchar( *argv[0] ); ++argv[0]; } putchar( '\n' ); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-98

...rnek 5.7-21 devam


/* * argv * *argv * **argv */ : char ** tipinde adres degiskeni. : char * tipinde adres degiskeni. : char tipi degisken.

printf( "sizeof argv : %u, sizeof *argv : %u, sizeof **argv : %u\n", sizeof argv, sizeof *argv, sizeof **argv ); return 0; } kt
while - 1

123 abc
while - 2

argv[...] --> 3760 3760 adresindeki karakter --> 1 3761 adresindeki karakter --> 2 3762 adresindeki karakter --> 3 argv[...] --> 3764 3764 adresindeki karakter --> a 3765 adresindeki karakter --> b 3766 adresindeki karakter --> c
while - 3

argv[...] --> 3760 3760 adresindeki karakter --> 1 3761 adresindeki karakter --> 2 3762 adresindeki karakter --> 3 argv[...] --> 3764 3764 adresindeki karakter --> a 3765 adresindeki karakter --> b 3766 adresindeki karakter --> c
for - 1

C:\ARG2.EXE dizgisi 11 karakter 123 dizgisi 3 karakter abc dizgisi 3 karakter (null) dizgisi 0 karakter
for - 2

C:\ARG2.EXE dizgisi 11 karakter 123 dizgisi 3 karakter abc dizgisi 3 karakter (null) dizgisi 0 karakter
while - 5

123 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-99

...rnek 5.7-21 kt devam


abc
while - 6

1 a
while - 7

1 a
while - 4

123 abc sizeof argv : 2, sizeof *argv : 2, sizeof **argv : 1


ift adres deikeni: argv:
&argv[0]

adres dizisi: argv[0]: argv[1]: argv[2]: ++argv argv[argc]:


&argv[0][0] &argv[1][0] &argv[2][0] . . .

komut satr argmanlar: ... ... ... ... ... ... ... ... . . . '\0' ... ... '\0'

'\0'

++(argv[...])

++(argv[...]) ifadesi dizgilerde ilerler;char * tipinde adres deeri dndrr. ++argv ifadesi adres dizisinde ilerler; char ** tipinde adres deeri dndrr.

rnek 5.7-22 arg3.c program. #include <stdio.h> #include <string.h> int main( int argc, char **argv ) { int i, j;
/* */ Asagidaki ifadeler ayni degeri verir: i. dizginin baslangic elemani : *argv[ i ] yada argv[ i ][ 0 ] 0.dizginin i.elemaninin adresi : argv[0] + i yada *argv + i

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-100

...rnek 5.7-22 devam


for ( i = 0; argv[i]; i++ ) { for ( j = 0; argv[i][j]; j++ ) putchar ( argv[ i ][ j ] ); putchar( '\n' ); }

/* 2-boyutlu dizi olarak listeleme */

for ( i = 0; *(argv+i); i++ ) { for ( j = 0; *(*(argv+i)+j); j++ ) putchar ( *( *(argv+i) + j) ); /* adres aritmetigi kullanarak listeleme */
/* * */ (*(argv+i))[ j ] yada *(argv[ i ] + j) deneyiniz !!!

putchar( '\n' ); } while ( --argc > 0 ) { putchar( (*++argv)[0] );


/* * * * * * * * */ /* * * * * * * */

(*++argv)[ 0 ] == *( *++argv + 0) == **++argv


Bu ifadede cift adres degiskeni argv'nin degeri artirildigi icin adres dizisinde ilerlenir. argv, adres dizisi baslangic elemanina, ++argv ise izleyen elemanina isaret eder. * yada [ ] uygulandiginda isaret edilen dizginin baslangic elemaninin adresini verir (adres dizisi elemaninin degeri). Tekrar * uygulandiginda bu adresteki char veri elde edilir. Dolayisiyla bu ifade daima dizginin baslangic elemanini verir.

putchar( *++(argv[0]) ); /* *++argv[0]

*/

Bu ifadede adres dizisi elemani olan ve dizgilerin baslangicina isaret eden adres degiskeni argv[0]'in degeri artirildigi icin dizgide ilerlenir. argv adres dizisine isaret eder. Onceki putchar cagrisinda argv artirildigi icin argv[0] artik adres dizisinin baslangic elemani degildir. Bir baska dizginin baslangic adresidir ve ++ uygulandiginda bu dizginin izleyen karakterine isaret eder. * uygulandiginda bu karakteri verir.

} return 0; } kt C:\ARG3.EXE 123 abc C:\ARG3.EXE 123 abc 12ab

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-101

5.8 Deien Sayda Argman Alan Fonksiyonlar


C dilinde, deien sayda argman alan (her arda farkl sayda ve farkl tiplerde argman alabilecek) fonksiyon oluturmak mmkndr (variable-length argument list function). rnek programlarda kullanlan scanf ve printf, bu ekilde alan standart ktphane fonksiyonlardr. C dilinde bir fonksiyon arld zaman, argmanlar programn stack alanna arda yer aldklar srann tersine yani sadan sola doru aktarlr. Buna gre C fonksiyon arma teknii'nde (C calling convention) son argman stack alanna ilk olarak, ilk argman ise en son yerletirilir. Dolaysyla ilk argman her fonksiyon arsnda ayn sabit offset'te bulunur. arlan fonksiyon ilk argmann bu sabit stack pozisyonunu esas alr ve argman listesinde ilerleyerek argmanlara eriir.
NOT: Bir C fonksiyonu arldnda, ar satrnda yer alan argmanlarn deerleri programn stack alanna kopyalanr. Stack son giren ilk kar (LIFO, Last In First Out) eklinde alan bir veri yapsdr; stack'a eklenen bir deer stack tavanna (stack top) yerletirilir (push) ve bylece stack genilemi olur. Yada stack'tan tavanda bulunan bir veri karlabilir (pop). Bu durumda da stack klm olur.
push stack top pop

stack bottom

Programn stack alan ise bu ekilde ynetilen ve fonksiyon arlar srasnda kullanlan geici verileri saklamak iin ayrlm ve ardan dnldnde boaltlan bellek alandr. Donanma ve derleyiciye gre deimekle birlikte, ar srasnda stack ilemleri pek ok derleyici tarafndan aadaki ekilde gerekletirilir: CPU'nun stack pointer register'i (SP), stack'n tavan pozisyonunu izler (en son veri eklenen pozisyon). Stack azalan bellek adresi ynnde (aa doru) byr. Yani bir fonksiyon dierini ardnda, stack daha ok bellek alan kullanr ve SP'nin deeri azalr. ardan dnldnde, stack klr ve SP'nin deeri artar. C fonksiyon arma teknii'nde (C calling convention), argmanlar stack alanna arda yer aldklar srann tersine yani sadan sola doru aktarlr. Buna gre son argman ilk olarak, ilk argman ise en son yerletirilir. lk argman sonrasna ise fonksiyon almasn tamamladktan sonra kontroln aktarlaca dn adresi (return address) yerletirilir. Aadaki ekilde de grld gibi C arma teknii'nde, ilk argman daima stack'ta SP'ye gre belli bir sabit offset'te

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-102 ve dn adresi ncesinde bulunur (bu offset, dn adresini saklamak iin gerekli olan byte saysna eittir). arlan fonksiyon, daima ayn offset'te bulunduu iin (aktarlan argman saysndan bamsz olarak) ilk argmana ve dolaysyla ilk argmann stack adresini esas alarak izleyen argmanlara eriebilir. Dier baz programlama dillerinde argmanlar stack alanna programda yer aldklar srada (soldan saa doru) yerletirilir ve bu durumda arlan fonksiyon ilk argmann yerini belirleyemeyecei iin, deien sayda argman listesine sahip fonksiyon oluturulamaz. Baz C derleyicileri dier dillerdeki arma tekniklerinin de kullanlabilmesine olanak salar. C arma teknii'nde, arlan fonksiyon aktarlacak argman saysn bilmez. Dolaysyla aran fonksiyon, stack'a yerletirilen argman saysn bildii iin SP'yi ayarlayarak stack' boaltr. Bu durum programn hz ve oluturulan kod uzunluu asndan bir dezavantajdr. nk programn farkl yerlerindeki her arnn stack alann boaltan kodlar iermesi gerekir. ekil 5.8-1 C arma teknii'nde, fonksiyona giri srasnda stack grnm.
Argmanlar stack alanna sadan sola doru yerletirilir. fonk( arg1, arg2, ..., argn ); . . argn . . . . arg2 arg1 son argman ilk olarak yerletirilir. stack byme yn Baz donanmlarda stack yukar doru byr (artan bellek adresi ynnde). ekildeki stack dzeninde ilk argman her arda SP'ye gre pozitif offset'te bulunur.

stack
artan bellek adresi

SP

dn adresi . .

Fonksiyon argmanlarnn yerletirildii stack dzeni donanma ve derleyiciye gre deiebilir ve ayrca derleyicilerin fonksiyon argmanlarna eriim teknikleri farkl olabilir. Bu nedenle deien sayda argmanlarn deerlerine erimek iin tanabilir bir teknie ihtiya vardr. ANSI C'de stdarg.h balk dosyas deien sayda argman alan fonksiyon oluturmak iin kullanlabilecek standart makro tanmlar ierir. Aada listelenen bu makrolarn kullanlmas, donanma ve derleyiciye gre farkllk gsterebilecek i yaplar gizleyerek basit ve tanabilir bir teknik salar:
va_start( va_list arguman_gostergesi, son_arguman ); /* stdarg.h */ va_arg( va_list arguman_gostergesi, tip ); /* stdarg.h */ /* stdarg.h */ va_end( va_list arguman_gostergesi ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-103

Yukardaki makrolar kullanlarak deien sayda argman alan fonksiyon aadaki ekilde oluturulur:
l

Fonksiyon bildirim ve tanmnda parantezler iinde sabit argmanlar ve bunlar izleyen nokta (...) bulunur. nokta derleyiciye bu fonksiyonun sabit argmanlardan baka saylar ve tipleri belli olmayan (0 yada daha fazla) argman alabileceini belirtir. Bu argmanlarn tipleri ve saylar belli olmad iin derleyici tip kontrolu yapamaz. lk olarak fonksiyon iinde, stdarg.h'de tanmlanm olan va_list tipinde bir argman gstergesi (arguman_gostergesi) bildirilir: va_list arguman_gostergesi; Bu deiken, listede bulunan argmanlara iaret eden bir basit adres deikenidir (argument pointer). arguman_gostergesi'nin deer atama ilemi ilk olarak va_start makrosu tarafndan yaplr. Daha sonra bu deiken, izleyen argmanlara erimek iin va_arg tarafndan kullanlr.

Fonksiyonun argman listesi en az bir sabit argman (her arda ayn olan) ile balamaldr. nk kullanlan makrolar, listede yer alan dier argmanlarn yerlerini bu argman esas alarak saptar. va_start makrosu altrlarak arguman_gostergesi'nin verilen sabit argman (fonksiyonun bildirilen son sabit argman olan son_arguman) izleyen ilk argmana iaret etmesi salanr. son_arguman, register saklama snfna sahip olamaz. va_start( arguman_gostergesi, son_arguman ); Bundan sonra arguman_gostergesi ilk parametresi olan va_arg altrlarak listedeki argmanlara eriilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-104

Her bir argmana erimek iin va_arg makrosu altrlr. lk parametresi olan arguman_gostergesi'nin iaret ettii argmann deerini veren bu makronun ikinci parametresi szkonusu argmann tipidir. arguman_gostergesi, her va_arg sonras izleyen argmana iaret eder. Bu makro, deien sayda argman listesindeki argman says kadar altrlabilir. arlan fonksiyon aktarlan argman saysn bilmedii iin, herhangi bir yolla va_arg makrosunun ka kez altrlaca saptanmaldr. Bunun iin eitli yollar mevcuttur: eer liste ayn tipte argmanlardan oluuyor ise liste sonu herhangi bir deer ile iaretlenebilir (tamsaylar iin 1, dizgi argmanlar iin uygun tip dnm yaplarak 0 yada NULL gibi); yada bir sabit argman ile bu say aktarlabilir. Hem argmanlarn saysn hem de tiplerini belirtmek iin printf fonksiyonunda olduu gibi sabit argman olarak bir format dizgisi aktarlabilir. Bir baka teknik ise, standart C ktphanesinde bulunan ve daha sonra aklanacak olan vprintf gibi bir baka deien sayda argman alan fonksiyonun kullanlmasdr.

Argman listesi tarandktan sonra son olarak va_end makrosu altrlr. Bu makro fonksiyondan dnlmeden nce arguman_gostergesi'ni sfrlar. va_end sonrasnda tekrar va_start altrlarak liste batan taranabilir. Liste sonuna gelmeden nce yine va_end ve va_start altrlarak liste tekrar batan taranabilir.

ekil 5.8-2 va_start, va_arg ve va_end makrolarnn kullanm.


stack va_arg va_end va_arg arguman_gostergesi va_start . . argn . . . . arg2 arg1 dn adresi . .

Aadaki rnek programda yer alan her iki fonksiyon da ayn ii yapar. sabit argman alan ve bunlar ekrana listeleyen SabitArg fonksiyonu, ayn ii yapan deien sayda argman alan bir fonksiyon olarak tanmlanr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-105

rnek 5.8-1 sabitarg.c program. #include <stdio.h> #include <stdarg.h> #include <string.h> void SabitArg( int i, long l, char *s ); void DegisArg( int i, ... ); int main(void) { SabitArg( 9, 19L, "DENEME" ); DegisArg( 9, 19L, "DENEME" ); return 0; } void SabitArg( int i, long l, char *s ) { puts("- SabitArg -"); printf("i : %d, l : %ld, s : %s\n", i, l, s ); } void DegisArg( int i, ... ) { va_list AdrArg; puts("- DegisArg -"); va_start( AdrArg, i ); printf("i : %d, ", i ); printf("l : %ld, ", va_arg( AdrArg, long ) ); printf("s : %s\n ", va_arg( AdrArg, char * ) ); va_end( AdrArg ); } kt - SabitArg i : 9, l : 19, s : DENEME - DegisArg i : 9, l : 19, s : DENEME

DegisArg fonksiyonunun prototipinde ve tanmnda int tipi sabit parametre i ve bunu izleyen nokta bulunur. Program makrolarn kullanmn rneklemek amacyla gelitirildii iin, DegisArg fonksiyonuna argman saysn ve tiplerini aktarmak iin herhangi bir teknik iermemektedir. lk olarak va_list tipinde AdrArg deikeni bildirilir. Argman gstergesi AdrArg ve sabit argman i kullanlarak va_start makrosu altrlr. Bylece AdrArg'nin deien sayda argman listesinde yer alan ve i deikenini izleyen ilk argmana iaret etmesi salanr. Bundan sonra iki kez altrlan
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-106

va_arg makrosu ilk olarak ikinci parametresi olan long tipinde 19 deerini ve daha sonra da "DENEME" dizgisi balangcna iaret eden char * tipindeki adres deerini verir. Fonksiyondan dnlmeden nce va_end altrlr. Deien sayda argman alan fonksiyon olutururken argmanlar fonksiyon ars srasnda genileyen (promoting) veri tipinde, dizi tipi yada fonksiyon tipinde olamaz. Dolaysyla float tipler double ile; char (signed yada unsigned) gibi genileyen tamsay tipler ise int (signed yada unsigned) ile deitirilmelidir. Ayrca listede adres deeri olarak sadece * eklenerek adres tipine evrilebilen (int yada char gibi) veri tipleri kullanlabilir. rnein int*[10] kullanlamaz.
NOT: UNIX System V'de kullanlan makrolar varargs.h'de bulunur. Aada UNIX System V'de deien sayda argman listesi alan bir fonksiyon rnei verilmitir: /* * varunix.c */ #include <stdio.h> #include <varargs.h> void PrntDizgi(); int main(void) { PrntDizgi( "abc", "def", "xyz", (char *)NULL ); return 0; } void PrntDizgi(va_alist) va_dcl { char *s; va_list AdrArg; va_start(AdrArg); while ( s = va_arg( AdrArg, char *) ) puts( s ); va_end( AdrArg ); } /* * Cikti: abc def xyz */ C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-107

rnek 5.8-2'de deien sayda argman alan PrintDizgi, PrintTams, PrintXYf, DizgiEkle ve HataYaz fonksiyonlar tanmlanmtr.
rnek 5.8-2 degisarg.c program. #include <stdio.h> #include <stdarg.h> #include <string.h> void void void char void PrintDizgi( PrintTams( PrintXYf( *DizgiEkle( HataYaz( char *Format, ... ); int Sayi, ... ); int Satir, int Kolon, char *Format, ... ); char *Dizgi, ... ); char *Format, ... );

char Dizgi[ BUFSIZ ]; int main(void) { Dizgi[0] = '\0'; PrintDizgi( "1-sN2-sN3-sN", "abc", "def", "xyz" ); PrintDizgi( "1-s,T2-sN", "bir", "iki" ); PrintTams ( 3, 1, 2, 3 ); PrintTams ( 2, 1, 2 ); PrintXYf ( 10, 40, "%s : %d\n", "Tamsayinin degeri", 34 ); puts( DizgiEkle( Dizgi, "Bu ", "bir ", "denemedir. \n", (char *)NULL ) ); HataYaz( "%s dosyasi bulunamadi", "DENEME" ); return 0; } void PrintDizgi( char *Format, ... ) { va_list AdrArg; puts("- PrintDizgi -"); va_start( AdrArg, Format ); for ( ;*Format; ++Format ) switch (*Format) { case 's': printf("%s", va_arg( AdrArg, char * ) ); break; case 'N': putchar( '\n' ); break; case 'T': putchar( '\t' ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-108

rnek 5.8-2 devam


break; default : putchar( *Format ); } va_end( AdrArg ); } void PrintTams( int Sayi, ... ) { int i; va_list AdrArg; puts("- PrintTams -"); printf("ekrana yazilan tamsayi sayisi : %d\n", Sayi ); va_start( AdrArg, Sayi ); for ( i = 0; i < Sayi; i++ ) printf( "%d. sayi : %d\n", i+1, va_arg( AdrArg, int ) ); va_end( AdrArg ); } void PrintXYf( int Satir, int Kolon, char *Format, ... ) { va_list AdrArg; puts( "- PrintXYf -" ); if ( strlen(Format) > 0 ) { printf("Kursor Pozisyonu Satir : %d, Kolon : %d\n", Satir, Kolon ); va_start( AdrArg, Format ); vprintf( Format, AdrArg ); va_end( AdrArg ); } } char *DizgiEkle( char *Dizgi, ... ) { char *s; va_list AdrArg; puts("- DizgiEkle -"); va_start( AdrArg, Dizgi ); while ( ( s = va_arg( AdrArg, char * ) ) != NULL ) strcat( Dizgi, s ); va_end( AdrArg ); return Dizgi; } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-109

...rnek 5.8-2 devam


void HataYaz( char *Format, ... ) { va_list AdrArg; puts("- HataYaz -"); va_start( AdrArg, Format ); fprintf( stderr, "Hata: " ); vfprintf( stderr, Format, AdrArg ); fprintf( stderr, "\n" ); va_end( AdrArg ); } kt - PrintDizgi 1-abc 2-def 3-xyz - PrintDizgi 1-bir, 2-iki - PrintTams ekrana yazilan tamsayi sayisi : 3 1. sayi : 1 2. sayi : 2 3. sayi : 3 - PrintTams ekrana yazilan tamsayi sayisi : 2 1. sayi : 1 2. sayi : 2 - PrintXYf Kursor Pozisyonu Satir : 10, Kolon : 40 Tamsayinin degeri : 34 - DizgiEkle Bu bir denemedir. - HataYaz Hata: DENEME dosyasi bulunamadi

Deien sayda dizgi argman ekrana yazan PrintDizgi fonksiyonunun sabit argman bir format dizgisidir. Format dizgisi, format belirleyici karakterler olarak dizgiler iin s harfini, NL (newline) karakteri iin N harfini ve tab boluu iin de T harfini ierir. PrintDizgi arlarnda format dizgisinde bulunan karakterler birer birer ekrana yazlr. Bu arada format dizgisinde s karakterine rastlandnda ise argman listesinden bir dizgi va_arg makrosu ile alnarak ekrana yazlr. N harfine rastlandnda ekrana '\n', T karakterine rastlandnda ise ekrana '\t' yazlr.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-110

PrintTams fonksiyonunun ilk argman, argman listesinde yer alan tamsay deerlerin saysn aktarr. DizgiEkle fonksiyonu ise, NULL ile sonlandrlm olan deien sayda argman listesinde bulunan dizgileri, ilk argman olan bellek adresine strcat fonksiyonunu kullanarak pepee yerletirir ve yine bu bellek adresini dndrr. puts fonksiyonu DizgiEkle arsndan dnen deer olan bellek adresini argman olarak alr ve bu adreste bulunan dizgiyi ekrana yazar. PrintXYf ve HataYaz fonksiyonlar ise yine deien sayda argman alan vprintf ve vfprintf'i arr. Standart C ktphanesinde bulunan vfprintf, vprintf ve vsprintf fonksiyonlar fprintf, printf ve sprintf fonksiyonlarna benzer:
int vfprintf( FILE *dosya_gostergesi, const char *Format, va_list AdrArg ); /* stdio.h */ int vprintf( const char *Format, va_list AdrArg ); /* stdio.h */ int int vsprintf( char *Dizgi, const char *Format, va_list AdrArg ); /* stdio.h */

Ancak bu fonksiyonlar argman listesi yerine argman listesine iaret eden bir adres deeri alrlar (va_list tipinde bildirilen AdrArg'nin deeri). vfprintf fonksiyonu argman listesinde bulunan deerleri Format ile belirtilen ekilde formatlanm "text" olarak dosya_gostergesi ile ifade edilen akma (bir disk dosyasna ait akm, stdout yada stderr); vprintf fonksiyonu, standart k'a (stdout); vsprintf fonksiyonu ise balang adresi Dizgi ile belirtilen bellek alanna yerletirir (vsprintf, son karakter olarak olarak bo karakter ekler). Format, printf fonksiyonunun format dizgisi ile ayn ekilde oluturulur ve ayn ileve sahiptir. vfprintf ve vprintf fonksiyonlar baarl ise oluan karakter saysn, hata durumunda ise (fonksiyon, akmn hata gstergesini deitirmi ise) negatif deer dndrr. vsprintf ise bo karakter (null character, '\0' ) hari Dizgi'ye yazlan karakter saysn dndrr. Yine bu fonksiyon da kt hatas durumunda negatif deer dndrr. Programda bu fonksiyonlar arlmadan nce ilk olarak va_start makrosu altrlmaldr. ar sonras ise va_end makrosu altrlmaldr. PrintXYf fonksiyonu 3 sabit argmana sahiptir. lk iki tamsay argman, format dizgisi ve deien sayda argman listesi izler. Bu fonksiyon iinde vprintf fonksiyonu, format dizgisini ve argman gstergesi olan AdrArg ile arlr. PrintXYf fonksiyonu, printf fonksiyonunun karakterleri belirtilen satr ve kolona yazan versiyonu haline getirilebilir. HataYaz fonksiyonunun ilk argman format dizgisidir. Bunu deien sayda argman listesi izler. lk olarak fprintf ars standart hata k'na "Hata: " dizgisini yazar. Format dizgisi (printf format dizgisi ile ayn ekilde alan) ve argman gstergesi AdrArg (va_start makrosu altrlarak deien argman listesine iaret etmesi salanan) ile arlan vfprintf fonksiyonu listede bulunan argmanlar format dizgisinde belirtilen formata gre ekrana yazar. Son olarak ekrana NL karakteri gnderilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-111

Bu blmde, deien sayda argman alabilen fonksiyonlarn oluturulmas ve kullanm anlatld. Derleyicinin prototip dnda kalan parametreler iin tip ve say kontrol yapamayaca gz nne alnarak bu uygulamalar ok dikkatli gerekletirilmelidir. n

5.9 Kendini aran Fonksiyonlar


C dilinde, bir fonksiyon kendisini direk yada indirek olarak arabilir. Bu ekilde alan fonksiyonlar, zyineli (recursive) fonksiyonlar olarak adlandrlr. Direk arda, kendini aran tek bir fonksiyon yer alr. ndirek arda ise, fonksiyon kendisini bir baka fonksiyon zerinden arr (rnek olarak, f1 fonksiyonu f2 fonksiyonunu arr ve f2 fonksiyonu da tekrar f1 fonksiyonunu arr). Bu blmde, direk olarak gerekleen zyineli arlara yer verilmitir. Aadaki programda, ekrandan girilen bir tamsaynn faktriyeli hesaplanr.
rnek 5.9-1 fakt1.c program. #include <stdio.h> int main(void) { long fakt = 1, sayac, sayi; printf("bir tamsayi giriniz : "); scanf("%ld", &sayi ); for ( sayac = 1; sayac <= sayi; sayac++ ) fakt = fakt * sayac; printf("%ld ! : %ld\n", sayi, fakt ); return 0; } Bilgi Girii bir tamsayi giriniz : 3 kt 3! : 6

Program ekrandan girilen 3 deeri iin 6 sonucunu verir. n saysnn faktriyeli, n! eklinde yazlr ("n faktriyel" olarak okunur) ve n dahil n'e kadar tm pozitif tamsaylarn arpmna eittir. rnek olarak;
n! == 1 x 2 x ... x n 3! == 3 x 2 x 1, yani 6 4! == 4 x 3 x 2 x 1, yani 24

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-112

Faktriyel fonksiyonu iin aadaki zyineli tanm mevcuttur:


1, eer n <= 1 ise n! = n * (n - 1)! dier durumlarda

rnek 5.9-2 fakt2.c program. #include <stdio.h> long fakt( long ); int main(void) { long sayi, sonuc; printf("bir tamsayi giriniz : "); scanf("%ld", &sayi ); sonuc = fakt( sayi ); printf("%ld ! : %ld\n", sayi, sonuc ); return 0; } long fakt( long n ) /* n! : n faktoriyel */ { long f; printf("cagri, n : %ld\n", n ); f = ( n <= 1 ) ? 1L : n * fakt( n-1 ); printf("donus, faktoriyel degeri : %ld\n", f ); return f; } Bilgi Girii bir tamsayi giriniz : 3 kt cagri, n : 3 cagri, n : 2 cagri, n : 1 donus, faktoriyel degeri : 1 donus, faktoriyel degeri : 2 donus, faktoriyel degeri : 6 3! : 6

fakt(3) ars: (3 <= 1) ? 1 : 3 * fakt(2) fakt(2) ars: (2 <= 1) ? 1 : 2 * fakt(1) fakt(1) ars: (1 <= 1) ? 1 : 3 * fakt(0) fakt(1) arsndan dn 4 fakt(2) arsndan dn 5 fakt(3) arsndan dn 6

1 2 3

rnek 5.9-2'de yer alan programda, yukardaki tanm kullanlarak faktriyel hesaplama ilemi iin kendini aran fakt fonksiyonu oluturulur.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-113

Bu program ekrandan 3 deeri girildiinde yine ayn kty verir. fakt fonksiyonuna, arlar izlemek iin iki ayr printf satr eklenmitir. ktda da grld gibi n'in deeri 1'den byk olduu zaman, fonksiyon fakt(n-1) ifadesi ile kendini arr. Bu ar ile argman olarak, n'in o andaki deerinin bir eksii aktarlr. Bu srada, aran fakt bloundaki ilemler askya alnr. ie arlar, n'in deeri 1 olana kadar devam eder ve son ar bu deer ile gerekletirilir. Son ar, aran bloa 1 deerini dndrr ve dier arlar da dnmeye balar. Bu ilemler, ekil 5.9-1'de ematik olarak gsterilmitir. Bir fonksiyonun kendini aracak ekilde yazlmas, bellek tasarrufu salamaz ve programn hzn arttrmaz. nk fonksiyonun zerinde ilem yapt deerler iin zaten stack alan ayrlr ve stack ilemleri yaplr. Fakat bu ekilde yazlan fonksiyonlarn kodlar daha ksadr ve okunabilirlii daha fazladr. Ayrca baz veri yaplar zerinde ilemler yapmak iin kod oluturma srasnda ok kolaylk salarlar (aa veri yapsnda olduu gibi). Baz algoritmalar da zyineli olarak tanmlanabilir (hzl-sralama (quick sort) algoritmas gibi). Fakat fonksiyon kendini bir kez aryor ise bu ilemin zyineli bir tanm yerine tekrar ile yaplmas daha uygundur. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

5-114

ekil 5.9-1 3!'in fakt fonksiyonu kullanlarak zyineli olarak hesaplanmas.


#include <stdio.h> int main(void) { ... sonuc = fakt( 3 ) ; ... } dnen deer 6, yani 3*2*1 6 n:3 1 fakt(3) ars long fakt( long n ) { return (3 <= 1) ? 1L : 3 * fakt( 3 - 1 ) ; } dnen deer 2, yani 2*1 5 n:2 2 long fakt( long n ) { return (2 <= 1) ? 1L : 2 * fakt( 2 - 1 ) ; } dnen deer 1 n:1 4

fakt(2) ars

3 long fakt( long n ) {

fakt(1) ars

return (1 <= 1) ? 1L : 1 * fakt( 1 - 1 ); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-1

BLM 6:
Adres Deikenleri ve ok-Boyutlu Diziler
C dilinde ok-boyutlu dizi (multi-dimensional array) "elemanlar dizi olan dizi" 'dir. Bu blmde ok-boyutlu dizilerin ve bu dizilerin elemanlarna iaret eden adres deikenlerinin bildirilmesi ve ok-boyutlu dizilerin fonksiyonlara argman olarak aktarlmas anlatlacaktr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-3

6.1 ok-Boyutlu Dizi Bildirimi


C dilinde ok-boyutlu dizi bildirimi, elemanlar dizi olan bir dizinin bildirimidir. stenen sayda boyuta (dimension) sahip dizi bildirilebilir. Bildirim deyimine eklenen her indeks, diziye bir boyut daha ekler:
Dizi [1.boyut] [ 2.boyut] [3.boyut] ... [n.boyut]

Aadaki bildirim deyiminde, 5 tamsaydan oluan tek-boyutlu tamsay dizi iDizi tanmlanr:
int iDizi [ 5 ] = { 0, 1, 2, 3, 4 };

ki-boyutlu (two-dimensional; 2-d array) iDizi2b ise aadaki gibi tanmlanr:


int iDizi2b [ 4 ] [ 5 ] = { { 0, 1, 2, 3, 4 }, /* iDizi2b[0] dizisi { 5, 6, 7, 8, 9 }, /* iDizi2b[1] dizisi { 2, 3, 4, 5, 6 }, /* iDizi2b[2] dizisi { 7, 8, 9, 0, 1 } /* iDizi2b[3] dizisi };

*/ */ */ */

nc indeks eklenerek -boyutlu tamsay dizi iDizi3b tanmlanabilir:


int iDizi3b [ 3 ] [ 4 ] [ 5 ] = { /* iDizi3b[0] dizisi */ { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, /* iDizi3b[1] dizisi */ { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, /* iDizi3b[2] dizisi */ { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } } };

/* /* /* /*

iDizi3b[0][0] dizisi iDizi3b[0][1] dizisi iDizi3b[0][2] dizisi iDizi3b[0][3] dizisi

*/ */ */ */

/* /* /* /*

iDizi3b[1][0] dizisi iDizi3b[1][1] dizisi iDizi3b[1][2] dizisi iDizi3b[1][3] dizisi

*/ */ */ */

/* /* /* /*

iDizi3b[2][0] dizisi iDizi3b[2][1] dizisi iDizi3b[2][2] dizisi iDizi3b[2][3] dizisi

*/ */ */ */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-4

Eksiksiz olduu iin ilk deer listelerinde yer alan deerleri snrlayan oklu parantezler kullanlmayabilir. Fakat parantezlerin kullanm okunabilirlii artrr. ki-boyutlu (2-b) iDizi2b, "5 tamsaydan oluan 4 diziden oluan" dizidir. Yani iDizi2b dizisi iDizi2b[0], iDizi2b[1], iDizi2b[2] ve iDizi2b[3] dizilerinden oluur. ki-boyutlu dizi, satir ve sutun'lardan oluan bir tablo (matriks) olarak dnlebilir. Dizide yer alan tamsaylara satir ve sutun indeksi (row indeks ve column index) kullanlarak iDizi2b [ satir ] [ sutun ] ifadesi ile eriilir. &iDizi2b [ satir ] [ sutun ] ifadesi ise dizi elemanlarnn bellek adreslerini verir:
Tablo: 1.sutun 2.sutun 3.sutun 4.sutun 5.sutun

iDizi2b[0]: iDizi2b[1]: iDizi2b[2]: iDizi2b[3]:

1.satir 2.satir 3.satir 4.satir

0 5 2 7

1 6 3 8

2 7 4 9

3 8 5 0

4 9 6 1

-boyutlu (3-b) iDizi3b dizisi ise, iki-boyutlu dizilerden oluur: "5 tamsaydan oluan 4 dizinin (1-b) oluturduu 3 diziden (2-b) oluan dizi". iDizi3b dizisinin ilk eleman olan iki-boyutlu iDizi3b[ 0 ] dizisi, "5 int veriden oluan 4 dizinin (1-b) oluturduu dizi"'dir. iDizi3b dizisinin elemanlar olan tamsay deerlere iDizi3b[ tablo ][ satir ][ sutun ] ifadesi ile eriilir. Dizi elemanlarnn bellek adreslerini ise &iDizi3b[ tablo ][ satir ][ sutun ] ifadesi verir:
3. Tablo 2. Tablo 0 1. Tablo

1 1 2 7 4 9 2 3 8 5 0

2 3 4 9 6 1

3 4 9 6 1

0 5 2 7

1 6 3 8

4 9 6 1

iDizi2b dizisi, tek-boyutlu dizilerin oluturduu satrlardan oluur ve bellekte birbirini izleyen satrlar olarak bulunur (ekil 6.1-2). Dolaysyla bellekte ilk olarak dizinin ilk satrn oluturan iDizi2b[0] dizisi bulunur. Bunu dier satrlar yani iDizi2b[1], iDizi2b[2] ve iDizi2b[3] dizileri izler. nceki blmlerde, tek-boyutlu diziler tanmlanrken ilk deer listesi bulunuyor ise eleman says verilmeden bo keli parantezlerle tanmland. Derleyici, bildirim deyimindeki ilk deer listesinde bulunan deerleri (0-boyutlu satrlar olarak dnlebilir) sayarak dizi boyutlarn tesbit eder. lk deer listesi ieren okboyutlu bir dizi bildirim deyiminde yada izleyen blmlerde anlatlaca gibi argman olarak ok-boyutlu dizi alan fonksiyonlarn parametre bildirim listesinde, satr saysn belirten 1.boyut kullanlmayabilir. nk dizi bellekte satrlar oluturan alt-diziler olarak saklanr ve dizinin satr says deil satr uzunluu nemlidir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-5

Bu durumda iDizi2b aadaki gibi tanmlanabilir:


int iDizi2b [ ] [ 5 ] = { ... };

Ayn ekilde -boyutlu iDizi3b dizisi de aadaki gibi tanmlanabilir:


int iDizi3b [ ] [ 4 ] [ 5 ] = { ... };

Sonu olarak, bir dizi eksiksiz ilk deer listesi ile tanmlanrken ilk boyut verilmeyebilir.

ki-boyutlu iDizi2b dizisinin ierdii tek-boyutlu dizi says dizinin 1.boyutu olan satr saysn verir: 2-b dizinin 1.boyutu:
2-b dizi satr says = Dizinin toplam byte says / Bir satrnn byte says

iDizi2b iin;
sizeof (iDizi2b) / sizeof (iDizi2b[0])

Satrlar oluturan bir tek-boyutlu dizinin ierdii tamsay eleman says da, dizinin stun saysn (2.boyut) verir: 2-b dizinin 2.boyutu:
2-b dizi stun says = Bir satrnn byte says / Bir tamsay elemann (0-boyutlu) byte says

iDizi2b iin;
sizeof (iDizi2b[0]) / sizeof (iDizi2b[0][0])

Bir -boyutlu dizi iDizi3b, 2-b dizilerin oluturduu tablolardan oluan bir dizidir. Buna gre dizinin ilk boyutu olan tablo saysn, dizinin ierdii 2-b dizi says verir (rnek 6.1-2): 3-b dizinin 1.boyutu (tablo says):
3-b dizinin tablo says = Dizinin toplam byte says / Bir tablonun (2-b dizilerden oluan) byte says iDizi3b iin; sizeof (iDizi3b) / sizeof (iDizi3b[0])

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-6

3-b dizinin 2.boyutu olan bir tablodaki satr saysn, tablonun ierdii tek-boyutlu dizi says verir: 3-b dizinin 2.boyutu:
3-b dizinin satr says = Bir tablonun (2-b dizilerden oluan) byte says / Bir tablodaki bir satrn (tek-boyutlu dizinin) byte says iDizi3b iin; sizeof (iDizi3b[0]) / sizeof (iDizi3b[0][0])

3-b dizinin 3.boyutu olan stun saysn ise herhangi bir tabloda bulunan herhangi bir satr oluturan tamsay elemanlarn says verir: 3-b dizinin 3.boyutu:
3-b dizinin stun says = Bir tablodaki bir satrn (tek-boyutlu dizinin) byte says / Bir satr oluturan bir tamsay elemann (0-boyutlu) byte says

iDizi3b iin;
sizeof (iDizi3b[0][0]) / sizeof (iDizi3b[0][0][0])

Aadaki ifadeler 2-b ve 3-b int dizilerin eleman saysn (rank) verir: 2-b int dizi iin:
sizeof (iDizi2b) / sizeof (iDizi2b[0][0]) yada sizeof (iDizi2b) / sizeof (int)

3-b int dizi iin:


sizeof (iDizi3b) / sizeof (iDizi3b[0][0][0]) yada sizeof (iDizi3b) / sizeof (int)

rnek 6.1-1 ve rnek 6.1-2'de bu ekilde oluturulan makrolar kullanlarak dizilerin tablo, satr ve stun saylar bulunur. ok-boyutlu dizi kavram ekil 6.1-1'de gsterilmitir. Bir tek-boyutlu dizi, tek bir satrdan oluur. 2-b dizi ise, birden fazla satr ieren ve satr-stun dzeninde indekslenen bir tablodur. Bir 3-b dizi birden fazla tablo ieren bir klasr (tablo-satr-stun eklinde indekslenen); 4-b dizi birden fazla klasr ieren bir kutu; 5-b dizi ise birden fazla kutu ieren bir raf vb... olarak dnlebilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-7

ekil 6.1-1 ok-boyutlu diziler.


Dizi[1.boyut ][2.boyut ][3.boyut ][4.boyut ][5.boyut ] . . . [n.boyut ]
0 1 2 1 2

0 1 2 0 1 2

Dizi[n]

Dizi[ ][n]
0 1 2 1 2

Dizi[ ][ ][n]
0 1 2 1 2

Dizi[ ][ ][ ][n]

0 1 2

0 2 0 1 1 2

...
Dizi[ ][ ][ ][ ][ ] ... [n]

Dizi[ ][ ][ ][ ][n]

rnek 6.1-1'de ilk olarak, 2-b dizi iDizi2b'nin elemanlarnn deerleri ve bellek adresleri listelenir. rnek programlarda satr ve stun saylarn hesaplayan makrolar yerine, #define ile tanmlanan isimler kullanlabilir:
#define #define SATIR SUTUN 4 5

Fakat bu deerlerin diziye deer eklendiinde deitirilmesi gerekir. Makrolar kullanldnda ise diziye deer eklendiinde programda hi bir deiiklik gerekmez.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-8

rnek 6.1-1 adr2b.c program. #include <stdio.h> #define Satir2b(s) sizeof(s)/sizeof(s[0]) /* satir sayisi #define Sutun2b(s) sizeof(s[0])/sizeof(s[0][0]) /* sutun sayisi int main(void) { int i, j; int iDizi2b [ ] [ 5 ] = { */ */

/* i ve j : satir ve sutun indeksleri

*/

*/ { 0, 1, 2, 3, 4 }, /* iDizi2b [ 0 ] */ { 5, 6, 7, 8, 9 }, /* iDizi2b [ 1 ] */ { 2, 3, 4, 5, 6 }, /* iDizi2b [ 2 ] */ { 7, 8, 9, 0, 1 } /* iDizi2b [ 3 ] }; /*


* * Adr2b adres degiskeni, 5 tamsayidan olusan diziye -iDizi2b dizisinin satirlarina- isaret eder

*/ int (*Adr2b) [ 5 ] = iDizi2b; puts( "satir, sutun: deger(adres) " ); for ( i = 0; i < Satir2b( iDizi2b ); i++ ) { for ( j = 0; j < Sutun2b( iDizi2b ); j++ ) printf( "%d,%d: %d (%p) ", i, j, iDizi2b [ i ] [ j ], &iDizi2b [ i ] [ j ] ); putchar( '\n' ); } iDizi2b, sizeof (iDizi2b) ); printf( "iDizi2b+1 : %p, sizeof(iDizi2b+1) : %u\n", iDizi2b+1, sizeof (iDizi2b+1) ); printf( "iDizi2b[1] : %p, sizeof(iDizi2b[1]) : %u\n", iDizi2b[1], sizeof (iDizi2b[1]) ); printf( "iDizi2b[1]+1 : %p, sizeof(iDizi2b[1]+1) : %u\n", iDizi2b[1]+1, printf( "iDizi2b[1][1] : %d, sizeof(iDizi2b[1][1]): %u\n", iDizi2b[1][1], printf( "iDizi2b : %p, sizeof(iDizi2b) : %u\n", puts( "\nDizi elemanlarinin degerlerinin listelenmesi : \n"); puts( "*( iDizi2b[ satir ] + sutun ) :" ); for ( i = 0; i < Satir2b(iDizi2b); i++ ) { for ( j = 0; j < Sutun2b(iDizi2b); j++ ) printf( "%d ", *( iDizi2b[ i ] + j ) ); putchar( '\n' ); } printf( "\nsizeof(Adr2b) : %u, sizeof(*Adr2b) : %u\n", sizeof ( Adr2b ), sizeof ( *Adr2b ) ); printf( "Adr2b : %p, Adr2b + 1 : %p\n", Adr2b, Adr2b + 1 ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-9

...rnek 6.1-1 devam


puts( "\nAdr2b[ satir ][ sutun ] :" ); for ( i = 0; i < Satir2b(iDizi2b); i++ ) { for ( j = 0; j < Sutun2b(iDizi2b); j++ ) printf( "%d ", Adr2b[ i ][ j ] ); putchar( '\n' ); } return 0; } kt
satir, sutun: deger(adres)

0,0: 0 (0F28) 0,1: 1 (0F2A) 0,2: 2 (0F2C) 0,3: 3 (0F2E) 1,0: 5 (0F32) 1,1: 6 (0F34) 1,2: 7 (0F36) 1,3: 8 (0F38) 2,0: 2 (0F3C) 2,1: 3 (0F3E) 2,2: 4 (0F40) 2,3: 5 (0F42) 3,0: 7 (0F46) 3,1: 8 (0F48) 3,2: 9 (0F4A) 3,3: 0 (0F4C) iDizi2b : 0F28, sizeof (iDizi2b) : 40 iDizi2b + 1 : 0F32, sizeof (iDizi2b + 1) : 40 iDizi2b[ 1 ] : 0F32, sizeof (iDizi2b[ 1 ]) : 10 iDizi2b[ 1 ] + 1 : 0F34, sizeof (iDizi2b[ 1 ] + 1) : 10 iDizi2b[ 1 ][ 1 ] : 6, sizeof (iDizi2b[ 1 ][ 1 ]) : 2
Dizi elemanlarinin degerlerinin listelenmesi : *( iDizi2b [ satir ] + sutun ) :

0,4: 4 1,4: 9 2,4: 6 3,4: 1

(0F30) (0F3A) (0F44) (0F4E)

0 5 2 7

1 6 3 8

2 7 4 9

3 8 5 0

4 9 6 1

sizeof(Adr2b) : 2, sizeof(*Adr2b) : 10 Adr2b : 0F28, Adr2b + 1 : 0F32


Adr2b [ satir ][ sutun ] :

0 5 2 7

1 6 3 8

2 7 4 9

3 8 5 0

4 9 6 1

ktda da grld gibi tamsay dizi elemanlar bellekte tek-boyutlu bir dizide olduu gibi 2-byte byklnde sral bellek alanlarnda bulunur. nceki blmde, tek-boyutlu dizinin elemanlarna dizinin balangcna iaret eden bir basit adres deikeni aracl ile eriilirken kullanlan adres aritmetii, ok-boyutlu diziler iin de geerlidir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-10

Dolaysyla 2-b dizi iDizi2b iin dizi ismi kullanlarak aadaki ifadeler oluturulabilir : iDizi2b ifadesi:
ki-boyutlu dizinin balang adresini verir (0F28) ve "5 int'ten oluan 4 dizinin oluturduu dizi" tipindedir. sizeof(iDizi2b) yada sizeof(int[4][5]) ifadeleri iDizi2b dizisinin toplam bykl olan 40 byte deerini verir.

iDizi2b + i ifadesi:
Dizi ismi iDizi2b'ye offset eklenerek, satrlar oluturan alt-dizilerin (1-b) balang adresleri alnabilir ( i : satr indeksi ). Dolaysyla iDizi2b + i, dizinin i. satrna iaret eder. Bu ekilde oluturulan ifadelere sizeof operatr uygulandnda yine 40 byte deeri elde edilir. Programn ktsnda da grld gibi, yine bu ifadeler de adres aritmetiine gre yorumlanr: iDizi2b iDizi2b iDizi2b iDizi2b + + + + 0 1 2 3 : : : : 0F28 ( yada iDizi2b : 0F28 ) 0F32 0F3C 0F46

*(iDizi2b + i) ifadesi:
Yukardaki ifadelere indirek deer operatr uygulandnda elde edilen deer "5 int'ten oluan dizi" tipindedir (10 byte) ve yine alt-dizilerin balang adresini verir: *(iDizi2b *(iDizi2b *(iDizi2b *(iDizi2b + + + + 0): 1): 2): 3): 0F28 ( yada *iDizi2b : 0F28 ) 0F32 0F3C 0F46

iDizi2b[ i ] ifadesi de yine alt-dizilerin balang adresini verir. Programn ktsnda da grld gibi (satr indeksi i : 1 iin), yukarda verilen iDizi2b + i ve iDizi2b[ i ] ifadelerinin her ikisi de alt-dizilerin balang adresini verir. Fakat bu iki ifadenin tipleri farkldr ve dolaysyla birbirlerine eit deildirler.

*(iDizi2b + i) + j ve *( *(iDizi2b + i) + j ) ifadeleri:


*( iDizi2b + i ) ifadesi alt-dizilerin balangcna iaret ettiine gre, bu ifadeye stun offseti ( j ) eklenerek alt-dizilerin (1-b) elemanlarnn bellek adresleri elde edilebilir: *( iDizi2b + i ) + j yada iDizi2b[ i ] + j ( yada &iDizi2b [ i ][ 0 ] + j ) Tekrar indirek deer operatr uygulandnda iaret edilen bellek alanlarnda bulunan tamsay deerler elde edilir (iDizi2b [ i ][ j ]): *(*( iDizi2b + i ) + j) yada *(iDizi2b[ i ] + j) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-11

j : 0 deeri iin **(iDizi2b + i) yada *iDizi2b[ i ] ifadeleri alt-dizilerin balang elemanlarnn deerlerini verir.

rnek 6.1-1'de dizi ismi ile oluturulan *( iDizi2b[ i ] + j ) ifadesi kullanlarak tm elemanlarn deerleri listelenir. 2-b dizi elemanlarna adres deikeni kullanlarakta eriilebilir. Bu amala, 2-b dizi iDizi2b iindeki tamsay deerlerden oluan 1-b diziye iaret eden adres deikeni Adr2b tanmlanr ve ilk deer olarak iDizi2b dizisinin balang adresi atanr:
int (*Adr2b)[ 5 ] = iDizi2b;

Genel format aadaki gibidir:


Bir satrda bulunan eleman says: stun says
tip (*adres_degiskeni) [ satir_uzunlugu ] = 2b_dizi_ismi ;

Bylece iDizi2b'nin satrlarn oluturan tek-boyutlu dizilere iaret eden Adr2b tanmlanm olur.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-12

ekil 6.1-2 2-b dizi iDizi2b ve Adr2b adres deikeni.

iDizi2b dizisi: ...


iDizi2b[0][0] : 0F28 0F2A 0F2C 0F2E 0F30 iDizi2b +1 Adr2b +1 0F32 iDizi2b[1] +1 0F34 0F36 0F38 0F3A 0F3C 0F3E 0F40 0F42 0F44 0F46 0F48 0F4A 0F4C iDizi2b[3][4] : 0F4E Bellek

0 1 2 3 4 5 6 7 8 9 iDizi2b 2 3 4 5 6 7 8 9 0 1 iDizi2b[3] iDizi2b[2] iDizi2b[1] iDizi2b[0]

... ...
Adr2b :

0F28

...

Adr2b adres deikeni "5 int veriden oluan diziye iaret eden adres deikeni" tipinde olduu iin, deeri ++ operatr uygulanarak artrldnda bellekte bir sonraki tekboyutlu diziye (dizinin bir sonraki satrna) iaret eder (yani deeri sizeof(int(*)[5])

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-13

yada sizeof(*Adr2b) kadar artar). ktda da grld gibi Adr2b adres deikeninin indirek deeri 10 byte byklndedir. Dizi ismi kullanlarak oluturulan ifadelerde olduu gibi, adres deikeni de satr-stun eklinde indekslenerek elemanlara eriilebilir. Adr2b[ satir ][ sutun ] dizi elemanlarnn deerlerini verir. Bu ifade iDizi2b[ satir ][ sutun ] ifadesi ile ayn deeri dndrr. Fakat derleyici indeks operatrnn adres deikenine uyguland ifadeleri, dizi ismine uyguland ifadelerden farkl yorumlar (izleyen blmde anlatlacak olan argman olarak ok-boyutlu dizi alan fonksiyonlarn parametre listesi hari) ve her ikisi iin farkl kod retir. Dizi ismi iDizi2b bir sabit gstergedir. Dizi ismi ile oluturulan ifade, "dizi balangcndan itibaren i * sutun_sayisi + j says kadar bellek alan (her biri tek bir 0boyutlu dizi eleman byklnde) atlanarak gelinen yerde bulunan deere eriim" anlamnda yorumlanr. Adres deikeni ile oluturulan ifade ise, "adres deikeninin deerine adres aritmetiine gre i * sutun_sayisi + j eklenerek elde edilen adreste bulunan deere eriim" anlamnda yorumlanr. ki-boyutlu dizinin eleman olan 1-b dizilere iaret eden adres deikeni ile oluturulan,
Adr2b[ satir ][ sutun ]

ifadesi aadaki ifade ile,


*( Adr2b[ satir ] + sutun )

ve dolaysyla,
*( *(Adr2b + satir ) + sutun )

ifadesi ile ayndr. iDizi2b dizisinin elemanlar sral bellek adreslerinde bulunduu iin eriim, dizinin tek bir elemanna iaret eden Adr adres deikeni kullanlarak aadaki ekilde gerekletirilebilir:
... int *Adr = &iDizi2b[ 0 ] [ 0 ]; ...
... /* indeks hesaplanarak degerlerin listelenmesi */

for ( i = 0; i < Satir2b(iDizi2b); i++ ) { for ( j = 0; j < Sutun2b(iDizi2b); j++ ) printf( "%d ", Adr [ i * Sutun2b(iDizi2b) + j ] ); putchar( '\n' ); } ... C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-14

Fakat dizi elemanlarna bu ekilde eriim, 2-b dizi grnm vermez ve ayrca izleyen blmlerde anlatlacak olan baz uygulamalarda kullanlmas mmkn deildir. rnek 6.1-2'de, 3-b dizi iDizi3b'nin satrlarn oluturan 2-b dizilere (tablolara) iaret eden adres deikeni Adr3b tanmlanr ve yine rnek 6.1-1'de olduu gibi adres aritmetii ile oluturulan ifadeler kullanlarak dizi elemanlarna eriilir.
rnek 6.1-2 adr3b.c program. #include <stdio.h> #define Tablo3b(s) sizeof(s)/sizeof(s[0]) #define Satir3b(s) sizeof(s[0])/sizeof(s[0][0]) #define Sutun3b(s) sizeof(s[0][0])/sizeof(s[0][0][0]) /* tablo sayisi /* satir sayisi /* sutun sayisi */ */ */

int main(void) { int i, j, k; /* i, j ve k : tablo, satir ve sutun indeksleri */ int iDizi3b [ ] [ 4 ] [ 5 ] = { { /* iDizi3b [0] */ { 0, 1, 2, 3, 4 }, /* iDizi3b[0][0] { 5, 6, 7, 8, 9 }, /* iDizi3b[0][1] { 2, 3, 4, 5, 6 }, /* iDizi3b[0][2] { 7, 8, 9, 0, 1 } /* iDizi3b[0][3] }, { /* iDizi3b [1] */ { 0, 1, 2, 3, 4 }, /* iDizi3b[1][0] { 5, 6, 7, 8, 9 }, /* iDizi3b[1][1] { 2, 3, 4, 5, 6 }, /* iDizi3b[1][2] { 7, 8, 9, 0, 1 } /* iDizi3b[1][3] }, { /* iDizi3b [2] */ { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } } }; /* * Adr3b adres degiskeni, tablolara -iDizi3b dizisinin satirlarina- isaret eder. */ int (*Adr3b) [ 4 ][ 5 ] = iDizi3b; puts( "Tablo, Satir, Sutun: Deger(Adres) :" ); for ( i = 0; i < Tablo3b(iDizi3b); i++ ) { printf("Tablo No : %d\n", i ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman
/* /* /* /* iDizi3b[2][0] iDizi3b[2][1] iDizi3b[2][2] iDizi3b[2][3]

*/ */ */ */

*/ */ */ */

*/ */ */ */

6-15

...rnek 6.1-2 devam


for ( j = 0; j < Satir3b(iDizi3b); j++ ) { for ( k = 0; k < Sutun3b(iDizi3b); k++ ) printf( "%d,%d,%d: %d(%p) ", i, j, k, iDizi3b[i][j][k], &iDizi3b[i][j][k] ); putchar( '\n' ); } putchar( '\n' ); } puts( "ifade : degeri, sizeof (ifade)" ); printf( "iDizi3b : %p, %u\n", iDizi3b, sizeof (iDizi3b) printf( "iDizi3b + 1 : %p, %u\n", iDizi3b + 1, sizeof (iDizi3b + 1) printf( "iDizi3b[1] : %p, %u\n", iDizi3b[1], sizeof (iDizi3b[1]) printf( "iDizi3b[1] + 1 : %p, %u\n", iDizi3b[1] + 1, sizeof (iDizi3b[1] + 1) printf( "iDizi3b[1][1] : %p, %u\n", iDizi3b[1][1], sizeof (iDizi3b[1][1]) printf( "iDizi3b[1][1] + 1 : %p, %u\n", iDizi3b[1][1] + 1, sizeof (iDizi3b[1][1] + 1) printf( "iDizi3b[1][1][1] : %d, %u\n", iDizi3b[1][1][1], sizeof (iDizi3b[1][1][1]) puts( "\nDizi elemanlarinin degerlerinin listelenmesi:\n" ); puts( "*( *( *(iDizi3b + i ) + j ) + k ) :" ); for ( i = 0; i < Tablo3b(iDizi3b); i++ ) { printf("Tablo No : %d\n", i ); for ( j = 0; j < Satir3b(iDizi3b); j++ ) { for ( k = 0; k < Sutun3b(iDizi3b); k++ ) printf( "%d ", *( *( *(iDizi3b + i) + j ) + k ) ); putchar( '\n' ); } putchar( '\n' ); } printf( "sizeof(Adr3b) : %u, sizeof(*Adr3b) : %u\n", sizeof (Adr3b), sizeof (*Adr3b) ); printf( "Adr3b : %p, Adr3b + 1 : %p\n", Adr3b, Adr3b + 1 ); puts( "\nAdr3b[ tablo ][ satir ][ sutun ]: " ); for ( i = 0; i < Tablo3b(iDizi3b); i++ ) { for ( j = 0; j < Satir3b(iDizi3b); j++ ) { for ( k = 0; k < Sutun3b(iDizi3b); k++ ) printf( "%d ", Adr3b[ i ][ j ][ k ] ); /* * *( *( *(Adr3b + i) + j ) + k ) */ putchar( '\n' ); } putchar( '\n' ); } C PROGRAMLAMA DILI, 1997 Ismet Kocaman ); ); ); ); ); ); );

6-16

...rnek 6.1-2 devam


return 0; } kt
Tablo, Satir, Sutun: Deger(Adres) :

Tablo No : 0 0,0,0: 0 (0EB6) 0,1,0: 5 (0EC0) 0,2,0: 2 (0ECA) 0,3,0: 7 (0ED4) Tablo No : 1 1,0,0: 0 (0EDE) 1,1,0: 5 (0EE8) 1,2,0: 2 (0EF2) 1,3,0: 7 (0EFC) Tablo No : 2 2,0,0: 0 (0F06) 2,1,0: 5 (0F10) 2,2,0: 2 (0F1A) 2,3,0: 7 (0F24)

0,0,1: 1 0,1,1: 6 0,2,1: 3 0,3,1: 8 1,0,1: 1 1,1,1: 6 1,2,1: 3 1,3,1: 8 2,0,1: 1 2,1,1: 6 2,2,1: 3 2,3,1: 8

(0EB8) (0EC2) (0ECC) (0ED6) (0EE0) (0EEA) (0EF4) (0EFE) (0F08) (0F12) (0F1C) (0F26)

0,0,2: 2 (0EBA) 0,1,2: 7 (0EC4) 0,2,2: 4 (0ECE) 0,3,2: 9 (0ED8) 1,0,2: 2 1,1,2: 7 1,2,2: 4 1,3,2: 9 2,0,2: 2 2,1,2: 7 2,2,2: 4 2,3,2: 9 (0EE2) (0EEC) (0EF6) (0F00) (0F0A) (0F14) (0F1E) (0F28)

0,0,3: 3 0,1,3: 8 0,2,3: 5 0,3,3: 0 1,0,3: 3 1,1,3: 8 1,2,3: 5 1,3,3: 0 2,0,3: 3 2,1,3: 8 2,2,3: 5 2,3,3: 0

(0EBC) (0EC6) (0ED0) (0EDA) (0EE4) (0EEE) (0EF8) (0F02) (0F0C) (0F16) (0F20) (0F2A)

0,0,4: 4 0,1,4: 9 0,2,4: 6 0,3,4: 1 1,0,4: 4 1,1,4: 9 1,2,4: 6 1,3,4: 1 2,0,4: 4 2,1,4: 9 2,2,4: 6 2,3,4: 1

(0EBE) (0EC8) (0ED2) (0EDC) (0EE6) (0EF0) (0EFA) (0F04) (0F0E) (0F18) (0F22) (0F2C)

ifade : degeri, sizeof (ifade) iDizi3b : 0EB6, 120 iDizi3b + 1 : 0EDE, 120 iDizi3b[1] : 0EDE, 40 iDizi3b[1] + 1 : 0EE8, 40 iDizi3b[1][1] : 0EE8, 10 iDizi3b[1][1] + 1 : 0EEA, 10

iDizi3b[1][1][1]

: 6, 2

Dizi elemanlarinin degerlerinin listelenmesi: *( *( *(iDizi3b + i ) + j ) + k ) :

Tablo No : 0 01234 56789 23456 78901 Tablo No : 1 01234 56789 23456 78901 Tablo No : 2 01234 56789 23456 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-17

...rnek 6.1-2 kt devam


78901 sizeof (Adr3b) : 2, sizeof (*Adr3b) : 40 Adr3b : 0EB6, Adr3b + 1 : 0EDE
Adr3b[ tablo ][ satir ][ sutun ]:

0 5 2 7 0 5 2 7 0 5 2 7

1 6 3 8 1 6 3 8 1 6 3 8

2 7 4 9 2 7 4 9 2 7 4 9

3 8 5 0 3 8 5 0 3 8 5 0

4 9 6 1 4 9 6 1 4 9 6 1

iDizi3b dizisi iDizi3b[0], iDizi3b[1] ve iDizi3b[2] tablolarndan (2-b diziler) oluur. Tablolar ise 1-b dizilerden oluur. Buna gre iDizi3b[0] tablosunun satrlar olan 1-b diziler: iDizi[0][0], iDizi[0][1], iDizi[0][2] ve iDizi[0][3]. Ayn ekilde iDizi3b[1] tablosunun satrlar; iDizi[1][0], iDizi[1][1], iDizi[1][2] ve iDizi[1][3] dizileri; iDizi3b[2] tablosunun satrlar ise iDizi[2][0], iDizi[2][1], iDizi[2][2] ve iDizi[2][3] dizileridir. Her 1b dizi ise 5 int deer (sutun says) ierir. rnek programda Adr3b adres deikenine indeks operatr uygulanarak oluturulan,
Adr3b [ i ] [ j ] [ k ]

ifadesi,
*( *( *( Adr3b + i ) + j ) + k )

ifadesi ile ayndr. Adr3b adres deikeni, "5 int deerden oluan 4 (1-b) diziden oluan diziye (2-b) iaret eden adres deikeni" tipindedir: yani int(*)[4][5] tipindedir. Dolaysyla, indirek deerine sizeof operatrnn uyguland sizeof (*Adr3b) ifadesi 40 deerini verir ( sizeof (int(*)[4][5]) ifadesi de ayn deeri verir ). Bu nedenle Adr3b + 1 ifadesi, iDizi3b dizisinin bir sonraki tablosuna (satrna) iaret eder (adres aritmetiine gre onaltlk 0EB6 saysna 1 deeri eklendiinde, bu deer indirek deerin tipi ile leklendii iin gerekte 1*40 deeri eklenir ve sonuta 0EDE says elde edilir).

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-18

Bu blmde son olarak 4-b dizi rneklenmitir. ekil 6.1-3'de bu diziyi oluturan tm alt-diziler ematik olarak gsterilmitir. n boyutlu bir dizi iin aadaki ifadeler oluturulabilir: n boyutlu dizi tanm (eksiksiz ilk deer listesi ile):
n-1 indeks

tip dizi_ismi [ ] [ 2.boyut ] ... [ n.boyut ] = { ... } ;

n boyutlu diziye iaret eden adres deikeni tanm:


n-1 indeks

tip (*adres_degiskeni_ismi ) [ 2.boyut ] ... [ n.boyut ] = dizi_ismi ;

Aadaki ifade dizinin 1.boyut deerini verir:


sizeof ( dizi_ismi ) / sizeof ( dizi_ismi [0] )

Aadaki ifade ise dizinin n.boyut deerini verir:


n- indeks 1 n indeks

sizeof (dizi_ismi [0] ... [0] )

/sizeof (dizi_ismi [0] ... [0][0] )

Bu blmde ok-boyutlu dizilerin tanmlanmas ve dizi elemanlarna adres deikeni aracl ile eriim anlatld. n
rnek 6.1-3 adr4b.c program. #include <stdio.h> #define #define #define #define Boyut1(s) sizeof(s)/sizeof(s[0]) Boyut2(s) sizeof(s[0])/sizeof(s[0][0]) Boyut3(s) sizeof(s[0][0])/sizeof(s[0][0][0]) Boyut4(s) sizeof(s[0][0][0])/sizeof(s[0][0][0][0])

int main(void) { int i, j, k, l;


/* 1.boyut (2) verilmeyebilir */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-19

...rnek 6.1-3 devam


int iDizi4b[ 2 ][ 3 ][ 4 ][ 5 ] = { { { { 0, 1, 2, 3, 4 } , { 5, 6, 7, 8, 9 } , { 0, 1, 2, 3, 4 } , { 5, 6, 7, 8, 9 } , } , { { 0, 1, 2, 3, 4 } , { 5, 6, 7, 8, 9 } , { 0, 1, 2, 3, 4 } , { 5, 6, 7, 8, 9 } , } , { { 0, 1, 2, 3, 4 } , { 5, 6, 7, 8, 9 } , { 0, 1, 2, 3, 4 } , { 5, 6, 7, 8, 9 } , } , }, { { { 0, { 5, { 0, { 5, } , { { 0, { 5, { 0, { 5, } , { { 0, { 5, { 0, { 5, } , } }; 1, 2, 6, 7, 1, 2, 6, 7, 3, 4 } 8, 9 } 3, 4 } 8, 9 } , , , ,
iDizi4b[1]

iDizi4b[0][0]

iDizi4b[0]

iDizi4b[1][0]

1, 2, 6, 7, 1, 2, 6, 7,

3, 4 } 8, 9 } 3, 4 } 8, 9 }

, , , ,
iDizi4b[1][2][0]

1, 2, 6, 7, 1, 2, 6, 7,

3, 4 } 8, 9 } 3, 4 } 8, 9 }

, , , ,
iDizi4b[1][2][3][4]

int (*Adr4b) [ 3 ][ 4 ][ 5 ] = iDizi4b; for ( i = 0; i < Boyut1(iDizi4b); i++ ) { for ( j = 0; j < Boyut2(iDizi4b); j++ ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-20

...rnek 6.1-3 devam


{ for ( k = 0; k < Boyut3(iDizi4b); k++ ) { for ( l = 0; l < Boyut4(iDizi4b); l++ ) printf( "%d ", Adr4b[ i ][ j ][ k ][ l ] ); putchar( '\n' ); } putchar( '\n' ); } putchar( '\n' ); } return 0; } kt 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5

1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6

2 7 2 7 2 7 2 7 2 7 2 7 2 7 2 7 2 7 2 7 2 7 2 7

3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8 3 8

4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9 4 9

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-21

ekil 6.1-3 4-boyutlu iDizi4b dizisini oluturan alt-dizilerin ematik olarak gsterilmesi.
int iDizi4b[ ] [ 3 ] [ 4 ] [ 5 ] = {
iDizi4b[0][0][3] iDizi4b[0][1][3] iDizi4b[0][1][2] iDizi4b[0][1][1] iDizi4b[0][1][0] iDizi4b[0][1]

...

};

iDizi4b[0][2][3] iDizi4b[0][2][2] iDizi4b[0][2][1] iDizi4b[0][2][0] iDizi4b[0][2]

iDizi4b
iDizi4b[0]

iDizi4b[0][0][2] iDizi4b[0][0][1] iDizi4b[0][0][0] iDizi4b[0][0]

0 5
iDizi4b[0][0][0][0]

1 6 1 6

2 7 2 7

3 8 3 8

4 9 4 9

0 5 0 5

1 6 1 6

2 7 2 7

3 8 3 8

4 9 4 9

0 5 0 5

1 6 1 6

2 7 2 7

3 8 3 8

4 9 4 9

0 5
iDizi4b[1]

iDizi4b[1][0]

iDizi4b[1][1]

iDizi4b[1][2]

0 5 0 5

1 6 1 6

2 7 2 7

3 8 3 8

4 9 4 9

0 5 0 5

1 6 1 6

2 7 2 7

3 8 3 8

4 9 4 9

0 5 0 5

1 6 1 6

2 7 2 7

3 8 3 8

4 9 4 9

iDizi4b[1][0][3] iDizi4b[1][0][2] iDizi4b[1][0][1] iDizi4b[1][0][0]

iDizi4b[1][1][3] iDizi4b[1][1][2] iDizi4b[1][1][1] iDizi4b[1][1][0]

iDizi4b[1][2][3] iDizi4b[1][2][3][4] iDizi4b[1][2][2] iDizi4b[1][2][1] iDizi4b[1][2][0]

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-22

6.2 ok-Boyutlu Dizilerin Fonksiyonlara Aktarlmas


C dilinde argmanlar fonksiyonlara deerleri ile aktarlr (call-by-value). arlan fonksiyon argman listesinde yer alan bir basit deikenin yada izleyen blmlerde anlatlacak olan bir yap deikeninin lokal kopyasn ald iin argmanlarn aran bloktaki deerlerini deitiremez. Bu durum, argmanlar dizi olduunda geerli deildir. nk nceki blmlerde de anlatld gibi, bir tek-boyutlu dizi ismi fonksiyon arsnda argman olarak yer aldnda dizinin deerleri yerine balang elemannn bellek adresi aktarlr (call-by-reference) ve fonksiyon aran bloktaki dizi elemanlarn deerlerini deitirebilir. Fonksiyon tanmnda karlk gelen parametre ise, aktarlan adres deerinin atanabilecei bir adres deikenidir. Parametre bildiriminin indeks operatr kullanlarak dizi bildirimi eklinde (array notation yada subscript notation) yapldnda da yine parametre adres deikenidir. rnek olarak tamsay elemanlardan oluan tek-boyutlu iDizi1b dizisini argman olarak kabul eden bir fonksiyon, aadaki ekillerde tanmlanabilir : Dizi tanm:
int iDizi1b[ ] = { 0, 1, 2 };

Fonksiyon ars:
fonk( iDizi1b );

Fonksiyon tanm:
void fonk( int Adr1b [ 3 ] ) { ... }

yada
void fonk( int Adr1b [ ] ) { ... }

yada
void fonk( int *Adr1b ) { ... }

Yukardaki parametre tanm da birbirinin ayndr ve bildirilen Adr1b, bir adres deikenidir. Dizinin balang elemannn ar srasnda aktarlan adresi, tek bir int deikene iaret eden Adr1b adres deikenine atanr ve bu adres deikeni aracl ile aran bloktaki dizi elemanlarna eriilir. ok-boyutlu diziler bellekte alt-dizilerden oluan satrlar olarak (row-major order) saklanr. Bir ok-boyutlu dizi ismi, dizinin ilk satrna iaret eder ve ilk satrn balang
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-23

adresini veren sabittir. Dolaysyla izleyen paragraflarda da anlatlaca gibi, bir okboyutlu dizi ismi arda argman listesinde yer aldnda, fonksiyona ar srasnda dizinin ilk satrna iaret eden adres deeri aktarlr. Bir tek-boyutlu dizinin satrlar 0boyutlu alt-diziler olan tamsay deikenler oluturur. Dolaysyla ayn durum tek-boyutlu diziler iin de geerlidir ve Adr1b adres deikeni aran bloktaki tekboyutlu iDizi1b dizisinin satrlarn oluturan 0-boyutlu tamsay dizi elemanlarna yada bir baka deyile dizinin satrlarna iaret eder. arlan fonksiyon dizi boyutlarn bilmedii iin, dizinin eleman says aada olduu gibi fonksiyona aktarlmaldr: Fonksiyon ars:
fonk( iDizi1b, sizeof iDizi1b / sizeof iDizi1b[0] );

Fonksiyon tanm:
void fonk( int Adr1b [ ], size_t ELEMAN_SAYI ) { ... }

ok-boyutlu bir dizi bellekte birbirini izleyen satrlar olarak bulunduu iin, dizi elemanlarna sral olarak eriilirken en sada bulunan indeks en hzl deien indeks olacaktr. Dizi bildiriminde dizinin satr saysn belirten ilk indeks, derleme srasnda dizi iin gerekli olan bellek alan byklnn saptanmasna yardmc olur. ndeks hesaplarnda etkili olmaz. Dolaysyla bir ok-boyutlu diziyi bir fonksiyona argman olarak aktarmak iin, fonksiyon tanmndaki karlk gelen parametre bildirimi dizinin satr uzunluunu (stun saysn) iermelidir. Satr says gereksizdir nk ar srasnda aktarlan, dizinin satrlarn oluturan dizilere iaret eden adres deeridir. rnek 6.2-1'de iki, ve drt-boyutlu diziler, dizi deerlerini listeleyen fonksiyonlara argman olarak aktarlr. Ayrca programda bir 2-b dizinin 1. ve 2. satrlarn deitiren fonksiyon tanmlanmtr.
rnek 6.2-1 fonkdizi.c program. #include <stdio.h> #include <string.h> /* memcpy icin */ void void void void Liste2b( Liste3b( Liste4b( Degis2b( int int int int (*)[ 5 ] (*)[ 4 ][ 5 ] (*)[ 3 ][ 4 ][ 5 ] (*)[ 5 ] ); ); ); );

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-24

... rnek 6.2-1 devam


int iDizi2b [ ] [ 5 ] =
{ { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } };

int iDizi3b [ ] [ 4 ] [ 5 ] =
{ { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } } };

int iDizi4b [ ] [ 3 ] [ 4 ] [ 5 ] =
{ { { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } } }, { { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } } }, };

int main(void) { printf( "sizeof iDizi2b : %u\n", sizeof iDizi2b ); Liste2b( iDizi2b ); printf( "sizeof iDizi3b : %u\n", sizeof iDizi3b ); Liste3b( iDizi3b ); printf( "sizeof iDizi4b : %u\n", sizeof iDizi4b ); Liste4b( iDizi4b ); Degis2b( iDizi2b ); puts( "2b dizinin 1. satiri ile 2. satirinin degistirilmesi: " ); Liste2b( iDizi2b ); return 0; } void Liste2b( int (*Adr2b)[ 5 ] ) { int i, j; puts( "- 2b dizi listeleme-" ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-25

... rnek 6.2-1 devam


printf("sizeof Adr2b : %u, sizeof *Adr2b : %u, ", sizeof Adr2b, sizeof *Adr2b ); printf("sizeof *Adr2b / sizeof (int) : %u\n", sizeof *Adr2b / sizeof (int) ); for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 5; j++ ) printf( "%d ", Adr2b[ i ][ j ] ); putchar( '\n' ); } } void Liste3b( int (*Adr3b)[ 4 ][ 5 ] ) { int i, j, k; puts( "- 3b dizi listeleme-" ); printf("sizeof Adr3b : %u, sizeof *Adr3b : %u, ", printf("sizeof *Adr3b / sizeof (int) : %u\n", for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 4; j++ ) { for ( k = 0; k < 5; k++ ) printf( "%d ", Adr3b[ i ][ j ][ k ] ); putchar( '\n' ); } putchar( '\n' ); } } void Liste4b( int (*Adr4b)[ 3 ][ 4 ][ 5 ] ) { int i, j, k, l; puts( "- 4b dizi listeleme-" ); printf("sizeof Adr4b : %u, sizeof *Adr4b : %u, ", printf("sizeof *Adr4b / sizeof (int) : %u\n", sizeof Adr4b, sizeof *Adr4b ); sizeof *Adr4b / sizeof (int) ); sizeof Adr3b, sizeof *Adr3b ); sizeof *Adr3b / sizeof (int) );

for ( i = 0; i < 2; i++ ) { for ( j = 0; j < 3; j++ ) { for ( k = 0; k < 4; k++ ) { for ( l = 0; l < 5; l++ ) printf( "%d ", Adr4b[ i ][ j ][ k ][ l ] ); putchar( '\n' ); } putchar( '\n' ); } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-26

... rnek 6.2-1 devam


putchar( '\n' ); } } void Degis2b( int (*a2b)[ 5 ] ) { int t[ 5 ]; memcpy( t, a2b+1, sizeof t ); memcpy( a2b+1, a2b, sizeof a2b[1] ); memcpy( a2b, t, sizeof a2b[0] ); } kt sizeof iDizi2b : 40 - 2b dizi sizeof Adr2b : 2, sizeof *Adr2b : 10, sizeof *Adr2b / sizeof (int) : 5 01234 56789 23456 78901 sizeof iDizi3b : 120 - 3b dizi sizeof Adr3b : 2, sizeof *Adr3b : 40, sizeof *Adr3b / sizeof (int) : 20 01234 56789 23456 78901 01234 56789 23456 78901 01234 56789 23456 78901 sizeof iDizi4b : 240 - 4b dizi sizeof Adr4b : 2, sizeof *Adr4b : 120, sizeof *Adr4b / sizeof (int) : 60 01234 56789 23456 78901 01234 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-27

... rnek 6.2-1 kt devam


56789 23456 78901 01234 56789 23456 78901

01234 56789 23456 78901 01234 56789 23456 78901 01234 56789 23456 78901 2b dizinin 1. satiri ile 2. satirinin degistirilmesi: - 2b dizi sizeof Adr2b : 2, sizeof *Adr2b : 10, sizeof *Adr2b / sizeof (int) : 5 56789 01234 23456 78901

Programda tanmlanan 2-b dizi iDizi2b'nin bir satr, 5 tamsaydan oluan dizidir ( int[5] tipinde 4 dizi bulunduu iin, satr says : 4 ). Bu nedenle aktarlan adres deeri 5 tamsaydan oluan diziye iaret eder ve dolaysyla int(*)[5] tipindedir (ekil 6.2-1). Parametre bildirimleri aadaki ekilde de yaplabilir: Dizi eklinde bildirim:
void Liste2b( int Adr2b [4] [5] ) {...}

lk boyut deeri verilmeden dizi eklinde bildirim:


void Liste2b( int Adr2b [ ] [ 5 ] ) {...}

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-28

Dizinin satrlarna iaret eden adres deikeni eklinde bildirim:


void Liste2b( int (*Adr2b) [ 5 ] ) {...}

iDizi3b'nin bir satr ise 5 tamsaydan oluan 4 dizidir ( int[4][5] tipinde 3 dizi bulunduu iin satr says : 3 ). Aktarlan adres deeri 5 tamsaydan oluan 4 dizinin oluturduu diziye iaret eder ve int(*)[4][5] tipinde olacaktr. Aadaki parametre bildirimlerinin nde de dizinin satrlarna iaret eden adres deikeni bildirilir: Dizi eklinde bildirim:
void Liste3b( int Adr3b [ 3 ] [ 4 ] [ 5 ] ) {...}

lk boyut deeri verilmeden dizi eklinde bildirim:


void Liste3b( int Adr3b [ ] [ 4 ] [ 5 ] ) {...}

Dizinin satrlarna iaret eden adres deikeni eklinde bildirim:


void Liste3b( int (*Adr3b) [ 4 ] [ 5 ] ) {...}

iDizi4b'nin bir satr, 5 tamsaydan oluan 4 dizinin oluturduu 3 diziden oluan dizidir ( int[3][4][5] tipinde 2 dizi bulunduu iin satr says : 2 ). ar srasnda aktarlan adres deeri bu dizilere iaret eder ve int(*)[3][4][5] tipindedir. Aadaki her parametre bildirimi de ayndr ve int(*)[3][4][5] tipinde Adr4b adres deikeni bildirilir: Dizi eklinde bildirim:
void Liste4b( int Adr4b [ 2 ] [ 3 ] [ 4 ] [ 5 ] ) {...}

lk boyut deeri verilmeden dizi eklinde bildirim:


void Liste4b( int Adr4b [ ] [ 3 ] [ 4 ] [ 5 ] ) {...} Dizinin satrlarna iaret eden adres deikeni eklinde bildirim: void Liste4b( int (*Adr4b) [ 3 ] [ 4 ] [ 5 ] ) {...}

Sonu olarak parametre bildirimlerinde dizinin alt-dizilerini oluturan satrlarn saysn veren ilk boyut deeri gereksizdir. zleyen boyut deerleri bir satrn uzunluunu verdii iin parametre bildiriminde verilmelidir. Bildirim ekilde de yaplabilir. Fakat
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-29

programlarda parametre bildiriminin dizi eklinde ilk boyut deeri verilmeden yaplmas, aktarlan adres deerinin bir diziye ait olduunu belirttii iin tercih edilebilir. Programn ktsnda da grld gibi Adr2b, Adr3b ve Adr4b, bu programn oluturulduu donanmda 2-byte byklnde adres deikenleridir. Fakat bu adres deikenlerinin indirek deerlerine uygulanan sizeof operatrnn ktlarnda da grld gibi tipleri farkldr (farkl uzunlukta dizi satrlarna iaret ederler). Dolaysyla bu adres deikenlerinden herhangi birine herhangi bir tamsay deer eklendiinde, eklenen deer adres aritmetiine gre bir satrn byte uzunluu ile leklenir ve adres deikeni bir sonraki satra iaret eder. rnek olarak iDizi2b'nin satrlarna iaret eden Adr2b adres deikenine eklenen tamsay 1 deeri, adres aritmetiine gre otomatik olarak aadaki ekilde leklenir:
1 * satr uzunluu yada 1 * sizeof ( *Adr2b ) yada 1 * 5 * sizeof (int)

Adr3b iin:
1 * satr uzunluu yada 1 * sizeof ( *Adr3b ) yada 1 * 4 * 5 * sizeof (int)

Adr4b iin:
1 * satr uzunluu yada 1 * sizeof ( *Adr4b ) yada 1 * 3 * 4 * 5 * sizeof (int)

rnek programda yer alan fonksiyon tanmlarnda, dizi elemanlarnn deerlerini adres deikenleri aracl ile listeleyen for dnglerinde, dng sayac snrlar sabit deerler olarak verildi. Bu deerler fonksiyonlara, size_t tipinde bildirilen parametrelerle aktarlabilir. Bylece ilgili fonksiyonun her arsnda, ayn boyut saysna sahip fakat farkl sayda eleman olan diziler listelenebilir. Dizi satrlarna iaret eden adres deikeni parametrelerin bildiriminde parantezler gereklidir nk indeks operatr ( [ ] ), indirek deer operatrnden ( * ) daha yksek nceliklidir. Parantezler kullanlmad taktirde bildirimler adres dizisi bildirimleri olacaktr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-30

ekil 6.2-1 iDizi2b, iDizi3b ve iDizi4b dizilerinin satrlarn oluturan alt-diziler ve bu alt-dizilere iaret eden adres deikenleri.
int iDizi2b [ ] [ 5 ] =

{
Adr2b Adr2b + 1 Adr2b + 2 Adr2b + 3

Dizinin satr uzunluu = 5 (stun says)


{ 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 }

};
int iDizi3b [ ] [ 4 ][ 5 ] = Dizinin satr uzunluu = 4 x 5 = 20 (stun says)
{ { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }

{
Adr3b Adr3b + 1 Adr3b + 2

};
int iDizi4b [ ] [ 3 ][ 4 ][ 5 ] =

{
Adr4b
{

Dizinin satr uzunluu = 3 x 4 x 5 = 60 (stun says)


{ { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } } },

Adr4b + 1

{ { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } }, { { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 2, 3, 4, 5, 6 }, { 7, 8, 9, 0, 1 } } }

};

Dizilerin indekslenmesi ileminin (array subscripting) tanmna gre dizi_ismi[ indeks ] ifadesi, *(dizi_ismi + indeks ) ifadesine etir ve bu deime zellii olan bir ilemdir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

6-31

rnek programda yer alan ok-boyutlu dizi isimleri ile aadaki birbirine e ifadeler oluturulabilir:
ndeks ifadeleri: iDizi2b [ i ] [ j ] iDizi3b [ i ] [ j ] [ k ] iDizi4b [ i ] [ j ] [ k ] [ l ]

Adres ve offset ifadeleri: *( iDizi2b [ i ] + j ) *( iDizi3b [ i ] [ j ] + k ) *( iDizi4b [ i ] [ j ] [ k ] + l )

*( *( iDizi2b + i ) + j ) *( *( *( iDizi3b + i ) + j ) + k ) *( *( *( *( iDizi4b + i ) + j ) + k ) + l )

kinci grupta yer alan ifadeler ilenirken iDizi2b [ i ], iDizi3b [ i ] [ j ] ve iDizi4b [ i ] [ j ] [ k ] ifadeleri dizi tipindedir ve tamsaylardan oluan diziye iaret eden sabit adres deerine evrilir. Bu ifadelere eklenen j, k ve l deerleri ise adres aritmetiine gre bir tamsaynn byte says ( sizeof (int) ) ile arplr. Bu ifadeler, dizi listeleme fonksiyonlar iinde tanmlanan adres deikenleri kullanlarakta oluturulabilir. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-1

BLM 7: Dinamik Bellek Ynetimi


C dilinde, bir dizinin bykl derleme srasnda (compile-time) sabittir. Dolaysyla dizi bildirilirken, programda gerekli olabilecek maksimum sayda eleman saklayacak kadar byk olduundan emin olunmaldr. Bu nedenle byk miktarda bellek alan programn alma sresinin ounda kullanlmadan bekler. Sonu olarak, gerek duyulduunda istenen miktarda bellek alann programn almas srasnda ayrmak (allocation) ve gerek kalmad zaman bu alan baka kullanmlar iin serbest brakmak (deallocation) olduka verimli olacaktr. Programn almas srasnda (run-time) bellek alan ayrma ilemi dinamik bellek yerletirme (dynamic memory allocation) olarak; bu amala yaplan ilemler ise dinamik bellek ynetimi (dynamic memory management) olarak adlandrlr. Programlarda static ve global veriler bellein static veri alanna; otomatik veriler ise stack alanna yerletirilir. Dinamik veriler ise bellein heap olarak adlandrlan ksmna yerletirilir. Dinamik bellek alanna eriim, bu amala kullanlan fonksiyonlar tarafndan dndrlen ve ayrlan bellek blounun balangcna iaret eden adres deerleri araclyla gerekleir. Bu blmde, dinamik bellek ynetimi iin kullanlan standart ktphane fonksiyonlar (malloc, calloc, realloc, ve free) ve diziler iin dinamik bellek alan ayrlmas anlatlacaktr. Ayrca bu amala eitli fonksiyonlar tanmlanacaktr. n
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-3

7.1 Standart C'de Dinamik Bellek Kullanm


Standart C ktphanesinde dinamik bellek kullanm iin malloc, calloc, realloc ve free fonksiyonlar bulunur. Bu fonksiyonlarn prototipleri ise stdlib.h balk dosyasnda bulunur. malloc fonksiyonu, n byte byklnde bellek alan ayrr ve hatasz alr ise bu alann balang adresini dndrr. Dndrlen adres deeri herhangi bir adres tipine (indirek deerinin bykl n'den fazla olmayan) evrilebilir. Hata durumunda bo adres deeri (NULL; null pointer) dndrr.
void *malloc( size_t n ); /* stdlib.h */

malloc tarafndan ayrlan bellek alannda, herhangi bir deer atanmadan nce bulunan deerler belirsizdir. calloc fonksiyonu ise, her biri n byklnde el_sayi kadar elemandan oluan dizi iin bellek alan ayrr ( el_sayi * n byte); dizinin her byte'na 0 (sfr) deerini atar ve dizinin balang elemanna iaret eden adres deerini dndrr. Hata durumunda bo adres deeri dndrr. Dndrlen adres deeri, byte olarak bykl n'den fazla olmayan herhangi bir tipe iaret eden adres tipine evrilebilir.
void *calloc( size_t el_sayi, size_t n ); /* stdlib.h */

realloc fonksiyonu nceki malloc, calloc yada realloc ars ile ayrlm olan heap alann geniletmek yada daraltmak iin kullanlr. Dolaysyla ilk argman olarak nceki malloc, calloc yada realloc arsnn dndrd adres deerini alr (adr). realloc fonksiyonu istenen miktarda bellek alan (n byklnde) ayrabiliyor ise, orijinal verileri (adr tarafndan iaret edilen bellek alannda bulunan) yeni ayrlan alana kopyalar ve yeni adresi dndrr. nceki bellek alan serbest braklr. Yeni ayrlan bellek alan ncekinden daha byk ise, nceki veriler bu alann balangcndan itibaren kopyalanr. Fakat artan bellek alanndaki deerler belirsizdir. Eer daha kk bir bellek alan ayrlyor ise, nceki verilerin sadece bu alana sabilecek miktar kopyalanr. realloc ars, adr'nin deeri bo adres deeri olduunda malloc( n ) ars ile ayndr (orijinal veriler ayrlan bellek alanna kopyalanmaz).
void *realloc( void *adr, size_t n ); /* stdlib.h */

Dndrd adres deerine yine dier fonksiyonlarda olduu gibi tip evirme uygulanabilir. Hata durumunda bo adres deeri dndrr ve nceki ayrlan bellek alan deimeden kalr.
void free( void *adr ); /* stdlib.h */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-4

Eer adr bo adres deikeni deil ise, iaret ettii bellek alan serbest braklr. Aksi taktirde fonksiyon hi birey yapmaz. Sadece malloc, calloc yada realloc ars ile ayrlm olan bellek alan serbest braklr. Programdan klrken free ars gerekmeyebilir. Fakat programn anlalabilirlii asndan mutlaka ayrlm bulunan bellek alanlar free fonksiyonu arlarak serbest braklmaldr. rnek 6.1-1'de 2-b dizi iDizi2b'ye iaret eden adres deikeni Adr2b bildirildi. Adr2b adres deikeni, 2-b dizinin satrlarn oluturan 1-b dizilere iaret eder ve int(*)[ 5 ] tipindedir. rnek 6.1-2'de ise 3-b dizi iDizi3b'ye iaret eden Adr3b adres deikeni bildirilir. Bu adres deikeni int(*)[ 4 ][ 5 ] tipindedir ve iDizi3b'nin satrlarn oluturan 2-b dizilere iaret eder. rnek 7.1-1'de 2-b ve 3-b diziler iin dinamik olarak bellek alan ayrlr ve bu alanlarn balangc adresleri 2-b ve 3-b dizilere iaret eden adres deikenlerine atanr. Ayrlan bellek alanlarna deer atamak iin rastgele say reten standart ktphane fonksiyonu rand kullanlmtr:
int rand( void ); /* stdlib.h */

rnek 7.1-1 din2b3b.c program. #include <stdio.h> #include <stdlib.h> #define #define #define #define #define #define #define NL '\n' RandomSayi(min, max) \ ((rand() % (int)(((max)+1) - (min))) + (min)) NoSatir2b NoSutun2b NoTablo3b NoSatir3b NoSutun3b 4 5 3 4 5

int main(void) { int i, j, k, dNoSatir2b = NoSatir2b, dNoTablo3b = NoTablo3b; int (*Adr2b)[ NoSutun2b ], (*Adr3b) [ NoSatir3b ] [ NoSutun3b ]; /* 2-b ve 3-b diziler icin dinamik bellek alani ayrilmasi. */ Adr2b = ( int(*)[ NoSutun2b ] )malloc( dNoSatir2b * NoSutun2b * sizeof (int) ); if ( Adr2b == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 1 ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-5

... rnek 7.1-1 devam


} Adr3b = ( int(*)[ NoSatir3b ][ NoSutun3b ] )malloc( dNoTablo3b * NoSatir3b * NoSutun3b * sizeof (int) );

if ( Adr3b == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 2 ); } for ( i = 0; i < dNoSatir2b; i++ ) for ( j = 0; j < NoSutun2b; j++ ) Adr2b [ i ] [ j ] = RandomSayi( 0, 9 ); for ( i = 0; i < dNoTablo3b; i++ ) for ( j = 0; j < NoSatir3b; j++ ) for ( k = 0; k < NoSutun3b; k++ ) Adr3b [ i ] [ j ] [ k ] = RandomSayi( 0, 9 ); /* Elemanlarin degerlerinin listelenmesi. */ puts( "\n2-b dizi : " ); for ( i = 0; i < dNoSatir2b; i++ ) { for ( j = 0; j < NoSutun2b; j++ ) printf( "%d ", *(*(Adr2b + i) + j) ); putchar( NL ); } puts( "\n3-b dizi : " ); for ( i = 0; i < dNoTablo3b; i++ ) { for ( j = 0; j < NoSatir3b; j++ ) { for ( k = 0; k < NoSutun3b; k++ ) printf( "%d ", *(*(*(Adr3b + i) + j) + k) ); putchar( NL ); } putchar( NL ); } free( Adr2b ); free( Adr3b ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-6

... rnek 7.1-1 devam


kt 2-b dizi : 17409 48824 55171 15276 3-b dizi : 14232 21685 76189 27954 3 4 7 9 6 6 6 0 1 1 4 3 5 0 5 6 2 1 2 1 0 2 0 1 3 3 7 9 2 4 9 3 3 8 7 8 8 8 0 8

Programda da grld gibi malloc fonksiyonu dizilerin tamam iin bellek alan ayrr ve bu alanlarn balangcna iaret eden adres deerini dndrr. Dndrlen adres deeri, dizilerin satrlarna iaret eden adres deeri tipine evrilerek yine bu ekilde bildirilmi olan adres deikenlerine atanr. Eriim, bu adres deikenleri aracl ile gerekletirilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-7

Program derlenirken, adres deikenleri bildirimlerinde kullanlan NoSutun2b, NoSatir3b ve NoSutun3b deerlerinin sabit olmas gerekmektedir.
ekil 7.1-1 ki-boyutlu i2b dizisi ve -boyutlu i3b dizisi.
i2b i2b[0]'n adresi i2b[0] i2b[1] i3b i3b[0]'n adresi i2b[0][0]'n adresi i2b[1][0]'n adresi i2b[0][0] int deger int deger i2b[1][0] i2b[0][1] int deger int deger i2b[1][1] i2b[0][2] int deger int deger i2b[1][2]

i3b[0] i3b[1]

i3b[0][0]'n adresi i3b[1][0]'n adresi i3b[0][0][0] i3b[0][0][1] int deger int deger int deger i3b[0][2][1] i3b[0][0][2] int deger int deger int deger i3b[0][2][2] i3b[0][0][3] int deger int deger int deger i3b[0][2][3] i3b[0][0][0]'n adresi i3b[0][1][0]'n adresi i3b[0][2][0]'n adresi

i3b[0][0] i3b[0][1] i3b[0][2]

int deger int deger int deger i3b[0][2][0]

i3b[1][0][0] i3b[1][0] i3b[1][1] i3b[1][2] i3b[1][0][0]'n adresi i3b[1][1][0]'n adresi i3b[1][2][0]'n adresi int deger int deger int deger i3b[1][2][0]

i3b[1][0][1] int deger int deger int deger i3b[1][2][1]

i3b[1][0][2] int deger int deger int deger i3b[1][2][2]

i3b[1][0][3] int deger int deger int deger i3b[1][2][3]

Ancak 2-b dizinin satr saysn belirten NoSatir2b ve 3-b dizinin satr saysn belirten NoTablo3b deerleri, programn almas srasnda belirlenebilir (programda bunu ifade etmek iin ayn isimde fakat d harfi ile balayan dNoSatir2b ve dNoTablo3b deikenleri tanmlanr ve malloc arlarnda kullanlr). Dolaysyla bu teknik,

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-8

dizilerin tm boyut deerlerinin program derlenirken belli olmad durumlarda dinamik bellek alan ayrmak iin kullanlamaz.

2-b ve 3-b diziler iin dinamik bellek alani ayrlmas


ekil 7.1-1'de ematik olarak gsterildii gibi 2-b ve 3-b dizi bildirimleri ile dizi elemanlar ve bir grup adres sabiti (pointer constant) oluturulur. ki-boyutlu i2b bildirimi:
int i2b [ 2 ] [ 3 ];

-boyutlu i3b bildirimi:


int i3b [ 2 ] [ 3 ] [ 4 ];

ekilde grld gibi 2-b i2b dizisi bildirimi ile i2b, i2b[0] ve i2b[1] adres sabitleri oluur. Ayrca 6 tamsay deer iin bellek alan ayrlr. i3b dizisi bildirimi ile i3b, i3b[0], i3b[1], i3b[0][0], i3b[0][1], i3b[0][2], i3b[1][0], i3b[1][1], ve i3b[1][2] adres sabitleri oluur. Bunlardan hi biri lvalue deildir. fadelerde sabit adres deerlerine dnrler. Ayrca i3b bildirimi ile 24 tamsay deer iin bellek alan ayrlr. Dizi ismi i2b'ye iki kez indirek deer operatr uygulandnda dizide bulunan ilk tamsay deer elde edilir ( **i2b ). i2b, alt-dizilerin balang eleman olan tamsay deerlerin adreslerini veren adres sabitleri dizisine iaret eder. i2b[...] ifadeleri dizinin satrlarn oluturan 1-b dizilere iaret eder ve *i2b[...] ifadeleri balang elemanlarnn deerlerini verir. 3-b dizide bulunan ilk elemann deerini almak iin ise dizi ismi i3b'ye indirek deer operatr kez uygulanmaldr ( ***i3b ). i3b, ift adres sabitleri dizisine ( i3b[...] ) iaret eder. i3b[...] ifadeleri ise, alt-dizilerin balang adreslerini veren i3b[...][...] adres sabiti dizilerine iaret eder. Buna gre, **i3b[...] ifadeleri ve *i3b[...][...] ifadeleri altdizilerin balang elemanlarnn deerlerini verir. Bu ifadelerle oluturulan aadaki rnek programda tamsay deerler ekrana listelenir:
/* * i2b3b.c programi. */ #include <stdio.h> int main(void) { int i, j; int i2b [ 2 ] [ 3 ]

={ 9, 1, 2, 7, 4, 5

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-9

... rnek i2b3b.c devam


}; int i3b [ 2 ] [ 3 ] [ 4 ] = { 8, 1, 0, 0, 7, 2, 1, 0, 6, 3, 2, 1, 5, 4, 3, 2, 4, 5, 4, 3, 3, 6, 5, 4 }; printf( "**i2b : %d\n", **i2b ); for ( i = 0; i < 2; i++ ) printf( "*i2b[%d] : %d\n", i, *i2b[i] ); putchar( '\n' ); printf( "***i3b : %d\n", ***i3b ); for ( i = 0; i < 2; i++ ) printf( "**i3b[%d] : %d\n", i, **i3b[i] ); putchar( '\n' ); for ( i = 0; i < 2; i++ ) for ( j = 0; j < 3; j++ ) printf( "*i3b[%d][%d] : %d\n", i, j, *i3b[i][j] ); return 0; } Cikti : **i2b :9 *i2b[0] : 9 *i2b[1] : 7 ***i3b : 8 **i3b[0] : 8 **i3b[1] : 5 *i3b[0][0] *i3b[0][1] *i3b[0][2] *i3b[1][0] *i3b[1][1] *i3b[1][2] :8 :7 :6 :5 :4 :3

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-10

2-b ve 3-b diziler iin programn almas srasnda dinamik bellek alan kullanmak iin ayn eriim sistemi adres deikenleri ile oluturulmaldr. rnek 7.1-2 ve rnek 7.1-3'de 2-b ve 3-b diziler iin bu ekilde dinamik bellek alan ayrlr.
rnek 7.1-2 din2b.c program. #include <stdio.h> #include <stdlib.h> #define #define NL '\n' RandomSayi(min, max) ((rand() % (int)(((max)+1) - (min))) + (min))

void List2b( int **Adr2b, int NoSatir2b, int NoSutun2b ); int main(void) { int i, j, dNoSatir2b = 2, dNoSutun2b = 3; int **Adr2b; if ( (Adr2b = (int **)malloc( dNoSatir2b * sizeof (int*) )) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit(1); } for ( i = 0; i < dNoSatir2b; i++ ) if ( (Adr2b[ i ] = (int *) malloc( dNoSutun2b * sizeof (int) )) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit(2); } for ( i = 0; i < dNoSatir2b; i++ ) for ( j = 0; j < dNoSutun2b; j++ ) Adr2b[ i ][ j ] = RandomSayi( 0, 9 ); for ( i = 0; i < dNoSatir2b; i++ ) { for ( j = 0; j < dNoSutun2b; j++ ) printf( "%d ", *(*(Adr2b + i ) + j ) ); putchar( NL ); } List2b( Adr2b, dNoSatir2b, dNoSutun2b ); free( Adr2b ); for ( i = 0; i < dNoSatir2b; i++ ) free( Adr2b[ i ] ); return 0; } void List2b( int **Adr2b, int NoSatir2b, int NoSutun2b ) { int i, j;

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-11

... rnek 7.1-2 devam


for ( i = 0; i < NoSatir2b; i++ ) { for ( j = 0; j < NoSutun2b; j++ ) printf( "%d ", Adr2b[ i ][ j ] ); putchar( NL ); } } kt 1 0 1 0 7 9 7 9 4 4 4 4

Programda grld gibi 2-b dizinin satr ve stun saylar (dNoSatir2b ve dNoSutun2b) tamsay deikenlerdir ve programn almas srasnda girilebilir. Dinamik 2-b dizi iin ilk olarak bir ift adres deikeni (double pointer) bildirilir:
int **Adr2b;

Bu adres deikenine, dNoSatir2b says kadar int* tipinde adres deikeni iin malloc arlarak ayrlan bellek alannn balang adresi int** tipine evrilerek atanr:
Adr2b = (int **)malloc( dNoSatir2b * sizeof (int*) )

Bylece 2-b dizinin satrlarna iaret eden adres deikenleri iin bellek alan ayrlm olur. Bu alanda, 2-b dizinin satrlarnn balang adreslerinden oluan adres dizisi saklanacaktr. ift adres deikeni bu alana iaret ettii iin indeks operatr ile oluturulan Adr2b[ i ] ifadesi de bu alana eriir. for dngs iinde bir baka malloc ars yer alr:
Adr2b[ i ] = (int *)malloc( dNoSutun2b * sizeof (int) )

Bu ar ile tamsay deerleri saklamak iin ayrlan dNoSatir2b says kadar dNoSutun2b*sizeof (int) uzunluunda her alann balang adresi int* tipine evrilerek Adr2b[ i ] ile eriilen ve nceki malloc arsnda ayrlm olan bellek alanna atanr. Bylece dizi elemanlar ve dizi elemanlarna eriim iin gerekli olan tm adres deikenleri iin bellek alanlar ayrlm olur. RandomSayi makrosu ile retilen 0 - 9 aras tamsay deerler, Adr2b[ i ][ j ] ile eriilen bellek alanlarna atanr. Daha sonra dizi elemanlarnn deerleri ekrana listelenir. Listeleme, List2b fonksiyonunda olduu gibi uygun ekilde tanmlanm bir fonksiyona ift adres deikeni deeri aktarlarak gerekletirilebilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-12

rnek 7.1-3 din3b.c program. #include <stdio.h> #include <stdlib.h> #define #define NL '\n' RandomSayi(min, max) ((rand() % (int)(((max)+1) - (min))) + (min))

void List3b( int ***Adr3b, int NoTablo3b, int NoSatir3b, int NoSutun3b ); int main(void) { int i, j, k, dNoTablo3b = 2, dNoSatir3b = 3, dNoSutun3b = 4; int ***Adr3b; if ( (Adr3b = (int ***)malloc( dNoTablo3b * sizeof (int**))) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 1 ); } for ( i = 0; i < dNoTablo3b; i++ ) { if ( (Adr3b[ i ] = (int **)malloc( dNoSatir3b * sizeof (int*))) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 2 ); } for ( j = 0; j < dNoSatir3b; j++) { if ( (Adr3b[ i ][ j ] = (int *)malloc( dNoSutun3b * sizeof (int))) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 3 ); } } } for ( i = 0; i < dNoTablo3b; i++ ) for ( j = 0; j < dNoSatir3b; j++ ) for ( k = 0; k < dNoSutun3b; k++ ) Adr3b[i ][ j ][ k ] = RandomSayi( 0, 9 ); for ( i = 0; i < dNoTablo3b; i++ ) { for ( j = 0; j < dNoSatir3b; j++ ) { for ( k = 0; k < dNoSutun3b; k++ ) printf( "%d ", Adr3b[i ][ j ][ k ] ); putchar( NL ); } putchar( NL ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-13

... rnek 7.1-3 devam


} List3b( Adr3b, dNoTablo3b, dNoSatir3b, dNoSutun3b ); free( Adr3b ); for ( i = 0; i < dNoTablo3b; i++ ) { free ( Adr3b[ i ] ); for ( j = 0; j < dNoSatir3b; j++) free( Adr3b[ i ][ j ] ); } return 0; } void List3b( int ***Adr3b, int NoTablo3b, int NoSatir3b, int NoSutun3b ) { int i, j, k; for ( i = 0; i < NoTablo3b; i++ ) { for ( j = 0; j < NoSatir3b; j++ ) { for ( k = 0; k < NoSutun3b; k++ ) printf( "%d ", Adr3b[i ][ j ][ k ] ); putchar( NL ); } putchar( NL ); } } kt 1740 9488 2455 1711 5276 1423 1740 9488 2455 1711 5276 1423

3-b dizi iin ise, ilk olarak ift adres deikenleri dizisine iaret eden bir l adres deikeni (triple pointer) bildirilir:
int ***Adr3b;

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-14

Bu adres deikenine ift adres deikenleri iin ayrlan bellek alannn balang adresi atanr:
Adr3b = (int ***)malloc( dNoTablo3b * sizeof (int**))

Tekrar malloc fonksiyonu arlarak dNoTablo3b says kadar adres dizisi iin (herbiri dNoSatir3b says kadar adres deikeninden oluan) bellek alan ayrlr:
Adr3b[ i ] = (int **)malloc( dNoSatir3b * sizeof (int*))

Bu alanlarn balang adresleri nceki malloc ars ile ift adres deikenleri dizisi iin ayrlm bulunan bellek alanna, Adr3b[ i ] indeks ifadesi ile eriilerek atanr. Yine ayn dng iinde ift adres dizisinin elemanlarnn iaret ettii adres dizilerinin elemanlarna, tamsay deerler iin ayrlan bellek alanlarnn balang adresleri atanr:
Adr3b[ i ][ j ] = (int *)malloc( dNoSutun3b * sizeof (int))

Bylece 3-b dinamik dizinin elemanlar ve elemanlarna eriim iin gerekli olan tm adres deikenleri iin bellek alan ayrlm olur. Yine nceki rnekte olduu gibi, ayrlan bellek alanlarna atanan rastgele tamsay deerler ekrana listelenir. rnek 7.1-4'de 2-b tamsay dizilere dinamik bellek alan ayrmak iin Din2b fonksiyonu tanmlanr:
rnek 7.1-4 dinfonk.c program. #include <stdio.h> #include <stdlib.h> #define #define #define #define int void void void NL '\n' RandomSayi(min, max) ((rand() % (int)(((max)+1) - (min))) + (min)) MAXSATIR 10 MAXSUTUN 10 int NoSatir2b, int NoSutun2b int **Adr2b, int NoSatir2b int **Adr2b, int NoSatir2b, int NoSutun2b int **Adr2b, int NoSatir2b, int NoSutun2b ); ); ); );

**Din2b( Free( DegerAta2b( List2b(

int main(void) { int dNoSatir2b = 0, dNoSutun2b = 0; int **Adr2b; printf( "Satir Sayisi ? " ); scanf( "%d", &dNoSatir2b ); if ( dNoSatir2b > MAXSATIR ) printf( "Sutun Sayisi ? " ); scanf( "%d", &dNoSutun2b ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

dNoSatir2b

= MAXSATIR;

7-15

... rnek 7.1-4 devam


if ( dNoSutun2b > MAXSUTUN ) dNoSutun2b = MAXSUTUN; if ( (Adr2b = Din2b( dNoSatir2b, dNoSutun2b )) == NULL ) { fprintf( stderr, "Din2b: Bellek alani ayrilamadi !!!\n" ); exit(1); } DegerAta2b( Adr2b, dNoSatir2b, dNoSutun2b ); List2b( Adr2b, dNoSatir2b, dNoSutun2b ); Free ( Adr2b, dNoSatir2b ); return 0; } int **Din2b( int NoSatir2b, int NoSutun2b ) { int i; int **Adr2b; if ( (Adr2b = (int **)malloc( NoSatir2b * sizeof (int *) )) == NULL ) return (int**)NULL; for ( i = 0; i < NoSatir2b; i++ ) if ( (Adr2b[ i ] = (int *)malloc( NoSutun2b * sizeof (int) )) == NULL ) return (int**)NULL; return Adr2b; } void Free( int **Adr2b, int NoSatir2b ) { int i; free( Adr2b ); for ( i = 0; i < NoSatir2b; i++ ) free( Adr2b[ i ] ); } void DegerAta2b( int **Adr2b, int NoSatir2b, int NoSutun2b ) { int i, j; for ( i = 0; i < NoSatir2b; i++ )

... rnek 7.1-4 devam


for ( j = 0; j < NoSutun2b; j++ ) Adr2b[ i ][ j ] = RandomSayi( 0, 9 ); } void List2b( int **Adr2b, int NoSatir2b, int NoSutun2b ) { int i, j; for ( i = 0; i < NoSatir2b; i++ ) { for ( j = 0; j < NoSutun2b; j++ ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-16

... rnek 7.1-4 devam


printf( "%d ", Adr2b[ i ][ j ] ); putchar( NL ); } } Bilgi Girii Satir Sayisi ? 5 Sutun Sayisi ? 20 kt 1 5 1 7 3 7 5 4 6 1 4 1 2 1 2 0 7 3 8 3 9 1 2 9 3 4 1 2 2 4 8 5 1 7 1 8 2 6 9 1 2 7 8 5 3 4 6 5 4 8

Programda malloc arlarnn dndrd deerler hata durumlarnn saptanmas iin test edilmitir. Dinamik bellek kullanrken en ok yaanan problem, ayrlan alanlarn dna talmasdr (memory leak). Ayrca programda farknda olmadan artk kullanlmad halde serbest braklmam olan bellek alanlar, programn ihtiya olan bir baka yerinde bellek yetmemesi sorununu dourabilir. malloc yada calloc ile ayrlan bellek alannn bykln deitirmek iin aadaki programda tanmlanan remalloc fonksiyonu blounda grld gibi ilk olarak yine malloc kullanlarak istenen byklkte bellek alan ayrlr. nceki malloc yada calloc ars ile ayrlm olan bellek alannda bulunan veriler bu yeni ayrlan alana kopyalanr (memcpy ars). Son olarak nceki bellek alan serbest braklr.
rnek 7.1-5 remalloc.c program. #include <stdio.h> #include <stdlib.h> #include <string.h> #define MaxInt #define BlokBoy #define ToplamByte(x) 19 5 ((x+BlokBoy)*sizeof(int))

void *remalloc( void *Adr, size_t YeniBlokByte, size_t EskiBlokByte ); int main(void) { int *Adr = NULL, *OncekiAdr = NULL; int i, Onceki = 0; for ( i = 0; i < MaxInt; i++ ) { C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-17

... rnek 7.1-5 devam


if ( i % BlokBoy == 0 ) { OncekiAdr = Adr; Adr = remalloc( Adr, ToplamByte(i), ToplamByte(Onceki) ); Onceki = i; if ( Adr == NULL ) { free( OncekiAdr ); fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 1 ); } printf( "%p : %u byte bellek alani ayrildi !!!\n", Adr, ToplamByte(i) ); } Adr[ i ] = i; } for ( i = 0; i < MaxInt; i++ ) printf( "%d, ", Adr[ i ] ); putchar( '\n' ); free( Adr ); return 0; } void *remalloc( void *Adr, size_t YeniBlokByte, size_t EskiBlokByte ) { void *t; if ( (t = malloc( YeniBlokByte )) == NULL ) return NULL; if ( Adr != NULL ) { memcpy( t, Adr, ( YeniBlokByte > EskiBlokByte ) ? EskiBlokByte : YeniBlokByte ); free( Adr ); } return t; } kt 0EFA : 10 byte bellek alani ayrildi !!! 1108 : 20 byte bellek alani ayrildi !!! 111E : 30 byte bellek alani ayrildi !!! 113E : 40 byte bellek alani ayrildi !!! 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,

Tm bu ilemler gelimi standart ktphane fonksiyonu realloc kullanlarak gerekletirilebilir (rnek 7.1-6). realloc fonksiyonu nceki arda ayrlan blok yeterli
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-18

bolua sahip ise yerinde geniletir ve veri kaydrma yapmaz. Programda for dngs iinde 19 tamsay deer iin dinamik bellek alan ayrlr ve ayrlan alanlara dng sayacnn deeri atanr. Dng blounda yer alan ilk if deyiminde dng sayacnn deerinin 5'in katlar olup olmad kontrol edilir. nk programda realloc fonksiyonu ayrd bellek alann 5 tamsaylk bloklar halinde artrr. Bu uygulama, her defasnda ayrlan alan bir tamsaylk alan kadar geniletmekten daha verimlidir. Programdaki ilk realloc arsna, ilk argman olarak bo adres deeri (NULL) aktarlr. Bu ar malloc ars ile ayndr.
rnek 7.1-6 realloc.c program. #include <stdio.h> #include <stdlib.h> #define MaxInt 19 #define BlokBoy 5 #define ToplamByte(x) ((x+BlokBoy)*sizeof(int)) int main(void) { int *Adr = NULL, *OncekiAdr = NULL; int i; for ( i = 0; i < MaxInt; i++ ) { if ( i % BlokBoy == 0 ) { OncekiAdr = Adr; Adr = realloc( Adr, ToplamByte(i) ); if ( Adr == NULL ) { free( OncekiAdr ); fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 1 ); } printf( "%p : %u byte bellek alani ayrildi !!!\n", Adr, ToplamByte(i) ); } Adr[ i ] = i; } for ( i = 0; i < MaxInt; i++ ) printf( "%d, ", Adr[ i ] ); putchar( '\n' ); free( Adr ); return 0; } kt 0EFA : 10 byte bellek alani ayrildi !!! 1108 : 20 byte bellek alani ayrildi !!! 1108 : 30 byte bellek alani ayrildi !!! C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-19

...rnek 7.1-6 kt devam


1108 : 40 byte bellek alani ayrildi !!! 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,

Ekrandan girilecek olan deer says belli olmayan bir uygulamada, programdaki for dngs yerine bilgi girii deyimleri ieren bir dng yerletirilir ve dng iinde bilgi girii devam ettike realloc ile dizi geniletilir. Program dngden k ve bilgi giriini sona erdirmek iin gerekli deyimleri iermelidir (rnein bilgi giriini sonlandrmak iin kullanc tarafndan zel bir say girilmesi istenebilir).

Dizgilere iaret eden adres dizisi ve dinamik bellek kullanm


nceki blmlerde elemanlar dizgilere iaret eden adres deikenleri olan adres dizileri tanmland. Adres dizisinin elemanlar olan adres deikenlerinin iaret ettii farkl uzunluktaki dizgiler iin dinamik bellek alan ayrlabilir. Aadaki rnek programda, farkl uzunluklarda 6 dizgi (ragged array) iin dinamik bellek alan ayrlr ve bu alanlarn balang adresleri adres dizisinin elemanlar olan adres deikenlerine atanr. Programda dizgilerin uzunluklarnn ve ierdikleri karakterlerin rastgele olmas iin RandomSayi makrosu ve RandomDizgi fonksiyonu tanmlanmtr.
rnek 7.1-7 adrdindz.c program. #include <stdio.h> #include <stdlib.h> #include <string.h> #define #define NoSatir 6 RandomSayi( min, max ) ((rand() % (int)(((max)+1) - (min))) + (min))

char *RandomDizgi( int BOY ); int main(void) { int i, dNoSutun; char *RndDizgi; char *AdrDinDz [ NoSatir ]; for ( i = 0; i < NoSatir; i++ ) { dNoSutun = RandomSayi( 5, 30 ); if ( (RndDizgi = RandomDizgi( dNoSutun )) == NULL ) { dNoSutun = 10; RndDizgi = "123456789"; } if ( (AdrDinDz [ i ] = (char *)malloc( dNoSutun * sizeof(char) )) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-20

...rnek 7.1-7 devam


exit( 1 ); } strncpy( AdrDinDz[ i ], RndDizgi, dNoSutun ); free ( RndDizgi ); printf( "AdrDinDz [ %d ] : %s\n", i, AdrDinDz[ i ], AdrDinDz[i] ); } printf( "AdrDinDz [ 2 ] printf( "AdrDinDz [ 2 ] [ 3 ] printf( "*AdrDinDz printf( "(*AdrDinDz)[ 4 ] printf( "*(*AdrDinDz + 4) for ( i = 0; i < NoSatir; i++ ) free( AdrDinDz [ i ] ); return 0; } char *RandomDizgi( int BOY ) { char *RndDizgi; int i; if ( (RndDizgi = (char *)malloc( BOY * sizeof (char) )) == NULL ) return NULL; for ( i = 0; i < BOY-1 /* bos karakter icin ilave byte */; i++ ) RndDizgi[ i ] = (char)(RandomSayi( 97, 122 )); RndDizgi[ i ] = '\0'; printf( "Random Dizgi --> %s\n", RndDizgi ); return RndDizgi; } kt Random Dizgi --> hqghumeaylnlfdxfirc AdrDinDz [ 0 ] : hqghumeaylnlfdxfirc Random Dizgi --> scxggbwkfnqduxwfnfozvsrtk AdrDinDz [ 1 ] : scxggbwkfnqduxwfnfozvsrtk Random Dizgi --> prepggxrpnrvy AdrDinDz [ 2 ] : prepggxrpnrvy Random Dizgi --> tmwcysyycqpevikeffmzni AdrDinDz [ 3 ] : tmwcysyycqpevikeffmzni Random Dizgi --> kkasvwsrenzkycxf AdrDinDz [ 4 ] : kkasvwsrenzkycxf Random Dizgi --> tlsgypsfadpooefxzbcoejuvpva AdrDinDz [ 5 ] : tlsgypsfadpooefxzbcoejuvpva AdrDinDz [ 2 ] : prepggxrpnrvy AdrDinDz [ 2 ] [ 3 ] : p *AdrDinDz : hqghumeaylnlfdxfirc C PROGRAMLAMA DILI, 1997 Ismet Kocaman : %s\n", : %c\n", : %s\n", : %c\n", : %c\n", AdrDinDz [ 2 ] AdrDinDz [ 2 ] [ 3 ] *AdrDinDz (*AdrDinDz) [ 4 ] *(*AdrDinDz + 4) ); ); ); ); );

7-21

...rnek 7.1-7 kt devam


(*AdrDinDz)[ 4 ] *(*AdrDinDz + 4) : u : u

Bu uygulamann pratik olmayan yn, her dizgi iin ayr bir malloc arsnn gerekiyor olmasdr. n

7.2 Yaplar ve Dinamik Bellek Kullanm


Yap deikenleri izleyen blmde anlatlacaktr. Fakat konu btnl asndan dinamik yaplara bu blmde yer verilmitir. rnek 8.4-5'de bir adet yap deikeni iin malloc fonksiyonu kullanlarak dinamik bellek alan ayrlr. Aadaki rnek programda ise yine tek bir yap deikeni, yapi deikenlerinden oluan bir yap dizisi, 2-b yap dizisi ve elemanlar 2-b yap dizisinin elemanlarna iaret eden 2-b adres dizisi iin dinamik bellek alan kullanm yer alr. rneklerde, program kodunun nasl alt metinde anlatld iin ok fazla aklama satrna yer verilmemitir. Aadaki dinstru.c rneinde program kodu, bir program kodunun anlalabilir olmasn salamak iin aklama satrlarnn etkili kullanmn gstermek amacyla aklama satrlar ile anlatlmtr. n
rnek 7.2-1 dinstru.c program.
/* * */ Bu programda yapilar icin dinamik bellek alani ayrilmasi orneklenmistir.

#include <stdio.h> #include <stdlib.h> #include <string.h> #define #define #define NL BOY ELSayi '\n' 10 5

/* exit ve malloc,calloc, free fonksiyonlari icin */ /* strcpy fonksiyonu icin */ /* newline karakteri */

/* Kayit yapi tipinin tanimlanmasi */

typedef struct KAYIT { char dizgi [ BOY + 1 ]; int i; } Kayit;


/* fonksiyon prototipleri */

Kayit Kayit void void

**Din2as ***Dinap_2as Free2as ( Freeap_2as

( int NoSatir2b, int NoSutun2b ); ( int NoSatir2b, int NoSutun2b ); Kayit **p_2as, int NoSatir2b ); ( Kayit ***p_ap_2as, int NoSatir2b );

int main(void) { int i, j, dNoSatir2b = 2, dNoSutun2b = 3;

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-22

... rnek 7.2-1 devam


Kayit *p_s, *p_as, **p_2as, ***p_ap_2as;
: : : : /* /* /* /* pointer to structure pointer to array of structures pointer to 2-d array of structures pointer to 2-d array of pointers to 2-d array of */ */ */

structures
/* p_s p_as p_2as p_ap_2as */ /* tek bir Kayit yapisi icin dinamik bellek ayrilmasi */

*/

Kayit yapisina isaret eden adres degiskeni. Kayit yapilarindan olusan diziye (yapi dizisi) isaret eden adres degiskeni. 2-boyutlu Kayit yapi dizisine isaret eden adres degiskeni. 2-b Kayit yapi dizisinin elemanlarina isaret eden 2-b adres dizisine isaret eden adres degiskeni.

if ( (p_s = (Kayit *)calloc( 1, sizeof (Kayit))) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 1 ); }
/* Kayit yapisina deger atama */

strcpy( p_s->dizgi, "XyZabc123K" ); p_s->i = 99;


/* Kayit yapisinin listelenmesi */

puts( "Kayit Yapisi :" ); printf( "(*p_s).dizgi : %s, (*p_s).i : %d\n", (*p_s).dizgi, (*p_s).i ); printf( "p_s[0].dizgi : %s, p_s[0].i : %d\n", p_s[0].dizgi, p_s[0].i );
/* ayrilan dinamik bellek alaninin serbest birakilmasi */

free( p_s );
/* * ELSayi adet yapidan olusan yapi dizisi icin dinamik bellek * alani ayrilmasi: * eleman sayisi programin calismasi sirasinda girilebilir. */

if( (p_as = (Kayit *)calloc( ELSayi, sizeof (Kayit))) == NULL ) { fprintf( stderr, "Bellek alani ayrilamadi !!!\n" ); exit( 2 ); }
/* yapi dizisine deger atama */

for (i = 0; i < ELSayi; i++ ) { strcpy( p_as[ i ].dizgi, "XyZabc123K" ); p_as[ i ].i = i+1; }
/* yapi dizisinin listelenmesi */

puts( "Kayit Yapi Dizisi :" ); for (i = 0; i < ELSayi; i++ ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-23

... rnek 7.2-1 devam


printf( "%s %d\n", p_as[ i ].dizgi, p_as[ i ].i );
/* yapi dizisi icin ayrilan bellek alaninin serbest birakilmasi */

free( p_as );
/* * 2-b yapi dizisi icin dinamik bellek alani ayrilmasi: * Satir ve Sutun sayilari programin calismasi sirasinda * girilebilir. */

if ( (p_2as = Din2as( dNoSatir2b, dNoSutun2b )) == NULL ) { fprintf( stderr, "Din2as: Bellek alani ayrilamadi !!!\n" ); exit( 3 ); }
/* 2-b yapi dizisine deger atama */

for ( i = 0; i < dNoSatir2b; i++ ) for ( j = 0; j < dNoSutun2b; j++ ) { strcpy( p_2as[ i ][ j ].dizgi, "XyZabc123K" ); p_2as[ i ][ j ].i = i * j + 2; }
/* 2-b yapi dizisinin listelenmesi */

puts( "2-b Yapi Dizisi :" ); for ( i = 0; i < dNoSatir2b; i++ ) { for ( j = 0; j < dNoSutun2b; j++ ) printf( "%s %d ", p_2as[ i ][ j ].dizgi, p_2as[ i ][ j ].i ); putchar( NL ); }
/* * 2-b adres dizisi icin bellek alani ayrilmasi. */

if ( (p_ap_2as = (Kayit***)Dinap_2as( dNoSatir2b, dNoSutun2b )) == NULL ) { fprintf( stderr, "Dinap_2as: Bellek alani ayrilamadi !!!\n" ); exit( 4 ); }
/* * adres dizisine yukaridaki deyimlerde olusturulan 2-b yapi * dizisinin elemanlarinin adreslerinin atanmasi. */

for ( i = 0; i < dNoSatir2b; i++ ) for ( j = 0; j < dNoSutun2b; j++ ) p_ap_2as[ i ][ j ] = &p_2as[ i ][ j ];
/* * 2-b adres dizisinin elemanlarinin isaret ettigi yapilarin degerlerinin listelenmesi. */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-24

... rnek 7.2-1 devam


puts( "2-b adres dizisi ile 2-b Yapi Dizisine erisim :" ); for ( i = 0; i < dNoSatir2b; i++ ) { for ( j = 0; j < dNoSutun2b; j++ ) printf( "%s %d ", p_ap_2as[ i ][ j ]->dizgi, p_ap_2as[ i ][ j ]->i ); putchar( NL ); }
/* 2-b yapi dizisi icin ayrilan dinamik alanin serbest birakilmasi */

Free2as( p_2as, dNoSatir2b );


/* 2-b adres dizisi icin ayrilan dinamik alanin serbest birakilmasi */

Freeap_2as( p_ap_2as, dNoSatir2b ); return 0; }


/* * Din2as fonksiyonu 2-boyutlu yapi dizisi icin dinamik bellek alani ayirir ve bu alana * isaret eden adres degerini dondurur. */

Kayit **Din2as( int NoSatir2b, int NoSutun2b ) { int i; Kayit **p_2as;


/* 2-b dizinin satirlarina isaret eden adres degiskenleri icin bellek alani ayrilmasi. */

if ( (p_2as = (Kayit **)malloc( NoSatir2b * sizeof (Kayit*) )) == NULL ) return (Kayit**)NULL;


/* * 2-b dizinin satirlarini olusturan 1-b diziler (elemanlari Kayit yapilari olan) icin bellek * alani ayrilmasi. */

for ( i = 0; i < NoSatir2b; i++ ) if ( (p_2as[ i ] = (Kayit *)malloc( NoSutun2b * sizeof (Kayit) )) == NULL ) return (Kayit**)NULL; return p_2as; }
/* * Dinap_2as fonksiyonu Kayit tipinde yapilara isaret eden adres degiskenlerinden * olusan 2-b adres dizisi icin dinamik bellek alani ayirir ve bu alana isaret eden * adres degerini dondurur. */

Kayit ***Dinap_2as( int NoSatir2b, int NoSutun2b ) { int i; Kayit ***p_ap_2as;


/* * 2-b adres dizisinin satirlarina isaret eden cift adres degiskenleri icin bellek alani ayrilmasi. */

if ( (p_ap_2as = (Kayit ***)malloc( NoSatir2b * sizeof (Kayit**) )) == NULL ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-25

... rnek 7.2-1 devam


return (Kayit***)NULL;
/* * 2-b adres dizisinin satirlarini olusturan 1-b diziler (elemanlari Kayit tipi yapilara * isaret eden adres degiskenleri olan) icin dinamik bellek alani ayrilmasi. */

for ( i = 0; i < NoSatir2b; i++ ) if ( (p_ap_2as[ i ] = (Kayit **)malloc( NoSutun2b * sizeof (Kayit*) )) == NULL ) return (Kayit***)NULL; return p_ap_2as; }
/* * Free2as fonksiyonu, Din2as fonksiyonu tarafindan ayrilan dinamik bellek * bloklarini serbest birakir. */

void Free2as( Kayit **p_2as, int NoSatir2b ) { int i;


/* * 2-b dizinin satirlarina isaret eden adres degiskenleri icin ayrilan bellek alaninin serbest * birakilmasi. */

free( p_2as );
/* * 2-b dizinin satirlarini olusturan 1-b diziler (elemanlari Kayit yapilari olan) icin ayrilan * bellek alaninin serbest birakilmasi. */

for ( i = 0; i < NoSatir2b; i++ ) free( p_2as[ i ] ); }


/* * Dinap_2as fonksiyonu tarafindan ayrilan dinamik bellek alanini serbest birakir. */

void Freeap_2as( Kayit ***p_ap_2as, int NoSatir2b ) { int i;


/* * * */ 2-b adres dizisinin satirlarina isaret eden cift adres degiskenleri icin ayrilan dinamik bellek alaninin serbest birakilmasi.

free( p_ap_2as );
/* * 2-b adres dizisinin satirlarini olusturan 1-b diziler (elemanlari Kayit tipi yapilara isaret * eden adres degiskenleri olan) icin ayrilan dinamik bellek alaninin serbest birakilmasi. */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

7-26

...rnek 7.2-1 devam


for ( i = 0; i < NoSatir2b; i++ ) free( p_ap_2as[ i ] ); } kt Kayit Yapisi : (*p_s).dizgi : XyZabc123K, (*p_s).i : 99 p_s[0].dizgi : XyZabc123K, p_s[0].i : 99 Kayit Yapi Dizisi : XyZabc123K 1 XyZabc123K 2 XyZabc123K 3 XyZabc123K 4 XyZabc123K 5 2-b Yapi Dizisi : XyZabc123K 2 XyZabc123K 2 XyZabc123K XyZabc123K 2 XyZabc123K 3 XyZabc123K 2-b adres dizisi ile 2-b Yapi Dizisine erisim : XyZabc123K 2 XyZabc123K 2 XyZabc123K XyZabc123K 2 XyZabc123K 3 XyZabc123K 2 4 2 4

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-1

BLM 8: Yap Deikenleri


C dili, mevcut deiken tiplerine ilave olarak (basit deikenler, diziler gibi), dier baz tiplerin tanmlanmasna olanak salar. Bunlardan biri de, yap deikenidir. Bu blmde, yap deikeninin bildirimi ve programlarda kullanm anlatlmtr. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-3

8.1 Yap Deikeni Bildirimi


Birbiri ile ilgili deikenlerin ortak bir isim altnda toplanmas ile yap deikeni (yada ksaca yap) oluturulur. Yap eleman olan deikenler farkl tiplerde olabilir. Deikenlerin bu ekilde organize edilerek bir btn halinde ilenebilmesi, zellikle ok sayda deiken ieren programlarda byk kolaylk salar. Bir yap, tek bir deikenden de oluabilir. Yap deikeni eitli ekillerde bildirilebilir:
l

lk olarak elemanlarn bellekte bulunu ekillerini temsil eden bir yap ablonu bildirilir. Yap ablonu bildiriminin genel ekli:
struct etiket_ismi { yap eleman bildirimleri ... ; };

Daha sonra, ablon bildiriminde yer alan struct anahtar kelimesi ve bunu izleyen yap etiketi (yada yap ismi) kullanlarak, ayn ablona sahip yap deikenleri bildirilir:
struct etiket_ismi degisken_listesi;

rnek olarak aada, proje bilgileri ieren proje ablonu bildirilir. ablon, projenin ismi iin isim karakter dizisini, proje balang ve biti tarihleri iin ise long tamsay deikenler basla ve son'u ierir:
/* sablon bildirimi */ struct proje { char *isim; long basla; long son; };

struct anahtar kelimesinden sonra yer alan "proje" ismi, yap etiketidir ve sadece yapnn ablonunu yada bir baka deyile iskeletini tanmlama ilevini yerine getirir. proje olarak adlandrlan ablonu bildirildikten sonra, "struct proje" kelimeleri dier veri tipleri gibi kullanlabilecek yap veri tipini oluturur. Bu ablona sahip p1, p2 ve p3 yap deikenleri aadaki ekilde bildirilir:

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-4 /* yapi degiskeni bildirimi */ struct proje p1, p2, p3;


l

Yap deikeni bildirimi aadaki ekilde de yaplabilir:


struct { yap eleman bildirimleri ... ; } degisken_listesi;

Fakat bu bildirimde etiket bulunmadndan dolay, baka bir yerde ayn ablona sahip deiken bildirmek iin ablonun tekrar yazlmas gerekir. rnek olarak aada etiket kullanlmadan, elemanlar snrlayan blok sonu oklu parantezinden sonra virglle ayrlm deiken listesi yazlarak, ayn deyimde ayn ablona sahip birden fazla yap deikeni bildirilir:
struct { char *isim; long basla; long son; } p1, p2, p3;
l

Dier bir yol ise, ilk yap deikeni bildiriminde etiket kullanlmasdr. Bylece, ayn ablon daha sonraki bildirimlerde kullanlabilir:
struct proje { char *isim; long basla; long son; } p1; ... struct proje p2, p3;

Yukarda anlatlan bildirim ekillerinden herhangi biri kullanlabilir. Programn okunabilirliini arttracak ve daha sonra baz deiiklerin kolayca yaplabilmesini salayacak en pratik yol seilmelidir. Genellikle, ablon bildirimleri bir include dosyasna yada programn ilk satrlarna yerletirilir. Daha sonra bu ablonlarn etiket isimleri kullanlarak, ayn ablonlara sahip yap deikenleri bildirilir. Bu uygulama ok daha pratiktir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-5

Sonu olarak yap deikeni bildiriminin genel ekli aadaki gibidir:


struct [etiket_ismi] { eleman bildirimleri...; } degisken_listesi;

Burada etiket kullanm, seime bal olduu iin keli parantezler ([ ]) arasnda verilmitir. rnek 8.1-1'de, proje1 ve proje2 ablonlar kullanlarak struct proje1 tipinde p1 yap deikeni ve struct proje2 tipinde p2 yap deikeni bildirilir. ablon bildiriminde deiken ismi yer almadka, bellek alan ayrlmaz. Dolaysyla, proje1 ve proje2 yap etiketleri bellek alanna sahip deildir, fakat yap tipindeki p1 ve p2 deikenleri iin bellek alan ayrlr. isim, basla ve son deikenleri, p1 ve p2 yapsnn elemanlardr. Programda da grld gibi, bir yapnn eleman isimleri dier yaplarda eleman ismi olarak yada deiken ismi olarak kullanlabilir.

rnek 8.1-1 yapi1.c program. #include <stdio.h> #include <string.h> struct proje1 { char *isim; long basla; long son; }; #define ELEMAN_SAYI 10 struct proje2 { char isim[ ELEMAN_SAYI + 1 ]; long basla; long son; }; int main(void) { struct proje1 p1; struct proje2 p2; long son = 1997; p1.isim = "xyz"; p1.basla = 1991L; p1.son = 1997L; printf("p1.isim: %s, p1.basla: %ld, p1.son: %ld\n", p1.isim, p1.basla, p1.son); printf("p1 : %d byte\n", sizeof( p1 ) ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-6

... rnek 8.1-1 devam


printf("p1.isim : %d byte\n", sizeof( p1.isim ) ); printf("p1.basla : %d byte\n", sizeof( p1.basla ) ); printf("p1.son : %d byte\n", sizeof( p1.son ) ); strcpy( p2.isim, "xyz" ); p2.basla = 1991L; p2.son = son; printf("p2.isim: %s, p2.basla: %ld, p2.son: %ld\n", p2.isim, p2.basla, p2.son); printf("p2 : %d byte\n", sizeof( p2 ) ); printf("p2.isim : %d byte\n", sizeof( p2.isim ) ); printf("p2.basla : %d byte\n", sizeof( p2.basla ) ); printf("p2.son : %d byte\n", sizeof( p2.son ) ); return 0; } kt p1.isim: xyz, p1.basla: 1991, p1.son: 1997 p1 : 10 byte p1.isim : 2 byte p1.basla : 4 byte p1.son : 4 byte p2.isim: xyz, p2.basla: 1991, p2.son: 1997 p2 : 20 byte p2.isim : 11 byte p2.basla : 4 byte p2.son : 4 byte

Bir yapnn elemanlarna yap eleman operatr ( . ) yada dier adyla nokta operatr kullanlarak eriilebilir. Bu operatrn kullanlmas ile oluturulan yap_degiskeni.eleman_ismi ifadesi, yap elemanlar iin bellekte ayrlan alanlara eriimi salad iin, bir deiken isminin kullanlabilecei her yerde kullanlabilir. Programda yer alan atama deyimleri ile yap elemanlarna eitli deerler atanr. p1 yapsnn isim eleman char * tipinde bir adres deikenidir. p2 yapsnn isim eleman ise bir karakter dizisidir. #define n-ilemci komutu kullanlarak ELEMAN_SAYI sembolik sabiti tanmlanr. Bildirimde isim karakter dizisinin eleman says, dizgi sonunu belirten bo karakter iin yer ayrmak amacyla ELEMAN_SAYI + 1 olarak verilir. p1.isim adres deikenine atama deyimi ile proje ismi olarak "xyz" dizgisi atanr. p2.isim karakter dizisine ise proje ismi olarak yine ayn dizgi, dizgi kopyalama fonksiyonu strcpy fonksiyonu kullanlarak atanr. long tamsay tipindeki p1.basla ve p2.basla deikenlerine 1991 deeri, p1.son deikenine ise 1997 deeri atanr. p2.son deikenine ise atama deyiminde long tamsay deiken son kullanlarak yine ayn deer atanr. Program ekrana p1 ve p2 yaplarnn bellek alan byklklerini ve ayrca yap elemanlarnn bellek alan byklklerini ve deerlerini listeler. Program 2-byte bellek adreslerine sahip bir donanmda yukardaki kty verir. Fakat bu deerler 4-byte bellek
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-7

adreslerine sahip bir donanmda farkl olacaktr. Bir yapnn bellek alan bykl donanma gre deiebilir. Dolaysyla, C programlarnn tanabilir olmas iin, yap elemanlarnn bellek adresleri zerinde yaplan ilemler buna gre dzenlenmelidir. rnek 8.1-2'de grld gibi, bir yap deikeni bir baka yap deikeni ierebilir. rnek programda proje balama ve sona erme tarihleri gn ve ay olarak kaydedilir. Bu amala proje ablonu iinde GunAy ablonuna sahip basla ve son elemanlar bildirilir ve bylece p.basla.gun, p.basla.ay, p.son.gun ve p.son.ay elemanlar oluur. Program p yapsnn elemanlarnn deerlerini ekrana listeler.
rnek 8.1-2 yapi2.c program. #include <stdio.h> struct GunAy { short gun; short ay; }; struct proje { char *isim; struct GunAy basla; struct GunAy son; }; int main(void) { struct proje p = { "xyz", 15, 12, 31, 12 }; printf("proje ismi: %s\n", p.isim ); printf("proje baslama gun/ay: %d/%d, ", p.basla.gun, p.basla.ay ); printf(" sona erme gun/ay: %d/%d\n", p.son.gun, p.son.ay); return 0; } kt proje ismi: xyz proje baslama gun/ay: 15/12, sona erme gun/ay: 31/12

rnek programlarda yalnzca yap eleman operatr ( . ) kullanlarak yap elemanlarna eriim ilemi yer ald. Yaplar zerinde, yap deikeninin bir btn olarak ele alnd dier baz ilemler de gerekletirilebilir. Bir yap, ayn tipte (ayn ablona sahip) bir baka yapya atanabilir, bir fonksiyona argman olarak aktarlabilir. Ayrca, yap deeri dndren fonksiyon tanmlanabilir. Fakat, iki yap birbiri ile karlatrlamaz. Bu ilem, yap elemanlar ile gerekletirilebilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-8

Global yada static (blok ii yada blok d) yap deikenlerine ilk deer atama sadece elemanlarna karlk gelen sabit deerler yada sabit ifadelerin, oklu parantezlerle snrl listesi ile yaplabilir. Otomatik yap deikenlerine de ayn ekilde ilk deer atama yaplabilir, fakat eer bu ilem ilk deer listesi yerine tek bir ifade ile yaplacak ise, ayn tipteki bir baka yap yada yap deeri dndren bir fonksiyon ars eitlenerek de gerekletirilebilir. lk deer listesinde yer alan sabit deer yada sabit ifade says, eleman saysndan az ise, kalan elemanlarn ilk deerleri 0 olur. Daha fazla ilk deerin bulunmas derleme srasnda hata oluturur. lk deer atama yaplmadnda, global yada static yap deikenlerinin elemanlarnn ilk deerleri 0 olur. Otomatik yap deikenlerinin elemanlarnn ilk deerleri ise belirsizdir. rnek 8.1-3'de, global yap deikenleri g1 ve g2 bildirilir. g1'e sabit deer listesi ile ilk deer atama yaplr. Ayrca, fonk blou iinde de s1, s2, s3 ve s4 otomatik yap deikenleri ve static yap deikeni s5 bildirilir. s2 yapsna sabit deer listesi ile ilk deer atama yaplr. s1'e ayn tipteki g1, s3'e ise koul operatrnn test ifadesine bal olarak s1 yada s2 atanarak ilk deer atama ilemi gerekletirilir. Program ekrana yap elemanlarnn deerlerini listeler. ktda da grld gibi, ilk deer atama yaplmayan global yap g2 ve blok ii static yap s5'in elemanlarnn ilk deerleri 0 olur. Otomatik yap s4'n elemanlarnn deerleri ise belirsizdir.
rnek 8.1-3 ilkyapi1.c program. #include <stdio.h> #define SECIM 1 struct yapi { int i; long x; } g1 = { 66, 33L }, g2; int main(void) { struct yapi s1 = g1, s2 = { 77, 55L }, s3 = ( SECIM ? s1 : s2 ), s4; static struct yapi s5; printf("g1.i : %d, g1.x : %ld\n", g1.i, g1.x ); printf("g2.i : %d, g2.x : %ld\n", g2.i, g2.x ); printf("s1.i : %d, s1.x : %ld\n", s1.i, s1.x ); printf("s2.i : %d, s2.x : %ld\n", s2.i, s2.x );

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-9

...rnek 8.1-3 devam


printf("s3.i : %d, s3.x : %ld\n", s3.i, s3.x ); printf("s4.i : %d, s4.x : %ld\n", s4.i, s4.x ); printf("s5.i : %d, s5.x : %ld\n", s5.i, s5.x ); return 0; } kt g1.i g2.i s1.i s2.i s3.i s4.i s5.i : 66, : 0, : 66, : 77, : 66, : 689, : 0, g1.x g2.x s1.x s2.x s3.x s4.x s5.x : 33 :0 : 33 : 55 : 33 : 277479424 :0

rnek 8.1-4'de, 4 tamsay elemana sahip global yap deikeni g1, blok d (external) static yap deikenleri e1 ve e2, blok ii (internal) static yap deikeni s3 ve otomatik yap deikenleri s1 ve s2 bildirilir.
rnek 8.1-4 ilkyapi2.c program. #include <stdio.h> struct yapi { int i, j; long x, y; } g1 = { 1, 2 }; static struct yapi e1 = { 1, 2 }; static struct yapi e2; int main(void) { struct yapi s1 = { 1, 2 }, s2; static struct yapi s3 = { 1, 2 }; printf( "g1.i : %d, g1.j : %d, g1.x : %ld, g1.y : %ld\n", g1.i, g1.j, g1.x, g1.y ); printf( "e1.i : %d, e1.j : %d, e1.x : %ld, e1.y : %ld\n", e1.i, e1.j, e1.x, e1.y ); printf( "e2.i : %d, e2.j : %d, e2.x : %ld, e2.y : %ld\n", e2.i, e2.j, e2.x, e2.y ); printf( "s1.i : %d, s1.j : %d, s1.x : %ld, s1.y : %ld\n", s1.i, s1.j, s1.x, s1.y ); printf( "s2.i : %d, s2.j : %d, s2.x : %ld, s2.y : %ld\n", s2.i, s2.j, s2.x, s2.y ); printf( "s3.i : %d, s3.j : %d, s3.x : %ld, s3.y : %ld\n", s3.i, s3.j, s3.x, s3.y ); return 0; } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-10

...rnek 8.1-4 devam


kt g1.i : 1, e1.i : 1, e2.i : 0, s1.i : 1, s2.i : 689, s3.i : 1, g1.j : 2, e1.j : 2, e2.j : 0, s1.j : 2, s2.j : 0, s3.j : 2, g1.x : 0, e1.x : 0, e2.x : 0, s1.x : 0, s2.x : 65409162, s3.x : 0, g1.y : 0 e1.y : 0 e2.y : 0 s1.y : 0 s2.y : 49363 s3.y : 0

Programda, e2 ve s2 yaplarna ilk deer atama yaplmamtr. Bu durumda, ktda da grld gibi, e2 yapsnn elemanlarnn ilk deerleri 0 olur. s2 yapsnn elemanlarnn ilk deerleri ise belirsizdir. g1, e1, s1 ve s3 yap deikenlerine ilk deer atama, eleman saysndan daha az sayda sabit deer ieren liste ile yaplr. Listede bulunan deerler, yap elemanlarna srayla atanr. Kalan elemanlarn ilk deerleri, ktda da grld gibi 0 olur. n

8.2 Yap Dizisi


Ayn ablona sahip birden fazla yap deikenine ihtiya duyulduunda yap dizisi kullanlr:
struct etiket_ismi dizi_ismi[ eleman_says ];

rnek 8.2-1'de yer alan struct bildirimi ile, bellekte struct proje veri tipinde 3 yap deikeni iin yer ayrlr:
struct proje p[ EL_SAYI ];

Burada p, proje yap ablonuna sahip 3 adet yap deikeninden oluan yap dizisidir. p'nin tipi struct proje[3] olur.
rnek 8.2-1 yapidiz1.c program. #include <stdio.h> #define EL_SAYI 3 #define DIZGI_BOY 10 struct proje { char *isim; long basla; long son; };

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-11

...rnek 8.2-1 devam


int main(void) { struct proje p[ EL_SAYI ]; char dizgi[ EL_SAYI ][ DIZGI_BOY+1 ]; int i; for ( i = 0; i < EL_SAYI; ++i ) { p[i].isim = dizgi[i]; printf( "proje ismi, baslama, bitis ? " ); scanf( "%10s%ld%ld", p[i].isim, &p[i].basla, &p[i].son ); } for ( i = 0; i < EL_SAYI; ++i ) printf( "%10s %4ld %4ld\n", p[i].isim, p[i].basla, p[i].son ); return 0; } Bilgi Girii proje ismi, baslama, bitis ? proje1 1991 1992 proje ismi, baslama, bitis ? proje2 1992 1994 proje ismi, baslama, bitis ? proje3 1994 1995 kt proje1 1991 1992 proje2 1992 1994 proje3 1994 1995

Dizide bulunan yap elemanlarna eriim iin,


dizi_ismi[ indeks ].eleman_ismi

ifadesi kullanlr. rnek 8.2-1'de yap elemanlarna bu ekilde oluturulan p[i].isim, p[i].basla ve p[i].son ifadeleri ile eriilir. scanf fonksiyonu, klavyeden girilen bilgileri argman olarak aktarlan bellek adreslerine atar. Bu fonksiyonun argman listesinde, yap elemanlarnn bellek adreslerini veren p[i].isim, &p[i].basla ve &p[i].son ifadeleri bulunur. p[i].isim bir adres deikenidir ve bir karekter dizisinin bellekte bulunduu alann balangcna iaret eder. Bu nedenle p[i].isim ifadesine & operatr uygulanmaz. p[i].isim aracl ile, klavyeden girilen proje ismini dizgi sabiti olarak bellee yerletirmek iin, bu adres deikeninin geerli bir bellek alanna iaret etmesi gerekir. Programda, yap dizisi bildirimini izleyen satrda dizgi karakter dizisi bildirilir. Bu bildirim ile en fazla 10 karekter uzunluunda 3 adet dizgi sabiti iin bellek alan ayrlr (11. eleman, dizgi sonunu belirleyen \0 karakteri iindir).
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-12

Daha sonra for dngs iinde,


p[i].isim = dizgi[i];

atama deyimi ile ayrlan bu alanlarn balang adresleri, adres deikeni p[i].isim'e aktarlr. Bylece scanf ars ncesinde p[i].isim adres deikeninin dizgilerin saklanabilecei geerli bir bellek alanna iaret etmesi salanr. Klavyeden girilen proje isimleri bu bellek alanlarna yerletirilir. Bu ilem yaplmad taktirde, adres deikeni p[i].isim'in deeri geerli herhangi bir bellek adresi olmayaca iin programn almas srasnda, "bo adres deikenine deer atama" hatas ( null pointer assignment ) oluacaktr. rnek 8.2-1'de kullanlan proje ablonunda, isim eleman char tipi verilere iaret eden bir adres deikeni olarak bildirildi. isim eleman, char tipi bir dizi olarak bildirildiinde, dizgi dizisi bildirimi ile bellek alan ayrmaya gerek kalmayacaktr. nk her isim eleman iin ayrlan alan, p[i] yapsnda bulunan bir karakter dizisi olacaktr. Bu durumda rnek 8.2-1 aadaki ekilde yazlabilir:
rnek 8.2-2 yapidiz2.c program. #include <stdio.h> #define EL_SAYI 3 #define DIZGI_BOY 10 struct proje { char isim[ DIZGI_BOY+1 ]; long basla; long son; }; int main(void) { struct proje p[ EL_SAYI ]; int i; for ( i = 0; i < EL_SAYI; ++i ) { printf( "proje ismi, baslama, bitis ? " ); scanf( "%10s%ld%ld", p[i].isim, &p[i].basla, &p[i].son ); } for ( i = 0; i < EL_SAYI; ++i ) printf( "%10s %4ld %4ld\n", p[i].isim, p[i].basla, p[i].son ); return 0; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-13

...rnek 8.2-2 devam


Bilgi Girii proje ismi, baslama, bitis ? proje1 1991 1992 proje ismi, baslama, bitis ? proje2 1992 1994 proje ismi, baslama, bitis ? proje3 1994 1995 kt proje1 1991 1992 proje2 1992 1994 proje3 1994 1995

Bu rnekte de yine scanf fonksiyonunun ikinci argman olan p[i].isim ifadesine & operatr uygulanmamtr. nk C dilinde indeksi verilmeyen dizi ismi, dizinin balang elemannn bellek adresini veren adres sabitidir. Okunabilirlii arttrmak amacyla, rnek programlarda hata kontrol deyimlerine yer verilmemitir.
rnek 8.2-3 yapidiz3.c program. #include <stdio.h> #define EL_SAYI(s) sizeof(s)/sizeof(s[0]) struct proje { char *isim; long basla, son; } p[ ] = { "proje1", 1991, 1992, "proje2", 1992, 1994, "proje3", 1994, 1995, }; int main(void) { int i; for ( i = 0; i < EL_SAYI(p); ++i ) printf( "%10s %4ld %4ld\n", p[i].isim, p[i].basla, p[i].son ); return 0; } kt proje1 1991 1992 proje2 1992 1994 proje3 1994 1995

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-14

rnek 8.2-3'de proje ablonu bildirilir ve bu ablona sahip yaplardan oluan p yap dizisi tanmlanr. Yine ayn deyimde, p yap dizisine yap elemanlarna karlk gelen sabit deer listesi ile ilk deer atama yaplr. p yap dizisi global olarak (blok dnda) tanmland iin, ilk deer atama ilemi (listede yer alan deerlerin ayrlan bellek alanlarna yerletirilmesi) program almaya balamadan nce ve sadece bir kez yaplr. rnek programda, yap dizisi tanmnda keli parantezlerin ii bo braklmtr. Derleyici, ilk deer listesinde bulunan deerleri sayarak dizi boyutlarn hesaplar ve bylece p'nin tipi tamamlanm olur. Eer ilk deer listesi bulunmuyor ise, dizi boyutlar mutlaka belirtilmelidir. Programda for dngs ile dizi boyunca ilerleyerek elemanlar listelenir. Dngnn test ifadesinde kullanlan EL_SAYI(s) makrosu, derleme ncesi C nilemcisi tarafndan #define satrnda tanmland gibi,
sizeof(p)/sizeof(p[0])

ifadesi ile deitirilir. Bu ifade, derleme srasnda dizideki yap deikeni saysn yani dizinin eleman saysn verir. sizeof( p[0] ) yerine sizeof( struct proje ) kullanlabilir. nk her iki sizeof ifadesi de, dizide yer alan tek bir yapnn bellek alan bykln verir. Dngde dizinin eleman says saysal olarak verilmedii iin, dizide yer alan yaplarn tipi deitirildiinde yada ilk deer listesine ilave yapldnda program iinde eleman says ile ilgili herhangi bir deiiklik gerekmez. Dngde dizi sonunun belirlenmesi, ilk deer listesi sonuna yerletirilecek olan bo adres deikeni deeri (NULL) kontrol edilerek de yaplabilir. rneklerde grld gibi, yap dizileri de dier diziler gibi bildirilir ve ilk deer atama yaplr. Yap dizisinin her bir eleman, bir baka alt-veri grubu oluturur. Herhangi bir yap deikeni iin geerli olan ilk deer atama kurallar, yap dizisinin eleman olan ve alt-veri grubu oluturan yaplar iin de geerlidir. Dolaysyla, alt-veri grubu elemanlarna ilk deer atama, yine oklu parantezlerle snrlanm ve virgllerle ayrlm sabit deer yada sabit ifadelerle yaplr. ok boyutlu dizilerin aksine, yap dizisinde yer alan alt-veri gruplarnn elemanlar farkl veri tiplerinde olabilecei iin, i parantezler sadece ilk deer listesinin eksiksiz olduu durumlarda kullanlmayabilir. rnek 8.2-3'de ilk deer listesi eksiksiz olduu iin, dizideki alt-veri gruplarn oluturan yaplara karlk gelen ilk deerler parantezlerle snrlandrlmamtr. Fakat listenin tam olmad durumlarda ilk deerlerin dizinin her srasna yada bir baka deyile her yapsna karlk gelecek ekilde parantezlerle snrlandrlmas zorunludur. Aksi taktirde, veri tipleri birbirine uymayaca iin hata oluacaktr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-15

rnein, sadece isim elemanna ilk deer atama yaplacak ise aadaki kullanlmaldr:
struct proje { char *isim; long basla, son; } p [ ] = { { "proje1" }, { "proje2" }, { "proje3" }, };

ifade

Bu yap dizisi tanmnda yer alan ilk deer listesi, alt-veri grubu oluturan yap deikenlerinin basla ve son elemanlar iin herhangi bir ilk deer iermez. Dolaysyla, basla ve son elemanlarnn ilk deeri 0 olur. Btn global ve static dizilerde olduu gibi, ilk deer atama yaplmayan global ve static yap dizilerinin elemanlarnn ilk deerleri 0 olur; otomatik yap dizilerinin elemanlarnn ilk deerleri ise belirsizdir. rnek 8.1-2'de proje yaps iinde yer alan her GunAy yaps bir alt-veri grubu oluturur. lk deer atama aadaki ekilde yapldnda, p.son.ay elemannn ilk deeri 0 olur:
static struct proje p = { "xyz", 15, 12, 31 };

Bu deyimdeki ilk deer listesinde, alt-veri gruplarna karlk gelen ilk deerler parantezlerle snrlanmad iin, gerekli sayda ilk deer kullanlr ve kalan deerlerle yapnn izleyen eleman olan alt-veri grubuna ilk deer atama yaplr. Buna gre, xyz dizgisi p.isim elemanna, 15 ve 12 deerleri ilk alt-veri grubunu oluturan p.basla yapsnn p.basla.gun ve p.basla.ay elemanlarna ve 31 deeri de p yapsnn izleyen eleman olan ve bir baka alt-veri grubu oluturan p.son'un p.son.gun elemanna ilk deer olarak atanr. Listede daha baka sabit deer bulunmadndan dolay, p.son.ay elemannn ilk deeri 0 olur. Aadaki bildirim deyiminde, 15 saysn snrlayan i parantezler, ilk alt-veri grubuna atanacak deerleri ifade eder. Sonu olarak p.basla.gun'n ilk deeri 15, p.basla.ay'n ilk deeri 0, p.son.gun ve p.son.ay'n ilk deerleri ise srasyla 12 ve 31 olur.
static struct proje p = { "xyz", { 15 }, 12, 31 };

rnek 8.2-4'de struct Yapi1 tipinde t yaps bildirilir ve bu yapnn eleman olan iki karakter dizisi (s1 ve s2) iin bellekte her biri 5 karakter uzunluunda sabit byklkte alanlar ayrlr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-16

rnek 8.2-4 yapidiz4.c program. #include <stdio.h> struct Yapi1 { char s1[5], s2[5]; }; struct Yapi2 { char *s1, *s2; }; int main(void) { struct Yapi1 t = { { 'a', 'b', 'c' }, "xyz" }; struct Yapi2 p = { "abc", "xyz" }; int i; printf("t.s1 : %d, t.s2 : %d, p.s1 : %d, p.s2 : %d byte\n", sizeof( t.s1 ), sizeof( t.s2 ), sizeof( p.s1 ), sizeof( p.s2 ) ); printf("t.s1 : %s, t.s2 : %s, p.s1 : %s, p.s2 : %s\n", t.s1, t.s2, p.s1, p.s2 ); for ( i = 0; i < sizeof(t.s1); i++ ) printf("t.s1[%d] : %c, ", i, t.s1[i] ); puts( "" ); for ( i = 0; i < sizeof(t.s2); i++ ) printf("t.s2[%d] : %c, ", i, t.s2[i] ); puts( "" ); i = 0; while ( p.s1[i] ) { printf("p.s1[%d] : %c, p.s1+%d : %d\n", i, p.s1[i], i, p.s1+i ); i++; } for ( i = 0; p.s2[i] ; i++ ) printf("p.s2[%d] : %c, p.s2+%d : %d\n", i, *(p.s2+i), i, p.s2+i ); return 0; } kt t.s1 : 5, t.s2 : 5, p.s1 : 2, p.s2 : 2 byte t.s1 : abc, t.s2 : xyz, p.s1 : abc, p.s2 : xyz t.s1[0] : a, t.s1[1] : b, t.s1[2] : c, t.s1[3] : , t.s1[4] : , t.s2[0] : x, t.s2[1] : y, t.s2[2] : z, t.s2[3] : , t.s2[4] : , p.s1[0] : a, p.s1+0 : 70 p.s1[1] : b, p.s1+1 : 71 C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-17

...rnek 8.2-4 devam


p.s1[2] : c, p.s2[0] : x, p.s2[1] : y, p.s2[2] : z, p.s1+2 : 72 p.s2+0 : 74 p.s2+1 : 75 p.s2+2 : 76

Bildirimde ilk deer atama yaplarak bu alanlara abc ve xyz dizgileri yerletirilir. s1 ve s2 karakter dizilerinin ilk deer atama yaplmayan elemanlarnn deerleri bo karakter ('\0') olur. Fakat bellekte ayrlan alanlarn sadece bir ksm kullanlmtr.
ekil 8.2-1 t ve p yap deikenlerinin sembolik bellek grnm.
Bellek

:
t.s1[0] t.s1[1] t.s1[2] t.s1[3] t.s1[4] t.s2[0] t.s2[1] t.s2[2] t.s2[3] t.s2[4] 'a' 'b' 'c' '\0' '\0' 'x' 'y' 'z' '\0' '\0'

t yaps

: :
p.s1 p.s2 70 p yaps 74

: :
'a' 'b' 'c' '\0' 'x' 'y' 'z' '\0'

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-18

Bellek tasarrufu sz konusu olduunda, yap elemanlar olarak karakter dizileri yerine, dizgilere iaret eden adres deikenleri kullanlr. Programda bildirilen p yapsnn elemanlar, bellekte baka bir yerde bulunan dizgilere iaret eden adres deikenleridir. Bylece dizgiler iin sadece gerekli miktarda bellek alan ayrlr (dizgi sonunu belirten NUL karakteri (null character) ve dizgilerde bulunan karakter says kadar bellek alan). zellikle eleman saysnn ok fazla olduu uygulamalarda bu yol nemli lde bellek tasarrufu salar. Yap eleman operatr ( . ) ve indeks operatr ( [ ] ) ayn operatr nceliine sahiptir. Fakat grup ilikileri soldan saa doru olduu iin, t ve p yap deikenlerindeki karakter dizilerinin elemanlarna eriim iin kullanlan ifadelerde parantez kullanm gereksizdir. rnein, (t.s1)[i] ve t.s1[i] ifadeleri ayndr. Programda deiik kullanmlar rneklemek amacyla, p.s1 adres deikeninin iaret ettii dizgideki karakterler while dngsnn test ifadesinde dizgi sonunu belirleyen bo karekter kontrol yaplarak listelenir. Ayrca, p.s2 aracl ile eriim iin adres aritmetii kullanlmtr. ekil 8-2.1'de t ve p yap deikenlerinin ilk deer atamalar yapldktan sonraki sembolik bellek grnm verilmitir. n

8.3 Yaplar ve Adres Deikenleri


Yaplar da bellekte saklandklar iin, herhangi bir yapnn bellek adresi alnabilir. Dolaysyla, bir yapya iaret eden adres deikeni (yap adres deikeni) bildirilebilir. rnek 8.3-1'de, struct proje tipinde p yap deikeni ve struct proje * tipinde ap adres deikeni bildirilir.
rnek 8.3-1 adryapi1.c program. #include <stdio.h> #include <string.h> struct proje { char *isim; long basla; long son; }; int main(void) { struct proje p = { "yeni proje", 1991L, 1994L }; struct proje *ap = &p; char *dizgi = "YENI PROJE";

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-19

...rnek 8.3-1 devam


printf("sizeof( struct proje * ) : %d, sizeof( ap ) : %d, sizeof( p ): %d byte\n\n", sizeof( struct proje * ), sizeof(ap), sizeof(p) ); printf("ap->isim: %s, ap->basla: %ld, ap->son: %ld\n", ap->isim, ap->basla, ap->son ); printf("(*ap).isim : %s, (*ap).basla : %ld, (*ap).son : %ld\n", (*ap).isim, (*ap).basla, (*ap).son ); printf("(&p)->isim: %s, (&p)->basla: %ld, (&p)->son: %ld\n\n", (&p)->isim, (&p)->basla, (&p)->son ); strcpy( ap->isim, dizgi ); ap->basla = 1990L; puts("YENI PROJE dizgisi ve 1990 degeri atandiktan sonra ...\n"); printf("p.isim : %s, p.basla : %ld, p.son : %ld\n", p.isim, p.basla, p.son ); printf("proje isminin 3. karakteri : %c\n\n", *(ap->isim + 2) ); puts("bellek adresleri :"); printf("&p : %d, &(p.isim) : %d, &(p.basla) : %d, &(p.son) : %d\n", &p, &(p.isim), &(p.basla), &(p.son) ); printf("ap : %d, &(ap->isim) : %d, &(ap->basla) : %d, &(ap->son) : %d\n", ap, &(ap->isim), &(ap->basla), &(ap->son) ); return 0; } kt sizeof(struct proje *) : 2, sizeof(ap) : 2, sizeof(p): 10 byte ap->isim : yeni proje, ap->basla : 1991, ap->son (*ap).isim : yeni proje, (*ap).basla : 1991, (*ap).son (&p)->isim : yeni proje, (&p)->basla : 1991, (&p)->son YENI PROJE dizgisi ve 1990 degeri atandiktan sonra ... p.isim : YENI PROJE, p.basla : 1990, p.son : 1994 proje isminin 3. karakteri : N : 1994 : 1994 : 1994

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-20

...rnek 8.3-1 kt devam


bellek adresleri : &p : 3940, &(p.isim) ap : 3940, &(ap->isim) : 3940, : 3940, &(p.basla) : 3942, &(p.son) &(ap->basla) : 3942, &(ap->son) : 3946 : 3946

ap adres deikenine bildirim deyiminde ilk deer olarak, p'nin &p ifadesi ile alnan bellek adresi atanr. Bylece, ap adres deikeninin p yapsna iaret etmesi salanr. ktda da grld gibi ap, 2 byte byklnde bir adres deikenidir ve tad deer p yapsnn bellek adresidir (3940). Adres deikeni aracl ile yap elemanlarna indirek eriim iin, ok operatr (->) ile oluturulan ifadeler kullanlr. rnek programda p yapsnn isim, basla ve son elemanlarna eriim iin srasyla,
ap->isim, ap->basla ve ap->son

ifadeleri kullanlr. Adres deikeni aracl ile eriim, nokta operatr (.) ile oluturulan aadaki ifadelerle de gerekletirilebilir:
(*ap).isim, (*ap).basla ve (*ap).son

Fakat ok operatr ile oluturulan ifadeler, sadece tek bir operatr ierdii iin daha pratiktir. Programda grld gibi ap yerine yap deikeninin bellek adresini veren &p kullanlarak oluturulan,
(&p)->isim, (&p)->basla ve (&p)->son

ifadeleri ile de yap elemanlarna erimek mmkndr. Bildirim srasnda, p yapsna parantezlerle snrl sabit deer listesi ile ilk deer atama yaplr. Yapnn isim eleman, bellekte baka bir yerde bulunan "yeni proje" dizgi sabitinin bellek adresini alr. Dolaysyla ap->isim, bu karakter dizisinin balangcna iaret eder. Programda daha sonra, strcpy fonksiyonu kullanlarak ap->isim tarafndan iaret edilen bellek alanna "YENI PROJE" dizgisi kopyalanr. ktda da grld gibi ap->isim + 2 ifadesi, ikinci offset'te bulunan elemann (dizgi sabitinin 3. karakteri) bellek adresini; *(ap->isim + 2) ise bu adreste bulunan 1 byte deeri (N karakteri) verir. Programda son olarak p yapsnn ve yap elemanlarnn bellek adresleri listelenir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-21

ekil 8.3-1'de, ap adres deikeni ve p yapsnn sembolik bellek grnm verilmitir:


ekil 8.3-1 ap adres deikeni ve p yapsnn sembolik bellek grnm. : Bellek
ap 3940

: : ...
1990 p.isim

p.basla p yaps

1994

p.son

: :
'Y' 'E' 'N' 'I' '' 'P' 'R' 'O' 'J' 'E' '\0'

Sonu olarak, herhangi bir yap elemanna kullanlr: nokta operatr kullanlarak:

eriim iin aadaki kombinasyonlar

yapi_degiskeni.eleman_ismi (*adres_degiskeni).eleman_ismi

(1) (2)

ok operatr kullanlarak: (&yapi_degiskeni)->eleman_ismi (3) (4) adres_degiskeni->eleman_ismi

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-22

Yap operatrleri ( . ve -> ), adres deikeni operatrlerinden ( * ve & ) daha yksek ncelie sahiptir. Dolaysyla, (2) ve (3) no.'lu ifadelerde hata olumamas iin parantezlerin kullanm zorunludur. rnein (2) no.'lu ifadede parantezler kullanlmad taktirde, *adres_degiskeni.eleman_ismi ifadesi *(adres_degiskeni.eleman_ismi) ile ayn olacaktr ve parantezler iindeki ifade bir adres deikeni olmad iin hata oluacaktr. Yap elemannn bellek adresini veren,
&(adres_degiskeni->eleman_ismi) yada &(yapi_degiskeni.eleman_ismi)

ifadelerinde ise operatr nceliinden faydalanlarak parantezler kaldrlabilir. Ayn operatr nceliine sahip . ve -> operatrlerinin grup ilikileri (associativity) soldan saa dorudur. Dolaysyla rnek 8.1-2'deki (yapi2.c program) p yaps ve bu yapya iaret eden struct proje * tipindeki ap adres deikeni ile oluturulan ve her iki operatrn de kullanld aadaki 4 ifade birbirine eittir:
p.basla.gun ap->basla.gun (p.basla).gun (ap->basla).gun

ekil 8.3-2'de grld gibi ifade soldan saa doru ilenirken ilk rastlanan nokta operatr ile p.basla oluturulur. Bundan sonra rastlanan ikinci nokta operatr p.basla ile gun elemann birletirir. Yap operatrleri . ve ->, fonksiyon arma ve indeks operatrleri ile birlikte (srasyla ( ) ve [ ] ) ncelik listesinin en st srasnda bulunurlar. Bu nedenle operatr etkileri (binding) dier operatrlerden fazladr.
ekil 8.3-2 p.basla.gun ifadesinin soldan saa ilenmesi.
soldan saa

basla

gun

(p l basla)

(p l basla) l gun

rnek 8.3-2'de ok operatr, ++ ve -- operatrleri ile birlikte kullanlr. Programda 3 yapdan oluan t yap dizisi ve bu yap dizisinin elemanlarna iaret eden p adres deikeni bildirilir. Adres deikenine bildirim srasnda yap dizisinin balang eleman olan yapnn bellek adresi atanr (dizi ismi t, balang elemannn bellek adresini veren
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-23

sabittir). Bu nedenle, ilk printf deyimi ekrana t[0] yapsnn elemanlarnn deerlerini listeler. Bu ilem aadaki deyim ile de gerekletirilebilir:
printf( "t->i : %d, t->s : %s\n", t->i, t->s );

Aadaki her iki for dngs de yap dizisinde bulunan yaplarn elemanlarnn deerlerini listeler:
for ( j = 0; j < sizeof(t)/sizeof(t[0]); j++ ) printf( "%d, %s\n", (t+j)->i, (t+j)->s ); for ( j = 0; j < sizeof(t)/sizeof(t[0]); j++ ) printf( "%d, %s\n", t[j].i, t[j].s ); rnek 8.3-2 adryapi2.c program. #include <stdio.h> struct yapi { int i; char *s; }; struct yapi t[ ] = { 30, "ABC", 40, "EFG", 50, "MNO" }; struct yapi *p = t; int main(void) { char c; int j; printf( "p->i : %d, p->s : %s\n", p->i, p->s ); j = ++p->i; printf( "islem 1 : \t p->i : %d, p->s : %s, j : %d\n", p->i, p->s, j ); j = p++->i; printf( "islem 2 : \t p->i : %d, p->s : %s, j : %d\n", p->i, p->s, j ); c = *p->s++; printf( "islem 3 : \t p->i : %d, p->s : %s, c : %c\n", p->i, p->s, c ); c = *p++->s; printf( "islem 4 : \t p->i : %d, p->s : %s, c : %c\n", p->i, p->s, c ); c = *p--->s; printf( "islem 5 : \t p->i : %d, p->s : %s, c : %c\n", p->i, p->s, c ); j = (++p)->i; printf( "islem 6 : \t p->i : %d, p->s : %s, j : %d\n", p->i, p->s, j ); j = p->i++; printf( "islem 7 : \t p->i : %d, p->s : %s, j : %d\n", p->i, p->s, j );

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-24

...rnek 8.3-2 devam


c = (*p->s)++; printf( "islem 8 : \t p->i : %d, p->s : %s, c : %c\n", p->i, p->s, c ); return 0; } kt p->i : 30, p->s : ABC islem 1 : p->i : 31, p->s : ABC, j : 31 islem 2 : p->i : 40, p->s : EFG, j : 31 islem 3 : p->i : 40, p->s : FG, c :E islem 4 : p->i : 50, p->s : MNO, c : F islem 5 : p->i : 40, p->s : FG, c :M islem 6 : p->i : 50, p->s : MNO, j : 50 islem 7 : p->i : 51, p->s : MNO, j : 50 islem 8 : p->i : 51, p->s : NNO, c : M

Programda yer alan dier 8 ilem ve ilgili deyimler unlardr: lem 1:


j = ++p->i;

Bu deyim ile yap dizisinin, p adres deikenin iaret ettii yapsnn i elemannn deeri arttrlr. Daha sonra yeni deer j deikenine atanr. Ekrana 31 deeri ve ABC dizgisi yazlr. Bu deyim parantezler kullanlarak aadaki ekilde yazlabilir: j = ++(p->i);

lem 6:

j = (++p)->i;

i elemannn deerini almadan nce adres deikeninin deerini arttrmak iin (++p)->i ifadesi kullanlabilir. ktda da grld gibi, bu deyim sonrasnda p adres deikeni dizideki bir sonraki yapya iaret eder ve ekrana bu yapnn elemanlarnn deerleri listelenir. j deikenine arttrma sonras eriilen i elemannn deeri (50) atanr. Bu ilemde parantezler kullanlarak operatr etkisi deitirilmitir.

lem 2:

j = p++->i;

ktda da grld gibi, bu deyim ile i elemannn deeri j deikenine atandktan sonra adres deikeninin deeri arttrlarak bir sonraki yapya iaret etmesi salanr. Parantezler kullanlarak yazlan aadaki ifade ile ayndr: j = (p++)->i;

lem 7:

j = p->i++;

Bu deyimde, i elemannn deeri j deikenine atandktan sonra arttrlr. Dolaysyla ekranan j'nin deeri olarak 50, i elemannn deeri olarak ise 51 yazlr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-25

lem 3:

c = *p->s++;

p->s adres deikeni "EFG" karakter dizisinin balang elemanna iaret eder. Dolaysyla bu deyimde, *p->s ile alnan 'E' deeri c deikenine atanr ve s'in bir sonraki karakter alanna (F karakterinin bulunduu alan) iaret etmesi salanr (*s++ gibi).

lem 4:

c = *p++->s;

s'in iaret ettii karakter (F) alndktan sonra p'nin deeri arttrlr. p adres deikeni dizide bulunan bir sonraki yapya iaret eder.

lem 5:

c = *p--->s;

Yukardaki ilemin tersi. s'in iaret ettii karakter (M) alndktan sonra p'nin deeri eksiltilir. p adres deikeni dizide bulunan bir nceki yapya iaret eder.

lem 8:

c = (*p->s)++;

Bu deyimde s'in iaret ettii deer c deikenine atandktan sonra arttrlr. s'in iaret ettii alanda saklanan M karakterinin ASCII deeri arttrldnda N karakterinin ASCII deerine eit olaca iin ekrana "NNO" dizgisi yazlr.

Yap deikenlerine iaret eden adres dizisi :


Ayn ablona sahip birden fazla yap deikenine ihtiya duyulduunda, yap dizisi bildirilebilir. struct proje yap tipindeki, N sayda yap deikeni iin, p yap dizisi aadaki ekilde bildirilir :
struct proje p[ N ];

Fakat eleman says arttnda, dizi elemanlarna eriim yavalar ve ilemlerde kullanlan bellek miktar artar. C dilinde, elemanlar yaplara iaret eden adres deikenleri olan adres dizisi bildirilebilir. Adres dizisi ile eriim daha hzl gerekleir ve yap dizisi zerinde yaplan ilemlerde bellek tasarrufu salanr. Aada, struct proje tipindeki yaplarn bellek adresini tayan N adet adres deikeninden oluan adr_dizi adres dizisi bildirilir:
struct proje *adr_dizi[ N ];

rnek 8.3-3'de typedef kullanlarak BILGI yap veri ismi tanmlanr. Yeni veri ismi tanmlanrken byk harf kullanlarak szkonusu veri isminin programc tarafndan oluturulduu belirtilir ve bu yolla programn okunabilirlii artm olur. Ayn veri ismi #define n-ilemci komutu kullanlarakta tanmlanabilir. Tek fark typedef deyimleri derleyici tarafndan, #define deyimleri ise n-ilemci tarafndan ilenir. Fakat baz durumlarda n-ilemci tarafndan yaplamayan karmak metin deitirme ilemleri, typedef kullanldnda derleyici tarafndan yaplabilir. Programda BILGI[3] tipinde p yap dizisi bildirilir. Daha sonra, yine 3 elemanl adres dizisi adr_dizi bildirilir. lk for
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-26

dngs ile adr_dizi dizisine p yap dizisinin eleman olan yap deikenlerinin bellek adresleri atanr. kinci for dngsnde ise, adres dizisi araclyla eriilen yaplarn elemanlarnn deerleri listelenir. Programda son olarak i ie iki for dngs kullanlarak yaplarn isim elemanlarnn iaret ettii dizgilerin karakterleri birer birer listelenir. rnein i deikeninin deeri 0 olduunda (adr_dizi[0]->isim) adres deikeni abc dizgisine iaret eder. (adr_dizi[0]->isim)[ j ] ifadesindeki j deikeninin deeri dizgi sonunu belirten '\0' karakterine rastlanncaya kadar arttrlarak abc dizgisi boyunca ilerlenir ve karakterler ekrana listelenir. Bo karaktere rastlannca for dngsnden klr ve ayn ilemler p dizisinin bir sonraki yapsnn isim eleman ile tekrarlanr.
rnek 8.3-3 adryapi3.c program. #include <stdio.h> #define EL_SAYI(s) sizeof(s)/sizeof(s[0]) typedef struct { char *isim, *adres, *tel_no; int yas; } BILGI; BILGI p[ ] = { { "abc", "xxx", { "def", "yyy", { "mno", "zzz", }; BILGI *adr_dizi[ EL_SAYI(p) ]; #include <stdio.h> int main(void) { int i, j; for ( i = 0; i < EL_SAYI(p); i++) *( adr_dizi + i ) = p + i; printf("sizeof( p ) : %d, sizeof( adr_dizi ) : %d\n", sizeof( BILGI[ EL_SAYI(p) ] sizeof( BILGI*[ EL_SAYI(p) ] puts("yapi elemanlari :"); for ( i = 0; i < EL_SAYI(p); i++) printf("%4s, %4s, %8s, %3d\n", adr_dizi[i]->isim, adr_dizi[i]->adres, adr_dizi[i]->tel_no, adr_dizi[i]->yas ); for ( i = 0; i < EL_SAYI(p); i++) for (j = 0; (adr_dizi[i]->isim)[ j ] ; j++ ) printf(" %c\n", (adr_dizi[i]->isim)[ j ] ); return 0; } C PROGRAMLAMA DILI, 1997 Ismet Kocaman "123 456", 23 }, "789 012", 34 }, "890 123", 30 },

), ) );

8-27

...rnek 8.3-3 devam


kt sizeof( p ) : 24, sizeof( adr_dizi ) : 6 yapi elemanlari : abc, xxx, 123 456, 23 def, yyy, 789 012, 34 mno, zzz, 890 123, 30 a b c d e f m n o

rnek 8.3-4'de yap adres deikeni kullanmlar rneklenmitir. lk olarak typedef kullanlarak yap veri tipi ismi YAPI tanmlanr. YAPI tipi, tamsay i deikeni, tamsay verilere iaret eden pi adres deikeni ve dizgilere iaret eden t adres deikeninden oluur. Programda, YAPI tipinde 4 yap deikeninden oluan yap dizisi YDizi, YAPI tipindeki yap deikenlerine iaret eden aYapi adres deikeni ve yine elemanlar YAPI tipindeki yaplara iaret eden yap adres dizisi aDizi bildirilir.
rnek 8.3-4 adryapi4.c program. #include <stdio.h> #define BOY 4 #define ELNo(s) sizeof(s)/sizeof(s[0]) typedef struct { int i, *pi; char *t; } YAPI; YAPI YDizi[BOY], *aYapi, *aDizi[BOY]; int n[ ] = { 2, 4, 1, 3 }; char *s[ ] = { "iki", "dort", "bir", "uc" }; void Listele( YAPI ** ); void Sirala( YAPI ** ); int main( void ) { int j; /* yapi dizisine ve adres dizisine deger atama */ for ( j = 0; j < BOY; j++ ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-28

...rnek 8.3-4 devam


{ YDizi[j].i = YDizi[j].pi YDizi[j].t aDizi[j] } printf( "YDizi'nin eleman sayisi : %d\n", ELNo(YDizi) ); printf( "YDizi'nin bir elemaninin byte sayisi : %d\n", sizeof(YAPI) ); /* yapi dizisinin elemanlarinin degerlerinin listelenmesi */ for ( j = 0; j < BOY; j++ ) printf( "YDizi[%d].i : %d, *YDizi[%d].pi : %d, YDizi[%d].t : %s\n", j, YDizi[j].i, j, *YDizi[j].pi, j, YDizi[j].t ); /* yapi dizisinin elemanlarinin degerlerinin listelenmesi */ for ( j = 0; j < BOY; j++ ) { printf("(*(YDizi+%d)).i : %d,", j, (*(YDizi+j)).i ); printf("*(*(YDizi+%d)).pi : %d,", j, *(*(YDizi+j)).pi ); printf("(*(YDizi+%d)).t : %s\n", j, (*(YDizi+j)).t ); } /* yapi dizisinin elemanlarinin degerlerinin listelenmesi */ aYapi = YDizi; printf("\naYapi->i : %d, *aYapi->pi : %d, aYapi->t : %s, ", aYapi->i, *aYapi->pi, aYapi->t ); printf("*(++aYapi)->pi : %d\n", *(++aYapi)->pi ); --aYapi; Listele( &aYapi ); printf("aYapi->i : %d, *aYapi->pi : %d, aYapi->t : %s\n", aYapi->i, *aYapi->pi, aYapi->t ); printf("\nSiralama Oncesi degerler ...\n"); for ( j = 0; j < BOY; j++ ) { printf( "aDizi[%d]->i : %d, *aDizi[%d]->pi : %d,", j, aDizi[j]->i, j, *aDizi[j]->pi ); printf( "aDizi[%d]->t : %s\n", j, aDizi[j]->t ); } Sirala( aDizi ); printf( "\nSiralama Sonrasi degerler ...\n" ); for ( j = 0; j < BOY; j++ ) { printf( "aDizi[%d]->i : %d, *aDizi[%d]->pi : %d,", j, aDizi[j]->i, j, *aDizi[j]->pi); C PROGRAMLAMA DILI, 1997 Ismet Kocaman *(n + j); = (n + j); = *(s + j); = &YDizi[j];

8-29

...rnek 8.3-4 devam


printf( "aDizi[%d]->t : %s\n", } return 0; } void Listele( YAPI **aaYapi ) { puts("Listele ... "); printf("(*aaYapi)->i : %d, *(*aaYapi)->pi : %d, (*aaYapi)->t : %s\n", (*aaYapi)->i, *(*aaYapi)->pi, (*aaYapi)->t ); (*aaYapi)++; } void Sirala( YAPI *aaDizi[ ] ) { int n, m; YAPI *T; for ( n = 0; n < BOY; n++ ) for ( m = n+1; m < BOY; m++ ) if ( *aaDizi[n]->pi > *aaDizi[m]->pi ) { T = aaDizi[m]; aaDizi[m] = aaDizi[n]; aaDizi[n] = T; } } kt YDizi'nin eleman sayisi : 4 YDizi'nin bir elemaninin byte sayisi : 6 YDizi[0].i : 2, *YDizi[0].pi : 2, YDizi[0].t : iki YDizi[1].i : 4, *YDizi[1].pi : 4, YDizi[1].t : dort YDizi[2].i : 1, *YDizi[2].pi : 1, YDizi[2].t : bir YDizi[3].i : 3, *YDizi[3].pi : 3, YDizi[3].t : uc (*(YDizi+0)).i (*(YDizi+1)).i (*(YDizi+2)).i (*(YDizi+3)).i : 2,*(*(YDizi+0)).pi : 2,(*(YDizi+0)).t : 4,*(*(YDizi+1)).pi : 4,(*(YDizi+1)).t : 1,*(*(YDizi+2)).pi : 1,(*(YDizi+2)).t : 3,*(*(YDizi+3)).pi : 3,(*(YDizi+3)).t : iki : dort : bir : uc j, aDizi[j]->t );

aYapi->i : 2, *aYapi->pi : 2, aYapi->t : iki, *(++aYapi)->pi : 4 Listele ... (*aaYapi)->i : 2, *(*aaYapi)->pi : 2, (*aaYapi)->t : iki aYapi->i : 4, *aYapi->pi : 4, aYapi->t : dort Siralama Oncesi degerler ... aDizi[0]->i : 2, *aDizi[0]->pi : 2,aDizi[0]->t : iki aDizi[1]->i : 4, *aDizi[1]->pi : 4,aDizi[1]->t : dort C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-30

...rnek 8.3-4 devam


aDizi[2]->i : 1, *aDizi[2]->pi : 1,aDizi[2]->t : bir aDizi[3]->i : 3, *aDizi[3]->pi : 3,aDizi[3]->t : uc Siralama Sonrasi degerler ... aDizi[0]->i : 1, *aDizi[0]->pi : 1,aDizi[0]->t : bir aDizi[1]->i : 2, *aDizi[1]->pi : 2,aDizi[1]->t : iki aDizi[2]->i : 3, *aDizi[2]->pi : 3,aDizi[2]->t : uc aDizi[3]->i : 4, *aDizi[3]->pi : 4,aDizi[3]->t : dort

for dngs blounda, YDizi ve aDizi dizilerine deer atama yaplr. YDizi'deki yaplarn i ve pi elemanlarna srasyla, n dizisinin elemanlarnn deerleri ve adresleri atanr; t elemanna ise dizgilere iaret eden s adres dizisinin elemanlarnn deerleri olan dizgi adresleri atanr. Ayrca aDizi adres dizisine, YDizi'de bulunan yaplarn bellek adresleri atanr. Bylece, aDizi'nin elemanlar olan adres deikenleri, YDizi'nin elemanlar olan yaplara iaret eder. YDizi, YAPI[BOY] tipindedir. aDizi ise YAPI*[BOY] tipindedir. Atama deyimi,
aYapi = YDizi;

ile aYapi adres deikeninin YDizi'nin balang elemanna iaret etmesi salanr. Bunu izleyen printf satrnda, aYapi kullanlarak yap dizisinin balang elemannn deerleri listelenir. Ok operatr (->), indirek deer operatrnden (*) daha yksek ncelie sahip olduu iin, *aYapi->pi ifadesinde parantez kullanlmamtr. Fakat okunabilirlii arttrmak iin *(aYapi->pi) ifadesi kullanlabilir. aYapi adres deikeni balangta, YDizi[0] yapsna iaret ettii iin,
*(++aYapi)->pi

ifadesi dizideki bir sonraki yapnn elemanlarna eriimi salar. aYapi adres deikenine -- operatr uygulanarak, tekrar dizi balangcna iaret etmesi salanr. Listele fonksiyonu balnda bildirilen ift adres deikeni aaYapi, ar ile aktarlan aYapi adres deikeninin adresini alr (Bu bildirim, YAPI *aaYapi[ ] eklinde yaplabilir). Bylece aran bloktaki aYapi adres deikeninin tad adres deerini deitirebilir. ktda da grld gibi Listele fonksiyonu, aaYapi aracl ile yap elemanlarna eriir ve (*aaYapi)++ ifadesi ile aYapi adres deikeninin deerini arttrarak dizideki bir sonraki yapya iaret etmesini salar ve aran bloa dner. Listele blounda yer alan *(*aaYapi)->pi ifadesinde yine ilave parantezlere gerek yoktur. Bunun yerine *( (*aaYapi)->pi ) kullanm sadece okunabilirlii arttrr. Listele bloundaki, (*aaYapi)->i ifadesinde *aaYapi dndaki parantezler gereklidir. nk -> operatr daha yksek ncelie sahiptir ve parantezler kullanlmad taktirde, *aaYapi->i ifadesi *(aaYapi->i) ile ayndr ve i bir adres deikeni olmad iin hata oluur.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-31

Listele arsndan sonra aYapi adres deikeni kullanlarak gerekletirilen eriim, dizideki bir sonraki yapy listeler. Programda son olarak aDizi adres dizisi kullanlarak yap dizisi elemanlar sralanr. Sralama ilemi adres dizisi zerinde yapld iin, YDizi'deki sralama deimez (ekil 8.3-3). Sirala fonksiyonuna argman olarak aDizi aktarlr. Sirala fonksiyonu adres dizisinin balang elemannn bellek adresini alarak aDizi dizisinin elemanlarnn deerlerine eriir. Bu adres deerleri aracl ile yapnn elemanlarna erierek aadaki test ifadesi ile karlatrma yapar:
*aaDizi[n]->pi > *aaDizi[m]->pi

Daha sonra, adres deerleri aktarlarak sralama yaplr. ar sonras aDizi adres dizisi kullanlarak sralanm deerler ekrana yazlr. ekil 8.3-3'de Sirala ve Listele arlar ncesi ve sonras sembolik bellek grnm verilmitir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-32

ekil 8.3-3 Sralama ncesi sembolik bellek grnm.


Bellek aDizi[0] : aDizi[1] : aDizi[2] : aDizi[3] :

:
YDizi YDizi+1

aDizi adres dizisi


YDizi+2 YDizi+3

: :
aYapi :
YDizi

aYapi adres deikeni

: :
YDizi[0] :
2 n s[0]

YDizi[0].i YDizi[0].pi YDizi[0].t

YDizi[1] :

4 n+1 s[1]

YDizi[2] :

YDizi yap dizisi


1 n+2 s[2]

YDizi[3] :

3 n+3 s[3]

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-33

ekil 8.3-3 devam...


Sralama sonras aDizi adres dizisinin ve Listele fonksiyonu arldktan sonra aYapi adres deikeninin sembolik bellek grnm:
Bellek aDizi[0] : aDizi[1] : aDizi[2] : aDizi[3] :

:
YDizi+2 YDizi

aDizi adres dizisi


YDizi+3 YDizi+1

: :
aYapi :
YDizi+1

aYapi adres deikeni

: :
YDizi[0] :
2 n s[0]

YDizi[0].i YDizi[0].pi YDizi[0].t

YDizi[1] :

4 n+1 s[1]

YDizi[2] :

YDizi yap dizisi


1 n+2 s[2]

YDizi[3] :

3 n+3 s[3]

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-34

ekil 8.3-3 devam...


n ve s dizilerinin sembolik bellek grnm:
YDizi[1].pi YDizi[3].pi YDizi[2].pi YDizi[0].pi

Bellek

:
n[0] : n[1] : n[2] : n[3] :
2 4

n dizisi
1 3

YDizi[1].t

YDizi[0].t

YDizi[3].t

YDizi[2].t

: :
s[0] : s[1] : s[2] : s[3] : ... ... s dizisi ... ...

: :
'i' 'k' 'i' '\0' 'd' 'o' 'r' 't' '\0' 'b' 'i' 'r' '\0' 'u' 'c' '\0'

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-35

Yap eleman olarak fonksiyona iaret eden adres deikeni :


Bir fonksiyon ismi, fonksiyonun adresini verir. nceki blmlerde anlatld gibi, basit bir fonksiyona iaret eden adres deikeni aadaki ekilde oluturulur: fonksiyon bildirimi:
void fonk1( void );

fonksiyona iaret eden adres deikeni bildirimi:


void (*adr_fonk)( void );

atama ile adres deikeninin fonksiyona iaret etmesi salanr:


adr_fonk = fonk1;

Aadaki rnek programda bildirilen YDizi yap dizisi, elemanlar karakter dizisine ve fonksiyona iaret eden adres deikenleri olan FYapi tipindeki yaplardan oluur. YDizi[ 0 ] ve YDizi[ 1 ], FYapi tipinde yaplardr. YDizi[0].adr_fonk ve YDizi[1].adr_fonk yap elemanlar ise fonksiyona iaret eden adres deikenleridir. Bu ifadelerde indeks operatr ([ ]) ile dizinin eleman olan herhangi bir yap deikenine ve yap eleman operatr (.) kullanlarakta bu yapnn eleman olan adres deikenine eriim gerekletirilir. Programda grld gibi fonksiyon arlar, (*YDizi[ i ].adr_fonk)( ) deyimi ile yaplr. Nokta operatr (.), indirek deer operatrnden (*) daha yksek ncelie sahip olduu iin YDizi[ i ].adr_fonk ifadesi parantezlerle snrlandrlmamtr.
rnek 8.3-5 adryapi5.c program. #include <stdio.h> #define EL_SAY(s) sizeof(s)/sizeof(s[0]) typedef struct /* etiket ismi kullanilabilir */ { char *FAdi; void (*adr_fonk)(void); } FYapi; void fonk1( void ), fonk2( void ), fonk3( void ); FYapi YDizi[ ] = { { "fonk1", fonk1 }, { "fonk2", fonk2 } };

int main(void) { int i; C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-36

...rnek 8.3-5 devam


for ( i = 0; i < EL_SAY( YDizi ); i++ ) { printf(" YDizi[%d].FAdi : %s --> ", i, YDizi[i].FAdi ); (*YDizi[ i ].adr_fonk)(); } puts( " fonksiyon adresleri : "); printf("\t\t fonk1 : %p, fonk2 : %p, fonk3 : %p\n", fonk1, fonk2, fonk3 ); puts( " eleman adresleri : "); printf("\t\t YDizi[0].adr_fonk : %p, YDizi[1].adr_fonk : %p\n", /* fonk2 referansinin fonk3 olarak degistirilmesi */ YDizi[1].adr_fonk = fonk3; YDizi[1].FAdi = "fonk3"; puts( " atama sonrasi eleman adresleri : "); printf("\t\t YDizi[0].adr_fonk : %p, YDizi[1].adr_fonk : %p\n", YDizi[0].adr_fonk, YDizi[1].adr_fonk ); printf(" YDizi[1].FAdi : %s --> ", YDizi[ 1 ].FAdi ); (*YDizi[ 1 ].adr_fonk)(); return 0; } void fonk1(void) { puts("fonksiyon 1 ..."); } void fonk2(void) { puts("fonksiyon 2 ..."); } void fonk3(void) { puts("fonksiyon 3 ..."); } kt YDizi[0].FAdi : fonk1 --> fonksiyon 1 ... YDizi[1].FAdi : fonk2 --> fonksiyon 2 ... fonksiyon adresleri : fonk1 : 00AC, fonk2 : 00BC, fonk3 : 00CC eleman adresleri : YDizi[0].adr_fonk : 00AC, YDizi[1].adr_fonk : 00BC atama sonrasi eleman adresleri : YDizi[0].adr_fonk : 00AC, YDizi[1].adr_fonk : 00CC YDizi[1].FAdi : fonk3 --> fonksiyon 3 ... C PROGRAMLAMA DILI, 1997 Ismet Kocaman YDizi[0].adr_fonk, YDizi[1].adr_fonk );

8-37

ktda listelenen adres deerlerinden de anlalaca gibi programda atama ile YDizi[1].adr_fonk adres deikeninin fonk2 yerine fonk3 fonksiyonuna iaret etmesi salanr.

Yap elemanlarnn offset'lerinin hesaplanmas :


Bir yapya iaret eden adres deikeni ile herhangi bir diziye iaret eden adres deikeni kavramsal olarak ayndr. Dizi adres deikeni dizinin her elemanna eriebildii gibi, yap adres deikeni de yapnn her elemanna eriebilir. Fakat kullanm ekilleri farkldr. Dizideki her eleman ayn tipte olduu iin, eit byklkte ve sral bellek alanlarnda bulunurlar. Dolaysyla herhangi bir dizi elemanna, bu elemann dizinin balangcndan itibaren ka byte sonra bulunduu (yani offset miktar) belli olduu iin, sralana bal olarak kullanlan saysal indeks yardm ile eriilebilir. Bu amala, aadaki her iki ifade de kullanlabilir:
dizi ismi ve indeks ifadesi : dizi[i] adres deeri ve offset ifadesi : *(dizi+i)

Tamsay i deikeni ilk ifadede indeks deikeni, ikincisinde ise offset deikenidir. Fakat yapnn her bir eleman farkl tipte olabilecei iin, bu ekilde oluturulan herhangi bir ifade kullanlarak elemanlara eriim mmkn olmaz. Her yap elemannn sembolik bir ismi vardr ve bu isim, ayr bir tip ve offset ifade eder. Yap elemanlar bellekte, yap iinde bildirildikleri srada ve artan bellek adreslerinde bulunurlar.

ANSI C'nin bir zellii olarak, yap elemanlarnn offset deerlerinin tanabilir bir ekilde saptanabilmesi iin stddef.h balk dosyasnda offsetof makrosu tanmlanmtr. Bu makro n-ilemci tarafndan geniletildiinde size_t tipinde sabit bir ifadeye dnr ve bir yap elemannn yap balangcndan itibaren offset deerini byte olarak verir:
offsetof( yapi_veri_tipi, eleman_ismi ); /* stddef.h */

yapi_veri_tipi'deki herhangi bir p yaps iin &p.eleman_ismi ifadesi bir adres sabiti olmaldr. Bu makro daha sonra anlatlacak olan bit-alanlar ile kullanlamaz. Aadaki rnek programda ilk olarak sizeof operatr kullanlarak s yapsnn bellek alan bykl ve elemanlarnn offset deerleri hesaplanr. ktda grld gibi, adr elemannn &s.adr ifadesi ile alnan bellek adresi (4628) ve hesaplanan bellek adresi (4627) ayn deildir. Donanma bal olarak, yap eleman olan veriler derleyici tarafndan 2 (yada 4) ile blnebilen bellek adreslerine yerletirilir (bu ilem alignment olarak adlandrlr). Bu nedenle, bellekte bulunan herhangi bir yap iinde isimsiz bo alanlar (donanma bal olarak bir yada daha fazla byte) oluabilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-38

rnek 8.3-6 adryapi6.c program. #include <stdio.h> #include <stddef.h> struct YAPI { int i; double f; char c, *adr; }; int main(void) { struct YAPI s = { 1, 0.7, 'A', "dizgi" }; puts("elemanlarin degerleri ve bellek adresleri:"); printf("\ti : %d, f : %1.1f, c : %c, adr : %s \n", s.i, s.f, s.c, s.adr ); printf("\t&s : %d, &s.i : %d, &s.f : %d, &s.c : %d, &s.adr : %d\n", &s, &s.i, &s.f, &s.c, &s.adr ); puts("elemanlarin -hesaplanan- offset degerleri :"); printf("\ts.i : %d, s.f : %d, s.c : %d, s.adr : %d byte.\n", /* s.i */ 0, /* s.f */ sizeof( s.i ), /* s.c */ sizeof( s.i ) + sizeof( s.f ), /* s.adr */ sizeof( s.i ) + sizeof( s.f ) + sizeof( s.c ) ); printf("s yapisinin -hesaplanan- byte sayisi : %d byte.\n", sizeof( s.i ) + sizeof( s.f ) + sizeof( s.c ) + sizeof( s.adr) ); printf("adr elemaninin -hesaplanan- bellek adresi : %d\n", (unsigned)&s + sizeof(s.i) + sizeof( s.f ) + sizeof( s.c ) ); puts("\nelemanlarin gercek offset degerleri (offsetof makrosu):"); printf("\ts.i : %d, s.f : %d, s.c : %d, s.adr : %d byte.\n", /* s.i */ offsetof( struct YAPI, i ), /* s.f */ offsetof( struct YAPI, f ), /* s.c */ offsetof( struct YAPI, c ), /* s.adr */ offsetof( struct YAPI, adr ) ); printf("s yapisi : %d byte.\n", sizeof(s) ); printf("adr elemaninin bellek adresi : %d\n", (unsigned)&s + offsetof( struct YAPI, adr ) ); return 0; } kt elemanlarin degerleri ve bellek adresleri: i : 1, f : 0.7, c : A, adr : dizgi &s : 4616, &s.i : 4616, &s.f : 4618, &s.c : 4626, &s.adr : 4628 elemanlarin -hesaplanan- offset degerleri : s.i : 0, s.f : 2, s.c : 10, s.adr : 11 byte. C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-39

... rnek 8.3-6 kt devam


s yapisinin -hesaplanan- byte sayisi : 13 byte. adr elemaninin -hesaplanan- bellek adresi : 4627 elemanlarin gercek offset degerleri (offsetof makrosu): s.i : 0, s.f : 2, s.c : 10, s.adr : 12 byte. s yapisi : 14 byte. adr elemaninin bellek adresi : 4628

rnek 8.3-6'da s yapsnn c eleman, bulunduu adresteki (4626) bir byte'lk bellek alann kullanr. adr eleman yukarda bahsedilen donanm zelliinden dolay, hemen c elemann izleyen bellek adresi (4627) yerine bir sonraki ift adrese (4628) yerletirilir. Bu nedenle, c eleman ile adr eleman arasnda bir byte'lk bo alan (hole) oluur (ekil 8.3-4).
ekil 8.3-4 s yapsnn sembolik bellek grnm.
Bellek

:
s.i 4616 s.f 4618 2 byte

8 byte

s.c 4626 s.adr 4628

1 byte
bo alan

2 byte

ktda da grld gibi, adr'nin offset deerini toplamn kullanarak hesaplayan,

elemanlarn byte saylarnn

sizeof(s.i) + sizeof(s.f) + sizeof(s.c)

ifadesi bo alan dikkate almad iin hatal sonu verir. Ayrca ayn teknik kullanlarak hesaplanan s yapsnn byte says (13) ve adr elemannn adresi (4627) hataldr. Fakat ktda grld gibi offsetof makrosu kullanlarak doru deerler elde edilir. Sonu olarak bir yapnn bellek alan, elemanlarnn sizeof ile alnan byte saylarnn
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-40

toplamna eit olmayabilir. Fakat sizeof operatr yapnn tamamna uygulandnda, yap iinde bulunan bo alanlar da dikkate aldndan dolay doru sonucu verir. Ayn ekilde, rnek 8.1-1'de sizeof operatr p2 yaps iin 19 yerine 20 byte sonucunu verir. Pek ok C derleyicisi, yap elemanlarnn bellek dzeni zerinde kontrol salayan derleyici seeneklerine yada derleyici komutlarna sahiptir. Yukarda bahsedilen donanm zelliinden baka, veri tiplerinin byte saylar da donanma gre deiir. Dolaysyla yap elemanlarnn offset deerleri de donanma gre farkllk gsterir (2byte bellek adreslerine sahip donanmdaki deerler, 4-byte bellek adreslerine sahip donanmdakilerden farkl olacaktr). Sonu olarak, C programlarnn tanabilir olmas ve hatasz alabilmesi iin, yap elemanlarnn bellek adresleri zerinde yaplan ilemlerde, saysal offset deerleri kullanlmamaldr. Bu ilemler, yukarda anlatlan teknikler kullanldnda, C derleyicisi tarafndan hatasz olarak gerekletirilir. rnek 8.3-7'de global yap ablonlar AltProje ve Proje tanmlanr. Proje ablonunun elemanlarndan biri AltProje ablonuna sahip 2 elemanl Alt yap dizisidir. Programda malloc fonksiyonu kullanlarak tek bir Proje yaps iin bellek alan ayrlr ve bu alann bellek adresi ap yap adres deikenine atanr. Daha sonra bu adres deikeni ile yap elemanlarna eriim gerekletirilir ve elemanlara eitli deerler atanr. Programn sonunda atanan bu deerler ekrana listelenir. n
rnek 8.3-7 adryapi7.c program. #include <stdio.h> #include <stdlib.h> #include <string.h> struct AltProje { char isim[15]; long Basla; long Bitis; }; struct Proje { char isim[15]; long Basla; long Bitis; struct AltProje Alt[2]; }; struct Proje *ap; int main(void) { if ( ( ap = (struct Proje *)malloc( sizeof(struct Proje) ) ) == NULL ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-41

...rnek 8.3-7 devam


{ puts("hata: bellek alani ayrilamadi"); exit(0); } strcpy( ap->isim, "Ana Proje " ); ap->Basla = 1994; ap->Bitis = 1997; strcpy( (ap->Alt[0]).isim, "Alt Proje1" ); (ap->Alt[0]).Basla = 1994; (ap->Alt[0]).Bitis = 1995; strcpy( (ap->Alt[1]).isim, "Alt Proje2" ); (ap->Alt[1]).Basla = 1995; (ap->Alt[1]).Bitis = 1997; printf("PROJE: %s, Basla : %ld, Bitis : %ld\n", ap->isim, ap->Basla, ap->Bitis ); printf("PROJE: %s, Basla : %ld, Bitis : %ld\n", (ap->Alt[0]).isim, (ap->Alt[0]).Basla, (ap->Alt[0]).Bitis ); printf("PROJE: %s, Basla : %ld, Bitis : %ld\n", (ap->Alt[1]).isim, (ap->Alt[1]).Basla, (ap->Alt[1]).Bitis ); return 0; } kt PROJE: Ana Proje , Basla : 1994, Bitis : 1997 PROJE: Alt Proje1, Basla : 1994, Bitis : 1995 PROJE: Alt Proje2, Basla : 1995, Bitis : 1997

8.4 Yap Deikenleri ve Fonksiyonlar


Yaplar fonksiyonlara argman olarak aktarlabilir. Bu durumda, yapnn tamam fonksiyonun argman alanna kopyalanr. Fonksiyon, aktarlan yapnn lokal kopyasn ald iin aran bloktaki yap elemanlarna eriemez. Fakat fonksiyona yapnn bellek adresi aktarldnda, aran bloktaki yap elemanlarna eriim mmkn olur. Sonu olarak, yaplar fonksiyonlara aadaki ekillerde aktarlabilir:
l

yapnn bellek adresinin aktarlmasyla : Bunun iin fonksiyon argman olarak, yapya iaret eden adres deikeni yada yap deikenine adres operatr (&) uygulanmas ile oluturulan ifade kullanlr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-42

Ayrca bir fonksiyon arda argman olarak yap adresi bekliyor ise, bu fonksiyonun tanmnda yer alan ve argmana karlk gelen parametre de yap adres deikeni olarak bildirilmelidir.
l arda yap ismini argman olarak kullanarak yapnn tamamnn kopyasnn aktarlmas ile:

Fakat bu durumda fonksiyon iinden aran bloktaki yapya eriilemez. Aadaki rnekte, p1 ve p2 yaps listele fonksiyonuna argman olarak aktarlr. listele fonksiyonu bu yaplarn lokal kopyalarn alr ve programn banda tanmlanan global ablon kullanlarak bildirilen proje parametresine atar. Daha sonra alnan bu deerleri ekrana listeler. listele fonksiyonu aran blokta yer alan yapya eriemez. Programda grld gibi yap ablonu etiket ismi, yap eleman isimleri yada fonksiyonun parametre isimleri ayn olabilir (listele fonksiyonunun proje parametresi).
rnek 8.4-1 yapfonk1.c program. #include <stdio.h> struct proje { char *isim; long basla; long son; }; void listele( struct proje ); int main(void) { static struct proje p1 = { "proje1", static struct proje p2 = { "proje2", listele( p1 ); listele( p2 ); p1 = p2; puts( "atama sonrasi yapi elemanlarinin degerleri :" ); listele( p1 ); listele( p2 ); return 0; } void listele( struct proje proje ) { printf("%6s %4ld %4ld\n", proje.isim, proje.basla, proje.son ); } 0L, 0L }; 1994L, 2000L };

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-43

...rnek 8.4-1 devam


kt proje1 0 0 proje2 1994 2000 atama sonrasi yapi elemanlarinin degerleri : proje2 1994 2000 proje2 1994 2000

Programda, p2 yaps p1 yapsna atanr ve atama ilemi sonras elemanlarn deerleri tekrar listele fonksiyonu arlarak ekrana listelenir. ANSI C'de bir yap, ayn tipte (ayn ablona sahip) bir baka yapya atanabilir. Fakat bo alanlar bir yap dierine atanrken, yaplar fonksiyonlara argman olarak aktarlrken yada fonksiyonlardan deer olarak dndrme srasnda kopyalanmayabilir. ki yap == operatr ile karlatrlamaz. Yaplarda boluk (padding bytes) bulunmadndan emin olunduu taktirde string.h balk dosyasnda bulunan memcmp fonksiyonu kullanlarak karlatrma yaplabilir. Ak olarak bildirim srasnda ilk deer atama yaplmadnda otomatik yaplarn ilk deerleri belirsizdir. Bu nedenle boluklarda bulunan deerler de belirsiz olacaktr. Ayrca boluklar yapnn bir paras olmasna karn isimsiz alanlar olduklar iin yap deikeni static yada global bildirildii durumlarda bile bu alanlarda bulunan ilk deerler 0 yerine belirsiz deerler olacaktr. Bu durum yaplarn bir btn olarak karlatrlmasn olanaksz klar. Bir yap iin calloc fonksiyonu (stdlib.h) kullanlarak bellek alan ayrld taktirde, ayrlan bellek alanndaki tm bit deerleri boluk alanlar da dahil olmak zere 0 olur. Fakat bu sfrlama ilemi malloc yada realloc fonksiyonlar (stdlib.h) tarafndan yaplmaz. memset fonksiyonu (string.h) kullanlarak bellek alan sfrlanabilir ve daha sonra memcmp ile karlatrma ilemi yaplabilir. Sonu olarak karlatrma ilemi elemanlar karlatrlarak yaplmaldr. Bu tanabilir bir tekniktir. C programlarnda yaplarn atanmas ve karlatrlmas pek sk gerek duyulan ilemler deildir. Programda p1 ve p2 yaplar oluturulan program kodu ve hz asndan daha verimli olaca iin blok ii static olarak bildirilmitir. rnek 8.4-2'de, struct proje tipinde p yap dizisi ve s yaps bildirilir. Daha sonra yap dizisinin herbir elemannn adres operatr ile alnan bellek adresi proje_oku fonksiyonuna argman olarak aktarlr. Yapya ekrandan deer okuyan proje_oku ve yapnn deerlerini ekrana listeleyen proje_list fonksiyonlarnn tanmnda parametre olarak, struct proje tipindeki yaplara iaret eden adres deikeni bildirilir. Dolaysyla, her iki fonksiyon da aldklar adres deerlerini bu adres deikenine atayarak, aran blokta yer alan yap (main fonksiyonunun lokal yaps) zerinde ilemler yapar.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-44

rnek 8.4-2 yapfonk2.c program. #include <stdio.h> #include <string.h> #define EL_SAYI 3 #define DIZGI_BOY 10 struct proje { char isim[ DIZGI_BOY + 1 ]; long basla; long son; }; void proje_oku ( struct proje * ); void proje_list( struct proje * ); int main(void) { static struct proje s = { "proje s", 1991L, 2000L }; static struct proje p[ EL_SAYI ]; int i; for ( i = 0; i < EL_SAYI; ++i ) proje_oku ( &p[i] ); for ( i = 0; i < EL_SAYI; ++i ) proje_list( &p[i] ); proje_list( &s ); printf( "%10s %4ld %4ld\n", s.isim, s.basla, s.son ); return 0; } void proje_oku( struct proje *ap ) { printf( "proje ismi, baslama, bitis ? " ); scanf( "%10s%ld%ld", ap->isim, &ap->basla, &ap->son ); } void proje_list( struct proje *ap ) { printf("%10s %4ld %4ld\n", ap->isim, ap->basla, ap->son ); if ( !strcmp( ap->isim, "proje s" ) ) strcpy( ap->isim, "PROJE S" ); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-45

...rnek 8.4-2 devam


Bilgi Girii proje ismi, baslama, bitis ? proje ismi, baslama, bitis ? proje ismi, baslama, bitis ? kt proje1 proje2 proje3 proje s PROJE S 1991 1992 1992 1994 1994 1995 1991 2000 1991 2000 proje1 1991 1992 proje2 1992 1994 proje3 1994 1995

proje_list fonksiyonu sadece yap elemanlarnn deerlerini listeledii iin, aran blokta yer alan yapya eriimi gerekmez. Yani proje_list fonksiyonu, parametre olarak struct proje tipindeki adres deikeni yerine, struct proje tipindeki herhangi bir yap deikeni ile tanmlanabilir. Bu durumda, ar ile yapnn tamam aktarlr ve fonksiyon yapnn lokal kopyasn alr. Programda ayrca, aran bloktaki yap elemanlarnn deerlerine adres deikeni araclyla eriimi gstermek iin proje_list fonksiyonu iinde s yapsnn isim elemanna "PROJE S" dizgisi atanr. Bellek tasarrufu szkonusu olduunda, adres aktarm tercih edilmelidir. Programda her iki fonksiyona da yaplan arlarda, yap dizisi elemanlarndan birinin adresi aktarld. Fonksiyonlar, tekbir yap adresi alacak ekilde tanmland iin, yap dizisinin herhangi bir elemann adresinin aktarm ile tek bir yapnn adresinin aktarm arasnda fark olmayacaktr. Dolaysyla, proje_list( &p[i] ) ve proje_list( &s ) arlarnn her ikisi de, tek bir proje yapsnn bellek adresini aktarr. C dilinde bir diziyi bir fonksiyona deeri ile aktarmak mmkn deildir. Ancak dizinin adresi aktarlabilir. Dolaysyla fonksiyon, dizinin bellek alanlarna eriebilir. Fakat herhangi bir dizinin, aadaki indirek metod kullanlarak adresi yerine deerleri aktarlabilir ve bu yolla fonksiyonun asl diziye eriimi nlenmi olur. Bu amala rnek 8.4-3'de eleman dizi olan global yap deikeni s tanmlanr. Bu yapnn eleman olan Dizi dizisine, main blou iinde strcpy fonksiyonu kullanlarak "Dizilerin degerleri " dizgisi (karakter dizisi) kopyalanr. Yaplar fonksiyonlara deerleri ile aktarld iin, s yaps fonk fonksiyonu arsnda argman olarak kullanlr ve bu yolla ayn dizgi fonk fonksiyonuna aktarlr. Programda da grld gibi fonk fonksiyonunun parametre ismi global yap deikeni ile ayn olabilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-46

rnek 8.4-3 yapfonk3.c program. #include <stdio.h> #include <string.h> struct YAPI { char Dizi[ 50 ]; }; struct YAPI s; void fonk( struct YAPI s ) { strcat( s.Dizi, "ile aktarilmasi ... " ); printf("fonk icinde s.Dizi : \n\t%s\n", s.Dizi ); } int main(void) { strcpy( s.Dizi, "Dizilerin degerleri " ); printf("fonk cagrisi oncesi - main - s.Dizi : \n\t%s\n", s.Dizi ); fonk( s ); printf("fonk cagrisi sonrasi - main - s.Dizi : \n\t%s\n", s.Dizi ); return 0; } kt fonk cagrisi oncesi - main - s.Dizi : Dizilerin degerleri fonk icinde s.Dizi : Dizilerin degerleri ile aktarilmasi ... fonk cagrisi sonrasi - main - s.Dizi : Dizilerin degerleri

ktda da grld gibi Dizi dizisi, fonk blou iinde yeni bir dizgi eklendii halde deimeden kalr. Fakat bu uygulamann baz sakncalar vardr. Fonksiyon ars srasnda argman deerleri programn yt (stack) alanna kopyalanr. Eer bu yolla byk bir dizi aktarlyor ise, dizi elemanlar snrl yt alannda ok yer kaplar. Fakat dizi isminin argman olarak yer ald bir arda, tek bir adres deeri aktarlaca iin fazla yt alan kullanlmam olur. Bir fonksiyon, yap deeri dndrecek ekilde tanmlanabilir. Aadaki programda struct SAYI tipinde s1, s2 ve stoplam yaplar bildirilir. Ayrca prototipte de grld gibi, struct SAYI tipindeki iki yapy argman olarak alan ve bu yaplarn elemanlarnn toplamn yine ayn tipteki n yaps ile dndren YapiTopla fonksiyonu tanmlanr. Fonksiyon ars ile YapiTopla fonksiyonunun argman alanna s1 ve s2 yaplarnn a
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-47

ve b elemanlarnn deerleri kopyalanr. ar satrna dndrlen deerler stoplam yapsna atanr. Bylece ayn tipteki iki yapnn elemanlarnn deerlerinin toplam, argman olarak yap deeri alan ve yine yap deeri dndren bir fonksiyon kullanlarak elde edilir.
rnek 8.4-4 yapfonk4.c program. #include <stdio.h> struct SAYI { int a, b; }; struct SAYI YapiTopla( struct SAYI, struct SAYI ); int main(void) { struct SAYI s1 = { 10, 20 }, s2 = { 50, 100 }, stoplam; printf( "s1.a : %d, s1.b : %d\n", s1.a, s1.b ); printf( "s2.a : %d, s2.b : %d\n", s2.a, s2.b ); stoplam = YapiTopla( s1, s2 ); printf( "stoplam.a : %d, stoplam.b : %d\n", stoplam.a, stoplam.b ); return 0; } struct SAYI YapiTopla( struct SAYI i, struct SAYI j ) { struct SAYI n; n.a = i.a + j.a; n.b = i.b + j.b; return ( n ); } kt s1.a : 10, s1.b : 20 s2.a : 50, s2.b : 100 stoplam.a : 60, stoplam.b : 120

rnek 8.4-5'de fonk fonksiyonuna yap adresi aktarlr ve fonksiyon yapya iaret eden adres deikeni dndrr. fonk fonksiyonu iinde malloc fonksiyonu kullanlarak P1 ablonuna sahip tek bir yap iin bellek alan ayrlr ve bu alann adresi yine ayn fonksiyon iinde tanmlanan ap1 yap adres deikenine atanr. Bu adres deikeni kullanlarak bellekte yap iin ayrlan alanlara eitli deerler atanr. fonk ars, ap1'in tad adres deerini dndrr ve ar satrnda bu deer s1 yap adres deikenine atanr. s1 ile oluturulan ifadeler kullanlarak bu alanlara atanan deerler ekrana listelenir. n
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-48

rnek 8.4-5 yapfonk5.c program. #include <stdio.h> #include <stdlib.h> struct P1 { char *m[3]; int n[3]; }; struct P2 { char *m; int n; }; struct P1 *fonk( struct P2 * ); int main(void) { struct P1 *s1; struct P2 s2 = { "bir", 1 }; s1 = fonk( &s2 ); printf("%s : %d\n", s1->m[0], s1->n[0] ); printf("%s : %d\n", s1->m[1], s1->n[1] ); printf("%s : %d\n", s1->m[2], s1->n[2] ); return 0; } struct P1 *fonk( struct P2 *ap2 ) { struct P1 *ap1; if ( ( ap1 = (struct P1 *)malloc( sizeof( struct P1 ) ) ) == NULL ) { puts("fonk hata: bellek alani ayrilamadi"); exit(0); } ap1->m[0] = "sifir"; ap1->m[1] = ap2->m; ap1->m[2] = "iki"; ap1->n[0] = 0; ap1->n[1] = ap2->n; ap1->n[2] = 2; return ap1; }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-49

...rnek 8.4-5 devam


kt sifir : 0 bir : 1 iki : 2

8.5 Union Deikeni


Bir union deikeni (yada ksaca union), format olarak yap deikenine benzer fakat kullanm amac farkldr. Union deikeni kullanlarak farkl zamanlarda, farkl tiplerde veriler ayn bellek alannda saklanabilir. Bir yap deikeni, derleyicinin bildirilmi olan elemanlarn tamam iin bellek alan ayrmasn salar. Bir union ise sadece en byk eleman kadar bellek alan kullanr. Bir yap deikeninin elemanlar birbirini izleyen ayr bellek alanlarnda bulunur. Bir union deikeninin elemanlar ise bellekte st ste bulunur. Bir union deikeni, en byk elemann saklayacak kadar bellek alanna sahip ve tm elemanlarnn offset'leri 0 olan yap gibi dnlebilir. Union deikeni ok sk kullanlmaz. Ancak baz sistem seviyesinde programlama gerektiren uygulamalarda kullanlrlar. Bildirim ekli yap deikenine benzer, fakat bildirimde struct anahtar szc yerine union anahtar szc kullanlr:
union [etiket_ismi] { union eleman bildirimleri ...; } union_degiskeni;

Union deikenine bildirilen elemanlarn herhangi birinin tipindeki deerler atanabilir. Elemanlara eriim yap deikenlerinde olduu gibi nokta operatr kullanlarak gerekletirilir:
union_degiskeni.eleman_ismi

yada union deikenine iaret eden bir adres deikeni kullanlarak aadaki ifade ile gerekletirilir:
union_adres_degiskeni->eleman_ismi

rnek 8.5-1'de 3 elemanl union deikeni u bildirilir ve elemanlarna eitli deerler atanr. Daha sonra Listele fonksiyonu kullanlarak atanan deerler ekrana listelenir. Bir union deikeninin en son deer atanan elemanna eriilebilir. Farkl bir elemana eriim yapldnda elde edilecek deer kullanlan derleyici ve donanma gre
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-50

(implementation-dependent) deiir ve belirsizdir (rnek 8.5-1'de yer alan son atama ileminde olduu gibi). Bir union deikeninin bellek alan dzenlemesi derleyici tarafndan yaplr fakat en son hangi elemanna atama yapld programc tarafndan izlenmelidir. Dolaysyla rnek 8.5-1'de bu amala utip deikeni kullanlmtr. Bir union deikenine ilk deer atama, bildirim srasnda ilk elemann tipinde oklu parantezlerle snrl sabit bir deer kullanlarak yaplabilir. Dier elemanlara ilk deer atama yaplamaz. Dolaysyla sadece ilk deer atama srasnda elemanlarn sras sz konusudur. Atanan herhangi bir ilk deer ilk elemann tipine gre yorumlanr. lk deer atama yaplmayan global yada static union deikeninin ilk deerleri 0, otomatik union'larn ise belirsizdir. Yap deikenleri ile yaplan ilemlerin ayns union deikenlerine de uygulanr: atama, bir btn olarak kopyalama, adresinin alnmas ve elemanlarna eriim gibi.
rnek 8.5-1 union1.c program. #include <stdio.h> #define TAMSAYI 1 #define DOUBLE 2 #define DIZGI 3 union SAYILAR { int i; double d; char *s; }; void Listele( union SAYILAR, int ); int main(void) { union SAYILAR u = { 55 }; /* u.i = 55 */ int utip; utip = TAMSAYI; Listele( u, utip ); u.d = 27.91; utip = DOUBLE; Listele( u, utip ); u.s = "dizgi"; utip = DIZGI; Listele( u, utip ); u.s = "dizgi"; utip = 4; Listele( u, utip ); u.d = 27.91; C PROGRAMLAMA DILI, 1997 Ismet Kocaman /* hatali tip */

8-51

...rnek 8.5-1 devam


utip = TAMSAYI; /* hatali tip */ Listele( u, utip ); return 0; } void Listele( union SAYILAR u, int utip ) { switch( utip ) { case TAMSAYI: printf("%d\n", u.i ); break; case DOUBLE: printf("%.2f\n", u.d ); break; case DIZGI: printf("%s\n", u.s ); break; default: printf("bilinmeyen union tipi : %d\n", utip ); } /* switch */ } kt 55 27.91 dizgi bilinmeyen union tipi : 4 23593

Bir union deikeni, yap deikeni yada dizi iinde bulunabilir. Bunun tersi de geerlidir yani bir union deikeni iinde bir yap deikeni yada dizi bulunabilir. Eriim yine yap deikenlerinde olduu gibi gerekletirilir. rnek 8.5-2'de yap dizisi YDizi'nin elemanlar bir union ieren yap deikenleridir. Programda ekrana YDizi[0] ve YDizi[1] yaplarnn eleman olan union deikeni UnDeg'in tamsay elemannn deeri, daha sonra da karakter dizisi olan elemannn ilk karakteri listelenir. n
rnek 8.5-2 union2.c program. #include <stdio.h> struct { char *s; int i; union C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-52

... rnek 8.5-2 devam


{ int j; char *c; } UnDeg; } YDizi[ ] = { { "dizgi1", 12, 27 }, { "dizgi2", 34, { 42 } }, }; /* YDizi[0] */ /* YDizi[1] */

int main(void) { printf("YDizi[0].UnDeg.j : %d\n", YDizi[0].UnDeg.j ); printf("YDizi[1].UnDeg.j : %d\n", YDizi[1].UnDeg.j ); YDizi[0].UnDeg.c = "abc"; YDizi[1].UnDeg.c = "xyz"; printf("*YDizi[0].UnDeg.c : %c\n", *YDizi[0].UnDeg.c ); printf("YDizi[1].UnDeg.c[0] : %c\n", YDizi[1].UnDeg.c[0] ); return 0; } kt YDizi[0].UnDeg.j : YDizi[1].UnDeg.j : *YDizi[0].UnDeg.c YDizi[1].UnDeg.c[0] 27 42 : a : x

8.6 Bit-Alan
Bir yap yada union deikeninin eleman olarak bildirilen bit-alan (bit-field) bellekte bir tamsay iin ayrlan alann belli bir ksmndaki bir yada daha fazla yan yana bit'ten oluur. Donanmla ilgili baz zel uygulamalar bir int verinin bulunduu bellek alannn paralarna eriimi ve buralardaki bit deerleri zerinde ilemler yaplmasn gerektirir. Bu durumda bit deerlerine eriim iin, bit pozisyonlarna karlk gelen maskeleri ve bitoperatrlerini kullanmak gerekmez. Byk bir programda baz kontrol parametrelerinin farkl zamanlarda ald deerleri saptamak iin 1 ve 0 deerlerini saklamak iin iki ayr tamsay deiken yerine, bu deerleri bit-byklnde eriilebilir alanlara blnm tek bir tamsay deikende saklamak bellek alan tasarrufu salar. Bir bit-alan (yada ksaca alan) yalnzca int, signed int yada unsigned int olarak bildirilebilir. int olarak bildirildiinde kullanlan derleyiciye bal olarak signed yada unsigned olabilir. Dolaysyla programlarn tanabilir olmas iin signed yada unsigned olduu belirtilmelidir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

8-53

Bit alan tanm:


struct etiket {
/* bit-alan bildirimleri */

unsigned alan_ismi : genislik; ... } degisken_ismi;

Her bit-alan bir alan ismi (alan_ismi), ":" ve alann bit saysn belirten genislik (genislik) ile bildirilir. Bit-alanlarna adres operatr (&) uygulanamaz. Bit-alanlarnn bellekteki dizilii (soldan saa yada sadan sola doru) kullanlan derleyici ve donanma gre deiir ve bu nedenle belli bir bellek dzenini esas alarak gelitirilen programlar tanabilir deildir. Bit-alanlar tamsay deerlerdir ve aritmetik ilemlerde kullanlabilir. Bit-alan bir tamsay iin ayrlan bellek snrn geemez bu nedenle bir int alandan daha geni bit-alan bildirilemez. rnek 8.6-1'de, 3 adet 1-bitlik alandan oluan bit-alan deikeni BitDeg bildirilir. Daha sonra bildirilen bit-alanlarna srasyla 1, 0 ve 1 deerleri atanr. Atanan deerler ? operatr ile oluturulan ifadeler kullanlarak ekrana listelenir.n
rnek 8.6-1 bitalan.c program. #include <stdio.h> struct BitSablon { unsigned alan1 : 1, alan2 : 1, alan3 : 1; }; struct BitSablon BitDeg; int main(void) { BitDeg.alan1 = 1; BitDeg.alan2 = 0; BitDeg.alan3 = 1; printf("BitDeg.alan1 : %c\n", BitDeg.alan1 ? '1' : '0' ); printf("BitDeg.alan2 : %c\n", BitDeg.alan1 ? '1' : '0' ); printf("BitDeg.alan3 : %c\n", BitDeg.alan1 ? '1' : '0' ); return 0; } kt BitDeg.alan1 : 1 BitDeg.alan2 : 0 BitDeg.alan3 : 1

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-1

BLM 9: Giri/k lemleri


Giri/k ilemleri (I/O, Input/Output) C dilinin dnda tutulmutur. Bu nedenle, giri/k ilemleri kullanlan C derleyicisiyle birlikte salanan ktphane fonksiyonlar ile gerekletirilir. Dier programlama dillerinin aksine, I/O ilemlerinin ayrntlar dilin dnda tutularak standart C ktphanesine yerletirilmitir ve bylece C dilinin tanabilir bir dil olma zellii korunmutur. nk farkl bilgisayar sistemleri, I/O ilemleri iin farkl teknikler kullanr. Derleyiciler, ANSI standart I/O ktphanesinden baka, birka I/O fonksiyon grubu salar. Bir giri/k ilemi, herhangi bir disk dosyasndan okumak ve bu dosyaya yazmak, klavyeden girilen bilgileri okumak, ktlar ekrana gndermek yada evre birimlerine eitli komutlar gndermek olabilir. Klavye ve ekran giri/k ilemleri (console I/O) nceki blmlerde anlatld. Bu blmde, disk dosyalarna eriim (disk I/O) ve ilgili teknikler anlatlacaktr. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-2

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-3

9.1 Standart Disk Giri/k lemleri


Disk dosyalar floppy disket, hard disk yada manyetik teyp gibi kalc ortamlarda saklanan programlar ve verilerdir. Disk dosyalarna eriim iin iki tip I/O fonksiyon grubu bulunur:
l

Akm I/O (buffered stream I/O) fonksiyonlar,

l Dk-seviyeli I/O (unbuffered low-level I/O yada system I/O) fonksiyonlar.

Akm fonksiyonlar ANSI standardnda (standart fonksiyonlar) tanmland iin, bu fonksiyonlar kullanlarak yazlan programlar bir donanmdan dierine tanabilir. Akm fonksiyonlar, disk eriimi srasnda transfer edilen verilerin geici olarak saklanmas iin iletim sistemi tarafndan bellekte oluturulan bir tampon alan (buffer) kullanrlar. Diskten bilgiler byte gruplar halinde okunur ve tampon alana yazlr. Diskten bilgi okuyan I/O fonksiyonu, aslnda daha nceden diskten byte grubu halinde okunarak tampon alana aktarlm olan bilgileri okur. Ayn ilem yazma srasnda da fakat tampon alandan diske doru gerekleir. Bylece, tampon alan kullanlarak farkl hzlarda alan ve verileri farkl ekillerde yneten donanm birimlerinin birlikte almas salanr. Pek ok akm I/O fonksiyonu, veriler disk dosyasndan okunurken yada dosyaya yazlrken eitli format evrimleri yapar (binary deerlerin, ASCII deerlere evrilmesi). Yine standart ktphanede yer alan akm I/O fonksiyonlar fread ve fwrite, binary verilerin format deitirme yaplmadan okunmas ve yazlmas iin kullanlr. Akm fonksiyonlar, eriim srasnda akm kontrol etmek iin gerekli olan bilgileri bir veri yapsnda tutar. FILE olarak adlandrlan bu veri yaps, balk dosyas stdio.h'de tanmlanmtr. Bir disk dosyas, daha sonra anlatlacak olan akm I/O fonksiyonu fopen ile aldnda, bu fonksiyon tarafndan aran bloa, disk dosyasnn eriim bilgilerini (tampon alann yeri, tampon alandaki karakter pozisyonu, dosyadan okuma yada dosyaya yazma ilemlerinden hangisinin yapld, I/O srasnda hata yada okuma srasnda dosya sonu durumunun oluup olumad bilgisi gibi) tayan FILE yapsna iaret eden bir adres deeri dndrlr. Programda izleyen tm akm I/O ilemleri, akm (stream) olarak adlandrlan bu adres deeri aracl ile eriilen bilgiler kullanlarak gerekletirilir. Buna gre bir akmn almas, bir disk dosyas yada bir evre birimi ile (klavye, ekran, modem yada yazc gibi) veri iletiim hatt oluturulmas anlamna gelir. Bir akma yazmak, bir disk dosyasna, ekrana, modem'e, yazcya yada bir baka evre birimine bilgilerin gnderilmesini; bir akmdan okumak ise bir disk dosyasndan, klavyeden, modemden yada bir baka evre biriminden bilgilerin alnmasn ifade eder. Szkonusu akm kapatldnda ise, bu veri iletiim hatt kesilmi olur.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-4

Bir C program almaya balad anda, baz standart I/O akmlar otomatik olarak alr. Standart akmlar, C programlarnn ortam ile iletiimini salar ve disk dosyalar gibi alp, kapatlmaz. DOS ve UNIX iletim sistemlerinin her ikisinde de bulunan 3 akm unlardr: stdin (standart giri), stdout (standart k), ve stderr (standart hata). Dier iki akm sadece DOS iletim sisteminde alr: stdaux (standart yardmc) ve stdprn (standart yazc). Buna gre stdin akmndan okumak ifadesi ile, stdin'in okunan dosyann FILE yapsnn adresini tad ifade edilir. stdin, yukarda bahsedildii gibi bir C program almaya baladnda otomatik olarak alan ve klavye ile ilgili olan akmdr. ekil 9.1-1'de, DOS altnda alan 5 standart I/O akm ve bu akmlarla ilgili donanm birimleri grlmektedir. rnek programlarda, standart giri ve standart k akmlar kullanld. Ekrana bilgi yazmak iin sk sk kullanlan printf fonksiyonu, stdout akmna yazar. Fakat printf fonksiyonu daha genel amal bir fonksiyon olan ve herhangi bir akma yazabilen fprintf'in zel bir eklidir. Aadaki her iki deyim de bilgisayar ekranna deneme dizgisini yazar:
printf( "deneme\n" ); fprintf( stdout, "deneme\n" );

Klavyeden bilgi girii iin kullanlan scanf fonksiyonu ise stdin akmndan okur. Bu fonksiyonun, herhangi bir akmdan okuyabilen karl ise fscanf fonksiyonudur. Bu fonksiyonlar, izleyen paragraflarda anlatlacaktr.
ekil 9.1-1 Standart giri/k akmlar.
Ekran Program

stdout stderr
Klavye . . #include <stdio.h> . . .

stdaux

Modem

Printer

stdprn stdin

Dk-seviyeli I/O fonksiyonlar, tampon alan kullanmazlar ve hibir format evirme ilemi yapmazlar. Bu ilemlerin, programda yaplmas gerekir. Bu nedenle daha sonra anlatlacak olan text tipi dosyalara eriim iin uygun deillerdir. Bu fonksiyonlar kullanlarak yazlan programlar tanabilir deildir. Fakat donanm zerinde kontrol artar ve direk eriim saladklar iin daha hzldrlar.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-5

Bu fonksiyonlar, akm I/O fonksiyonlar ile birlikte kullanlamaz. Kullanldnda dosya eriimi srasnda oluabilecek hatalar veri kaybna sebep olabilir. Bu blmde, akm I/O fonksiyonlar anlatlacaktr.

Bir disk dosyasnn oluturulmas, dosyaya yazma ve dosyann kapatlmas


rnek 9.1-1'deki textyaz.c program, A: srcsnde bulunan diskte test.asc isimli bir text dosyas oluturur ve bu dosyaya deneme dizgisini yazar. Standart giri/k fonksiyonlar arlaca zaman gerekli baz tip, makro rutini tanmlar ve fonksiyon prototiplerini ieren standart giri/k balk dosyas stdio.h, nceki rneklerde olduu gibi aadaki deyim kullanlarak programa dahil edilmelidir:
#include <stdio.h>

Disk dosyalar zerinde ilemler aadaki ekilde gerekletirilir:


l

lk olarak bir dosya gstergesi bildirilir; FILE * tipinde bir adres deikeni. Dosya gstergesi bildiriminin genel ekli aada verilmitir:
FILE *dosya_gstergesi;

rnek programlarda ounlukla dosya gstergesi ismi olarak fp (file pointer) kullanlmtr. Fakat bunun yerine geerli herhangi bir isim kullanlabilir.
NOT: FILE adres deeri ve bu deerin atand FILE adres deikeninden bahsedilirken "akm" yada "dosya gstergesi" ifadeleri kullanlabilir. Program almaya balamadan nce otomatik olarak alan 5 akm da (stdin, stdout, stderr, stdaux (DOS), stdprn (DOS) ) birer dosya gstergesidir. Fakat bunlara adres deeri atanamaz, nk her biri stdio.h'de tanmlanm ve ayr bir FILE * tipi sabit adres deerine karlk gelen sembolik isimdir (dosya gsterge sabitleri). stdin (standart giri akm) normal olarak klavyeye (standart giri dosyas) baldr; stdout ve stderr ise ekrana (standart k dosyas) baldr. stdin ve stdout ynlendirilebilir ( > ve | kullanlarak ), fakat stderr daima ekrana baldr ve tampon alan kullanmaz. Bu blmde disk dosyalar ile ilgili ilemler anlatld iin yerine gre karkl nlemek amacyla, "akma yazmak" ifadesi yerine, "bir disk dosyasna yada standart k'a yazmak"; "bir akmdan okumak" ifadesi yerine "bir disk dosyasndan yada standart giri'ten okumak" ifadeleri kullanlabilir. Standart akmlar alp kapatlmaz (baz zel durumlar dnda). Dolaysyla "bir akmn almas yada kapatlmas", "bir disk dosyasnn alp kapatlmas"'n ifade eder.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-6
l

fopen fonksiyonu kullanlarak disk dosyas alr. fopen fonksiyonu dosya eriimini salayan FILE tipi veri adresi dndrr. FILE veri tipi, stdio.h balk dosyasnda _iobuf ablonuna sahip ve dosya eriimi ile ilgili daha nceki paragraflarda bahsedilen bilgileri ieren bir yap tipi (struct veri tipi) olarak tanmlanmtr. Bu adres deeri, dosya gstergesi deikenine atanr. Disk dosyas aldktan sonra, standart ktphanede yer alan eitli giri/k fonksiyonlar ile eriim gerekletirilir. Bu fonksiyonlarn isimleri pek ok ekran ve klavye fonksiyonu ismine benzer fakat "f" harfi ile balar ( fprintf, fscanf, fputs, fputc, fgets, fgetc gibi) ve ayrca parametre olarak dosya gstergesi alrlar. lemler tamamlandnda disk dosyas, kapatlr. fclose fonksiyonu kullanlarak

rnek 9.1-1 textyaz.c program. #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp; if ( (fp = fopen( "a:\\test.asc", "w" )) == NULL ) { puts("test.asc dosyasi acilamadi"); exit(1); } fputs( "deneme", fp ); fputc( '\n', fp ); fclose( fp ); return 0; }

rnek 9.1-1'de ilk olarak,


FILE *fp;

deyimi ile dosya gstergesi fp bildirilir. Bunu izleyen if deyiminin test ifadesinde, fopen ars yer alr. fopen fonksiyonuna iki argman aktarlr. lk argman alacak dosyann diskteki ismini (dosya_ismi), dieri ise dosyann hangi amala alacan yani eriim tipini (mod) belirtir:
FILE *fopen( char *dosya_ismi, char *mod ); /* stdio.h */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-7

Bu argmanlar, dizgi sabiti yada dizgi adresi olabilir. Tablo 9.1-1'de dosya ilemlerinde kullanlan eriim tipleri ve ilevleri listelenmitir. Dosyann disk ismi ("a:\\test.asc") yalnzca fopen fonksiyonu tarafndan dosya alrken kullanlr. Program iinde dier giri/k fonksiyonlar kullanlarak dosyaya yaplan tm eriimler, dosyann disk ismi yerine dosya gstergesi fp kullanlarak gerekletirilir. Ayn anda alacak olan dosyalarn her biri iin, ayr bir dosya gstergesi bildirilmelidir. Bir defada alabilecek maksimum dosya says (standart balk dosyas stdio.h'de FOPEN_MAX makrosu ile tanmlanr ve bu sayya standart dosyalar da dahildir) snrldr. test.asc dosyas, oluturulurken eriim tipi olarak "w" kullanld iin tabloda da grld gibi yazma amacyla almtr.
Tablo 9.1-1 Eriim tipleri ve ilevleri. r r+ w Diskte mevcut bir dosyay okumak iin amak, Diskte mevcut bir dosyay okumak/yazmak iin amak.

Bir dosya oluturmak ve yazmak iin amak, Eer ayn isimde bir dosya mevcut ise iindekiler silinir ve yeni veriler ayn dosyaya yazlr. Bir dosya oluturmak ve okumak/yazmak iin amak, Eer ayn isimde bir dosya mevcut ise iindekiler silinir ve yeni veriler ayn dosyaya yazlr. a a+ Diskte mevcut bir dosyay verileri sonuna eklemek amacyla amak, Eer dosya diskte mevcut deilse oluturulur. Diskte mevcut bir dosyay verileri sonuna eklemek/okumak amacyla amak, Eer dosya diskte mevcut deilse oluturulur.
NOT: w ve w+ eriim tipleri kullanlrken, diskte ayn isimde bir dosya bulunuyor ise iindeki mevcut bilgiler kaybedilecei iin dikkatli olmak gerekir.

w+

fopen arsndan dnen FILE tipi veri adresi, fp adres deikenine atanr:
dosya gstergesi dosya ismi

if ( ( fp = fopen( "a:\\test.asc" , "w" ) ) == NULL)


eriim tipi

NOT: Dosya ismi dizgisinde pepee iki ters kesme (\\) kullanlmtr. Bunun nedeni, \t'nin tab boluunu ifade etmesidir. ift ters kesme kullanlarak, t karakterinden C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-8 nceki ters kesmenin etkisi kaldrlr. Bylece derleyici \ ve t karakterlerinin kombinasyonunu, tab escape dizini olarak almaz. Burada ayrca dosyann eriim tipini bildiren argmann, stten tek trnaklarla snrl bir karakterden oluan ve bu karakterin ASCII kodunu dndren karakter sabiti ('w') deilde, ift trnaklarla snrl ve bellek adresi dndren bir dizgi sabiti ("w") olduuna dikkat edilmelidir. Dosya ismi ("test.asc"), DOS iletim sisteminde en fazla 8 karakterden oluur ve seime bal olarak nokta ile ayrlm en fazla 3 karakterden oluan uzants olabilir. Genel olarak dosyann ismi, ierdii verilerin trn; uzants ise uygulamay ifade edecek ekilde belirlenir. Bu rnekte dosya ismi, deneme amacyla ASCII karakterler ieren bir dosya oluturulduunu ifade etmek ve \t (tab) kullanmn rneklemek iin test.asc olarak belirlenmitir. Dosya isminde izin verilen maksimum karakter says, kullanlabilecek karakterler ve dosyann bulunduu yeri gsteren dizin (path) bilgisinin yazl iletim sistemine gre deiebilir.

if deyiminde, fp'ye gizli atama ile atanan adres deerinin NULL adres deeri olup olmad test edilir:
gizli atama

if ( (fp = fopen("a:\\test.asc", "w"))

== NULL)

nk herhangi bir sebepten dolay dosya alamyor ise, fopen fonksiyonu FILE tipi adres deeri yerine NULL adres deeri (bo adres deeri 0) dndrr ve if deyiminin doru ksm alarak programdan klr. rnek programda, dosya aldktan sonra fputs, fputc ve fclose fonksiyonlar arlr. puts fonksiyonu, argman olarak verilen dizgiyi (dizgi sabiti yada dizgi adresi olarak), sonuna bir yeni-satr karakteri (NL, newline, \n) ekleyerek standart k akm, stdout'a (yani bilgisayar ekranna) yazar:
int puts( char *dizgi ); /* stdio.h */

fputs fonksiyonu da ayn ekilde alr. Fakat ikinci argman olarak bir dosya gstergesi alr. Dolaysyla, dizgiyi bir disk dosyasna yada standart ka yazabilir. Ayrca dizgi sonuna NL karakteri eklemez:
int fputs( char *dizgi, FILE *dosya_gostergesi ); /* stdio.h */

Her iki fonksiyon da, dizgi sonunu belirleyen null (\0) karakterini ktya yazmaz. Bu fonksiyonlar hatasz olarak altnda negatif olmayan bir deer, hata olumas durumunda ise EOF dndrr. Aadaki deyimlerin her ikisi de ekrana deneme dizgisini yazar:
puts( "deneme" ); fputs( "deneme\n", stdout ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-9

Programda bir NL karakterini dosyaya yazmak iin fputc fonksiyonu kullanld. Bu fonksiyon karakter c'yi ( unsigned char olarak ) k akmna yazar:
int fputc( int c, FILE *dosya_gostergesi ); /* stdio.h */

kinci argman dosya_gostergesi, daha nce de bahsedildii gibi yazma amacyla alm bir disk dosyasna ait dosya gstergesi yada stdout, stderr gibi bir standart k akmdr. Fonksiyon hatasz alr ise, akma yazlan karakteri (int)(unsigned char) olarak dndrr. Hata durumunda ise EOF dndrr. fputc fonksiyonu, putc makrosu ile ayndr:
int putc( int c, FILE *dosya_gostergesi ); /* stdio.h */

Buna gre aadaki deyimler ayn ii yapar:


putc( 'A', stdout ); fputc( 'A', stdout );

Standart k akmna yazan ve stdio.h'de tanmlanan putchar makrosu, putc makrosu ile ayndr:
int putchar( int c ); /* stdio.h */

Buna gre, putchar(c) ve putc(c, stdout) ayndr. fopen ile yazma amacyla alarak, deneme dizgisi ve NL karakteri yazlan disk dosyas, fclose fonksiyonu ile kapatlarak programdan klr. fclose fonksiyonu, hatasz olarak dosya kapatma ilemini gerekletirir ise 0 deerini, hata oluur ise EOF dndrr:
int fclose( FILE *dosya_gostergesi ); /* stdio.h */

fopen ile alan dosyalar, programdan klrken otomatik olarak kapatlr. Fakat fclose kullanlarak dosyalarn kapatlmas daha uygundur. fclose fonksiyonu dosya gostergesi ile disk dosyas arasndaki ba koparr. Bir programda, bir defada alabilecek dosya says snrldr (en fazla FOPEN_MAX kadar dosya alabilir. Bu sabit stdio.h'de tanmlanmtr ve genel olarak 20'dir). Bu nedenle, ok fazla sayda dosya ile alan bir programda ilemleri tamamlanan bir dosyann kapatlmas nem kazanabilir. Blm giriinde anlatld gibi fputs ve fputc gibi standart disk I/O fonksiyonlar, dizgileri ve karakterleri bellekteki bir tampon alana yazarlar. Bu tampon alan tamamen dolduktan sonra, buradaki bilgiler disk dosyasna aktarlr. Bu ilem flushing olarak adlandrlr.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-10

fclose fonksiyonu, bu alanda bulunan yazlmam bilgilerin dosyaya aktarlmasn salar ve veri kayb nlenir. Ayrca serbest braklan tampon alan baka bir ilemde kullanlabilir. fflush ve fclose fonksiyonlar kullanlarak bu tampon alann tam olarak dolmadan nce boaltlmas salanabilir:
int fflush( FILE *dosya_gostergesi ); /* stdio.h */

fflush fonksiyonu, tampon alanda bulunan tm kt bilgisini dosya_gostergesi ile belirtilen akma yazar ve hata olumaz ise 0, aksi taktirde EOF dndrr. Eer argman olarak bo adres deikeni (null pointer) verilir ise bu ilemi kt amacyla alm olan tm dosyalar iin yapar. Dosya fclose ile kapatlmam olsa da, bir C programndan normal k srasnda otomatik olarak dosya kapatma ilemi yaplr. Fakat programdan normal olmayan bir ekilde (rnein abort fonksiyonu arlarak yada programn almas kesilerek) dosya kapatlmadan klr ise, flushing ilemi yaplarak tampon alan boaltlmam olaca iin, bu alanda kalan bilgiler kaybolacaktr.

Bir disk dosyasndan okumak


textoku.c programnda, test.asc dosyas okuma amacyla (eriim tipi: r) alr. while dngsnn test ifadesinde, fgetc fonksiyonu tarafndan dndrlen deer tamsay c deikenine atanr ve bu deerin dosya sonunu belirten EOF (end-of-file) olup olmad kontrol edilir:
int fgetc( FILE *dosya_gostergesi ); /* stdio.h */

fgetc fonksiyonu, her arda dosya_gostergesi ile tanmlanan dosyann o andaki karakter pozisyonundan bir karakter okur ve pozisyon gstergesini bir sonraki karaktere iaret edecek ekilde arttrr. Hatasz altnda (int)(unsigned char) olarak okuduu karakteri, hata durumunda ise EOF dndrr. Fakat fgetc fonksiyonu, dosya sonuna ulaldnda da EOF dndrr. Daha sonra anlatlacak olan ferror ve feof makrolar kullanlarak bu iki durum birbirinden ayrt edilebilir.
rnek 9.1-2 textoku.c program. #include <stdio.h> #include <stdlib.h> int main(void) { int c; FILE *fp; if ( (fp = fopen( "a:\\test.asc", "r" )) == NULL ) { C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-11

... rnek 9.1-2 devam


puts("test.asc dosyasi acilamadi"); exit(1); } while ( (c = fgetc( fp )) != EOF ) fputc( c, stdout ); fclose( fp ); return 0; } kt deneme

Standart C ktphanesinde yer alan getc makrosu da, fgetc fonksiyonuna benzer. Dosyadan okuduu karakteri dndrr. Hata olutuunda yada dosya sonuna ulaldnda ise yine EOF dndrr.
int getc( FILE *dosya_gostergesi ); /* stdio.h */

Ayrca, stdin akmndan okuyan getchar makrosu da, getc(stdin) ile ayndr:
int getchar( void ); /* stdio.h */

Text ve Binary Modlar


Bir text dosyas (metin dosyas yada ASCII dosya) okunabilir ASCII karakterler ierir (alfanumerik karakterler, noktalama iaretleri ve baz kontrol karakterleri) ve bir yada daha fazla satrdan oluur. Text dosyasnn ierii, iletim sisteminde bulunan herhangi bir dosya listeleme komutu ile satrlar halinde ekrana listelenebilir (rnein DOS iletim sisteminde TYPE komutu, UNIX iletim sisteminde cat komutu kullanlarak). Dosya iinde bulunan byte serilerinin (karakterlerin) satrlar halinde dzenlenmesini satr-sonu karakteri (EOL, end-of-line) salar. Satr-sonu karakteri, iletim sistemine gre farkllk gsterebilir. Bir C programnda satr sonunu belirtmek iin kullanlan newline karakteri (Sembolik olarak NL, karakter sabiti olarak '\n', ASCII kod olarak 10 yada 0x0A), UNIX iletim sisteminde bir text dosyasnda yine satr sonunu iaretler. Fakat DOS iletim sisteminde durum farkldr ve satr sonu carriage-return (CR, karakter sabiti olarak '\r', ASCII 13 yada 0x0D) ve line-feed (LF, ASCII 10 yada 0x0A) karakter kombinasyonu ile iaretlenir. Bu nedenle, DOS iletim sisteminde programda (bellekte) bulunan NL karakteri, disk dosyasna CR-LF karakter iftine evrilerek yazlr. Yine ayn ekilde, disk dosyasndan bu karakter ifti okunduunda, tek bir NL karakterine evrilerek bellee alnr. DOS
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-12

ortamnda kullanlan derleyiciler tarafndan salanan standart ktphane fonksiyonlar bu evirme ilemlerini otomatik olarak yapar. Fakat istendiinde diskten okuma yada diske yazma srasnda bu evirmelerin yaplmamas salanabilir. DOS derleyicileri kullanlrken bu ilemleri gerekletirmek iin, dosya iki ayr modda alr: text mod ve binary mod. Buna gre, DOS iletim sisteminde bir dosyadan okuma yada dosyaya yazma ilemi srasnda transfer edilen bu karakterlerin nasl yorumlanaca dosyann hangi modda aldna baldr. Bu modlar, translation mode (evirme modu) olarakta adlandrr. Her iki mod da, standart C ktphanesi tarafndan desteklenir. Fakat szkonusu evirme ilemleri C standardnda tanmlanmamtr ve tamamen belli bir iletim ortamnda alan derleyici ile birlikte verilen standart C ktphanesi tarafndan gerekletirilir. Bylece bir DOS dosyas text modunda aldnda evirme ilemleri otomatik olarak yaplr ve programda hi bir etki olmaz. Baz iletim sistemlerinde, rnein UNIX'te text mod ve binary mod ayrm olmad gz nnde bulundurulacak olursa, bu yaklam ile C programndaki text dosyas modeli UNIX yada DOS altnda alrken korunmu olur. eitli iletim ortamlarnda program gelitirirken, bu tip farkllklar dikkate alnmaldr. Dosyann hangi modda alaca, fopen fonksiyonunun ikinci argman olan mod dizgisine, eriim tipinden (yada eriim modu) sonra eklenen ikinci bir harf ile belirtilir. mod dizgisinde sadece eriim tipi yer ald zaman (Tablo 9.1-1), dosyann text modunda alaca kabul edilir (default mode). Buna gre nceki rneklerde oluturulan test.asc dosyas text modunda oluturulmu bir dosyadr ve biraz sonra da anlatlaca gibi okuma-yazma ilemleri srasnda baz evirmeler gerekleir. mod dizgisine eriim tipinden sonra yerletirilen b harfi (rnein "rb", "w+b" yada "wb+" gibi), dosyann binary modunda alacan belirtir. Dosya binary modunda aldnda okuma ve yazma ilemleri srasnda hi bir evirme yaplmaz.
NOT: Text mod, DOS derleyicilerinde translated mode olarakta adlandrlr. Baz DOS derleyicileri ile alrken, text mod ak olarak ifade edilmek istendiinde mod dizgisinde t harfi kullanlr (rnein "rt", "wt" gibi). Bunun bir ANSI standart modu olmadna dikkat edilmelidir. Bu harf kullanlmad zaman yine text mod kabul edilir. Aadaki program, yukarda bahsedilen NL ve CR karakterlerinin kullanmn rnekler: /* CRNL.C */ #include <stdio.h> int main(void) { int i; for ( i = 0; i < 5000; i++ ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-13

crnl.c devam
{ printf("i : %04d", i ); if ( i == 2000 ) putchar('\n'); else putchar('\r'); } printf("\nNL : 0x%02X, CR : 0x%02X", '\n', '\r' ); printf("\nNL : %d, CR : %d", '\n', '\r' ); return 0; } kt: i : 2000 i : 4999 NL : 0x0A, CR : 0x0D NL : 10, CR : 13 ktda da grld gibi 2000'e kadar olan saylar ayn satra, bu saydan sonras ise bir alt satra yazlr. Programda son olarak NL ve CR karakterlerinin ASCII karakter kodlar onaltlk ve onluk say sistemlerinde ekrana listelenir. Programn kts, standart k bir disk dosyasna ynlendirilip, oluturulan bu dosya iletim sisteminde bulunan bir listeleme komutu ile ekrana listelendiinde, kt yine ayn ekilde grlr.

mod dizgisi sadece eriim tipi bilgisini ierdii iin, textyaz.c ve textoku.c programlarnda okuma ve yazma ilemleri text modunda gereklemitir. textyaz.c program tarafndan oluturulan test.asc dosyas DOS iletim sisteminin DIR komutu ile listelendiinde, bulunduu fihristte 8 byte byklnde bir dosya olarak grlr. Fakat dosyaya, 6 karakterden oluan deneme dizgisi ve bir NL karakteri olmak zere toplam 7 karakter yazld. Bunun nedeni text modunda yaplan evirme ilemidir. rnek 9.1-3'de, text modunda oluturulan test.asc dosyasnda bulunan karakterler ve ASCII kodlar, dosya nce text modunda alarak ve daha sonrada binary modda alarak listelenir:
rnek 9.1-3 mod1.c program. #include <stdio.h> #include <stdlib.h> #include <ctype.h> int main(void) { int c; FILE *fp; C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-14

... rnek 9.1-3 devam


puts( "test.asc: r - text modunda okuma." ); if ( !(fp = fopen( "a:\\test.asc", "r" )) ) { puts("test.asc dosyasi acilamadi"); exit(1); } while ( (c = fgetc( fp )) != EOF ) printf( "%c 0x%02X, %d\n", isprint(c) ? c : ' ', c, c ); printf( "EOF (end-of-file) : %d\n", c ); fclose( fp ); puts( "test.asc: rb - binary modunda okuma." ); if ( !(fp = fopen( "a:\\test.asc", "rb" )) ) { puts("test.asc dosyasi acilamadi"); exit(2); } while ( (c = fgetc( fp )) != EOF ) printf( "%c 0x%02X, %d\n", isprint(c) ? c : ' ', c, c ); printf( "EOF (end-of-file) : %d\n", c ); fclose( fp ); return 0; } kt
test.asc: r - text modunda okumatest.asc: rb - binary modunda okuma.

d e n e m e

0x64, 0x65, 0x6E, 0x65, 0x6D, 0x65, 0x0A,

100 101 110 101 109 101 10 NL

d e n e m e

EOF (end-of-file) : -1

0x64, 0x65, 0x6E, 0x65, 0x6D, 0x65, 0x0D, 0x0A,

100 101 110 101 109 101 13 10

CR-LF

EOF (end-of-file) : -1 Okuma kolayl asndan ktlar yanyana listelenmitir !

mod1.c programnn kts incelendiinde, text modunda okuma yapldnda dizgi sonunda sadece bir karakter (toplam 7 karakter), binary modunda ise iki karakter (toplam 8 karakter) grlr. nk, dosya text modunda yazma amacyla aldnda NL karakteri yazlmadan nce CR-LF karakter iftine evrilir. Ayn dosya yine text modunda okuma amacyla aldnda, okunan CR-LF karakter ifti tekrar tek bir NL karakterine evrilir. Dolaysyla, test.asc dosyas text modunda oluturulduu iin diskte fazladan bir karakter ierir. Yine text modunda okunduunda bu iki karakter tek bir karaktere evrildii iin ktda sadece NL karakteri grlr. Fakat, binary modunda
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-15

byle bir evirme ilemi yaplmaz. Bu nedenle, text modunda yazlan test.asc dosyas binary modunda okunduu zaman ktda CR-LF kombinasyonu grlr. Dosya binary modunda yazlm olsayd, diskte 7 byte byklnde grlecek ve her iki modda da, son karakter olarak sadece 0x0A grlecekti. Genel olarak dosya hangi modda yazlm ise o modda okunur. Burada, ieriini evirme yaplmadan okumak iin text modunda oluturulan bir dosya binary modunda almtr. UNIX iletim sisteminde bu evirmeler yaplmad iin ve mod ayrm bulunmad iin, dosya diskte 7 byte olarak bulunur (ls komutu ile listelendiinde). NL ve LF karakterleri ayndr (0x0A). Fakat rneklerde de grld gibi bu karakter DOS iletim sisteminde bellekte ve diskte farkl yorumlanrlar. Bu konu ile ilgili olarak verilen son rnek olan rnek 9.1-4'de, NL ieren NLDizgi dizgisi, ilk olarak text modunda alan text dosyasna daha sonrada binary modunda alan binary1 dosyasna yazlr. CR ve NL karakterleri ieren CR_NLDizgi dizgisi ise binary modunda alan binary2 dosyasna yazlr. Program altrldktan sonra oluturulan bu dosyann ierii izleyen blmlerde anlatlacak olan dump program kullanlarak hi bir evirme yaplmakszn onaltlk karakter kodlar olarak listelenir. Ayrca her bir dump ktsndan sonra, DOS iletim sisteminde bulunan TYPE komutu kullanlarak dosyalar listelenir. ktda ak olarak grld gibi, DOS iletim sisteminde bir text satrnn CR-LF kombinasyonu ile sonlanmas gerekir. UNIX'te ise C programlarnda olduu gibi tek bir NL ile sonlanr. Yukardaki paragraflarda, iletim ortamna gre farkllk gsteren satr-sonu (EOL) karakteri anlatld. letim ortamna gre farkllk gsteren bir dier konu da, text modunda dosya sonunun saptanmasdr. DOS iletim sisteminin eski srmlerinde dosya sonu pozisyonunu saptamak iin dosya sonu iareti olarak ^Z (Ctrl-Z, ASCII kod olarak 26 yada 0x1A) kullanld. Fakat bu teknik terkedilmitir ve dosya sonu, dosyann byte says bilgisi kullanlarak saptanr. Bylece dosyada bulunan son karakter sonrasn okuma giriimi bir dosya-sonu (end-of-file) durumu oluturur. Fakat dosya sonunu belirlemek iin dosya bykl bilgisi kullanlyor olsa da, text modunda okuma yaplrken dosya iinde ^Z karakterine rastlanrsa yine dosya-sonu durumu oluur ve ilem durdurulur (rnek 9.1-7). Binary modunda ^Z karakterinin zel bir anlam yoktur ve dosyada bulunan tm karakterler okunduktan sonra dosya-sonu durumu oluur. UNIX iletim sisteminde de (ve C dilinde) yine zel bir dosya sonu iareti yoktur. Programlarda kullanlan fonksiyonlar dosya-sonuna eriildiini ve okunacak karakter kalmadn belirtmek iin stdio.h'de tanml olan EOF deerini dndrr. Fakat ayn deer baz fonksiyonlar tarafndan hata durumunda da dndrld iin daha sonra anlatlacak olan baz zel makrolar kullanlarak bu iki durum birbirinden ayrt edilebilir. EOF, dosyada bulunan bir karakter deildir fakat belli bir durumu ifade eden zel bir koddur. EOF, stdio.h'de negatif bir tamsay deer (sisteme bal olmakla birlikte genel
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-16

olarak 0xFFFF, yani -1 kullanlr) olarak tanmlanmtr. fgetc fonksiyonu (ve getc makrosu) (int)(unsigned char) deerler dndrr ve bylece 127'den byk ASCII deerlerin negatif olmamas salanr. Ancak fonksiyonun hata yada dosya-sonu durumunu bildirmek iin dndrd negatif deerin saptanmas gerekir. Bu nedenle programda, okunan deerler 8 bit karakterler olmasna ramen, dosya sonunu belirten EOF kodunun tesbit edilebilmesi iin c deikeni char yerine int tipi deiken olarak bildirilmitir. rnek 9.1-2 ve 9.1-3'de grld gibi fgetc fonksiyonu, dosyada (yada akmda) bulunan son karakter pozisyonundan tesini okuma giriiminde bulunduu anda EOF dndrr ve dngden klr.
rnek 9.1-4 mod2.c program. #include <stdio.h> #include <stdlib.h> #define NLDizgi #define CR_NLDizgi "abc\n123\ndef" "abc\r\n123\r\ndef"

void DosyaYaz( char *, char *, char * ); int main(void) { DosyaYaz( "text", "w", NLDizgi ); DosyaYaz( "binary1", "wb", NLDizgi ); DosyaYaz( "binary2", "wb", CR_NLDizgi ); return 0; } void DosyaYaz( char *DosyaAdi, char *Mod, char *Dizgi ) { FILE *fp; if ( (fp = fopen( DosyaAdi, Mod )) == NULL ) { fprintf( stderr, "%s acilamadi.\n", DosyaAdi ); exit(1); } fputs( Dizgi, fp ); fclose(fp); }

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-17

... rnek 9.1-4 devam


kt
abc\n123\ndef dizgisinin text dosyasna text modu nda yazlmas. <enter> A:\> dump Dosya adi ? : text Hex (Dec) Hexadecimal Kodlar

ASCII Kod

000D(0013) 61 62 63 0D 0A 31 32 33 0D 0A 64 65 66 abc..123..def Toplam byte: 13 CR-LF CR-LF DOS TYPE kts: A:\> type text <enter> abc 123 def

abc\n123\ndef dizgisinin binary1 dosyasna binary modu nda yazlmas.


<enter> A:\> dump Dosya adi ? : binary1 Hex (Dec)

Hexadecimal Kodlar

ASCII Kod abc.123.def

000B(0011) 61 62 63 0A 31 32 33 0A 64 65 66 Toplam byte: 11 LF LF DOS TYPE kts: A:\> type binary1 <enter> abc 123 def

abc\r\n123\r\ndef dizgisinin binary2 dosyasna binary modu nda yazlmas.


<enter> A:\> dump Dosya adi ? : binary2 Hex (Dec)

Hexadecimal Kodlar

ASCII Kod

000D(0013) 61 62 63 0D 0A 31 32 33 0D 0A 64 65 66 abc..123..def Toplam byte: 13 CR-LF CR-LF DOS TYPE kts: A:\>type binary2 <enter> abc 123 def

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-18

Programlarda, sabit deerler yerine NULL ve EOF gibi sembolik sabitlerin kullanm tanabilirlii arttrr. nk bir baka donanmda ve iletim sisteminde bu deerler farkl olabilir. Byle bir durumda, sembolik sabitler kullanld iin programlarda deiiklik yapmak gerekmeyecektir. mod1.c programnda if deyimlerinde "==NULL" ifadesi kullanlmamtr. Bir if, while yada for deyiminin test ifadesinin dndrd 0 deeri yanl, baka herhangi bir deer ise doru kabul edilir. Burada if deyiminin test ksmnda fp adres deikeninin deeri kontrol edilir. Dosya herhangi bir sebeple alamaz ise fp adres deikenine fopen arsnn dndrd bo adres deeri (0) atanr ve !0 ifadesi ile test doru kabul edilerek if deyiminin doru blounda bulunan hata mesaj ve programdan k deyimleri altrlr. fp deikenine fopen arsndan 0 harici herhangi bir geerli deer (yani FILE tipi veri adresi) atanr ise test yanl kabul edilecei iin program almasna devam eder. rnek 9.1-5'de tamsaylardan oluan int tipi bir dizinin elemanlarnn deerleri text modunda alan sayilar.txt dosyasna yazlr.
rnek 9.1-5 sayitext.c program. #include <stdio.h> #include <stdlib.h> #define SATIRBOY #define DIZIBOY(s) 80 sizeof( s )/sizeof(s[0])

int dizi[] = { 123, 45, -25678, 500, -22 }; int main(void) { FILE *fp; char DosyaAd[] = "sayilar.txt", Buf[SATIRBOY+1]; int i; if ( (fp = fopen( DosyaAd, "w" )) == NULL ) { printf( "%s olusturulamadi\n", DosyaAd ); exit(1); } for ( i = 0; i < DIZIBOY(dizi); i++ ) fprintf( fp, "dizi[%d] : %6d\n", i, dizi[i] ); fclose( fp ); if ( (fp = fopen( DosyaAd, "r" )) == NULL ) { printf( "%s acilamadi\n", DosyaAd ); exit(2); } dizi[0] = 0; C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-19

... rnek 9.1-5 devam


fscanf( fp, "dizi[%d] : %d\n", &i, &dizi[0] ); printf( "dizi[%d] : %6d\n", i, dizi[0] ); fgets( Buf, SATIRBOY, fp ); printf( "%s", Buf ); while ( (i = fgetc( fp )) != '\n' ) printf( "%c", i ); rewind( fp ); printf( "\n-- rewind --\n" ); printf( "%s\n", fgets( Buf, SATIRBOY, fp ) ); fclose( fp ); return 0; } kt dizi[0] : 123 dizi[1] : 45 dizi[2] : -25678 -- rewind -dizi[0] : 123

Programda ilk olarak sayilar.txt dosyas yazma amacyla text modunda alr. Dosya ismi argman, fopen fonksiyonuna bir karakter dizisi ismi (DosyaAd) olarak verilir. Bu uygulama, dosya isminin dizgi sabiti olarak yazlmasndan daha pratiktir. Dosya aldktan sonra 5 elemanl tamsay dizi dizi'nin elemanlar, fprintf fonksiyonu kullanlarak formatlanm text eklinde dosyaya yazlr. fprintf fonksiyonu printf fonksiyonuna benzer ve deiken sayda argman kabul eder. Ancak format dizgisi format ile belirtilen ekilde formatlanm deerleri, printf fonksiyonundan farkl olarak sadece stdout akmna deil, dosya_gostergesi ile belirtilen disk dosyasna yada standart ka yazar. stderr akmna hata mesajlar yazlmasnda ounlukla fprintf fonksiyonu kullanlr (rnek 9.1-4). fprintf fonksiyonu yazlan karakter saysn dndrr. Akmda hata olumas durumunda ise negatif bir deer dndrr.
int fprintf( FILE *dosya_gostergesi, const char *format, ... ); /* stdio.h */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-20

. . fprintf( fp, "dizi[%d]: %6d\n", i, dizi[i]); . . sayilar.txt

dizi[0]: . .

123

Sonu olarak for dngs ile dosyaya, gerekli dnmler fprintf tarafndan yaplarak 5 adet dizgi yazlr. Dosya iletim ortamnda bulunan bir komut ile listelendiinde aadaki ekilde grlr:
dizi[0] : 123 dizi[1] : 45 dizi[2] : -25678 dizi[3] : 500 dizi[4] : -22

Dizgilerin dosyada bulunu ekillerine format dizgisi (printf fonksiyonunun format dizgisi ile ayn ekilde alr) karar verir. Aadaki her iki deyim de ayn ii yapar:
fprintf( stdout, "deneme\n" ); ve printf( "deneme\n" );

Daha sonra dosya text modunda okuma amacyla alr. Dosyadan ilk olarak fscanf fonksiyonu kullanlarak text bilgileri okunur.
int fscanf( FILE *dosya_gostergesi, const char *format, ... ); /* stdio.h */

Bu fonksiyon scanf gibi alr, fakat ilk argman olarak dosya gstergesini alr. kinci argman olan format dizgisinin formu ve ilevi, scanf format dizgisi ile ayndr ve dosyann bulunulan pozisyonundan itibaren taranan girdi alanlarnn nasl yorumlanacana karar verir. Sonu olarak disk dosyasndan yada standart giriten okunan dizgiler, belirtilen formata gre gerekli dnmler yaplarak C deiken deerlerine evrilir ve argman listesinde sralanan bellek adreslerine atanr. Fonksiyon hatasz olarak evrilen ve atanan alanlarn saysn dndrr. Bu sayya, okunan fakat atanmayan alanlarn says dahil deildir. Dndrlen 0 deeri, hi bir atama yaplmadn gsterir. Dosya sonuna gelindiinde EOF deeri dndrr. fscanf fonksiyonu scanf fonksiyonu ile ayndr. Fakat scanf fonksiyonu sadece standart giriten okur. fscanf ise dosya_gostergesi ile belirtilen bir disk dosyasndan da okuyabilir. Aadaki her iki deyim de ayn ii yapar:
fscanf( stdin, "%d", &i ); ve scanf( "%d", &i ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-21

Programda grld gibi fscanf format dizgisi, fprintf format dizgisi ile ayn olmaldr. Yani bilgiler yazldklar formatta okunmaldrlar. fscanf iki saysal deikene, dosyadaki ilk dizgiden gerekli dntrmeleri yaparak iki tamsay deeri okur. Okunan bilgiler printf ile ekrana listelenir. Bu noktada, dosyann ilk satr okunmu ve iki tamsay deere dntrlm bulunuyor. Dosyann ierii dz metin olduu iin izleyen satr da bir dizgi olarak ilem grebilir. fgets fonksiyonu kullanlarak ikinci dizgi okunur ve ekrana yazlr:
fgets( Buf, SATIRBOY, fp ); printf( "%s", Buf );

Bu fonksiyon, son argman olan dosya_gostergesi ile ifade edilen disk dosyasndan yada standart giriten okuduu dizgiyi, ilk argman olan dizgi karakter dizisine (bu bir dizgiye iaret eden char tipi adres deikeni de olabilir) saklar:
char *fgets( char *dizgi, int n, FILE *dosya_gostergesi ); /* stdio.h */

Karakterler, bulunulan dosya pozisyonundan itibaren ilk NL karakterine rastlayncaya kadar, dosya sonuna kadar yada okunan karakter says n-1'e (son karakter dizgi sonunu belirten NUL byte iin ayrlr) eit oluncaya kadar okunur. Okunan karakterler ilk argman olan karakter dizisine saklanr ve sonuna bo karakter (null karakter, \0) eklenir. Eer okunmu ise NL karakteri de karakter dizisine dahil edilir. Eer ikinci argman tamsay n'in deeri 1 ise, karakter dizisi bo olur (""). fgets fonksiyonu hatasz alr ise, ilk argman olan adres deerini dndrr. Dosya sonu (end-of-file) yada hata durumunu bildirmek iin NULL (bo adres deeri) dndrr. Yine daha sonra anlatlacak olan feof yada ferror makrolar kullanlarak bu iki durum birbirinden ayrt edilebilir. Bu fonksiyon gets fonksiyonuna benzer. fgets fonksiyonu NL karakterine rastlar ise bu karakter de, girilen dier karakterle birlikte saklanr. Fakat gets fonksiyonu okunan NL karakterini dizgiye aktarmaz. Ayrca gets fonksiyonu sadece standart giri akm stdin'den okur. gets tarafndan okunan ve saklanan karakterler snrlandrlamaz. Bu nedenle fgets kullanm daha uygundur. Her iki fonksiyon da, girilen karakterleri bir bo karakter ile sonlandrr:
char *gets( char *dizgi ); /* stdio.h */

gets fonksiyonu fgets ile ayn deerleri dndrr. sayilar.txt dosyasnn izleyen satrnda bulunan karakterler fgetc fonksiyonu kullanlarak birer birer okunur. while dngsnn test ifadesinde bulunan fgetc fonksiyonu, satr sonunu iaretleyen NL karakterine rastlayncaya kadar karakterleri okumaya devam eder.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-22

rewind fonksiyonu, dosyann pozisyon gstergesini dosyann bana ayarlar. Bu nedenle, son fgets ars dosyada bulunan ilk dizgiyi okur. Programdaki ilk fgets arsnda, okunan dizgi Buf dizisine aktarlr. fgets ayn zamanda ilk argman olan adres deerini (dizi ismi Buf, dizinin balang adresini verir) dndrd iin, okunan dizgi aadaki gibi listelenebilir:
printf( "%s\n", fgets( Buf, SATIRBOY, fp ) );

ok byk ASCII text dosyalar ile alrken, dizgilerle ilem yapmak (fputs, fgets fonksiyonlar kullanlarak), karakter karakter ilem yapmaktan (fputc, fgetc fonksiyonlar kullanlarak) daha hzldr.

Text ve Binary Format


Yukardaki rnekte, sayilar.txt dosyasna saysal deerler fprintf fonksiyonu kullanlarak yazld. fprintf fonksiyonu gerekli dnmleri yaparak, tamsay deerleri text modunda alan sayilar.txt dosyasna text formatnda yazd. Dosya okunurken yine ayn ekilde, gerekli ilemler fscanf fonksiyonu tarafndan yapld ve dosyada bulunan karakterler saysal deerlere evrilerek format dizgisinde belirtildii ekilde tamsay deikenlere atand. Formatlama ve evirme yapan bu fonksiyonlarla okuma-yazma ilemleri yapldnda veriler ASCII karakterler olarak okunur ve yazlr. Standart C ktphanesinde, deerlerin hi bir evirme ve formatlama yaplmakszn binary deerler olarak yazlmasn ve okunmasn salayan fwrite ve fread fonksiyonlar bulunur. rnek 9.1-5'de, text formatnda ASCII karakterler olarak sayilar.txt dosyasna yazlan tamsay deerler, binary formatta sayilar.bin dosyasna yazlr. Programda ilk olarak sayilar.bin dosyas binary modunda yazma amacyla alr ( "wb" ). Daha sonra fwrite fonksiyonu kullanlarak dizi dizisinin eleman olan 5 tamsay deerin tamam binary formatta sayilar.bin dosyasna yazlr. fwrite fonksiyonu, adr tarafndan iaret edilen bellek alanndan dosya_gostergesi ile belirtilen disk dosyasnn bulunulan pozisyonuna, belirtilen sayda ve byklkteki veri elemanlarn yazar. boy bir veri elemannn byte olarak bykln, elsayi ise bu byklkteki verilerden ka tane yazlacan belirtir:
size_t fwrite( const void *adr, size_t boy, size_t elsayi, FILE *dosya_gostergesi ); /* stdio.h */

Yazma ilemi sonras pozisyon gstergesi gncellenir. Fonksiyon yazlan veri eleman saysn dndrr. Bu saynn, yazlacak olan eleman saysndan az olmas hata olutuunu gsterir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-23

rnek 9.1-6 sayibin.c program. #include <stdio.h> #include <stdlib.h> #define DIZIBOY(s) sizeof(s)/sizeof(s[0]) int dizi[] = { 123, 45, -25678, 500, -22 }, Buf[ DIZIBOY(dizi) ]; int main(void) { FILE *fp; char DosyaAd[] = "sayilar.bin"; int i; if ( (fp = fopen( DosyaAd, "wb" )) == NULL ) { perror( "yazma hatasi" ); exit(1); } fwrite( dizi, sizeof(dizi), 1, fp ); fclose( fp ); if ( (fp = fopen( DosyaAd, "rb" )) == NULL ) { perror( "okuma hatasi" ); exit(2); } fread( Buf, sizeof(Buf), 1, fp ); for ( i = 0; i < DIZIBOY(Buf); i++ ) printf("dizi[%d] : %6d\n", i, Buf[i] ); fclose( fp ); return 0; } kt dizi[0] : 123 dizi[1] : 45 dizi[2] : -25678 dizi[3] : 500 dizi[4] : -22

rnek programda, ilk argman olarak elemanlar dosyaya yazlacak olan dizinin balang adresini veren dizi ismi, ikinci argman olarakta bu dizinin bellekte kaplad alann sizeof operatr ile alnan byte says (DOS ortamnda, 5 adet 2-byte tamsaydan oluan dizi olduu iin 10 byte) verilir. nc argman ise, verilen bellek adresinden

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-24

disk dosyasna bir adet 10 byte veri yazlacan belirten 1 deeridir. Son argman ise dosya gstergesi fp'dir:
fwrite( dizi, sizeof(dizi), 1, fp );

Bu ar aadaki ekilde de yaplabilir:


fwrite( &dizi[0], sizeof(dizi[0]), DIZIBOY(dizi), fp );

Bu durumda, 10 byte byklnde 1 dizi yerine, 2 byte byklnde 5 eleman yazlr. Dolaysyla her iki arda ayn ii yapar. Programda dosya tekrar okuma amacyla binary modunda ( "rb" ) alr. Bilgileri okumak iin fwrite fonksiyonun karl olan fread fonksiyonu kullanlr:
size_t fread( const void *adr, size_t boy, size_t elsayi, FILE *dosya_gostergesi ); /* stdio.h */

Bu fonksiyon, belirtilen sayda (elsayi) ve byklkteki (boy) verileri, dosyann bulunulan pozisyonundan okur ve adr ile iaret edilen bellek adresine saklar. lk argman basit bir deikenin, dizinin yada yap deikeninin adresi olabilir. Okuma ilemi sonras pozisyon gstergesi gncellenir. Fonksiyon okunan deerlerin saysn dndrr. Bu say, dosya sonuna eriildiinde yada okuma hatas olutuunda beklenenden az olacaktr. Daha sonra anlatlacak olan ferror ve feof makrolar kullanlarak bu iki durumdan hangisinin olutuu saptanabilir. Programda yer alan fread ars ile okunan deerler, 10 byte uzunluundaki Buf dizisine bir defada aktarlr:
fread( Buf, sizeof(Buf), 1, fp );

rnekteki fread ars aadaki ekilde de olabilir:


fread( &Buf[0], sizeof(Buf[0]), DIZIBOY(Buf), fp );

Burada tek bir elemann byte olarak boyutu verilir ve okunacak eleman says belirtilir. Her iki arda da 10 byte veri transferi gerekleir. Buf ve &Buf[0] ifadelerinin her ikisi de, dizinin balang adresini verir. Binary mod ve binary format birbirine kartrlmamaldr. Modlar (binary ve text) fopen fonksiyonuna aktarlan argmanlardr ve daha ncede anlatld gibi NL karakterinin evrilmesine ve EOF iaretlerinin yorumlanmasna etki eder. Formatlar ise (binary ve text) saysal deerlerin temsil edilme ekilleridir. Dolaysyla, text modunda alm bir dosyaya yazmak iin fwrite fonksiyonu kullanlr ise, her bir NL karakteri CR-LF ifti ile deitirilir. fread fonksiyonu kullanlarak text modunda alan bir dosyadan okuma yapldnda da, yine CR-LF karakterleri tek bir NL karakterine evrilir.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-25

Text mod, ASCII text dosyalarndan okumak ve bu dosyalara yazmak iin uygundur. Text mod kullanlr ise, NL karakteri CR-LF iftine evrilecei iin DOS'un TYPE komutu kullanlarak dosya ekrandan listelenebilir. Okuma-yazma teknii birbiri ile ayn olduu srece, ASCII karakter dizgileri ile ilemler yaplrken ve bunlar diske yazarken text yada binary formatn kullanlmas pek farketmez. Fakat text mod ve text format saysal deerleri yazmak ve okumak iin uygun deildir. Saysal deerleri (tamsaylar ve kayan-noktal saylar) binary moddaki dosyalara, binary formatta saklamak daha uygundur. Bunun sebepleri unlardr:
l

Binary format hemen hemen her zaman disk alanndan tasarruf salar. Text formatnda, "12345.678" rakamlar ASCII kodlar iin 8 byte, ondalk nokta iin bir byte ve deikenler arasndaki ayralar iin de bir yada daha fazla byte gerektirir. Binary formatta ise kayan-noktal bir say, deeri ne olursa olsun 4 byte kullanr. short tamsaylar sadece 2 byte kullanr (DOS ortamnda sayilar.bin dosyas diskte 10 byte, sayilar.txt dosyas ise 90 byte yer kaplar). Donanma bal olarak binary formattaki bir tamsay diskte daima 2 byte (DOS altnda) yer kaplar. Text formatndaki bir tamsay ise, eitli sayda byte kullanr; bu tek bir karakter olabilecei gibi (rnek; "5"), alt karakter de olabilir (rnek "-10186" ). Binary format kullanm bilgisayar zamanndan tasarruf salar. Saysal bir deeri diske yazmak iin fprintf kullanldnda, bilgisayar kendi kulland iki tabanl saylar karakter serilerine evirmelidir. Yine bu ilemler srasnda kullanlan fscanf ise, karakterleri bellee okurken tersini yapar ve ikili saylara evirir. Binary formatta bu evrimlerin hi biri olmaz.

ekil 9.1-2 Text modunda okuma ve yazma ilemleri srasnda satr-sonu karakterinin yorumlanmas.
Bellek

... ...
YAZMA

Disk
DISK

NL
OKUMA

CR-LF

... ...

Binary format kayan-noktal saylarn hassasiyetini korur. kili tabandan ASCII ondalk koda evirmek ve tekrar ilemi tersine tekrarlamak hassasiyeti etkileyebilir.
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-26
l

Dizilerin ve yaplarn binary olarak saklanmas hzldr. rnein 100 elemanl bir dizinin tamamn okumak ve her birini disk dosyasna yazmak gereksizdir (dng vs... ile). Yerine sadece bir kez fwrite fonksiyonu arlr ve saklanacak olan dizinin boyutlar aktarlr.

Grld gibi, binary format birok avantaj sunar. Aadaki program diskte 20 byte byklnde sayi.bin dosyas oluturur. fwrite fonksiyonu kullanlarak yazlan bilgiler fread fonksiyonu ile okunur. Bundan sonra dosyann pozisyon gstergesi rewind fonksiyonu ile baa alnr ve binary dosya fgetc fonksiyonu kullanlarak byte-byte okunur. Okunan deerler onaltlk saylar olarak listelenir.
rnek 9.1-7 bin.c program. #include <stdio.h> #include <stdlib.h> #define EL_SAY 10 int main(void) { FILE *fp; int dizi[ EL_SAY ], a_dizi[ EL_SAY ]; int i; for ( i = 0; i < EL_SAY; i++ ) dizi[ i ] = 790 + i; if ( (fp = fopen( "sayi.bin", "wb" )) == NULL ) { perror( "yazma hatasi" ); exit(1); } fwrite( &dizi[0], sizeof(dizi[0]), EL_SAY, fp ); fclose( fp ); if ( (fp = fopen( "sayi.bin", "rb" )) == NULL ) { perror( "okuma hatasi" ); exit(2); } fread( &a_dizi[0], sizeof(a_dizi[0]), EL_SAY, fp ); for ( i = 0; i < EL_SAY; i++ ) printf("dizi[%d] : %4d, 0x%04X\n", i, a_dizi[i], a_dizi[i] ); rewind( fp ); while ( (i = fgetc( fp )) != EOF ) printf( "%02X ", i ); fclose( fp ); return 0; } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-27

...rnek 9.1-7 devam


kt dizi[0] : 790, 0x0316 dizi[1] : 791, 0x0317 dizi[2] : 792, 0x0318 dizi[3] : 793, 0x0319 dizi[4] : 794, 0x031A dizi[5] : 795, 0x031B dizi[6] : 796, 0x031C dizi[7] : 797, 0x031D dizi[8] : 798, 0x031E dizi[9] : 799, 0x031F 16 03 17 03 18 03 19 03 1A 03 1B 03 1C 03 1D 03 1E 03 1F 03

0x031B ^Z
high-byte

... 03 19 03 1A 03 1B 03 ... 0x031A


low-byte

ktda grld gibi, diskteki 2 byte saylarn low byte', high byte ncesinde bulunur. lk iki byte 0x0316 yani 790 saysdr. Dierleri de bu ekilde devam eder. Diskte 20 byte yer kaplayan sayi.bin dosyas DOS iletim sisteminde bulunan TYPE komutu ile listelendiinde, dosya ASCII karakterler iermedii iin ekranda eitli grafik karakterler olarak listelenir. Fakat bu karakterlerin yalnzca 8 tane olduu grlr. Bunun nedeni, sayi.bin dosyas iinde bulunan 1A karakterinin DOS iletim sisteminde bir text dosyasnn sonunu iaretleyen EOF (Ctrl+Z) iareti olmasdr. Aslnda bu karakter, 0x031A ( 794 ) saysnn low byte'dr. Ayrca, bu dosya okumak amacyla text modunda alarak, yine fgetc fonksiyonu ile byte-byte okunduunda ancak 1A karakterine kadar olan 8 byte listelenir (16 03 17 03 18 03 19 03). rnekte grld gibi binary modunda 1A karakterinin hi bir anlam yoktur. Bu nedenle tm karakterler sorunsuz olarak listelenir. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-28

9.2 Giri/k Hatalarnn lenmesi


Giri/k hatalarnn saptanmasnda ve ilenmesinde giri/k fonksiyonlarnn dndrd deerler ve C ktphanesinde bulunan baz zel makro ve fonksiyonlar kullanlabilir. rnek programlarda dosya ama hatalarn saptamak iin fopen fonksiyonunun dndrd adres deerinin NULL olup olmad kontrol edildi. Ayrca baz fonksiyonlarn dndrdkleri deerin dosya sonuna gelindiini belirten EOF olup olmad kontrol edildi. Daha sonra rnek 9.1-4'de fprintf fonksiyonu kullanlarak, rnek 9.1-6 ve rnek 9.1-7'de ise perror fonksiyonu kullanlarak ekrana hata mesajlar yazld. rnek programlarda genel olarak, programn okunabilirliini arttrmak iin giri/k fonksiyonlar kullanlrken hata kontrol yaplmad.

FILE veri yaps, veri transferinde kullanlan tampon alana ait bilgileri (tampon alann yeri, tampondaki o anda okunacak yada yazlacak olan karakterin pozisyon bilgisi gibi), handle olarak adlandrlan dosya numarasn, giri/k ilemleri srasnda hata oluup olumadn yada okuma srasnda dosya sonuna eriilip eriilmediini gsteren kontrol ve durum bilgisi (hata gstergesi ve dosya-sonu gstergesi) ve dosyadan okuma yada yazma ilemlerinden hangisinin yapld bilgisini ierir. Okuma srasnda dosya sonuna erien bir fonksiyon dosya-sonu gstergesine (end-of-file indicator) 0 olmayan bir deer atar. Ayn ekilde, okuma yada yazma hatas ile karlaan bir fonksiyon hata gstergesine (error indicator) 0 olmayan bir deer atar. Baz ktphane fonksiyonlar hata durumunda da yanltc olabilecek EOF bilgisi dndrrler. Standart ktphane makrolar feof ve ferror hangi durumun gerekletiini saptamak iin kullanlabilir. clearerr fonksiyonu, hata gstergesini silerek hata durumunu ortadan kaldrr. rnek 9.2-1'de bu fonksiyon ve makrolar kullanlarak giri/k hatalar saptanr ve buna gre baz deyimler altrlr.
rnek 9.2-1 hatatest.c program. #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { FILE *fp_yaz, *fp_oku; int i; char isim[13] = ""; printf("Diskte bulunmayan bir dosya adi giriniz: "); gets( isim ); if ( *isim == '\0' ) { C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-29

...rnek 9.2-1 devam


fprintf( stderr, "Dosya ismi girilmedi\n" ); /* exit(1); */ } if ( (fp_oku = fopen( isim, "r" ) ) == NULL ) { perror( "Dosya okunamadi " ); fprintf( stderr, "Dosya okunamadi : %s\n", strerror( errno ) ); /* exit(2); */ } do { printf("Diskte bulunmayan bir baska dosya adi giriniz: "); gets( isim ); } while ( (fp_yaz = fopen( isim, "r" )) != NULL ); if ( (fp_yaz = fopen( isim, "w" )) == NULL ) { fprintf( stderr, "Dosya acilamadi" ); exit(3); } printf("\n%s dosyasi yazma amaciyla acildi.\n\n", isim ); if ( fgetc( fp_yaz ) == EOF ) fprintf( stderr, "Hata: fgetc okuyamadi\n"); if ( feof( fp_yaz ) ) fprintf( stderr, "EOF\n"); if ( ferror( fp_yaz ) ) fprintf( stderr, "Hata: ferror\n"); for ( i = 0; i < 10; i++ ) { printf("i: %d, ", i ); if ( fprintf( fp_yaz, "%d", i ) < 0 ) fprintf( stderr, "Hata: fprintf, "); if ( ferror( fp_yaz) ) fprintf( stderr, "Hata: ferror"); puts( "" ); if ( i == 4 ) { puts( "--clearerr--" ); clearerr( fp_yaz ); } if ( i == 7 ) { puts( "--fclose--" ); fclose( fp_yaz ); } C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-30

...rnek 9.2-1 devam


} /* for */ if ( fclose( fp_yaz ) ) fprintf( stderr, "Hata: fclose\n"); if ( (fp_oku = fopen( isim, "r" ) ) == NULL ) { fprintf( stderr, "%s dosyasi okunamadi\n", isim ); exit(4); } printf( "%s dosyasinda bulunan karakterler : ", isim ); while ( (i = fgetc( fp_oku )) != EOF ) fputc( i, stdout ); fclose( fp_oku ); puts( "" ); return 0; } kt Diskte bulunmayan bir dosya adi giriniz: deneme Dosya okunamadi : No such file or directory Dosya okunamadi : No such file or directory Diskte bulunmayan bir baska dosya adi giriniz: deneme deneme dosyasi yazma amaciyla acildi. Hata: fgetc okuyamadi Hata: ferror i: 0, Hata: ferror i: 1, Hata: ferror i: 2, Hata: ferror i: 3, Hata: ferror i: 4, Hata: ferror --clearerr-i: 5, i: 6, i: 7, --fclose-i: 8, Hata: fprintf, Hata: ferror i: 9, Hata: fprintf, Hata: ferror Hata: fclose deneme dosyasinda bulunan karakterler : 01234567

rnek 9.2-1'de ilk olarak diskte bulunmayan bir dosya (deneme dosyas) fopen fonksiyonu tarafndan okuma amacyla almak istenir. Bu durumda fopen bo adres deeri dndrr ve if blounda yer alan ve ekrana hata mesajlar yazan perror ve fprintf deyimleri altrlr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-31

Hata durumunu oluturan ktphane fonksiyonu arsnn hemen sonrasna yerletirilen perror fonksiyonu, ekrana ilk olarak argman olarak verilen dizgi'yi yazar. Bu dizgi, bo dizgi olabilir (""). Bunu, ":" iareti, sistem hata mesaj, bir boluk ve NL karakteri izler:
void perror( const char *dizgi ); /* stdio.h */

perror fonksiyonu kty, stderr'e yazar. Bylece hata mesajlar, ynlendirme yaplsa bile ekrana yazlr. Programda izleyen satrda grld gibi ayn sistem hata mesaj fprintf ve strerror fonksiyonu kullanlarak stderr'ye yazlabilir. Bu fonksiyon, hata_kodu tamsay deikeninin deerine karlk gelen sistem hata mesaj dizgisinin adresini dndrr:
char *strerror( int hata_kodu ); /* string.h */

Programda, strerror fonksiyonuna argman olarak errno deikeni aktarlr. Bir C ktphane fonksiyonunda hata olutuunda, fonksiyon global tamsay sistem deikeni errno'ya belli bir deer atar. perror fonksiyonu sistem hata mesajlar tablosunda bulunan ve errno'nun deerine karlk gelen mesaj ekrana yazar. zleyen satrdaki standart hata akmna yazan fprintf arsnda yer alan strerror fonksiyonu da, yine errno'nun deerine karlk gelen bu hata mesajna iaret eden bir adres deeri dndrr. Dolaysyla ktda da grld gibi her iki ar da ayn ii yapar. Programlarn tanabilir olmas iin direk errno deikeni kullanlarak hata mesaj listelemek uygun deildir. nk hata numaralar sisteme bal olarak deiebilir. Programdan k nlemek amacyla, ilk iki exit ars aklama satr haline getirilir. Programa tekrar bir dosya ismi girilir (deneme). Fakat bu dosya yazma amacyla alaca iin, yanllkla diskte bulunan bir dosya ismi girildiinde iindeki bilgiler kaybolacaktr. Girilen isimde bir dosyann diskte bulunmadndan emin olmak iin, dosya okuma amacyla alr. Eer dosya mevcut ise, do-while dngs diskte bulunmayan bir dosya ismi girilinceye kadar devam eder. Yine deneme dosyas yazma amacyla alr ve hata oluturmak iin fgetc fonksiyonu ile dosyadan okuma giriiminde bulunulur. Dosya yazma amacyla alm olduu iin okuma giriimi akmda hata oluturur. Sonu olarak fgetc fonksiyonu EOF dndrr. Fakat bunun gerekten bir EOF durumu olup olmad feof ve ferror makrolar kullanlarak anlalabilir. feof makrosu, alan dosyann FILE veri yapsnda bulunan dosya-sonu gstergesini belli bir deer iin kontrol eder. Dosyadan okuyan bir fonksiyon dosya sonuna eriir ise, bu gstergeye 0 olmayan bir deer atar. Bu deer, if deyiminin test ifadesinde yer alan feof makrosu tarafndan saptanr. Bu durumda makro 0 dnda bir deer dndrerek (aksi taktirde 0 dndrr) if deyiminin doru blounun almasn salar:
int feof( FILE *dosya_gostergesi ); /* stdio.h */

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-32

Ayn ekilde, ferror makrosu da hata gstergesini belli bir deer iin kontrol eder:
int ferror( FILE *dosya_gostergesi ); /* stdio.h */

dosya_gstergesi ile belirtilen dosyadan en son okuma yada dosyaya en son yazma ileminde hata oluur ise ilgili fonksiyon hata gstergesinin deerini deitirir ve 0 olmayan bir deer atar. Bunu saptayan ferror makrosu da 0 dnda bir deer dndrerek (aksi taktirde 0 dndrr) if deyiminin doru blounu altrr. Sonu olarak ktda da grld gibi, yazma amacyla alm bir dosyadan okuma giriiminde bulunulduu iin akmda hata olumutur ve bu bir EOF durumu deildir. Dosyaya for dngs iinde fprintf fonksiyonu ile i deikeninin deerleri yazlr. Hata gstergesi otomatik olarak silinmedii iin akmda hata durumu devam eder. i deikeninin deeri 4 olduunda arlan clearerr fonksiyonu, dosya_gostergesi ile ifade edilen dosyann hata ve dosya-sonu gstergelerini siler:
void clearerr( FILE *dosya_gostergesi ); /* stdio.h */

Grld gibi, clearerr arlarak sfrlanncaya kadar hata gstergesi deerini korur (daha sonra anlatlacak olan bir fseek, fsetpos yada rewind ars da hata gstergesini siler). i deikeninin deeri 7 olduunda dosya kapatlr. Dosyaya yazamad iin fprintf fonksiyonu negatif bir deer dndrr ve if bloundaki hata mesaj listelenir. Ayrca fprintf fonksiyonu hata gstergesi aktif hale getirir (0 olmayan bir deer atar). Bunu saptayan ferror fonksiyonu da if blounun doru ksmn altrarak ekrana hata mesaj yazar. Dng knda, fclose ile dosya tekrar kapatlmaya allr. Fonksiyon EOF dndrr ve if deyiminin doru ksm alarak ekrana hata mesaj listelenir. Programda son olarak deneme dosyasna yazlan karakterler listelenir. Grld gibi, fclose ile dosya kapatlmadan nceki tm deerler yazlr. Programlarda, herhangi bir hata durumunda programn almasn durdurarak kmak iin standart ktphane fonksiyonu exit kullanld. Bu fonksiyonun prototipi standart balk dosyas stdlib.h'de bulunur:
void exit( int tamsay ); /* stdlib.h */

exit fonksiyonuna argman olarak aktarlan tamsay k kodu olarak adlandrlr ve program altran ortama (DOS'ta ERRORLEVEL parametresine yada UNIX iletim sisteminde benzer bir shell deikenine) aktarlr. Eer program bir DOS toplu komut dosyas iinden altrlyor ise, bu dosyada bulunan IF ERRORLEVEL komutu ile dndrlen k kodu test edilerek sonuca gre eitli dallandrmalar yaplarak baz ilemler gerekletirilebilir. Genel olarak, normal bir k ifade etmek iin 0 deeri, hata olumas sonucu k ifade etmek iin ise 0 dnda herhangi bir deer (non-zero value) kullanlabilir. Programdan kmak iin main blou iinde kullanlan bir return ifade deyimi, exit(ifade) ile ayn ii yapar. exit fonksiyonu giri/k ilemleri iin alan dosyalar ile ilgili tm tampon alanlar boaltr (flushing) ve tm dosyalar kapatr. k kodu olarak, stdlib.h'de tanmlanm olan sembolik sabitler EXIT_SUCCESS ve
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-33

EXIT_FAILURE kullanlabilir. Bu sabitler, baarl yada hatal bir k ifade etmek ve programlarn tanabilir olmas iin kullanlabilir. rnek 9.2-2'de ilk olarak global sistem deikeni errno'ya 0 deeri atanr. Daha sonra diskte bulunmayan bir text dosyas (DOSYA) okuma amacyla almak istenir. fopen fonksiyonu, DOSYA dosyas diskte bulunmad iin okuma amac ile aamaz ve bo adres deeri dndrr. Bu nedenle, if deyiminin doru blounda bulunan deyimler altrlr.
rnek 9.2-2 error.c program. #include <stdio.h> #include <stdlib.h> #include <errno.h> /* errno degiskeni bildirimi icin */ int main(void) { FILE *fp_oku; errno = 0; printf( "errno : %d\n", errno ); if ( (fp_oku = fopen( "DOSYA", "r")) == NULL ) { printf( "errno : %d\n", errno ); perror( "DOSYA bulunamadi\n" ); exit(1); } return 0; } kt errno : 0 errno : 2 DOSYA bulunamadi : No such file or directory

ktda da grld gibi fopen ars sonras errno deikeninin deeri deiir. Bu deere gre almak zere, programlar iinde eitli hata rutinleri dallandrlabilir. Fakat daha nce de belirtildii gibi programlarn tanabilirlii asndan bu deerin kullanlmas uygun deildir. Bunun yerine, hata mesajlar perror fonksiyonu ile ekrana yazlr. printf fonksiyonu ktsn stdout'a yani standart k birimi ile ilgili akma gnderir. Standart k birimi ynlendirme yaplmad srece ekrandr. Dolaysyla printf ktlar ynlendirilmedii srece ekranda listelenir. Komut satrnda error > hata.err uygulandnda, printf fonksiyonunun ktlar disk dosyas hata.err'e ynlendirilir ve bu dosyaya yazlr. perror kts ise standart hata k akm olan stderr'e (dolaysyla
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-34

ekrana) gnderilir. Bylece standart kn bir kt dosyasna (hata.err) ynlendirilip ynlendirilmediine yada bir pipe ileminin ( "|" kullanlarak bir programn standart knn baka bir programn standart giriine yneltilmesi. rnek : prog1 | prog2 ) olup olmadna baklmakszn hata kts ekrana gnderilir:
printf kts hata.err dosyasna yazlr A:\> error > hata.err DOSYA bulunamadi perror kts ekrana yazlr : No such file or directory

Bu nedenle hata mesajlarnn ekrana yazlmasnda printf yerine perror fonksiyonu yada ounlukla stderr'e yazan fprintf ars tercih edilir. n

9.3 Giri/k lemlerinde Komut Satr Argmanlarnn Kullanlmas


Dosya isimleri, disk dosyalar zerinde giri/k ilemleri gerekletiren programlara komut satrndan aktarlabilir. Komut satrna girilen tm bilgiler program ismi de dahil olmak zere main fonksiyonunun argmanlardr. Aadaki rnekte yer alan dump program, herhangi bir disk dosyasn binary modunda aarak ierdii verileri onaltlk tabanda iki haneli tek byte deerler olarak standart ka yazar. Ayrca bu deerlerin ASCII karakter karlklar da her satrda listelenir. Grafik olarak ekrana yazlamayan karakterler "." ile deitirilir. Program isminden sonra komut satrna girilen argmanlar verilerin okunaca disk dosyas isimleri olarak ele alnr. Eer argman listesinde bulunan herhangi bir dosya alamaz ise ekrana hata mesaj yazlarak programdan klr. Herhangi bir argman girilmez ise, ekrandan dosya ismi sorulur. Dosya ismi girilmediinde ise, programn kullanm formatn belirten bilgi ve hata mesaj yazlarak programdan klr. Dosyalar binary modunda alarak, CR/LF karakter iftlerinin NL karakterine evrilmesi nlenmitir. Bu nedenle, DOS iletim sisteminde bulunan dir komutunun verdii dosya bykl ile dump ktsnda yer alan byte says ayndr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-35

rnek 9.3-1 dump.c program. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define BASLIK "Hex (Dec ) ------------- Hexadecimal Kodlar \ -------------- --- ASCII Kod ----" void Listele( char * ); int main( int argc, char *argv[]) { char DosyaAdi[ 13 ]; if ( argc == 1 ) { printf( "Dosya adi ? : " ); gets( DosyaAdi ); if ( '\0' == *DosyaAdi ) { fprintf( stderr, "Dosya adi girilmedi.\n" ); fprintf( stderr, "Kullanim: dump <dosya listesi>\n" ); exit(0); } Listele( DosyaAdi ); } else while ( *(++argv) ) { printf( "Dosya adi : %s\n", *argv ); Listele( *argv ); } return 0; } void Listele( char *GirisDosya ) { FILE *fp_oku; unsigned char Dizgi[ 16 ]; unsigned ToplamOku = 0; int i, Okunan; if ( (fp_oku = fopen( GirisDosya, "rb")) == NULL ) { fprintf( stderr, "%s acilamadi.\n", GirisDosya ); exit(1); } puts( BASLIK ); C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-36

...rnek 9.3-1 devam


while ( (Okunan = fread( Dizgi, 1, 16, fp_oku )) > 0 ) { ToplamOku += Okunan; printf( "%04X(%04u) ", ToplamOku, ToplamOku ); for ( i = 0; i < 16; ++i ) if ( i < Okunan ) { printf( " %02X", Dizgi[i]); if ( !isprint( Dizgi[i] ) ) Dizgi[i] = '.'; } else { printf( " " ); Dizgi[i] = ' '; } printf( " |%16.16s|\n", Dizgi ); } /* while */ printf( "Toplam byte: %d\n", ToplamOku ); fclose( fp_oku ); } kt nceki blmlerde dump ktlar verildi.

rnek 9.3-2'de tipik bir kelime, karakter ve satr sayma program olan say.c yer alr. Program komut satrndan girilen seeneklere (option yada switch) gre, yine komut satrnda yer alan bir yada daha fazla dosyann kelime, karakter yada satr saysn ekrana listeler. Komut satrnda sadece seenekler bulunuyor ise giri dosyas olarak standart giri kabul edilir. Programda yer alan ilk if deyiminin test ifadesinin doru olmas iin, komut satrnda program isminden baka argmanlarn bulunmas (argc > 1) ve bu argmanlardan ikincisinin ilk karakterinin seenek argman balangcn ifade eden '-' karakteri olmas gerekir:
*argv[1] == '-'

Burada, argv[1][0] == '-'' yada **++argv == '-' kullanlabilir. Fakat ikinci ifade argv'nin deerini deitirdii iin tercih edilmez. Bu iki koul salandnda if deyiminin doru blounda bulunan for dngs ile girilen seenekler belirlenir. Bunun iin char * tipindeki Opsiyon adres deikenine ikinci argmann birinci elemannn (argv[1]+1) bellek adresi atanr. Opsiyon deikeninin deeri arttrlarak izleyen seenek harfleri taranr. k, r ve s harflerinden baka herhangi bir harf girilir ise ekrana
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-37

girilen harf ile birlikte hata mesaj yazlarak programdan klr. Yine ayn blokta argman says 2'den byk ise seenek argmanndan sonra dosya isimleri girildii kabul edilir ve bu girilen isimlerin herbiri Say fonksiyonuna argman dizgisi bellek adresi olarak aktarlarak teker teker ilenir. Seenek argmanndan baka herhangi bir argman bulunmuyor ise bilgiler standart giriten okunur.
DOS iletim sisteminde say.c program iin 3 argmanl bir komut satr:
balang eleman argv[1][0] birinci eleman argv[1][1]

A:\> say -krs


argv[0] 1. arg. argv[1] 2. arg.

say.c
argv[2] 3. arg

argc = 3

rnek 9.3-2 say.c program. #include <stdio.h> #include <stdlib.h> #define #define #define #define #define #define #define KELIME BTABNL NL TAB BOSLUK DOGRU YANLIS 0 1 0 '\n' '\t' '' 1 /* kelime icin isaret /* bosluk, tab yada NL icin isaret */ */

void Say( int S, int K, int R, char *DosyaAd ); main( int argc, char *argv[] ) { char *Opsiyon; int S = YANLIS, K = YANLIS, R = YANLIS; int i; if ( argc > 1 && *argv[1] == '-' ) { for ( Opsiyon = argv[1]+1; *Opsiyon; ++Opsiyon ) switch( *Opsiyon ) { case 'k': K = DOGRU; break; case 'r': R = DOGRU; break; case 's': C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-38

... rnek 9.3-2 devam


S = DOGRU; break; default : fprintf( stderr, "Bilinmeyen opsiyon %c\n", *Opsiyon ); exit(0); } if ( argc > 2 ) for ( i = 2; i < argc; ++i ) Say( S, K, R, argv[i] ); else Say( S, K, R, "" ); } else { fprintf( stderr, "Kullanim : say -opsiyon [dosya_listesi]\n" ); fprintf( stderr, "Opsiyonlar : (k)elime, ka(r)akter, (s)atir \n" ); fprintf( stderr, "Ornek : say -krs say.c\n" ); exit(0); } return 0; } void Say( int S, int K, int R, char *DosyaAd ) { FILE *fp_oku; long SatirSayi = 0, KelimeSayi = 0, KarSayi = 0; int Onceki = BTABNL, c; if ( *DosyaAd == '\0' ) fp_oku = stdin; else if ( (fp_oku = fopen( DosyaAd, "r" )) == NULL ) { fprintf( stderr, "%s acilamadi\n", DosyaAd ); exit(1); } while ( (c = fgetc( fp_oku )) != EOF ) { ++KarSayi; if ( c == NL ) ++SatirSayi; if ( Onceki == BTABNL && c != BOSLUK && c != TAB && c != NL ) { ++KelimeSayi; Onceki = KELIME; } if ( Onceki == KELIME && (c == BOSLUK || c == TAB || c == NL) ) Onceki = BTABNL; } /* while */ C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-39

... rnek 9.3-2 devam


if ( ferror( fp_oku ) ) { fprintf( stderr, "%s okunamadi\n", DosyaAd ); exit(2); } if ( *DosyaAd == '\0' ) puts(" Giris Dosyasi : stdin"); else { printf(" Giris Dosyasi : %s\n", DosyaAd ); if ( fclose(fp_oku) ) { fprintf( stderr, "%s kapatilamadi\n", DosyaAd ); exit(3); } } if ( S == DOGRU ) printf( "\tsatir : %ld\n", SatirSayi );

if ( K == DOGRU ) printf( "\tkelime : %ld\n", KelimeSayi ); if ( R == DOGRU ) printf( "\tkarakter : %ld\n", KarSayi } kt A:\>say -krs say.c Giris Dosyasi : satir : kelime : karakter : say.c 175 553 3451 );

NOT: DOS iletim sistemi altnda say.c dosyas dir komutu ile listelendiinde, 3626 karakterden olutuu grlr. Bunun nedeni programda dosyann text modunda alm olmas ve dolaysyla diskteki CR/LF karakter iftlerinin bellekte tekbir NL ile temsil ediliyor olmasdr ( 175 + 3451 = 3626 ).

Argman girilmediinde yada ikinci argmann ilk karakteri '-' deil ise if deyiminin else ksmnda bulunan deyimler altrlr ve ekrana programn kullanm format yazlarak programdan klr. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-40

9.4 Rastgele Eriim


rnek programlarda grld gibi, giri ve k ilemleri normal olarak sral gerekleir. Yani her disk dosyasndan okuma yada disk dosyasna yazma, bir nceki ilemin yapld dosya pozisyonunu izleyen pozisyonda gerekleir. Okuma yada yazma ilemini gerekletiren fonksiyon, ilem sonras dosyann pozisyon gstergesini (yada okuma yazma kursor) izleyen pozisyona iaret edecek ekilde arttrr. C ktphanesinde bulunan baz fonksiyonlar kullanlarak istenen dosya pozisyonuna ulalabilir ve bylece sral olmayan (rastgele) eriim gerekletirilebilir. Bu fonksiyonlar fseek, ftell, fsetpos, fgetpos ve rewind fonksiyonlardr.
ekil 9.4-1 fseek fonksiyonu.

1234567890 karakterlerini ieren bir dosyada fseek ile pozisyon belirleme:


fseek( fp, 0L, 0) Dosya balangc Dosya sonu fseek( fp, 5L, 0) offset 0 offset 5 fseek( fp, 1L, 1) fseek( fp, 0L, 2)

...

9
1 byte

0 ...

fseek( fp, 5L, 0) fseek( fp, -10L, 2) fseek( fp, 0L, 0); fseek( fp, 5L, 0); fseek( fp, 1L, 1 ); fseek( fp, 5L, 0); fseek( fp, -1L, 1 ); fseek( fp, -10L, 2 );

fseek( fp, -1L, 1)

Dosya balangcna gider (1 deeri) Dosya balangcndan itibaren 5 karakter ileri gider (6. karakter pozisyonu). Sonra yine 1 karakter ilerler. (7. karakter yani 7 deeri) Dosya balangcndan itibaren 5 karakter ileri gider (6. karakter pozisyonu). Sonra 1 karakter geri gider. (5. karakter yani 5 deeri) Dosya sonundan itibaren 10 karakter geri gider (1 deeri)

nceki blmlerde de anlatld gibi bir disk dosyas fopen fonksiyonu ile alrken fonksiyonun ikinci argman olan mod dizgisinde r,w yada a eriim tipleri ile birlikte kullanlan + (art iareti), dosyann gncellemek yani hem okumak hem de yazmak amacyla alacan ifade eder. Okuma ve yazma ilemleri arasnda gidip gelirken, dosya pozisyonu belirleyen fonksiyonlar kullanlarak bu iki ilemin birbirinden ayrlmas salanr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-41

Argman olarak bir disk dosyasna ait dosya gstergesini alan rewind fonksiyonu, dosyann pozisyon gstergesini dosya balangcna ayarlar:
void rewind( FILE *dosya_gostergesi ); /* stdio.h */

rewind fonksiyonu daha nce rnek 9.1-5 ve 9.1-7'de kullanld. rewind arsndan sonra eriilen karakter dosyada bulunan ilk karakterdir. Bir disk dosyas okuma amacyla aldnda bu ilem otomatik olarak yaplr. Dosyada herhangi bir pozisyona ulalmak istendiinde fseek fonksiyonu kullanlr. Bir veri dosyasnda, herhangi bir karakterin pozisyonu yada bir baka deyile dosya balangcndan itibaren byte olarak offset'i, o karakterin dosyada bulunduu yeri ifade eder. Buna gre dosyadaki ilk karakter 0 pozisyonunda (offset deeri 0), ikinci karakter ise 1 pozisyonunda (offset deeri 1) bulunur. fseek fonksiyonu 3 argman alr: bir disk dosyasna ait dosya gstergesi (dosya_gostergesi), eriilmek istenen pozisyonun byte offset deeri olarak bir long tamsay deer (offset), offset'in nereye gre hesaplanacan belirten tamsay (mod):
int fseek( FILE *dosya_gostergesi, long offset, int mod ); /* stdio.h */

mod deeri, offset dosya balangcndan itibaren ise 0, pozisyon gstergesinin o anda bulunduu yere gre ise 1, dosya sonuna gre ise 2 olarak verilir. Ayrca pozitif offset deeri, dosyada ileri gitmek; negatif offset deeri ise dosyada geri gitmek anlamna gelir. Buna gre ekil 9.4-1'de eitli fseek arlar verilmitir. stdio.h balk dosyasnda mod deeri iin tanmlanm sembolik sabitler bulunur: SEEK_SET (0 deeri), SEEK_CUR (1 deeri) ve SEEK_END (2 deeri). Bir rewind ars ile aadaki fseek ars ayn ii yapar:
fseek( fp, 0L, SEEK_SET );

Fakat rewind ars, akmn hata gstergesini sfrlar. Fakat fseek fonksiyonu bu ilemi yapmaz. Her iki fonksiyon da, akmn dosya-sonu gstergesini sfrlar. Bir dier fark ise, rewind fonksiyonu hi bir deer dndrmez. fseek fonksiyonu, hata olumaz ise 0 dndrr. Hata durumunda ise 0 dnda herhangi bir deer dndrr. fseek fonksiyonu text modunda, CR-LF dnmlerinden dolay kstl kullanma sahiptir. Text modunda yalnzca aadaki fseek kullanmlar gvenilir sonular verir:
- offset deeri 0 ile, herhangi bir mod deerine gre yaplan pozisyon ayarlama ilemi: fseek( fp, 0L, SEEK_SET ); fseek( fp, 0L, SEEK_CUR ); fseek( fp, 0L, SEEK_END ); dosya balangcna gider bulunulan pozisyonda kalr dosya sonuna gider

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-42

- Dosya balangcndan itibaren, daha sonra anlatlacak olan ftell fonksiyonunun dndrd deer kullanlarak yaplan pozisyon belirleme ilemi: Pozisyon = ftell( fp ); fseek( fp, Pozisyon, SEEK_SET );

Binary modunda yukarda bahsedilen kstlamalar sz konusu deildir. ftell fonksiyonu, argman olarak bir dosya gstergesi alr ve ilgili disk dosyasnda o anda bulunulan pozisyonun dosya balangcndan itibaren byte olarak offset deerini dndrr:
long ftell( FILE *dosya_gostergesi ); /* stdio.h */

Hatasz alr ise dosyann pozisyon gstergesinin deerini, hata durumunda ise -1L deerini dndrr ve errno deikenine pozitif bir deer atar. Text modunda dndrlen offset deeri, yaplan dnmlerden dolay hatal olabilir. rnek 9.4-1'de binary modunda yazma ve gncelleme amacyla oluturulan veriler dosyasna, bir int ve bir double deer ieren yaplardan oluan yap dizisi Dizi yazlr. Programda daha sonra do-while dngs iinde ekrandan girilen kayt numarasna gre arama yaplr. Bunun iin fseek fonksiyonuna argman olarak aktarlmak zere offset deeri hesaplanr. Kayt numaralar 1'den balar. Fakat offset deerleri 0'dan balar. Bu nedenle, offset deeri hesaplanrken girilen kayt numarasnn 1 eksii kullanlr ( KayitNo - 1 ). Dosyada bulunan herbir kayt, EL_BOY(Dizi) makrosu ile hesaplanan miktar kadar alan kaplar (yani sizeof( struct KAYIT ) ifadesinin dndrd byte says kadar). Bu nedenle herhangi bir kaydn offset miktar, kayt numarasnn 1 eksii ile tekbir yapnn byte saysnn arpmna eittir:
( KayitNo - 1 ) * EL_BOY( Dizi )

Bu ilemin sonucunda elde edilen deer long tipine evrildikten sonra, herhangi bir kaydn dosya balangcna gre offset deeri saptanm olur ve bu deer fseek fonksiyonuna 2. argman olarak aktarlarak istenen pozisyona eriilebilir:
Offset = (long) ( (KayitNo - 1) * EL_BOY(Dizi) ); fseek( fp, Offset, SEEK_SET );

Kayt numaras 0 girildiinde dngden klr ve fseek ars ile dosya balangcna gidilir. Dosya sonuna eriilinceye kadar, i = 4 ve x = 16.4 iin dosyada bulunan kaytlar taranr. Bu deerleri ieren kaydn offset deeri ftell ars ile alnr. Dosya
C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-43

balangcndan itibaren byte olarak alnan bu offset deeri tekbir kaydn byte saysna blnerek kayt numaras bulunur:
Offset / EL_BOY(Dizi) rnek 9.4-1 ftlfsk.c program. #include <stdio.h> #include <stdlib.h> #define EL_SAYI(s) #define EL_BOY(s) (sizeof(s)/sizeof(s[0])) (sizeof(s[0]))

struct KAYIT { int i; double x; } Dizi[] = { { 1, 13.1 }, { 4, 16.4 }, { 3, 15.3 }, { 4, 16.4 }, { 5, 17.5 }, { 4, 16.4 }, }, kk; int main(void) { FILE *fp; long Offset; int KayitNo; if ( (fp = fopen( "veriler", "w+b")) == NULL ) { fprintf( stderr, "VERILER dosyasi acilamadi\n"); exit(1); } if ( fwrite( Dizi, sizeof(Dizi), 1, fp ) < 0 ) { fprintf( stderr, "VERILER dosyasina yazilamadi\n"); exit(2); } puts("-ftell/fseek-"); printf( "Kayit No (1-%d) giriniz, cikis icin 0\n", EL_SAYI(Dizi) ); do { printf("Kayit No ? "); scanf( "%d", &KayitNo ); if( ( KayitNo >= 1 ) && ( KayitNo <= EL_SAYI(Dizi) ) ) { Offset = (long)( (KayitNo - 1) * EL_BOY(Dizi) ); fseek( fp, Offset, SEEK_SET ); fread( &kk, EL_BOY(Dizi), 1, fp ); if ( feof(fp) || ferror(fp) ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-44

...rnek 9.4-1 devam


{ fprintf( stderr, "VERILER dosyasi okunamadi\n"); exit(3); } printf( "\ti:%d, x:%.1f\n", kk.i, kk.x ); } } while( KayitNo ); fseek( fp, 0L, SEEK_SET ); /* rewind( fp ); */ printf("i:4 ve x:16.4 icin kayitlarin listelenmesi\n"); while ( 1 ) { fread( &kk, EL_BOY(Dizi), 1, fp ); if ( feof(fp) || ferror(fp) ) break; if ( (kk.i == 4) && (kk.x == 16.4) ) { Offset = ftell(fp); printf("\tKayit no: %ld --> i=%d, x=%.1f\n", } } fclose(fp); return 0; } kt A:\>ftlfsk -ftell/fseekKayit No (1-6) giriniz, cikis icin 0 Kayit No ? 1 i:1, x:13.1 Kayit No ? 2 i:4, x:16.4 Kayit No ? 3 i:3, x:15.3 Kayit No ? 4 i:4, x:16.4 Kayit No ? 5 i:5, x:17.5 Kayit No ? 6 i:4, x:16.4 Kayit No ? 9 Kayit No ? 0 i:4 ve x:16.4 icin kayitlarin listelenmesi C PROGRAMLAMA DILI, 1997 Ismet Kocaman

Offset / EL_BOY(Dizi), kk.i, kk.x );

9-45

...rnek 9.4-1 kt devam


Kayit no: 2 --> i=4, x=16.4 Kayit no: 4 --> i=4, x=16.4 Kayit no: 6 --> i=4, x=16.4 A:\>

rnek 9.4-2'de, binary modunda alan veri.dat dosyasna "Bu Bir DENEMEdir." dizgisi yazlr. Disket dolu ise, bu durum fputs arsn izleyen if deyiminde bulunan fflush fonksiyonu tarafndan saptanr ve ekrana hata mesaj yazlarak programdan klr. Ayn dosya tekrar okuma ve gncelleme amacyla alr.
NOT: Programda fopen fonksiyonunun ilk argman olan dosya isminde fihrist ayrac olarak ters kesme "\" kullanlmtr ( "A:\\VERI.DAT"). Bu dosya ismi, programn yazld DOS iletim sistemi altnda unu ifade eder: A: srcsnn kk fihristinde bulunan ve uzants DAT olan dosya. Programlarn tanabilir olmas iin, dosya isminin ve uzantsnn uzunluklar ve ierdii karakterlerin ve dosyann bulunduu yeri ifade eden "path" bilgisinin ierdii karakterlerin (burada A:\\) iletim sistemine gre deiebilecei dikkate alnarak tanabilir dosya isimleri kullanlmaldr.

Programda while dngs iinde, dosya sonuna eriilinceye yada herhangi bir hata oluuncaya kadar eitli ilemler gerekletirilir. lk olarak, ftell kullanlarak izleyen fgetc ars ile dosyadan okunacak olan karakterin offset deeri saptanr ve long tamsay Offset deikenine atanr. fgetc ile okunan karakter tamsay i deikenine atanr ve izleyen if deyiminde bu karakterin kk harf olup olmad test edilir. Kk harf deil ise, fgetc tarafndan dosyann pozisyon gstergesi gncellendii iin, Offset deikeninin tad offset deeri kullanarak okuma ncesi pozisyona eriilir ve okunan karakter kk harfe evrilerek fputc fonksiyonu ile ayn pozisyona yazlr. Daha sonra izleyen karakter pozisyonuna bir arttrlan offset deerinin argman olarak kullanld fseek ars ile eriilir.
rnek 9.4-2 harfcev.c program. #include <stdio.h> #include <stdlib.h> #include <ctype.h> int main(void) { FILE *fp; long Offset; int i; if ( (fp = fopen( "A:\\VERI.DAT", "wb" )) == NULL ) C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-46

...rnek 9.4-2 devam


{ fprintf( stderr, "VERI.DAT olusturulamadi\n" ); exit(1); } fputs("Bu Bir DENEMEdir.", fp ); if ( fflush( fp ) ) { fprintf( stderr, "VERI.DAT dosyasina yazilamadi\n" ); exit(2); } fclose( fp ); if ( (fp = fopen( "A:\\VERI.DAT", "rb+" )) == NULL ) { fprintf( stderr, "VERI.DAT bulunamadi\n" ); exit(3); } while ( 1 ) { Offset = ftell( fp ); i = fgetc(fp); if ( (i == EOF) && (feof(fp) || ferror(fp)) ) break; if ( i != tolower(i) ) { fseek( fp, Offset, SEEK_SET ); fputc( tolower(i), fp ); printf("[%04ld] : %c --> %c\n", Offset, i, tolower(i) ); fseek( fp, Offset+1, SEEK_SET ); } else printf("[%04ld] : %c\n", Offset, i ); } return 0; } kt A:\> type veri.dat Bu Bir DENEMEdir. A:\> harfcev [0000] : B --> b [0001] : u [0002] : [0003] : B --> b [0004] : i [0005] : r C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-47

...rnek 9.4-2 kt devam


[0006] : [0007] : D --> d [0008] : E --> e [0009] : N --> n [0010] : E --> e [0011] : M --> m [0012] : E --> e [0013] : d [0014] : i [0015] : r [0016] : . A:\> A:\> type veri.dat bu bir denemedir.

ktda da grld gibi program veri.dat dosyas iindeki tm byk harfleri kk harfe evirir. Bu program, dosyada pozisyon belirleme ileminin hatasz yaplabilmesi iin ftell ve fseek fonksiyonlarnn birlikte kullanmn gstermek iin hazrlanmtr. Karakterlerin kk harfe evirme ilemi basit bir filtre program (standart giriten okuyan ve standart ka yazan) ile yaplabilir:
/* filtre.c */ #include <stdio.h> #include <ctype.h> int main(void) { int c; while ( (c=getchar()) != EOF ) putchar( tolower(c) ); return 0; }

Ayrca komut satrnda ynlendirme yaplarak ktnn bir disk dosyasna yazlmas salanabilir:
A:\> filtre < veri.dat > cikti A:\> type cikti bu bir denemedir. yada A:\> type veri.dat | filtre > cikti
( UNIX iletim sisteminde "type" komutunun karl olarak "cat" komutu kullanlabilir.)

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-48

fgetpos ve fsetpos fonksiyonlar:


fgetpos fonksiyonu, argman olarak bir disk dosyasna ait dosya gstergesini alr ve bu dosyann pozisyon gstergesinin deerini *pozisyon'a (pozisyon tarafndan iaret edilen bellek alanna) atar:
int fgetpos( FILE *dosya_gostergesi, fpos_t *pozisyon ); /* stdio.h */

fsetpos fonksiyonu ise, dosyann pozisyon gstergesini daha nceki fgetpos ars ile *pozisyon'a atanm olan deere ayarlar. Ayrca fsetpos ars, dosya-sonu gstergesini sfrlar:
int fsetpos( FILE *dosya_gostergesi, const fpos_t *pozisyon ); /* stdio.h */

Her iki fonksiyon da hatasz alr ise 0 deerini, hata durumunda ise 0 harici bir deer dndrr ve errno deikenine bir pozitif deer atar. Dosyann pozisyon gstergesinin deerini tayan pozisyon, stdio.h'de tanmlanm olan fpos_t veri tipinde bildirilen bir adres deikenidir. Aadaki rnekte, rnek 9.4-1'de de kullanlan yap dizisinin elemanlar teker teker binary modunda yazma ve gncelleme amacyla oluturulan veriler dosyasna yazlr. Her bir yapnn yazlaca dosya pozisyonu deeri, yazma ilemi ncesi fpos_t tipinde bildirilen PozDizi dizisinin elemanna fgetpos ars ile aktarlr. Dolaysyla herhangi bir kayit numaras dizi indeksi olarak kullanlarak eriilen PozDizi eleman, ayn kaydn pozisyon bilgisini tar. Programda bu teknik kullanlarak, dosyada bulunan kaytlar sondan baa doru listelenir.
rnek 9.4-3 fgpfsp.c program. #include <stdio.h> #include <stdlib.h> #define EL_SAYI(s) #define EL_BOY(s) typedef struct { int i; double x; } KAYIT; KAYIT Dizi[] = { { 1, 13.1 }, { 4, 16.4 }, { 3, 15.3 }, { 4, 16.4 }, { 5, 17.5 }, { 4, 16.4 }, }; KAYIT kk; (sizeof(s)/sizeof(s[0])) (sizeof(s[0]))

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-49

...rnek 9.4-3 devam


int main(void) { FILE *fp; fpos_t PozDizi[ EL_SAYI(Dizi) ]; int index; if ( (fp = fopen( "veriler", "w+b")) == NULL ) { fprintf( stderr, "VERILER dosyasi acilamadi\n"); exit(1); } for ( index = 0; index < EL_SAYI(Dizi); ++index ) { fgetpos( fp, PozDizi+index ); if ( fwrite( &Dizi[index], EL_BOY( Dizi ), 1, fp ) < 0 ) { fprintf( stderr, "VERILER dosyasina yazilamadi\n"); exit(2); } } puts("Kayit: i x \n------ ----- -----"); for ( index = EL_SAYI(Dizi); index > 0; --index ) { fsetpos( fp, &PozDizi[ index-1 ] ); fread( &kk, EL_BOY(Dizi), 1, fp ); printf( "%04d %-3d %-4.1f\n", index, kk.i, kk.x ); } fclose(fp); return 0; } kt A:\>fgpfsp Kayit: i x ------ ----- ----0006 4 16.4 0005 5 17.5 0004 4 16.4 0003 3 15.3 0002 4 16.4 0001 1 13.1 A:\>

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-50

Programda da grld gibi, fgetpos tarafndan alnan pozisyon deeri (*pozisyon ile eriilen), herhangi bir offset hesaplamasnda kullanlmamaldr. Pozisyon deeri kapal bir formatta saklanr ve sadece fsetpos arsnda kullanlmaldr. Ayn ekilde fsetpos fonksiyonu da, hesaplanan herhangi bir offset deeri ile deil, sadece fgetpos tarafndan alnan bir pozisyon deeri ile arlmaldr. Eer dosya balangcndan itibaren byte offset deeri olarak ifade edilen pozisyon bilgisine ihtiya var ise ftell fonksiyonu kullanlmaldr. Herhangi bir byte offsetine gitmek iin fseek kullanlmaldr.

sscanf ve sprintf fonksiyonlar:


rnek programlarda formatl veri girii iin scanf ve fscanf fonksiyonlar, formatl veri k iin ise printf ve fprintf fonksiyonlar kullanld. scanf fonksiyonu verileri standart giriten, fscanf ise herhangi bir dosyadan okur. printf fonksiyonu verileri standart ka, fprintf ise herhangi bir dosyaya yazar. sscanf ve sprintf fonksiyonlar ayn grupta yer alan bir dier fonksiyon iftidir. sscanf fonksiyonu verileri herhangi bir dizgiden (dizgi) okur ve ikinci argman olarak verilen format dizgisinde belirtildii ekilde evirerek argman listesinde karlk gelen deikenlere atar:
int sscanf( const char *dizgi, const char *format, ... ); /* stdio.h */

lk iki argman olan dizgi adreslerini, "..." ile ifade edilen ve deer atanacak olan deikenlerin adreslerinden oluan deiken uzunluktaki argman listesi izler. format dizgisi scanf fonksiyonu ile ayndr. sscanf fonksiyonu baarl olarak okunan ve evrilerek deikenlere atanan alan saysn dndrr. Okuma ilemi tamamlanmadan nce dizgi sonunu belirten bo karaktere rastlanr ise EOF dndrr. sprintf fonksiyonu da yine bir dizgiye formatl olarak yazar. "..." ile ifade edilen deiken uzunluktaki argman listesinde bulunan deikenlerin deerlerini, format dizgisinde (printf format dizgisi ile ayndr) belirtildii ekilde karakterlere evirerek dizgi dizgisine atar:
int sprintf( char *dizgi, const char *format, ...); /* stdio.h */

Fonksiyon aktarlan karakterlerin sonuna bo karakter ekleyerek dizgiyi sonlandrr. Bo karakter hari olmak zere atanan karakter saysn dndrr. Bu iki fonksiyon dizgi giri/k fonksiyonlar olarak adlandrlabilir. Aadaki rnek programda, yap dizisi Dizi'nin elemanlarnn deerleri, sprintf fonksiyonu kullanlarak "%-9s %5.2f\n" formatna gre karakter dizisine evrilerek Buf dizisine aktarlr. Daha sonra Buf karakter dizisi, fputs fonksiyonu kullanlarak text modunda yazma ve gncelleme amacyla oluturulan veri.dat dosyasna yazlr.

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-51

Ayn ilem, fprintf fonksiyonu kullanlarak aadaki ekilde de yaplabilir:


fprintf( fp, "%-9s %5.2f\n", Dizi[i].c, Dizi[i].d );

rnek 9.4-4 dizgi.c program. #include <stdio.h> #include <stdlib.h> #define EL_SAYI(s) (sizeof(s)/sizeof(s[0])) struct KAYIT { char c[5]; double d; } Dizi[ ] = { { "abc", 23.4 }, { "def", 4.56 }, { "xyz", 6.08 }, }; int main(void) { FILE *fp; char cc[5], Buf[BUFSIZ]; int i; double x; if ( (fp = fopen( "veri.dat", "w+" )) == NULL ) { fprintf( stderr, "VERI.DAT dosyasi olusturulamadi\n" ); exit(1); } for ( i = 0; i < EL_SAYI(Dizi); ++i ) { sprintf( Buf, "%-9s %5.2f\n", Dizi[i].c, Dizi[i].d ); fputs( Buf, fp ); } rewind(fp); while ( fgets( Buf, BUFSIZ, fp ) ) { sscanf( Buf, "%s %lf", cc, &x ); printf("%-9s %5.2f\n", cc, x ); } fclose(fp); return 0; } kt abc def xyz 23.40 4.56 6.08

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

9-52

rewind fonksiyonu arlarak pozisyon gstergesi dosya balangcna ayarlanr. veri.dat dosyasnda bulunan satrlar ilk olarak fgets fonksiyonu ile Buf dizisine aktarlr. Buf dizisinde bulunan karakterler sscanf fonksiyonu tarafndan "%s %lf" formatna gre evrilerek cc karakter dizisine ve x deikenine atanr. Ayn ilem, fscanf fonksiyonu kullanlarakta yaplabilir:
while ( fscanf( fp, "%s %lf", cc, &x ) != EOF ) printf("%-9s %5.2f\n", cc, x );

Programda Buf karakter dizisi bildirilirken eleman says BUFSIZ olarak verildi. BUFSIZ sembolik sabiti, stdio.h'de 256'dan byk bir tamsay deer olarak tanmlanmtr (pek ok derleyicide 512'dir). Programlarda kullanlmak zere oluturulan tampon alanlarn bykl rnek 9.4-4'de olduu gibi BUFSIZ olarak verilebilir. Ayn zamanda akm giri/k fonksiyonlar tarafndan kullanlan tampon alanlar herhangi bir ekilde deitirilmedike (default olarak) BUFSIZ byklndedir. n

C PROGRAMLAMA DILI, 1997 Ismet Kocaman

C Programlama Dili - Ornek Program Listesi ve Notlar

NOT
Tum programlar DOS 6.22 altinda Microsoft C6.0 derleyicisi kullanilarak uyari seviyesi 4 ile derlenmistir ve yine ayni ortamda denenmistir. Ayrica programlar ANSI C uyumlu olarak kodlanmistir. Fakat bu programlar hazirlanirken gosterilen tum cabaya ragmen gozden kacan hatalar olabilir. Bu konuda sorumluluk kullaniciya aittir. Ayrica programlarin calistirildigi isletim ortaminda olusabilecek direk yada indirek sorunlardan dolayi yazar sorumlu tutulamaz. Farkli isletim alinmalidir. ortamlarinda calisirken ciktilarin farkli olabilecegi dikkate

Bolum 9 - Giris/Cikis Islemleri


TEXTYAZ.C TEXTOKU.C MOD1.C CRNL.C MOD2.C SAYITEXT.C SAYIBIN.C BIN.C HATATEST.C ERROR.C DUMP.C SAY.C FTLFSK.C HARFCEV.C FILTRE.C FGPFSP.C DIZGI.C Ornek Ornek Ornek Sayfa Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Sayfa Ornek Ornek 9.1-1 9.1-2 9.1-3 9-9 9.1-4 9.1-5 9.1-6 9.1-7 9.2-1 9.2-2 9.3-1 9.3-2 9.4-1 9.4-2 9-39 9.4-3 9.4-4

Derlenmis Program Listesi: TEXTYAZ.EXE ASCII dosya "test.asc" olusturur. TEXTOKU.EXE ASCII dosya "test.asc" okur. MOD1.EXE "test.asc" dosyasini text ve binary modda listeler. MOD2.EXE "text", "binary1" ve "binary2" dosyalarini olusturur. CRNL.EXE CR ve NL karakterlerinin kullanimini ornekler. SAYITEXT.EXE "sayilar.txt" dosyasini olusturur. SAYIBIN.EXE "sayilar.bin" dosyasini olusturur. BIN.EXE "sayi.bin" dosyasini olusturur. HATATEST.EXE Giris/Cikis hatalarinin islenmesi. ERROR.EXE Giris/Cikis hatalarinin islenmesi. DUMP.EXE Onaltilik tabanda, binary modda dosya listeleme. SAY.EXE Bir text tipi dosyanin satir, kelime ve karakter sayilarini listeler. FTLFSK.EXE Rastgele erisim ve ftell/fseek fonksiyonlarinin kullanimi. "veriler" dosyasini olusturur. HARFCEV.EXE VERI.DAT dosyasini olusturur ve icindeki tum buyuk harfleri kucuk harfe cevirir. FILTRE.EXE Cok basit kucuk harfe cevirme programi. FGPFSP.EXE Rastgele erisim ve fgetpos/fsetpos fonksiyonlarinin kullanimi. "veriler" dosyasini olusturur. DIZGI.EXE VERI.DAT dosyasini olusturur. sscanf/sprintf fonksiyonlarinin kullanimini ornekler.

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

Bolum 8 - Yapi Degiskenleri


YAPI1.C YAPI2.C ILKYAPI1.C ILKYAPI2.C YAPIDIZ1.C YAPIDIZ2.C YAPIDIZ3.C YAPIDIZ4.C ADRYAPI1.C ADRYAPI2.C ADRYAPI3.C ADRYAPI4.C ADRYAPI5.C ADRYAPI6.C ADRYAPI7.C YAPFONK1.C YAPFONK2.C YAPFONK3.C YAPFONK4.C YAPFONK5.C UNION1.C UNION2.C BITALAN.C Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek 8.1-1 8.1-2 8.1-3 8.1-4 8.2-1 8.2-2 8.2-3 8.2-4 8.3-1 8.3-2 8.3-3 8.3-4 8.3-5 8.3-6 8.3-7 8.4-1 8.4-2 8.4-3 8.4-4 8.4-5 8.5-1 8.5-2 8.6-1

Derlenmis Program Listesi: YAPI1.EXE Yapi Degiskeni bildirimi ve ilk deger atama. YAPI2.EXE Yapi Degiskeni bildirimi ve ilk deger atama. ILKYAPI1.EXE Yapi Degiskeni bildirimi ve ilk deger atama. ILKYAPI2.EXE Yapi Degiskeni bildirimi ve ilk deger atama. YAPIDIZ1.EXE Yapi Dizileri. YAPIDIZ2.EXE Yapi Dizileri. YAPIDIZ3.EXE Yapi Dizileri. YAPIDIZ4.EXE Yapi Dizileri. ADRYAPI1.EXE Yapi Degiskenine isaret eden adres degiskeni. ADRYAPI2.EXE Yapi Degiskenine isaret eden adres degiskeni. ADRYAPI3.EXE Yapi Adres Dizisi. ADRYAPI4.EXE Yapi Adres Dizisi. ADRYAPI5.EXE Yapi elemani : fonksiyona isaret eden adres deg. ADRYAPI6.EXE Yapi elemanlarinin offset'lerinin hesaplanmasi. ADRYAPI7.EXE Yapi elemani olarak yapi dizisi. YAPFONK1.EXE Yapilarin fonksiyonlara aktarilmasi. YAPFONK2.EXE Yapi adresinin fonksiyona aktarilmasi. YAPFONK3.EXE Dizilerin fonksiyonlara degerleri ile aktarilmasi. YAPFONK4.EXE Yapi degeri donduren fonksiyon. YAPFONK5.EXE Yapi adresi donduren fonksiyon. UNION1.EXE Union degiskenlerin bildirilmesi. UNION2.EXE Yapi elemani olarak union degisken. BITALAN.EXE Bit-alani degiskeni bildirilmesi.

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

Bolum 7 - Dinamik Bellek Yonetimi


DIN2B3B.C I2B3B.C DIN2B.C DIN3B.C DINFONK.C REMALLOC.C REALLOC.C ADRDINDZ.C DINSTRU.C Ornek Sayfa Ornek Ornek Ornek Ornek Ornek Ornek Ornek 7.1-1 7-6 7.1-2 7.1-3 7.1-4 7.1-5 7.1-6 7.1-7 7.2-1

Derlenmis Program Listesi: DIN2B3B.EXE Dizilere isaret eden adres degiskeni ile dinamik 2-b ve 3-b dizilere erisim. (Satir uzunluklari sabit) I2B3B.EXE 2-b ve 3-b dizi isimlerine indirek deger operatorunun uygulanmasi. DIN2B.EXE 2-b dinamik dizilerin olusturulmasi. (tum boyutlar programin calismasi sirasinda girilebilir) DIN3B.EXE 3-b dinamik dizilerin olusturulmasi. (tum boyutlar programin calismasi sirasinda girilebilir) DINFONK.EXE Arguman olarak 2-b dizi alan ve dinamik bellek alani ayiran, serbest birakan, 2-b diziye deger okuyan ve listeleyen fonksiyonlar. REMALLOC.EXE Onceden ayrilmis dinamik bellek alaninin genisletilmesi (yada daraltilmasi) icin olusturulan -remalloc- fonksiyonu. REALLOC.EXE Onceden ayrilmis dinamik bellek alaninin genisletilmesi (yada daraltilmasi) icin Standart Kutuphane fonksiyonu realloc'un kullanilmasi. ADRDINDZ.EXE Farkli uzunlukta dizgilere erisim icin dinamik adres dizisinin olusturulmasi (dynamic ragged array). DINSTRU.EXE Yapilar ve dinamik bellek kullanimi.

Bolum 6 - Adres Degiskenleri ve Cok-Boyutlu Diziler


ADR2B.C ADR3B.C ADR4B.C FONKDIZI.C Ornek Ornek Ornek Ornek 6.1-1 6.1-2 6.1-3 6.2-1

Derlenmis Program Listesi: ADR2B.EXE 2-b dizilere isaret eden adres degiskeni. ADR3B.EXE 3-b dizilere isaret eden adres degiskeni. ADR4B.EXE 4-b dizilere isaret eden adres degiskeni. FONKDIZI.EXE 2-b, 3-b, 4-b dizilerin fonksiyonlara aktarilmasi.

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

Bolum 5 - Adres Degiskenleri


ADRESOP1.C SIZEOF.C ADRESOP2.C ADRESOP3.C ADRESOP4.C DIZI1.C DIZI2.C ARIT1.C ARIT2.C DIZI3.C DIZI4.C DIZI5.C ADR.C KARAK.C DIZGI.C ADRDIZGI.C ADRD.C CIFTADR.C ADRCEVIR.C VOID.C ENDIAN.C BITS.C DEGAKTAR.C REFAKTAR.C REFAKT2.C DIZGIBOY.C SIZE.C DIZGIKOP.C DIZGIKAR.C BLOKKOPY.C DIZGITAR.C ADRF10.C ADRF11.C ADRF12.C ADRF13.C ADRFONK1.C QSORT.C ADRFONK2C ADRFONK3.C FONKTAB1.C FONKTAB2.C ARG1.C ARG2.C ARG3.C SABITARG.C VARUNIX.C DEGISARG.C FAKT1.C FAKT2.C Ornek Sayfa Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Sayfa Sayfa Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Ornek Sayfa Ornek Ornek Ornek 5.1-1 5-5 5.1-2 5.1-3 5.1-4 5.2-1 5.2-2 5.2-3 5.2-4 5.2-5 5.2-6 5.2-7 5.2-8 5.3-1 5.3-2 5.4-1 5.4-2 5.5-1 5.6-1 5.6-2 5-43 5-45 5.7-1 5.7-2 5.7-3 5.7-4 5.7-5 5.7-6 5.7-7 5.7-8 5.7-9 5.7-10 5.7-11 5.7-12 5.7-13 5.7-14 5.7-15 5.7-16 5.7-17 5.7-18 5.7-19 5.7-20 5.7-21 5.7-22 5.8-1 5-86 5.8-2 5.9-1 5.9-2

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

5
Derlenmis Program Listesi: ADRESOP1.EXE Adres Degiskeni Bildirimi SIZEOF.EXE " ADRESOP2.EXE " ADRESOP3.EXE " ADRESOP4.EXE " DIZI1.EXE Adres Degiskenleri ve Diziler DIZI2.EXE " ARIT1.EXE " ARIT2.EXE " DIZI3.EXE Adres Degiskenleri ve Tek-Boyutlu Diziler DIZI4.EXE " DIZI5.EXE " ADR.EXE " KARAK.EXE Adres Degiskenleri ve Dizgiler DIZGI.EXE " ADRDIZGI.EXE Adres Dizileri ADRD.EXE " CIFTADR.EXE Cift Adres Degiskeni ADRCEVIR.EXE Adres Degiskenlerine Tip Donusturme Uygulanmasi VOID.EXE void * tipi adres degiskenleri ENDIAN.EXE " BITS.EXE " DEGAKTAR.EXE Adres Degiskenleri ve Fonksiyonlar REFAKTAR.EXE Fonksiyon Argumani olarak Adres Degiskenleri REFAKT2.EXE " DIZGIBOY.EXE Fonksiyon Argumani olarak Diziler SIZE.EXE " DIZGIKOP.EXE " DIZGIKAR.EXE " BLOKKOPY.EXE Adres Degeri Donduren Fonksiyonlar DIZGITAR.EXE " ADRF10.EXE Fonksiyon Argumani olarak Adres Dizileri ADRF11.EXE " ADRF12.EXE " ADRF13.EXE " ADRFONK1.EXE Fonksiyona Isaret eden Adres Degiskeni QSORT.EXE Bir fonksiyonun arguman olarak bir baska fonksiyona aktarilmasi ADRFONK2.EXE " ADRFONK3.EXE " FONKTAB1.EXE Fonksiyon Tablosu FONKTAB2.EXE " ARG1.EXE Komut Satiri Argumanlari ARG2.EXE " ARG3.EXE " SABITARG.EXE Degisen Sayida Arguman alan Fonksiyonlar VARUNIX.EXE " DEGISARG.EXE " FAKT1.EXE Kendini Cagiran Fonksiyonlar FAKT2.EXE "

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

Bolum 4 - Fonksiyonlar
FONK1.C FONK2.C FONKDIZI.C FONKADR.C GLOBAL1.C LOKAL.C BLOK1.C BLOK2.C EXTERN.C DOSYAA.C + DOSYAB.C STATIC.C ILKDEG1.C ILKDEG2.C ILKDIZ1.C ILKDIZ2.C BOSDIZGI.C ONISLE.C BAGLA1.C + BAGLA2.C Ornek Ornek Ornek Sayfa Ornek Sayfa Ornek Ornek Ornek 4.1-1 4.1-2 4.1-3 4-13 4.2-1 4-16 4.2-2 4.2-3 4.2-4

Ornek 4.2-5 Ornek Ornek Ornek Ornek Ornek Ornek Ornek 4.2-6 4.3-1 4.3-2 4.3-3 4.3-4 4.3-5 4.4-1

Ornek 4.5-1

Derlenmis Program Listesi: FONK1.EXE Fahrenhayt cevirme programi FONK2.EXE Fahrenhayt cevirme programi -SantiGrat fonksiyonuFONKDIZI.EXE Fonksiyon argumani olarak diziler FONKADR.EXE Fonksiyon argumani olarak fonksiyon ismi GLOBAL1.EXE Global Degiskenler LOKAL.EXE Global Degisken yerine fonksiyon argumani kullanimi BLOK1.EXE Blok Yapisi BLOK2.EXE Blok Yapisi EXTERN.EXE extern bildirim DOSYAA.EXE extern bildirim (DOSYAA.C+DOSYAB.C) STATIC.EXE static bildirim ILKDEG1.EXE ilk deger atama ILKDEG2.EXE ilk deger atama ILKDIZ1.EXE Dizilere ilk deger atama ILKDIZ2.EXE Dizilere ilk deger atama BOSDIZGI.EXE Bos Dizgiler ONISLE.EXE C Onislemcisi BAGLA1.EXE Bag Ozellikleri (Linkage) (BAGLA1.C+BAGLA2.C)

Bolum 3 - Kontrol Akisi


KONTROL.C Ornek 3.1-1 Derlenmis Program Listesi: KONTROL.EXE Kontrol Akisi deyimleri.

Bolum 2 - Tipler, Operatorler ve Ifadeler


ENUM.C.C TIP.C Ornek 2.3-1 Ornek 2.8-1

Derlenmis Program Listesi: ENUM.EXE enum sabitlerinin kullanimi. TIP.EXE Tip donusumlerini ornekler.

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

Bolum 1 - Giris ve Temel Kavramlar


C.C C-1.C Ornek 1.1-1 Ornek 1.1-1 versiyon 2

Derlenmis Program Listesi: C.EXE Ilk C programi. C-1.EXE Ilk C programi versiyon 2.

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

8 Isletim Sistemi : SunOS Derleme Komutu : cc -o prog prog.c

SunOS altinda farkli cikti listeleyen programlarin listesi


2.8-1 4.2-5 5.1-1 5.2-1 5.2-5 5.4-1 5.7-5 5.7-20 tip.c dosyaa.c adresop1.c dizi1.c dizi3.c adrdizgi.c size.c arg1.c bits.c adr2b.c din2b3b.c remalloc.c adryapi3.c union2.c adryapi1.c textyaz.c bin.c say.c crnl.c 4.5-1 5.1-2 5.2-2 5.2-6 5.5-1 5.7-11 5.7-21 bagla1.c adresop2.c dizi2.c dizi4.c ciftadr.c adrf11.c arg2.c endian.c adr3b.c din2b.c realloc.c adryapi4.c bitalan.c adryapi6.c textoku.c hatatest.c harfcev.c filtre.c 5.1-3 5.2-3 5.2-8 5.6-1 5.7-12 5.7-22 adresop3.c arit1.c adr.c adrcevir.c adrf12.c arg3.c sizeof.c adr4b.c din3b.c adrdindz.c adryapi5.c yapi1.c adryapi1.c mod1.c error.c 5.1-4 5.2-4 5.3-1 5.6-2 5.7-13 adresop4.c arit2.c Karak.c void.c adrf13.c varunix.c 6.2-1 7.1-4 7.2-1 8.5-1 8.2-4 fonkdizi.c dinfonk.c dinstru.c union1.c yapidiz4.c

6.1-1 7.1-1 7.1-5 8.3-3 8.5-2 8.3-1 9.1-1 9.1-7 9.3-2

6.1-2 7.1-2 7.1-6 8.3-4 8.6-1 8.3-6 9.1-2 9.2-1 9.4-2

6.1-3 7.1-3 7.1-7 8.3-5 8.1-1 8.3-1 9.1-3 9.2-2

9.1-4 9.3-1

mod2.c dump.c

Bu programlarin ciktilari ve yapilan degisiklikler (prompt #) BOLUM 2


* * * Ornek 2.8-1 tip.c programi. # TIP integral promotion OK ! c << 3 --> Sonuc 0 degildir c << 3 --> Sonuc 0 k1 : 100, k2 : -56, k3 : 44 k1 : 0x64, k2 : 0xFFFFFFC8, k3 : 0x2C uk1 : 100, uk2 : 200, uk3 : 44 uk1 : 0x64, uk2 : 0xC8, uk3 : 0x2C k1 : 0x7C k1 + k1 : 0xF8 k2 : 0xFFFFFFF8

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

BOLUM 4
* * * Ornek 4.2-5 dosyaa.c programi. Programi olusturmak icin dosyab.c ile birlestirilecek. ( Derleme: cc -o dosyaa dosyaa.c dosyab.c ) # DOSYAA i : 10, j : 20 * * * Ornek 4.5-1 bagla1.c programi. Programi olusturmak icin bagla2.c programi ile birlestirilecek. ( Derleme: cc [diger opsiyonlar...] -o bagla1 bagla1.c bagla2.c ) # BAGLA1 12.000000 123 13 45

BOLUM 5
* * * Ornek Dizi[0] icin Dizi[1] icin Dizi[2] icin 5.1-1 adresop1.c bellek adresi : 4026530788 bellek adresi : 4026530792 bellek adresi : 4026530796

* * * Ornek 5.1-2 adresop2.c n degiskeni : 4 byte, bellek adresi : 4026530796 adres degeri : 4 byte. * * * Ornek 5.1-3 adresop3.c adresler: &n : 4026530796, &k : 4026530792 degerler: p : 4026530796, *p : 1650, n : 1650, k : 1650 p : 4, n : 4, k : 4 byte * * * Ornek 5.1-4 adresop4.c int : 4, long : 4, double : 8 int * : 4, long * : 4, double * : 4 &i : 4026530796, &j : 4026530792 i : 10, j : 40, pi : 4026530796, *pi i : 89, j : 40, pi : 4026530796, *pi i : 42, j : 40, pi : 4026530796, *pi i : 42, j : 40, pi : 4026530792, *pi * * * Ornek Dizi[0] : 0, Dizi[1] : 1, Dizi[2] : 2, * * * Ornek Dizi[0] : 0, Dizi[1] : 1, Dizi[2] : 2,

: : : :

10 89 42 40

5.2-1 dizi1.c bellek adresi : 4026530788 bellek adresi : 4026530792 bellek adresi : 4026530796 5.2-2 dizi2.c bellek adresi : 4026530788 bellek adresi : 4026530792 bellek adresi : 4026530796 C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

10

* * * Ornek 5.2-3 arit1.c sizeof(char) : 1 sizeof(int) : 4 sizeof(double) : 8 (char *)0 + 1 : 1 (int *)0 + 1 : 4 (double *)0 + 1 : 8 * * * Ornek 5.2-4 arit2.c short i : 2 byte, pi : 4026530798, pi + 1 : 4026530800 long l : 4 byte, pl : 4026530792, pl + 1 : 4026530796 double x : 8 byte, px : 4026530784, px + 1 : 4026530792 &i : 4026530798, &i + 1 : 4026530800 &l : 4026530792, &l + 1 : 4026530796 &x : 4026530784, &x + 1 : 4026530792 * * * Ornek *(pDizi + 0) *(pDizi + 1) *(pDizi + 2) 5.2-5 dizi3.c : 0, bellek adresi pDizi + 0 : 4026530788 : 1, bellek adresi pDizi + 1 : 4026530792 : 2, bellek adresi pDizi + 2 : 4026530796

* * * Ornek 5.2-6 dizi4.c dizi elemanlarinin adresleri &Dizi[0] : 4026530788, &Dizi[0] + 0 : 4026530788, &Dizi[1] : 4026530792, &Dizi[0] + 1 : 4026530792, &Dizi[2] : 4026530796, &Dizi[0] + 2 : 4026530796, dizi elemanlarinin degerleri Dizi[0] : 0, *(Dizi + 0) : 0 Dizi[1] : 1, *(Dizi + 1) : 1 Dizi[2] : 2, *(Dizi + 2) : 2 dizi elemanlarinin adresleri pDizi + 0 : 4026530788 pDizi + 1 : 4026530792 pDizi + 2 : 4026530796 dizi elemanlarinin degerleri pDizi[0] : 0, *(pDizi + 0) : 0 pDizi[1] : 1, *(pDizi + 1) : 1 pDizi[2] : 2, *(pDizi + 2) : 2 pDizi = Dizi + 1 deyimi sonrasi degerler Dizi : 4026530788, pDizi : 4026530792, *pDizi : 1 pDizi - Dizi : 1 pDizi++ deyimi sonrasi degerler Dizi : 4026530788, Dizi + 2 : 4026530796, pDizi : pDizi > Dizi pDizi == Dizi + 2

Dizi + 0 : 4026530788 Dizi + 1 : 4026530792 Dizi + 2 : 4026530796

4026530796, *pDizi : 2

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

11

* p i p

* : = :

* Ornek 5.2-8 adr.c 4026530788, *p : 99, i : 0 *p++ 4026530792, *p : 88, i : 99

p : 4026530792, *p : 88, i : 99 i = *++p p : 4026530796, *p : 77, i : 77 p : 4026530796, *p : 77, i : 77 i = ++*p p : 4026530796, *p : 78, i : 78 p : 4026530796, *p : 78, i : 78 i = (*p)++ p : 4026530796, *p : 79, i : 78 0, 1, 2, 3, 4, 7, 8, 3, 9, 5, * * * Ornek 5.3-1 Karak.c sizeof a : 5, sizeof b : 5 strlen(a): 4, strlen(b): 4 210b8 210c0 023 * * * Ornek 5.4-1 adrdizgi.c sizeof AdrDizgi : 16, sizeof *AdrDizgi : 4 sizeof **AdrDizgi : 1 sizeof AdrDizgi[0] : 4, sizeof AdrDizgi[0][0] : 1 AdrDizgi : effffbe0, *AdrDizgi : 213bc **AdrDizgi : 97 AdrDizgi[0] : 213bc, AdrDizgi[0][0] : 97 AdrDizgi [ 0 ] : 213bc, *AdrDizgi [ 0 ] : a, AdrDizgi[ 0 ] dizgisi : a AdrDizgi [ 1 ] : 213be, *AdrDizgi [ 1 ] : b, AdrDizgi[ 1 ] dizgisi : bcd987 AdrDizgi [ 2 ] : 213c5, *AdrDizgi [ 2 ] : 1, AdrDizgi[ 2 ] dizgisi : 123 a bcd987 123 a bcd987 123 AdrDizgi[ 0 ] dizgisi 1 karakter. AdrDizgi[ 1 ] dizgisi 6 karakter. AdrDizgi[ 2 ] dizgisi 3 karakter. Adres Karakter ASCII kod ----- -------- --------AdrDizgi[ 0 ][ 0 ] : 213bc a 97 AdrDizgi[ 0 ][ 1 ] : 213bd 0 AdrDizgi[ 1 ][ 0 ] : 213be b 98

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

12 AdrDizgi[ AdrDizgi[ AdrDizgi[ AdrDizgi[ AdrDizgi[ AdrDizgi[ AdrDizgi[ AdrDizgi[ AdrDizgi[ AdrDizgi[ * * d &d &pd * : : : 1 1 1 1 1 1 2 2 2 2 ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ 1 2 3 4 5 6 0 1 2 3 ] ] ] ] ] ] ] ] ] ] : : : : : : : : : : 213bf 213c0 213c1 213c2 213c3 213c4 213c5 213c6 213c7 213c8 c d 9 8 7 99 100 57 56 55 0 49 50 51 0

1 2 3

Ornek 5.5-1 ciftadr.c 9.3, *pd : 9.3, **ppd : 9.3 effffbe8, pd : effffbe8, effffbe4, ppd : effffbe4

*ppd : effffbe8

* * * Ornek 5.6-1 adrcevir.c programi cDizi dizisi 8 byte. 1.byte : 0xA1 2.byte : 0xB2 3.byte : 0xC3 4.byte : 0xD4 5.byte : 0xA0 6.byte : 0xB0 7.byte : 0xC0 8.byte : 0xD0 *Adrc : 0xA0 Tams : 0xA0B0C0D0

NOT: adrcevir.c programinda asagidaki degisiklikler yapildi: ... unsigned char cDizi[] = { 0xA1, 0xB2, 0xC3, 0xD4, 0xA0, 0xB0, 0xC0, 0xD0 }, ... Adrc = (unsigned char *)( (unsigned int *)Adrc + 1 ); ... Tams = *(unsigned *)(Adrc + 4); printf( "Tams : 0x%08X\n", Tams ); ... * * * Ornek 5.6-2 void.c c : A i : 0xABCD, &i : effffbe8 effffbe8 adresinde bulunan effffbe9 adresinde bulunan effffbea adresinde bulunan effffbeb adresinde bulunan * * * Ornek

byte byte byte byte

: : : :

0x00 0x00 0xAB 0xCD

5.7-5 size.c programi

p adres degiskeni : 4 byte s karakter dizisi : 4 byte C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

13 123 dizgisi * * * pd[0] pd[1] pd[2] pd[3] pd[4] pd[0] pd[1] pd[2] pd[3] pd[4] * * * pd[0] pd[1] pd[2] pd[3] pd[4] pd[0] pd[1] pd[2] pd[3] pd[4] * * * pd[0] pd[1] pd[2] pd[3] pd[4] pd[0] pd[1] pd[2] pd[3] pd[4] : 4 byte

Ornek 5.7-11 adrf11.c : effffbc8, *pd[0] : 3.0, : effffbd0, *pd[1] : 1.9, : effffbd8, *pd[2] : 2.8, : effffbe0, *pd[3] : 5.7, : effffbe8, *pd[4] : 4.6, : : : : : effffbd0, effffbd8, effffbc8, effffbe8, effffbe0, *pd[0] *pd[1] *pd[2] *pd[3] *pd[4] : : : : : 1.9, 2.8, 3.0, 4.6, 5.7,

d[0] d[1] d[2] d[3] d[4] d[0] d[1] d[2] d[3] d[4]

: : : : : : : : : :

3.0 1.9 2.8 5.7 4.6 3.0 1.9 2.8 5.7 4.6

Ornek 5.7-12 adrf12.c : effffbc8, *pd[0] : 3.0, : effffbd0, *pd[1] : 1.9, : effffbd8, *pd[2] : 2.8, : effffbe0, *pd[3] : 5.7, : effffbe8, *pd[4] : 4.6, : : : : : effffbd0, effffbd8, effffbc8, effffbe8, effffbe0, *pd[0] *pd[1] *pd[2] *pd[3] *pd[4] : : : : : 1.9, 2.8, 3.0, 4.6, 5.7,

d[0] d[1] d[2] d[3] d[4] d[0] d[1] d[2] d[3] d[4]

: : : : : : : : : :

3.0 1.9 2.8 5.7 4.6 3.0 1.9 2.8 5.7 4.6

Ornek 5.7-13 adrf13.c : effffbc8, *pd[0] : 3.0, : effffbd0, *pd[1] : 1.9, : effffbd8, *pd[2] : 2.8, : effffbe0, *pd[3] : 5.7, : effffbe8, *pd[4] : 4.6, : : : : : effffbd0, effffbd8, effffbc8, effffbe8, effffbe0, *pd[0] *pd[1] *pd[2] *pd[3] *pd[4] : : : : : 1.9, 2.8, 3.0, 4.6, 5.7,

d[0] d[1] d[2] d[3] d[4] d[0] d[1] d[2] d[3] d[4]

: : : : : : : : : :

3.0 1.9 2.8 5.7 4.6 3.0 1.9 2.8 5.7 4.6

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

14

* * * Ornek 5.7-20 arg1.c programi argc : 3 argv[0] : arg1, 4 karakter argv[1] : arg1, 4 karakter argv[2] : arg2, 4 karakter NOT: arg1.c programinda argv[i] icin null check yaparak NULL degerin printf'e gitmesini onlemek gerekiyor. Aksi taktirde program calisirken "Segmentation Fault" hatasi olusur. (DOS'ta olusmaz). ... printf("argc : %d\n", argc ); for ( i = 0; i <= argc; i++ ) if ( argv[i] != '\0' ) printf("argv[%d] : %12s, %2u karakter\n", i, argv[ i ], strlen( argv[i] ) ); ... * * * Ornek 5.7-21 arg2.c programi # arg2 123 abc <enter> komutu ile cikti: while - 1 123 abc while - 2 argv[...] 4026531117 4026531118 4026531119 argv[...] 4026531121 4026531122 4026531123 while - 3 argv[...] 4026531117 4026531118 4026531119 argv[...] 4026531121 4026531122 4026531123

--> 4026531117 adresindeki karakter --> 1 adresindeki karakter --> 2 adresindeki karakter --> 3 --> 4026531121 adresindeki karakter --> a adresindeki karakter --> b adresindeki karakter --> c

--> 4026531117 adresindeki karakter --> 1 adresindeki karakter --> 2 adresindeki karakter --> 3 --> 4026531121 adresindeki karakter --> a adresindeki karakter --> b adresindeki karakter --> c

for - 1 arg2 dizgisi 4 karakter 123 dizgisi 3 karakter abc dizgisi 3 karakter for - 2 arg2 dizgisi 4 karakter 123 dizgisi 3 karakter C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

15 abc dizgisi 3 karakter while - 5 123 abc while - 6 1 a while - 7 1 a while - 4 123 abc sizeof argv : 4, sizeof *argv : 4, sizeof **argv : 1 NOT: arg2.c programinda "Segmentation Fault" hatasi almamak icin asagidaki null-check deyimleri eklendi... (Bu hata puts fonksiyonuna NULL aktarilinca olusur. Fakat DOS'ta ayni hata olusmaz ) ... puts( "for - 1" ); ... argv = av; for ( i = 0; i <= argc; i++ ) if ( *(argv + i ) != 0 ) printf( "%s dizgisi %u karakter\n", *(argv + i), strlen( argv[i] ) ); ... puts( "for - 2" ); ... for ( i = 0; i <= argc; i++, argv++ ) { if ( *argv != 0 ) printf( "%s dizgisi %u karakter\n", *argv, strlen( *argv ) ); ... } * * * Ornek 5.7-22 arg3.c arg3 123 abc arg3 123 abc 12ab * * * bits.c Tarih1 : C79F, (00000000000000001100011110011111) Tarih2 : FE630000, (11111110011000110000000000000000) Tarih2 - Gun 31, Ay 12, Yil 1999 Tarih2 - Gun 31, (11111) Tarih2 - Ay 12, (1100) C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

16 Tarih2 - Yil 99, (1100011) * * * endian.c i : 0xABCD, &i : effffbe8, (00000000000000001010101111001101) Adres: Deger: Hex,(Binary) ------ ------------------effffbe8 0x00,(00000000) effffbe9 0x00,(00000000) effffbea 0xAB,(10101011) effffbeb 0xCD,(11001101) n : 0xAB12CD34, &n : effffbe0, (10101011000100101100110100110100) Adres: Deger: Hex,(Binary) ------ ------------------effffbe0 0xAB,(10101011) effffbe1 0x12,(00010010) effffbe2 0xCD,(11001101) effffbe3 0x34,(00110100) NOT: endian.c programinda yukaridaki ciktiyi almak icin asagidaki degisiklikler yapildi: Satir 12 ve 25'de (char *) yerine (unsigned char *) yerlestirildi. * * * sizeof.c n : 4 byte, j : 12 byte, jj : 12 byte -sizeof- s : 4 byte, t : 5 byte -strlen- s : 4 karakter, t : 4 karakter char : 1, int : 4, long : 4 byte j dizisinin eleman sayisi : 3 jj dizisinin eleman sayisi : 3 j dizisi int[3] tipindedir : 12 byte -sizeof- t dizisinin eleman sayisi : 5 sizeof 2L : 4 byte, sizeof 2 : 4 byte sizeof "1234" : 5 byte strlen("1234") : 4 karakter * * * varunix.c abc def xyz

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

17

BOLUM 6
* * * Ornek 6.1-1 adr2b.c programi. satir, sutun: deger(adres) 0,0: 0 (effffbb0) 0,1: 1 (effffbb4) 0,2: 2 (effffbb8) 0,3: 3 4 (effffbc0) 1,0: 5 (effffbc4) 1,1: 6 (effffbc8) 1,2: 7 (effffbcc) 1,3: 8 9 (effffbd4) 2,0: 2 (effffbd8) 2,1: 3 (effffbdc) 2,2: 4 (effffbe0) 2,3: 5 6 (effffbe8) 3,0: 7 (effffbec) 3,1: 8 (effffbf0) 3,2: 9 (effffbf4) 3,3: 0 1 (effffbfc) iDizi2b : effffbb0, sizeof(iDizi2b) : 80 iDizi2b + 1 : effffbc4, sizeof(iDizi2b + 1) : 4 iDizi2b[ 1 ] : effffbc4, sizeof(iDizi2b[ 1 ]) : 20 iDizi2b[ 1 ] + 1 : effffbc8, sizeof(iDizi2b[ 1 ] + 1) : 4 iDizi2b[ 1 ][ 1 ] : 6, sizeof(iDizi2b[ 1 ][ 1 ]): 4 Dizi elemanlarinin degerlerinin listelenmesi : *( iDizi2b[ satir ] + sutun ) : 0 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 0 1 sizeof(Adr2b) : 4, sizeof(*Adr2b) : 20 Adr2b : effffbb0, Adr2b + 1 : effffbc4 Adr2b[ satir ][ sutun ] : 0 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 0 1 * * * Ornek 6.1-2 adr3b.c programi. Tablo, Satir, Sutun: Deger(Adres) : Tablo No : 0 0,0,0: 0(effffb10) 0,0,1: 1(effffb14) 0,0,4: 4(effffb20) 0,1,0: 5(effffb24) 0,1,1: 6(effffb28) 0,1,4: 9(effffb34) 0,2,0: 2(effffb38) 0,2,1: 3(effffb3c) 0,2,4: 6(effffb48) 0,3,0: 7(effffb4c) 0,3,1: 8(effffb50) 0,3,4: 1(effffb5c)

(effffbbc) 0,4: (effffbd0) 1,4: (effffbe4) 2,4: (effffbf8) 3,4:

0,0,2: 2(effffb18) 0,0,3: 3(effffb1c) 0,1,2: 7(effffb2c) 0,1,3: 8(effffb30) 0,2,2: 4(effffb40) 0,2,3: 5(effffb44) 0,3,2: 9(effffb54) 0,3,3: 0(effffb58)

Tablo No : 1 1,0,0: 0(effffb60) 1,0,1: 1(effffb64) 1,0,2: 2(effffb68) 1,0,3: 3(effffb6c) 1,0,4: 4(effffb70) C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

1,1,0: 1,1,4: 1,2,0: 1,2,4: 1,3,0: 1,3,4:

18 5(effffb74) 1,1,1: 6(effffb78) 1,1,2: 7(effffb7c) 1,1,3: 8(effffb80) 9(effffb84) 2(effffb88) 1,2,1: 3(effffb8c) 1,2,2: 4(effffb90) 1,2,3: 5(effffb94) 6(effffb98) 7(effffb9c) 1,3,1: 8(effffba0) 1,3,2: 9(effffba4) 1,3,3: 0(effffba8) 1(effffbac)

Tablo No : 2 2,0,0: 0(effffbb0) 2,0,4: 4(effffbc0) 2,1,0: 5(effffbc4) 2,1,4: 9(effffbd4) 2,2,0: 2(effffbd8) 2,2,4: 6(effffbe8) 2,3,0: 7(effffbec) 2,3,4: 1(effffbfc)

2,0,1: 1(effffbb4) 2,0,2: 2(effffbb8) 2,0,3: 3(effffbbc) 2,1,1: 6(effffbc8) 2,1,2: 7(effffbcc) 2,1,3: 8(effffbd0) 2,2,1: 3(effffbdc) 2,2,2: 4(effffbe0) 2,2,3: 5(effffbe4) 2,3,1: 8(effffbf0) 2,3,2: 9(effffbf4) 2,3,3: 0(effffbf8)

ifade : degeri, sizeof (ifade) iDizi3b : effffb10, 240 iDizi3b + 1 : effffb60, 4 iDizi3b[1] : effffb60, 80 iDizi3b[1] + 1 : effffb74, 4 iDizi3b[1][1] : effffb74, 20 iDizi3b[1][1] + 1 : effffb78, 4 iDizi3b[1][1][1] : 6, 4 Dizi elemanlarinin degerlerinin listelenmesi: *( *( Tablo 0 1 2 5 6 7 2 3 4 7 8 9 Tablo 0 1 2 5 6 7 2 3 4 7 8 9 Tablo 0 1 2 5 6 7 2 3 4 7 8 9 *(iDizi3b + i ) + j ) + k ) : No : 0 3 4 8 9 5 6 0 1 No : 1 3 4 8 9 5 6 0 1 No : 2 3 4 8 9 5 6 0 1

sizeof(Adr3b) : 4, sizeof(*Adr3b) : 80 Adr3b : effffb10, Adr3b + 1 : effffb60 Adr3b[ tablo ][ satir ][ sutun ]: 0 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 0 1 C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

19 0 5 2 7 0 5 2 7 1 6 3 8 1 6 3 8 2 7 4 9 2 7 4 9 3 8 5 0 3 8 5 0 4 9 6 1 4 9 6 1

* * * Ornek 6.1-3 adr4b.c programi. 0 5 2 7 0 5 2 7 0 5 2 7 1 6 3 8 1 6 3 8 1 6 3 8 2 7 4 9 2 7 4 9 2 7 4 9 3 8 5 0 3 8 5 0 3 8 5 0 4 9 6 1 4 9 6 1 4 9 6 1

0 5 2 7 0 5 2 7 0 5 2 7

1 6 3 8 1 6 3 8 1 6 3 8

2 7 4 9 2 7 4 9 2 7 4 9

3 8 5 0 3 8 5 0 3 8 5 0

4 9 6 1 4 9 6 1 4 9 6 1

* * * Ornek 6.2-1 fonkdizi.c programi. sizeof iDizi2b : 80 - 2b dizi listeleme sizeof Adr2b : 4, sizeof *Adr2b : 20, sizeof *Adr2b / sizeof (int) : 5 0 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 0 1 sizeof iDizi3b : 240 C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

20 - 3b dizi listeleme sizeof Adr3b : 4, sizeof *Adr3b : 80, sizeof *Adr3b / sizeof (int) : 20 0 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 0 1 0 5 2 7 0 5 2 7 1 6 3 8 1 6 3 8 2 7 4 9 2 7 4 9 3 8 5 0 3 8 5 0 4 9 6 1 4 9 6 1

sizeof iDizi4b : 480 - 4b dizi listeleme sizeof Adr4b : 4, sizeof *Adr4b : 240, sizeof *Adr4b / sizeof (int) : 60 0 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 0 1 0 5 2 7 0 5 2 7 1 6 3 8 1 6 3 8 2 7 4 9 2 7 4 9 3 8 5 0 3 8 5 0 4 9 6 1 4 9 6 1

0 5 2 7 0 5 2 7 0 5 2 7

1 6 3 8 1 6 3 8 1 6 3 8

2 7 4 9 2 7 4 9 2 7 4 9

3 8 5 0 3 8 5 0 3 8 5 0

4 9 6 1 4 9 6 1 4 9 6 1

2b dizinin 1. satiri ile 2. satirinin degistirilmesi: - 2b dizi listeleme sizeof Adr2b : 4, sizeof *Adr2b : 20, sizeof *Adr2b / sizeof (int) : 5 C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

21 5 0 2 7 6 1 3 8 7 2 4 9 8 3 5 0 9 4 6 1

BOLUM 7
* * * Ornek 7.1-1 din2b3b.c programi. 2-b 8 8 7 0 9 7 3 9 3-b 6 8 4 1 4 5 7 4 8 6 3 8 9 9 6 2 8 5 0 2 3 8 0 6 dizi : 3 5 1 9 2 6 4 0 5 3 7 6 dizi : 5 1 7 5 2 6 4 2 1 3 1 6 5 3 4 7 1 7 8 5 3 2 3 7 4 9 6 1 7 4 2 5 0 6 4 4

* * * Ornek 7.1-2 din2b.c programi. 8 5 8 5 8 1 8 1 3 7 3 7

* * * Ornek 7.1-3 din3b.c programi. 8 8 3 5 1 7 0 9 2 6 9 7 4 0 5 3 9 3 7 6 6 8 5 1 8 8 3 5 1 7 0 9 2 6 9 7 4 0 5 3 C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

22 9 3 7 6 6 8 5 1 * * * Ornek 7.1-4 dinfonk.c programi. Satir Sutun 8 8 3 9 7 4 6 8 5 4 5 4 8 8 5 Sayisi ? 5 Sayisi ? 20 5 1 7 0 9 2 0 5 3 9 3 7 1 7 4 1 5 2 2 1 7 4 3 1 3 7 6 5 3 2

6 6 6 6 4

* * * Ornek 7.1-5 remalloc.c programi. 214b8 24c88 24cb8 24d00 0, 1, : 20 byte bellek alani ayrildi !!! : 40 byte bellek alani ayrildi !!! : 60 byte bellek alani ayrildi !!! : 80 byte bellek alani ayrildi !!! 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, NOT: Ornek 7.1-5 remalloc.c programinda asagidaki cast gerekli. ... Adr = (int *)remalloc( Adr, ToplamByte(i), ToplamByte(Onceki) ); ...

* * * Ornek 7.1-6 realloc.c programi. 21380 24b50 24b50 24b50 0, 1, : 20 byte bellek alani ayrildi !!! : 40 byte bellek alani ayrildi !!! : 60 byte bellek alani ayrildi !!! : 80 byte bellek alani ayrildi !!! 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, NOT: Ornek 7.1-6 realloc.c programinda asagidaki cast gerekli. ... Adr = (int *)realloc( Adr, ToplamByte(i) ); ... * * * Ornek 7.1-7 adrdindz.c programi. Random Dizgi AdrDinDz [ 0 Random Dizgi AdrDinDz [ 1 Random Dizgi AdrDinDz [ 2 Random Dizgi AdrDinDz [ 3 Random Dizgi AdrDinDz [ 4 Random Dizgi AdrDinDz [ 5 --> ] : --> ] : --> ] : --> ] : --> ] : --> ] : mzrhlajoetbkwltztvie mzrhlajoetbkwltztvie hpfybpswajccvjof hpfybpswajccvjof eeebjzylneexk eeebjzylneexk zgasxfvxffucryjdugcmkk zgasxfvxffucryjdugcmkk ixjetobwkvdfqj ixjetobwkvdfqj hxatzivobcto hxatzivobcto C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

23 AdrDinDz [ 2 ] : eeebjzylneexk AdrDinDz [ 2 ] [ 3 ] : b *AdrDinDz : mzrhlajoetbkwltztvie (*AdrDinDz)[ 4 ] : l *(*AdrDinDz + 4) : l * * * Ornek 7.2-1 dinstru.c programi. Kayit Yapisi : (*p_s).dizgi : XyZabc123K, (*p_s).i : 99 p_s[0].dizgi : XyZabc123K, p_s[0].i : 99 Kayit Yapi Dizisi : XyZabc123K 1 XyZabc123K 2 XyZabc123K 3 XyZabc123K 4 XyZabc123K 5 2-b Yapi Dizisi : XyZabc123K 2 XyZabc123K 2 XyZabc123K 2 XyZabc123K 2 XyZabc123K 3 XyZabc123K 4 2-b adres dizisi ile 2-b Yapi Dizisine erisim : XyZabc123K 2 XyZabc123K 2 XyZabc123K 2 XyZabc123K 2 XyZabc123K 3 XyZabc123K 4 NOT: Ornek 7.2-1 dinstru.c programinda satir 210'da Kayit** yerine Kayit*** bulunacak. ... for ( i = 0; i < NoSatir2b; i++ ) if ( (p_ap_2as[ i ] = (Kayit **)malloc( NoSutun2b * sizeof (Kayit*) )) == NULL ) return (Kayit***)NULL; ...

BOLUM 8
* * * Ornek 8.3-3 adryapi3.c programi. sizeof( p ) : 48, sizeof( adr_dizi ) : 12 yapi elemanlari : abc, xxx, 123 456, 23 def, yyy, 789 012, 34 mno, zzz, 890 123, 30 a b c d e f m n o C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

24

* * * Ornek 8.3-4 adryapi4.c programi. YDizi'nin eleman sayisi : 4 YDizi'nin bir elemaninin byte sayisi : 12 * * * Ornek 8.3-5 adryapi5.c programi. YDizi[0].FAdi : fonk1 --> fonksiyon 1 ... YDizi[1].FAdi : fonk2 --> fonksiyon 2 ... fonksiyon adresleri : fonk1 : 10b48, fonk2 : 10b64, fonk3 : 10b80 eleman adresleri : YDizi[0].adr_fonk : 10b48, YDizi[1].adr_fonk : 10b64 atama sonrasi eleman adresleri : YDizi[0].adr_fonk : 10b48, YDizi[1].adr_fonk : 10b80 YDizi[1].FAdi : fonk3 --> fonksiyon 3 ...

* * * Ornek 8.5-1 union1.c 55 27.91 dizgi bilinmeyen union tipi : 4 1077668085 * * * Ornek 8.5-2 union2.c YDizi[0].UnDeg.j : 27 YDizi[1].UnDeg.j : 42 *YDizi[0].UnDeg.c : a YDizi[1].UnDeg.c[0] : x

programi.

programi.

* * * Ornek 8.6-1 BitDeg.alan1 : 1 BitDeg.alan2 : 0 BitDeg.alan3 : 1

bitalan.c

programi.

* * * Ornek 8.1-1 yapi1.c programi. p1.isim: xyz, p1.basla: 1991, p1.son: 1997 p1 : 12 byte p1.isim : 4 byte p1.basla : 4 byte p1.son : 4 byte p2.isim: xyz, p2.basla: 1991, p2.son: 1997 p2 : 20 byte p2.isim : 11 byte p2.basla : 4 byte p2.son : 4 byte * * * Ornek 8.2-4 yapidiz4.c programi. t.s1 : 5, t.s2 : 5, p.s1 : 4, p.s2 : 4 byte t.s1 : abc, t.s2 : xyz, p.s1 : abc, p.s2 : xyz t.s1[0] : a, t.s1[1] : b, t.s1[2] : c, t.s1[3] : t.s2[0] : x, t.s2[1] : y, t.s2[2] : z, t.s2[3] : p.s1[0] : a, p.s1+0 : 135300

, t.s1[4] : , t.s2[4] :

, ,

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

25 p.s1[1] p.s1[2] p.s2[0] p.s2[1] p.s2[2] : : : : : b, c, x, y, z, p.s1+1 p.s1+2 p.s2+0 p.s2+1 p.s2+2 : : : : : 135301 135302 135304 135305 135306

* * * Ornek 8.3-1 adryapi1.c programi. sizeof(struct proje *) : 4, sizeof(ap) : 4, sizeof(p): 12 byte ap->isim : yeni proje, ap->basla : 1991, ap->son : 1994 (*ap).isim : yeni proje, (*ap).basla : 1991, (*ap).son : 1994 (&p)->isim : yeni proje, (&p)->basla : 1991, (&p)->son : 1994 YENI PROJE dizgisi ve 1990 degeri atandiktan sonra ... p.isim : YENI PROJE, p.basla : 1990, p.son : 1994 proje isminin 3. karakteri : N bellek adresleri : &p : -268436508, &(p.isim) : -268436508, &(p.basla) : -268436504, &(p.son) : -268436500 ap : -268436508, &(ap->isim) : -268436508, &(ap->basla) : -268436504, &(ap>son) : -268436500 * * * Ornek 8.3-6 adryapi6.c programi. elemanlarin degerleri ve bellek adresleri: i : 1, f : 0.7, c : A, adr : dizgi &s : 4026530776, &s.i : 4026530776, &s.f : 4026530784, &s.c : 4026530792, &s.adr : 4026530796 elemanlarin -hesaplanan- offset degerleri : s.i : 0, s.f : 4, s.c : 12, s.adr : 13 byte. s yapisinin -hesaplanan- byte sayisi : 17 byte. adr elemaninin -hesaplanan- bellek adresi : 4026530789 elemanlarin gercek offset degerleri (offsetof makrosu): s.i : 0, s.f : 8, s.c : 16, s.adr : 20 byte. s yapisi : 24 byte. adr elemaninin bellek adresi : 4026530796 NOT: Programdaki tum %d'ler %u formata cevrilmistir.

* * * Ornek 8.3-1 adryapi1.c programi. sizeof(struct proje *) : 4, sizeof(ap) : 4, sizeof(p): 12 byte ap->isim : yeni proje, ap->basla : 1991, ap->son : 1994 (*ap).isim : yeni proje, (*ap).basla : 1991, (*ap).son : 1994 (&p)->isim : yeni proje, (&p)->basla : 1991, (&p)->son : 1994 YENI PROJE dizgisi ve 1990 degeri atandiktan sonra ... p.isim : YENI PROJE, p.basla : 1990, p.son : 1994 proje isminin 3. karakteri : N C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

26

bellek adresleri : &p : 4026530788, &(p.isim) : 4026530788, &(p.basla) : 4026530792, &(p.son) : 4026530796 ap : 4026530788, &(ap->isim) : 4026530788, &(ap->basla) : 4026530792, &(ap>son) : 4026530796 NOT: Programda tum %d'ler %u formata cevrilmistir.

BOLUM 9
* * * Ornek 9.1-1 textyaz.c programi.

NOT: test.asc dosyasini olusturur. Asagidaki degisiklik yapildi: ... if ( (fp = fopen( "test.asc", "w" )) == NULL ) ... ls -l test.asc -rw-rw-r-1 ismet

staff

7 Mar 25 12:43 test.asc

* * *

Ornek 9.1-2

textoku.c programi.

NOT: ... if ( (fp = fopen( "test.asc", "r" )) == NULL ) ... * * * Ornek 9.1-3 mod1.c programi. test.asc: r - text modunda okuma. d 0x64, 100 e 0x65, 101 n 0x6E, 110 e 0x65, 101 m 0x6D, 109 e 0x65, 101 0x0A, 10 EOF (end-of-file) : -1 test.asc: rb - binary modunda okuma. d 0x64, 100 e 0x65, 101 n 0x6E, 110 e 0x65, 101 m 0x6D, 109 e 0x65, 101 0x0A, 10 EOF (end-of-file) : -1 # ls -l test.asc -rw-rw-r-1 ismet staff #

7 Mar 25 12:43 test.asc

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

27

DOS /* * * * * * * * * * * * * * * * * * * * * * * */

Ciktisi !!! Cikti: test.asc: r - text modunda okuma. d 0x64, 100 e 0x65, 101 n 0x6E, 110 e 0x65, 101 m 0x6D, 109 e 0x65, 101 0x0A, 10 EOF (end-of-file) : -1 test.asc: rb - binary modunda okuma. d 0x64, 100 e 0x65, 101 n 0x6E, 110 e 0x65, 101 m 0x6D, 109 e 0x65, 101 0x0D, 13 <----- !!! 0x0A, 10 EOF (end-of-file) : -1

NOT: UNIX'te text ve binary mod farki yoktur. "a:\\test.asc" --> "test.asc" ... if ( !(fp = fopen( "a:\\test.asc", "r" )) ) ... if ( !(fp = fopen( "a:\\test.asc", "rb" )) ) ... * * * # cat abc 123 def # cat abc 123 def # cat abc 123 def Ornek 9.1-4 text mod2.c programi.

binary1

binary2

# dump Dosya adi ? : text Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

28 000B(0011) 61 62 63 0A 31 32 33 0A 64 65 66 | Toplam byte: 11

|abc.123.def

# dump Dosya adi ? : binary1 Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --000B(0011) 61 62 63 0A 31 32 33 0A 64 65 66 |abc.123.def | Toplam byte: 11 # dump Dosya adi ? : binary2 Hex (Dec ) ------------- Hexadecimal Kodlar 000D(0013) 61 62 63 0D 0A 31 32 33 0D 0A 64 | Toplam byte: 13 # ls -l * -rw-rw-r-1 ismet staff 11 Mar -rw-rw-r-1 ismet staff 13 Mar -rw-rw-r-1 ismet staff 11 Mar # DOS Ciktisi !!! A:\> type text abc 123 def A:\> type binary1 abc 123 def A:\> type binary2 abc 123 def A:\> dump Dosya adi ? : text Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --000D(0013) 61 62 63 0D 0A 31 32 33 0D 0A 64 65 66 |abc..123..def | Toplam byte: 13 A:\> dump Dosya adi ? : binary1 Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --000B(0011) 61 62 63 0A 31 32 33 0A 64 65 66 |abc.123.def | C Programlama Dili 1997, Ismet KOCAMAN

-------------- --- ASCII Kod --65 66 |abc..123..def

25 12:35 binary1 25 12:35 binary2 25 12:35 text

C Programlama Dili - Ornek Program Listesi ve Notlar

29 Toplam byte: 11 A:\> dump Dosya adi ? : binary2 Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --000D(0013) 61 62 63 0D 0A 31 32 33 0D 0A 64 65 66 |abc..123..def | Toplam byte: 13

* * * Ornek 9.1-7 bin.c programi. dizi[0] : 790, 0x00000316 dizi[1] : 791, 0x00000317 dizi[2] : 792, 0x00000318 dizi[3] : 793, 0x00000319 dizi[4] : 794, 0x0000031A dizi[5] : 795, 0x0000031B dizi[6] : 796, 0x0000031C dizi[7] : 797, 0x0000031D dizi[8] : 798, 0x0000031E dizi[9] : 799, 0x0000031F 00 00 03 16 00 00 03 17 00 00 03 18 00 00 03 19 00 00 03 1A 00 00 03 1B 00 00 03 1C 00 00 03 1D 00 00 03 1E 00 00 03 1F ls -l sayi.bin ciktisi: -rw-rw-r-1 ismet staff

40 Mar 25 08:22 sayi.bin

DOS ciktisi !!! : 16 03 17 03 18 03 19 03 1A 03 1B 03 1C 03 1D 03 1E 03 1F 03 NOT: Format 0x04X yerine UNIX'te 0x08X olmalidir. ... printf("dizi[%d] : %4d, 0x%08X\n", i, a_dizi[i], a_dizi[i] ); ... * * * Ornek 9.2-1 hatatest.c programi. NOT: ... #include <errno.h> ...

# # ls -l -rw-rw-r--rw-rw-r--rw-rw-r-#

1 ismet 1 ismet 1 ismet

staff staff staff

8 Mar 25 13:20 deneme 17 Mar 25 13:20 VERI.DAT 96 Mar 25 13:19 veriler

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

30

* * * # cat errno errno #

Ornek 9.2-2 error.log : 0 : 2

error.c programi.

* * * Ornek 9.3-1 dump.c programi. # ls -l sayi.bin -rw-rw-r-1 ismet

staff

40 Mar 25 08:22 sayi.bin

# dump Dosya adi ? : <enter> Dosya adi girilmedi. Kullanim: dump <dosya listesi> # dump sayi.bin Dosya adi : sayi.bin Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --0010(0016) 00 00 03 16 00 00 03 17 00 00 03 18 00 00 03 19 |................| 0020(0032) 00 00 03 1A 00 00 03 1B 00 00 03 1C 00 00 03 1D |................| 0028(0040) 00 00 03 1E 00 00 03 1F |........ | Toplam byte: 40 # dump Dosya adi ? : sayi.bin Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --0010(0016) 00 00 03 16 00 00 03 17 00 00 03 18 00 00 03 19 |................| 0020(0032) 00 00 03 1A 00 00 03 1B 00 00 03 1C 00 00 03 1D |................| 0028(0040) 00 00 03 1E 00 00 03 1F |........ | Toplam byte: 40 # dump sayi.bin xxx Dosya adi : sayi.bin Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --0010(0016) 00 00 03 16 00 00 03 17 00 00 03 18 00 00 03 19 |................| 0020(0032) 00 00 03 1A 00 00 03 1B 00 00 03 1C 00 00 03 1D |................| 0028(0040) 00 00 03 1E 00 00 03 1F |........ | Toplam byte: 40 Dosya adi : xxx xxx acilamadi. C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

31

# dump *.bin Dosya adi : sayi.bin Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --0010(0016) 00 00 03 16 00 00 03 17 00 00 03 18 00 00 03 19 |................| 0020(0032) 00 00 03 1A 00 00 03 1B 00 00 03 1C 00 00 03 1D |................| 0028(0040) 00 00 03 1E 00 00 03 1F |........ | Toplam byte: 40 # tty /dev/pts/4 # dump /dev/pts/4 Dosya adi : /dev/pts/4 Hex (Dec ) ------------- Hexadecimal Kodlar -------------- --- ASCII Kod --deneme ^D 0007(0007) 64 65 6E 65 6D 65 0A |deneme. | Toplam byte: 7 #

* * * Ornek # say Kullanim : Opsiyonlar: Ornek : # say -krs deneme ^D

9.3-2 say.c programi. say -opsiyon [dosya_listesi] (k)elime, ka(r)akter, (s)atir say -krs say.c

# ls -l say* -rw-rw-r-1 ismet -rw-rw-r-1 ismet

staff staff

20 Mar 25 13:04 sayilar.bin 85 Mar 25 13:04 sayilar.txt

* * * Ornek 9.4-2 harfcev.c programi. NOT: ... if ( (fp = fopen( "VERI.DAT", "wb" )) == NULL ) ... if ( (fp = fopen( "VERI.DAT", "rb+" )) == NULL ) ...

C Programlama Dili 1997, Ismet KOCAMAN

C Programlama Dili - Ornek Program Listesi ve Notlar

32

* * * CRNL.C programi. i : 2000 i : 4999 NL : 0x0A, CR : 0x0D NL : 10, CR : 13 Deneyiniz !!! # CRNL > CRNdosya # cat CRNdosya

* * * filtre.c programi. # filtre <enter> Bu Bir dENEMedir <enter> bu bir denemedir ^D

C Programlama Dili 1997, Ismet KOCAMAN

You might also like