You are on page 1of 110

Derleme: TD Software -Yazar: aatay EB

C Programlama Dersleri
Bu yazda renecekleriniz:
Bilgisayar ve Programlama nedir? Program yazmak iin gerekli aralar ve temin edebileceiniz adresler Algoritma gelitirme ve bunun zerine basit bir rnek printf fonksiyonunun kullanm ve bununla ilgili rnekler

Merhaba; Sanrm, C ve C++ adn bilgisayarla az ok har neir olan herkes en az bir kez duymutur. Sizde bu isimleri duyanlardansanz ve nedir, ne deildir, nasl kullanlr gibi birok soruya yant aryorsanz, doru yerdesiniz. nk bu yazyla balayarak C ve C++ ile programlamaya gireceiz. nce C ile yolumuza koyulup, belli bir olgunlua ulatktan sonra C++ ile devam edeceiz. Okuyucularmzn genelini dnerek, konuyu en temelden almay daha doru buldum. Yani hedefimiz, programlamay hi bilmeyen bir insann burada okuduklaryla belli bir yerlere ulamas. leri derece de olanlarsa sklmamak iin biraz beklemeli. Laf fazla uzatmadan balayalm.

Bilgisayar ve Programlama nedir? Bilgisayar ok basit dndmzde ana grevi yerine getiren bir makinedir. Girilen bilgiyi alr (INPUT), iler (PROCESSING) ve bu ilenmi veriden bir sonu (OUTPUT) karr. Bilgisayar, sadece donanm olarak almaz. nk yazlm olmadan, donanm ne yapacan bilemez. Bilgisayar donanmna ne yapacan syleyecek bir komutlar dizisi gerekir. Yapaca grevleri, ona anlatan komutlara program diyebiliriz. Yani donanma sen unu yap, sonra bulduun sonucu yle uraya ekle gibisinden iler yaptrmak programn veya bir baka deyile yazlmn iidir. Bir programc olarak bundan fazlasn bilmek elbette ki avantajdr. Ama bilgisayarn btn zelliklerini bilmeniz gerekmez. Yani yazacanz bir program iin o bilgisayarn zelliklerini bilmeseniz de olur. Bilgisayarn anlad tek dil, Makine Dilidir. Bu 16lk (Hexadecimal) sistemden oluan bir programlama tipidir. Makine dilini anlamak ok zordur ve bu dili kullanmak iin o bilgisayarn donanm zelliklerini mutlaka bilmeniz gerekir. C de ekrana yaz yazmanz salayan printf(); gibi ok basit bir fonksiyon, makine dilinde 1A BB 0D BC D5 FF C2 F7... gibi ok daha karmak ve hibir anlam ifade etmeyen bir hle dnr. Makine dili programlama dilleri arasnda en alt seviyedir.

Makine dilinden sonra Assembler Dili gelir. Makine dilini kullanmann zorluu ve karmaas zerine gelitirilen Assembler, daha basit bir yapdadr. Ama yine de C ile mukayese ederseniz ok daha zordur ve kullandnz bilgisayarn donanmna dair hlen bilgiye gereksinim duyarsnz. Assembler aadaki gibi karmak bir yapdadr.

SEGMENT COM WORD PUBLIC CODE ASSUME CS : COMDS : COM ORG 100H ENTRY: MOV DVX,OFFSET MSG MOV AH,g . . .

uan bunu anlamaya alp, hi zamannz harcamayn. nk reneceimiz dil C, ilerimizi ve dolaysyla hayatmz ok daha kolaylatrmaktadr. C, orta seviye bir programlama dilidir. Bunun anlam, hem yazmas kolay, hemde st seviye dillere gre daha ok eriim hakknzn olduudur. st seviye programlama dilleri ise BASIC, PASCAL, gibi dillerdir. st seviye dillerde, yazmas greceli olarak daha kolay olsa da C ile yapabileceklerimiz daha oktur. Program yazmak iin ne gerekir? Program yazabilmek iin hibir eye ihtiyacnz yoktur. Program yazmak iin Windowsun not defterini veya Linux'da Gedit, Kwrite gibi bir program bile kullanabilirsiniz. nemli olan yazlan programn derlenmesidir. Derlemeye compile ve derleme iini yapan derleyiciyeyse compiler denir. C iin internet zerinden birok Compiler bulabilirsiniz. Ben, program uygulamalarn GCC zerinden yapacam. Ayn ekilde bu derleyiciyi kurmanz tavsiye ederim. GCC gelmi gemi en iyi derleyicilerden biri olduu gibi, zgr bir yazlmdr! Richard Stallman tarafndan ak kaynak koduyla sunulmutur ve arzu ettiiniz takdirde, sonuna kadar deiiklik yapma imkannz vardr. ayet Windows iletim sisteminiz varsa GCC'yi kurmanz biraz skntl olabilir. Basit bir Google aratrmasyla, Bloodshed Dev-C++ adnda bir program buldum. GCC zerine kurulmu bir yaps varm. GCC ile uramak istemeyen Windows kullanclar, bu program deneyebilir. Algoritma Gelitirmek C dilini ve komutlarn renmek, programlamaya balamak iin arttr ama algoritma oluturamadmz srece bir program oluturmazsnz. Algoritma, mantktr. Yani neyi, nasl yapacanz belirtir. Algoritma tretmek iin gelitirilmi bir metot yok. Her program iin o metodu sizin bulmanz gerekiyor. Ama hi merak etmeyin, yazdnz program says arttka, algoritma kurmanz daha kolaylar. Algoritma, programlamann bel kemiidir. C dilinde kullanlan komutlar, BASIC veya FORTRAN gibi baka dillerde ie yaramaz. Fakat programlama mantn bir kere oturttursanz, C komutlarnn yerine pekl baka dillere ait komutlar da renebilir ve byk bir zorluk ekmeden dier dillerde de program yazabilirsiniz. Basit bir rnek zerinden dnelim. Bir markete gittiniz, kasada ki grevliye aldnz rn gsterdiniz, paray uzattnz, parann stn aldnz. Gnlk hayatta gayet normal olan bu durumu biraz deitirelim. Karnzda insan deil, elektronik bir kasiyer olsun. Ona gre bir algoritma gelitirirsek, 1-)rne bak; 2-)rn Fiyatn bul; 3-)Paray al; 4-)Alnan paradan rn fiyatn kar; 5-)Kalan paray ver. nsan zekasnn otomatik hle getirdii eylemleri, ne yazk ki bilgisayar bilmez ve ona biz retmek zorundayz. retirken de hata yapma hakkmz yoktur, nk yanl reti yanl programlamayla sonulanr.

C Programlama Dili
Temel Giri/k lemleri (BASIC I/O): C ile ilgili olarak bu ve nmzdeki yazlarda birok komut/fonksiyon greceiz. Ama hep kullanacamz ve ilk renmemiz gerekenler temel giri k fonksiyonlardr. C de klavyeden bir deer alabilmek iin scanf(); fonksiyonunu kullanrz. Ekrana herhangi bir ey yazdrmak iinse printf(); fonksiyonu kullanlr. Bir rnekle grelim;
#include<stdio.h> int main( void ) { printf("Hello World"); }

Eer bunu derleyicinizde yazp derlerseniz ve sonrasnda altrrsanz ekrana Hello World yazlacaktr. #include<stdio.h>, standart giri k balk dosyasn, programa dahil et gibi bir anlam tar. C'de (ve hemen hemen btn dier programlama dillerinde) bir ktphaneyi dahil etmek son derece rutin bir itir. Aksi halde giri-k fonksiyonlarn dahi her seferinde bizim batan tanmlamamz gerekirdi. main( ), bir programdaki ana fonksyiondur. Ondan sonra gelen ayra standarttr. Bir blou temsil eder. ki ayra iareti arasndaki alan main fonksiyonuna ait bir blou oluturur. printf ise yazdmz metini, ekrana bastrmaya yarayan, standart bir fonksiyonudur. ift trnak iaretleri iersine yazdnz herey printf sayesinde ekrana baslr. Dikkat ettiyseniz, her satr sonuna noktal virgl koyduk. Aslnda her satr deil, her komutan sonra noktal virgl koyduumuzu sylemek daha doru olacak. nk noktal virgl C dilinde komut ayrac anlamna gelir. imdi yukarda yazdmz basit program, biraz daha gelitirelim:
#include<stdio.h> int main( void ) { printf("Hello World\n"); printf("Merhaba Dnya"); return 0; }

Birka yeni satr gryorsunuz. Srayla ne olduklarn aklayalm. Az evvel yazdmz "Hello World" yazsnn sonuna "\n" ekledik. "\n" bir alt satra ge anlamna geliyor. Eer "\n" yazmazsak, ekranda "Hello WorldMerhaba Dnya" eklinde bir yaz kar. "\n" kullanrsak, "Hello World" yazldktan sonra, bir alt satra geilir ve ikinci satrda "Merhaba Dnya" yazdrlr. En altta "return 0;" adnda yeni bir komut fark etmisinizdir. Bunu eklemezseniz, program yine alr; ancak uyar verir. nk main fonksiyonu, geriye bir tam saynn dnmesini beklemektedir. Yazm olduumuz return ifadesiyle bu uyarlardan kurtulabilirsiniz. Detayna girmek iin henz erken, return konusuna ileride deineceiz. Yukarda ki programn aynsn yle de yazabilirdik:
#include<stdio.h> int main( void ) { printf("Hello World"); printf("\nMerhaba Dnya");

return 0;

Bir nce ve imdi yazdmz programlarn ekran kts ayndr. Bu rnekle anlatmak istediim, printf() fonksiyonunda '\n' konulan yerden sonrasnn bir alt satra deceidir.
#include<stdio.h> int main( void ) { printf("Hello World\nMerhaba Dnya"); return 0; }

Grdnz gibi tek bir printf(); kullanarak ayn ilemi yaptrdk. Varsayalm, ekrana ok uzun bir cmle yazmamz gerekti. rnein;
#include<stdio.h> int main( void ) { printf("Benim adm aatay EB ve Yazlm Mhendisiyim.\n"); return 0; }

Bu yazdmz program hata vermemesine karn, alma verimini azaltr. nk yazacaklarnz editr penceresine smazsa, yazlan okumak daha zahmetli olur. nemsiz bir detay gibi gelebilir, ama kod yazma verimini ciddi oranda dreceinden emin olabilirsiniz. Bu program aadaki gibi yazmamz daha uygundur:
#include<stdio.h> int main( void ) { printf("Benim adm " "aatay EB" "ve Yazlm Mhendisiyim.\n"); return 0; }

Tek bir printf(); fonksiyonu kullanlmtr. Ancak alt alta yazarak, metini tek seferde grlebilir hle getirdik. Program derleyip altrrsanz, alt alta satr yazlmaz. Cmle btn olarak gsterilir ve bir nceki rnekle tamamen ayndr. (Satrlarn alt alta grnmesini isteseydik; daha nce bahsettiimiz gibi '\n' koymamz gerekirdi.) Ekrana, Ali: "Naber, naslsn?" dedi. eklinde bir yaz yazdrmamz gerekiyor diyelim. Bu konuda ufak bir problem yaayacaz. nk printf(); fonksiyonu grd ilk iki ift trnak zerinden ilem yapar. Byle bir eyi ekrana yazdrmak iin aadaki gibi bir program yazmamz gerekir:
#include<stdio.h> int main( void ) { printf("Ali: \"Naber, naslsn?\" dedi.\n"); return 0; }

printf(); fonksiyonunu kullanmay sanrm iyice anladnz. printf( yazp, sonra ift trnak ayor, yazmak istediklerimizi yazyor, ift trna sonra da parantezi kapatyor, sonuna noktal virgl ekliyoruz. Alt satra gemek iinse, yazdklarmzn sonuna '\n' ekliyoruz. ift trnakl bir ey kullanmak iinse \ ... \ kullanyoruz. Hepsi bu! scanf(); fonksiyonuna gelince, bu banda bahsettiimiz gibi bizim giri (Input) fonksiyonumuzdur. Ancak yazm burada noktalyorum. nk deikenler iin iine girmekte ve onlar anlatmam uzun

srecek. Gelecek haftaki yazmda kaldmz yerden devam edeceiz. Yazdklarmla ilgili neri, eletiri veya sorunuz varsa, bana ulaabilirsiniz.

C Programlama Dersi - II
Bu yazda renecekleriniz:
Bloodshed Dev-C++'in kullanm Deikenler ve deiken tanmlamalar Deiken tipleri ve maksimum-minimum alabilecei deerler scanf() fonksiyonunun kullanm Aritmetik operatrler lemlerde ncelik sras Geen hafta bilgisayar ve programlamaya dair temel bilgileri ve printf( ); fonksiyonunu rendik. Bu hafta, kaldmz yerden devam edeceiz. lk yazyla ilgili herhangi bir sorunuz varsa, bana cagataycebi@gmail.com adresinden ulaabilirsiniz. Bu ufak bilgiden sonra, kaldmz yerden devam edelim.

Bloodshed Dev-C++
Okuyucularmzn bir ksm, Bloodshed Dev-C++'in kullanmyla ilgili eitli sorunlar yaam. Program nasl kullanabileceinize dair ufak bir aklamayla yazmza balamak yerinde olacaktr. ( Bu blm C derleyicisi olmayanlara yardmc olmak iin yazlmtr. Eer hli hazrda bir derleyiciniz varsa ve sorunsuz kullanyorsanz, "Deiken nedir? Tanm nasl yaplr?" blmnden devam edebilirsiniz. ) Dev-C++ kullanm olduka basit bir program. Bloodshed Dev-C++ web sitesinin Download ksmndan Dev-C++'i indirebilirsiniz. Dilerseniz bu balantya tklayarak yklemeniz de mmkn. ( Zaman iinde balant adresi almayabilir. ) Program baaryla indirip kurarsanz, geriye yapacak fazla bir ey kalmyor. Program menlerinden, File -> New-> Source File yaparak yeni bir kaynak dosyas an. ( Ctrl + N ile de ayn ilemi yapabilirsiniz. ) Aadaki kodu deneme amacyla, atnz dosyaya yazn:
#include<stdio.h> int main( void ) { // Hello World yazar. printf( "Hello World" ); // Sizden herhangi bir giri bekler. // Bylece program alp, kapanmaz. getchar( ); return 0; }

File -> Save As sekmesiyle, yazdnz dosyay kaydedin. ( Ctrl + S ile de kaydedebilirsiniz. ) Dosyann adn verdikten sonra sonuna .c yazn. rnein deneme.c gibi... Execute -> Compile sekmesine tklayn. ( Ksayol olarak Ctrl + F9'u kullanabilirsiniz. ) Artk programnz derlendi ve almaya hazr. Execute -> Run ile programnz altrn. ( Ctrl + F10'u da deneyebilirsiniz. ) Ekrana "Hello World" yazacaktr.

Eer yazdnz kodu tek seferde derleyip, altrmak isterseniz, Execute -> Compile & Run yolunu izleyin. ( Bu ilemin ksayol tuu, F9'dur. ) Yazdnz kodu nereye kaydederseniz, orada sonu .exe ile biten altrlabilir program dosyas oluacaktr. rnein C:\Belgelerim klasrne deneme.c eklinde bir dosya kaydedip, F9'a bastnzda, deneme.c'nin bulunduu klasrde deneme.exe diye bir dosya oluur. Oluan bu dosyay istediiniz yere tayabilir, dilediiniz gibi altrabilirsiniz. Deiken nedir? Tanm nasl yaplr? Deikenler, girdiimiz deerleri alan veya programn almasyla baz deerlerin atand, veri tutuculardr. Deiken tanmlamaysa, gelecek veya girilecek verilerin ne olduuna bal olarak, deiken tipinin belirlenmesidir. Yani a isimli bir deikeniniz varsa ve buna tamsay bir deer atamak istiyorsanz, a deikenini tamsay olarak tantmanz gerekir. Keza, a'ya girilecek deer eer bir karakter veya virgll say olsayd, deiken tipinizin ona gre olmas gerekirdi. Sanrm bir rnekle aklamak daha iyi olacaktr.
#include<stdio.h> int main( void ) { int a; a = 25; printf("a says %d",a); return 0; }

imdi yukardaki program anlamaya alalm. En ba satra, int a -int, ngilizce de integer'n ksaltmasdr- dedik. Bunun anlam, tamsay tipinde, a isimli bir deikenim var demektir. a=25 ise, a deikenine 25 deerini ata anlamna geliyor. Yani, a artk 25 saysn iinde tamaktadr. Onu bir yerlerde kullandnz zaman program, a'nn deeri olan 25'i ileme alacaktr. printf(); fonksiyonunun iersine yazdmz %d ise, ekranda tamsay bir deiken deeri gzkecek anlamndadr. ift trnaktan sonra koyacamz a deeri ise, grntlenecek deikenin a olduunu belirtir. Yalnz dikkat etmeniz gereken, ift trnaktan sonra, virgl koyup sonra deikenin adn yazdmzdr. Daha gelimi bir rnek yaparsak;
#include<stdio.h> int main( void ) { int a; int b; int toplam; a = 25; b = 18; toplam = a + b; printf("a says %d ve b says %d, Toplam %d.\n", a, b, toplam); return 0; }

Bu programn ekran kts yle olur; a says 25 ve b says 18, Toplam 43. Yazdmz bu programda, a, sonra b, nc olarakta toplam ismiyle 3 adet tamsay deiken tanttk. Daha sonra a'ya 25, b'ye 18 deerlerini atadk. Sonraki satrdaysa, a ile b'nin deerlerini toplayarak, toplam ismindeki deikenimizin iersine atadk. Ekrana yazdrma ksm ise yle oldu: tane %d koyduk ve ift trna kapattktan sonra, ekranda gzkme srasna gre, deikenlerimizin adn yazdk. printf(); fonksiyonu iersinde kullanlan %d'nin anlam, bir tamsay deikenin ekranda grntleneceidir. Deikenlerin yazlma srasndaki olaya gelince, hangisini nce grmek istiyorsak onu baa koyar sonra virgl koyup, dier deikenleri yazarz. Yani nce a deerinin gzkmesini istediimiz iin a, sonra b deerinin gzkmesi iin b, ve en sonda toplam deerinin gzkmesi iin toplam yazdk.

Bu arada belirtmekte fayda var, elimizdeki 3 tamsay deikeni, her seferinde int yazp, belirtmek zorunda deiliz. int a,b,toplam; yazarsakta ayn ilemi tek satrda yapabiliriz. imdi, elimizdeki program bir adm teye tayalm:
#include<stdio.h> int main( void ) { int saat; float ucret, toplam_ucret; char bas_harf; printf("alann ba harfini giriniz> "); scanf("%c",&bas_harf); printf("alma saatini giriniz> "); scanf("%d",&saat); printf("Saat cretini giriniz> "); scanf("%f",&ucret); toplam_ucret = saat * ucret; printf("%c baharfli alann, alaca cret: %f\n",bas_harf,toplam_ucret); return 0; }

Bu yazdmz program basit bir arpm ilemini yerine getirerek sonucu ekrana yazdryor. Yazlanlarn hepsini bir anda anlamaya almayn, nk adm adm hepsinin zerinde duracaz. Program incelemeye balarsak; deiken tanmn programmzn banda yapyoruz. Grdnz gibi bu sefer farkl tiplerde deikenler kullandk. Biri int, dier ikisi float ve sonuncusunu da char. int'n tamsay anlamna geldiini az evvel grdk. float ise 2.54667 gibi virgll saylar iin kullanlr. char tipindeki deikenler, a,H,q,... eklinde tek bir karakter saklarlar. Konu biraz karmak gzkse de, deiken tanmnda btn yapmanz gereken, deikeninizin tayaca veriye gre programn banda onun tipini belirtmektir. Bunun iin de tpk yukardaki programda olduu gibi, nce tipi belirtir, sonra da adn yazarsnz. Programmza dnersek, alma saati bir tamsay olacandan, onu saat isminde bir int olarak tanttk. cret virgll bir say olabilirdi. O nedenle onu float (yani virgll say) olarak bildirdik. Adn da saatucret koyduk. Farkettiiniz gibi, toplamucret isimli deikenimiz de bir float. nk bir tamsay (int) ile virgll saynn (float) arpm virgll bir say olmaktadr. Tabii 3.5x2=7 gibi tam say olduu durumlarda olabilir. Ancak hatadan saknmak iin toplamucret isimli deikenimizi bir float olarak belirtmek daha dorudur. steki programmzda olmasna karn, uana kadar scanf(); fonksiyonunun kullanmna deinmedik. scanf(); geen haftaki yazmzdan da rendiimiz gibi bir giri fonksiyonudur. Peki nasl kullanlr, tam olarak ne ie yarar? scanf(); kabaca klavyeden girdiiniz sayy veya karakteri almaya yarar. Kullanm ise yledir: nce scanf yazar, sonra parantez ve ardndan ift trnak aar, daha sonra alnacak deikene gre, %d, %f veya %c yazlr. %d int, %f float, %c char tipindeki deikenler iin kullanlr. Bundan sonra ift trna kapatp, virgl koyarsnz. Hemen ardndan & iareti ve atanacak deiken adn yazarsnz. Son olarak, parantezi kapatp noktal virgl koyarsnz. Hepsi budur. Yukardaki programda da scanf(); fonksiyonu grdnz gibi bu ekilde kullanlmtr. Sanrm gereinden ok laf oldu ve konu basit olduu halde zor gibi gzkt. Yukardaki skntdan kurtulmak iin ok basit bir program yazalm. Bu programn amac, klavyeden girilen bir sayy, ekrana aynen bastrmak olsun.
#include<stdio.h> int main( void ) { int sayi; printf("Deer giriniz> "); scanf("%d",&sayi);

printf("Girilen deer: %d\n",sayi); return 0; }

Grdnz gibi hibir zor taraf yok. Klavyeden girilecek bir tamsaynz varsa, yapmanz gereken nce deikenin tipini ve adn belirtmek, sonra scanf( ); fonksiyonunu kullanmak. Bu fonksiyonu kullanmaya gelince, scanf(" yazdktan sonra deiken tipine gre %d, %c, veya %f, yazp, ardndan & iaretini kullanarak atanacak deikenin adn belirtmekten ibaret. Fark etmisinizdir, printf(); ve scanf(); fonksiyonlarnn her ikisinde de %d koyduk. nk scanf( ); ve printf( ); fonksiyonlarn deiken tipi simgeleri ayndr. Aadaki tablodan hangi deiken tipinin nasl deklare edileceini, ka byte yer kapladn, maksimum/minimum alabilecei deerleri ve giri/k fonksiyonlaryla nasl kullanlabileceini bulabilirsiniz. Tanmlamalar ve fonksiyon uygulamalar, degisken isimli bir deiken iin yaplmtr. TP Karakter Ksa Tam Say Tamsay Uzun Tamsay aretsiz Tamsay aretsiz Uzun Tamsay Virgll Say Uzun Virgll Say DEKLARASYON char degisken; scanf( ); Minimum printf( ); printf("% scanf("%c" c",degisk ,&degisken -128 en); ); printf("% scanf("%d d",degisk ",&degiske -32768 en); n); printf("% scanf("%d d",degisk ",&degiske -32768 en); n); printf("% scanf("%ld ld",degisk ",&degiske -2147483648 en); n); printf("% scanf("%u" u",degisk ,&degisken 0 en); ); printf("% scanf("%lu lu",degisk ",&degiske 0 en); n); printf("% scanf("%f", f",degiske &degisken) 1,17549e-38 n); ; printf("% scanf("%lf" lf",degisk ,&degisken 2,22504e-308 en); ); Maksimum 127 Byte 1

short degisken;

32767

int degisken;

32767

long int degisken; unsigned int degisken; long unsigned degisken; float degisken;

2147483647

65535

4294967295

3,40282e+38 1,79769e+30 8

double degisken;

Verilen bu deerler; iletim sisteminden, iletim sistemine, farkllk gsterebilir. En doru deerleri almak iin sizeof( ), fonksiyonunu kullanmak gerekir. Aada yazm olduum bir program bulacaksnz. Kendi bilgisayarnzda derleyip, altrrsanz, size deikenlerin boyutunu ve alabilecei maksimum-minimum deerleri verecektir:
#include<stdio.h> #include<limits.h> #include<float.h> int main( void ) { printf( "\nTIP\t\t

BOYUT\t\t MIN\t \tMAX\n" );

");

printf("==============================================================\n

printf( "char\t\t: %d byte(s)\t%d\t\t%d\n", sizeof(char),CHAR_MIN,CHAR_MAX ); printf( "short\t\t: %d byte(s)\t%d\t\t%d\n", sizeof(short), SHRT_MIN, SHRT_MAX ); printf( "int\t\t: %d byte(s)\t%d\t%d\n", sizeof(int), INT_MIN, INT_MAX ); printf( "unsigned int\t: %d byte(s)\t\t\t%u\n",sizeof(unsigned),UINT_MAX ); printf( "long\t\t: %d byte(s)\t%ld\t%ld\n", sizeof(long), LONG_MIN, LONG_MAX ); printf( "float\t\t: %d byte(s)\t%e\t%e\n", sizeof(float), FLT_MIN, FLT_MAX ); printf( "double\t\t: %d byte(s)\t%e\t%e\n\n", sizeof(double), DBL_MIN, DBL_MAX ); return 0; }

Program inceleyip, detaylara girmeyin. Sadece altrp, sonular grmeniz yeterli. rnein, Ubuntu ykl x86 tabanl bir bilgisayarda, karnza yle bir ekran gelecektir:
TIP BOYUT MIN MAX ============================================================== char : 1 byte(s) -128 127 short : 2 byte(s) -32768 32767 int : 4 byte(s) -2147483648 2147483647 unsigned int : 4 byte(s) 4294967295 long : 4 byte(s) -2147483648 2147483647 float : 4 byte(s) 1.175494e-38 3.402823e+38 double : 8 byte(s) 2.225074e-308 1.797693e+308

Sanrm hi istemediim bir ey yaparak, kafanz kartrdm. Dilerseniz, burada keselim ve bunlar ileriye dnk olarak bir kenarda dursunlar. Yine de daha fazla bilgi isterseniz, Teach Yourself C in 21 Days yazsna gz atabilirsiniz. Ama dediim gibi bunlarn sonraya braklmas, uygun olacaktr. u ana kadar rendiklerimizle girilen herhangi iki saysnn ortalamasn hesaplayan bir program yazalm. Balamadan nce, deikenlerimizin ka tane ve nasl olacan dnelim. uras kesin ki, alacamz iki say iin 2 farkl deikenimiz olmal. Bir de ortalamay hesapladmzda bulduumuz deeri ona atayabileceimiz bir baka deikene ihtiyacmz var. Peki deikenlerimizin tipleri ne olacak? Banda belirttiimiz gibi yazmamz gereken program herhangi iki say iin kullanlabilmeli. Sadece tamsay demiyoruz, yani virgll bir say da girilebilir. O halde, girilecek iki saynn deiken tipi float olmal. Bunu double da yapabilirsiniz, fakat bykl asndan gereksiz olacaktr. Ortalamalarn atanaca nc deikene gelince, o da bir float olmal. ki virgll saynn ortalamasnn tamsay kmas dnlemez. Oluturduumuz bu nbilgilerle programmz artk yazabiliriz.
#include<stdio.h> int main( void ) { float sayi1,sayi2,ortalama; printf("ki say giriniz> "); scanf("%f%f",&sayi1,&sayi2); ortalama = ( sayi1 + sayi2 ) / 2; printf("Ortalama sonucu: %f'dir",ortalama); return 0; }

Yukarda yazl programda, bilmediimiz hibir ey yok. Gayet basit ekilde izah edersek, 2 say alnp, bunlar toplanyor ve ikiye blnyor. Bulunan deerde ortalama isminde bir baka deikene

atanyor. Burada yabanc olduumuz, sadece scanf(); kullanmndaki deiiklik. scanf(); fonksiyonuna bakn. Dikkat edeceiniz gibi, deikenlerden ikisine de tek satrda deer atadk. Ayr ayr yazmamz da mmknd, ancak kullanm asndan byle yazmak ak ekilde daha pratiktir. Bu konuda bir baka rnek verelim. Diyelim ki, biri int, dieri float, sonuncusuysa char tipinde 3 deikeni birden tek scanf(); ile almak istiyorum. Deikenlerin isimleri, d1,d2 ve d3 olsun. Nasl yaparz?
scanf("%d%f%c",&d1,&d2,&d3);

Peki aldmz bu deikenleri ekrana tek printf(); ile nasl yazdrabiliriz?


printf("%d %f %c",d1,d2,d3);

Grld gibi bu iin yle aman aman bir taraf yok. Fonksiyonlarn kullanmlar zaten birbirine benziyor. Tek yapmanz gereken biraz pratik ve el alkanl. Aritmetik Operatr ve fadeleri ste yazdmz programlarn hemen hemen hepsinde aritmetik bir ilem kullandk. Ama aritmetik ilemleri tam olarak anlatmadk. Ksaca;
( + ) : Art ( - ) : Eksi ( / ) : Blme ( * ) : arpma ( % ) : Modl

Burada bilinmeyen olsa olsa modl ilemidir. Modl kalanlar bulmaya yarar. Yani diyelim ki 15'in 6'ya olan blmnden kalann bulmak istiyorsunuz. O halde 15%6 = 3 demektir. Veya, 7'nin 3'e blmnden kalan bulacaksanz, o zamanda 7%3 = 1 elde edilir. Bu C'de ska kullanacamz bir aritmetik operatr olacak. lem srasna gelince, o da yle olur. En nce yaplan ilem parantez ( ) iidir. Sonra * / % gelir. arpma, blme ve modl iin, soldan saa hangisi daha nce geliyorsa o yaplr. En son yaplanlarsa art ve eksidir. Keza, bu ikisi arasnda, nce olan solda bulunandr. Blme ilemine dair, bir iki ufak olay daha var. 4/5 normalde 0.8 etmektedir. Ancak C iin 4/5 sfr eder. nk program, iki tamsaynn blnmesiyle, sonucu tamsay elde etmeyi bekler. leride tipleri birbiri arasnda deitirmeye deineceiz. Ama imdilik bu konuda bir-iki rnek yapalm:
* * * * * 8/4+2 => 2 + 2 => 4 8-4*2+-12 => 8 - 8 + -12 => -12 15*4/2%4*7 => 60/2%4*7 => 30%4*7 => 2*7 => 14 31+7/2-83%5*2-2 => 31+ 3 - 3 * 2 - 2 => 31 + 3 - 6 - 2 => 26 (31-7) * 2 + 83 / (5%2) => 24 * 2 + 83 / 1 => 48 + 83 => 131

Bu aritmetik ifadeleri henz bir C program iin denemedik. Ancak burada keselim. Bunu yapmay dier yazmza saklayalm. Eer uramak isterseniz klavyeden alnacak 3 saynn ortalamasn bulan bir program yazabilirsiniz. Yada girilecek 2 tamsay arasnda btn aritmetik ilemleri -ikisin arpmn, toplamn, birbirine blmn ve farkn- bulan ve sonular ekrana yazdran bir program da yazmanz mmkn. Herhangi bir yerde taklr ve bana ulamak isterseniz mail adresime yazmanz kafi. Haftaya grrz.

C Programlama Dersi - III


Bu yazda renecekleriniz:
Kodlarnza aklama (comment) koymak Cast Operator Koullu (Conditional) fadeler Koullu Operatrler ( if, else, vs... ) likisel (Relational) Operatrler Birleik (Compound) Operatrler Konuyla ilgili rnek sorular

Kodlarnza aklama (comment) koymak


Yazlm mhendislerinin en byk sknts kod yazmak deildir. Yazlm bir kodu okuyup anlamak -hele ki byk bir projeden sz ediyorsak- asl banza bela olacak konudur. Bundan korunmak iin kodlarmza aklama/yorum koyarz. C programlama dilinde iki ekilde aklama koymak mmkndr. Bunlardan bir tanesi, satr baznda yaplr. Dieriyse, belirli bir blou yorumlamaya yarar. Compiler her iki ekilde de, aklama olarak belirlemi yerleri ilemeyecektir. Aadaki rnekte satr ve blok olarak, nasl kodlarnza aklama getirebileceinizi grebilirsiniz:
/*ok satrl bir aklama. Yldzlar arasnda kalan btn alan, yorum olarak deerlendirilir ve derleyici (compiler) tarafndan ilenmez. */ #include<stdio.h> int main( void ) { //Tek satrlk bir aklama. printf("Hello World\n"); }

Cast Operator
Cast operator'un Trke karl olacak bir kelime aklma gelmedi. Ancak cast operatoru u ekilde aklayabiliriz. Bir deiken tipini rnein (Tam say-int), bir baka tipe (virgll say-float) gibi dntrmek isterseniz, o zaman cast operator kullanrz. Aadaki kodu yazp derleyin.
#include<stdio.h> int main( void ) { int bolunen = 12, bolen = 8; float bolum; bolum = bolunen / bolen; printf("Sonuc: %f\n",bolum); return 0; }

Program kts; "Sonuc: 1.000000" olacaktr: Normalde 1.5 kmasn beklediiniz sonucun, 0.000000 kmasnn nedeni casting kullanmamamzdr. Bir tam sayy, bir baka tam sayya blerseniz, sonu bir baka tam say kar. Ve C programlama dili, bir virgll sayy tam sayya atamaya kalktnzda, herhangi bir yuvarlama ilemi yapmadan, virglden sonras atar. Cast Operator u ekilde kullanlmaldr: degisken_1 = ( tip ) degisken_2; Elimizdeki bu bilgiye gre programmz tekrar yazalm.
#include<stdio.h> int main( void ) { int bolunen = 12, bolen = 8; float bolum; bolum = (float)bolunen / bolen; printf("Sonuc: %f\n",bolum); return 0; }

Sonu bu sefer, beklediimiz gibi 1.5 kacaktr. Aadaki rnei inceleyelim:


#include<stdio.h> int main( void ) { printf("Sonuc: %f\n", 2 / 4); return 0; }

rendiimiz zere, bunun da sonucu 0.5 yerine, 0 olarak gzkecektir. Sonucu doru yazdrmak iin (float)2/4 eklinde yazmanz yeterlidir. Ancak dahi basit bir yntem olarak 2/4.0 veya 2.0/4 yazarsanz yine ayn sonucu elde edersiniz.nk bu durumda saylardan bir tanesi float olmaktadr. Kullanlan deiken tiplerinden hangisi bykse, sonu o deikenin tipinde dner. Yksek deiken bellekte daha fazla yer kaplamaktadr. Bunun doal bir sonucu olarakta, domine eden o'dur. Deikenlerin bykln daha nceki dersimizde vermitik. Ancak hatrlamak asndan, aaya bakabilirsiniz.
(DK) char <-> int <-> long <-> float <-> double (YKSEK)

kan sonucu, daha dk bir deiken tipine atamaya kalkarsanz, o zaman veri kayb yaanr. Ve rnein float 1.5 olan sonucu int deikene 1.0 olarak kaydedilir. rendiklerinizin pekimesi iin bir program yazalm. Bu programda, klavyeden girilen, bir virgll saynn, yuvarlanp, tam say olmas gsterilsin:
#include<stdio.h> int main( void ) { float girilen_sayi; printf("Ltfen bir say giriniz> "); scanf("%f",&girilen_sayi); printf("Saynn yuvarlanm hali: %d\n", (int)(girilen_sayi+0.5)); return 0; }

Koullu (Conditional) fadeler


if Bilgisayarda yaplan btn mantksal ilemler kaba bir temele dayanr. artlar saland halde yaplacak ilem belirlenir. Ve artlar salandnda, bu ilemler yaplr. artlarn kontrol edilmesini, C (ve daha birok) programlama dilinde if operatrn kullanarak yaparz. if operatrnn genel kullanm yaps u ekildedir:
if( koul ) { komut(lar) }

Eer if'in altnda birden ok komut varsa, ayra iareti (veya kme parantezi) koymamz gerekir. ayet if'ten sonra, tek komut bulunuyorsa, ayra koyup-koymamak size kalmtr. Zorunluluu yoktur. rnek bir program yazalm. Bu programda kullancnn klavyeden, bir tam say girsin. Ve bizde girilen say, 100'den bykse, ekrana yazdralm:
#include<stdio.h> int main( void ) { int girilen_sayi; printf("Ltfen bir tam say giriniz> "); scanf("%d",&girilen_sayi); if( girilen_sayi > 100 ) printf("Girilen say 100'den byktr\n"); return 0; }

if-else Baz durumlarda, bir koulun doruluuna gre sonu yazdrmak yetmez. Aksi durumda da ne yapacamz belirtmek isteriz. Bunun iin if-else yapsn kullanrz. if-else yaps u ekildedir:
if( koul ) { komut(lar) } else { komut(lar) }

nceki yazdmz program dnelim; 100'den byk olduunda, ekrana kt alyorduk. Bu programa bir zellik daha ekleyelim ve 100'den kkse, bunu da syleyen bir yapy oluturalm:
#include<stdio.h> int main( void ) { int girilen_sayi; printf("Ltfen bir tam say giriniz> "); scanf("%d",&girilen_sayi); if( girilen_sayi > 100 ) printf("Girilen say 100'den byktr\n"); else printf("Girilen say 100'den kktr\n"); return 0; }

rnekte grdnz gibi, bir koulun doruluunu program kontrol ediyor ve buna doru olursa, baz ilemler yapyor. ayet verilen koul yanlsa, o zaman daha baka bir ilem yapyor. Ancak ikisini de yapmas gibi bir durum sz konusu deil.Aadaki ak diyagramlarnda (flowchart) her iki durumu da grebilirsiniz. if Yaps: if-else Yaps:

likisel (Relational) Operatrler


Koullu operatrlerde, koulun doruluunu kontrol ederken kullandmz ilikisel operatrler, aada verilmitir: < > == <= >= != Kktr Byktr Eittir Kk eittir Byk eittir Eit deildir

Birleik (Compound) Operatrler


Baz durumlarda, kontrol edeceimiz koul, tek bir parametreye bal deildir. rnein, bir kiinin yann 65'den kk olup olmadna bakabiliriz. Ama 65'den kk ve 18 yandan byk olup olmadna karar vermek istersek, o zaman Birleik/Birletirici Operatrler'i kullanmamz uygun olacaktr. Compound operator'ler aadaki gibidir: && || and or ve veya

not

tersi

Bu operatrlerin mantksal (logical) doruluk tablosu da u ekildedir: p 0 0 1 1 q 0 1 0 1 p&&q 0 0 0 1 p||q 0 1 1 1 !p 1 1 0 0

rnek Sorular
Soru 1: Klavyeden alnacak bir deerin, 18 ile 65 arasnda olup olmadn kontrol eden bir program yaznz: Soru 2: Kendisine verilen iki tam sayy, blecek ve sonucu virgll say olarak gsterecek bir blme ilemini program hazrlaynz. (ayet blen 0 olarak verilirse, blme ilemi yaplmamaldr.) Not: Yukarda verilmi zmler, daha efektif olabilirdi. Ancak verdiim cevaplarn herkes tarafndan anlalmasn istediimden, ii biraz uzatm olabilirim. Sizin vereceiniz cevaplarn gidi yollar elbette ki farkl olabilir. Cevap1:
/* Girilen yan, 18 ile 65 arasnda olup olmadn belirler. */ #include<stdio.h> int main( void ) { int girilen_yas; printf("Ltfen yanz giriniz> "); scanf("%d",&girilen_yas); if( girilen_yas >= 18 && girilen_yas <= 65 ) printf("Girilen ya, 18 ile 65 arasndadr.\n"); //Girilen ya 18 ile 65 arasnda deilse, aadaki else //blou alr. else { //Girilen ya 18'den kkse if( girilen_yas < 18 ) printf("Girilen ya, 18'den kktr.\n"); //Girilen ya 65'ten bykse else printf("Girilen ya, 65'ten byktr.\n"); } }

Cevap2:
/* Kendisine verilen iki tam sayyla blme ilemi yapan program. */ #include<stdio.h> int main( void ) { int bolunen, bolen; float sonuc; printf("Blnecek sayy giriniz> "); scanf("%d",&bolunen); printf("Blen sayy giriniz> "); scanf("%d",&bolen); //Bolen, 0 ise, bir say sfra blnemeyeceinden, //program sorun kartacaktr. Bu yzden, //bolenin 0 olmamas kontrol ediliyor. if( bolen != 0 ) { sonuc = (float)bolunen / bolen; //.2f, virglden sonra 2 basamak gsterilmesi //iindir. printf("Sonuc: %.2f\n",sonuc); } else printf("Hata: Say 0'a blnemez!\n"); }

C Programlama Dersi - IV
Bu yazda renecekleriniz:
ie gemi (Nested) koullu ifadeler if - else if merdiveni switch - case ifadesi Arttrma (Increment) ve azaltma (Decrement) ilemleri Gelimi atama (Advanced Assignment) yntemleri Conditional Operator ( ? ) Konuyla ilgili rnek sorular

ie gemi (Nested) fadeler


Daha nce, koullu ifadeleri grmtk. Hatrlatmak iin zerinden geersek, if ile bir ifadeyi

kontrol ediyor ve doruysa, buna gre ilemler yapyorduk. Bir de if - else yaps vard. if - else yapsnda da, koulu gene kontrol ediyor, doruysa if blounun altnda kalanlar yapyorduk; yanlsa, else blounda olan kodlar ileme alnyordu. Son derece basit bir mantk zerine kurulmu bu yapyla, yaplamayacak kontrol yoktur. Ancak yle durumlar vardr ki, if - else yaps yeterli verimlilii sunamaz. Diyelim ki, birden fazla kontrol yapmanz gereken bir durum olutu. Hatta rnek vererek konuyu daha da somutlatralm. stenilen bir programda, klavyeden size ya bilgisi veriliyor. Siz de bu bilgiye gre, ayet ya 18'den kkse ocuk; 18-30 ya arasnda gen; 30-50 ya arasnda ortaya diye bir mesaj bastryorsunuz. Basit bir program. imdi bunu sadece if yapsyla kuruyor olsaydk, her seferinde yan uygun aralklara dp dmediini kontrol eder ve ona gre sonucu ekrana bastrrdk. Ama bu son derece verimsiz bir yntem olurdu. nk zaten ya bilgisinin gen olduuna dair bir karar vermisek, sonrasnda tutup bunun yal olup olmadn kontrol etmenin bir esprisi olmayacaktr. Verilebilecek en kt cevab aada bulabilirsiniz:
/* Sorulan soruya verilebilecek en kt cevap. */ #include<stdio.h> int main( void ) { int girilen_yas; printf("Ltfen yanz giriniz> "); scanf("%d",&girilen_yas); if( girilen_yas < 18 ) printf("Daha ocuk yatasnz, hayatn bandasnz.\n"); if( girilen_yas >= 18 && girilen_yas <= 30 ) printf("Genliin, gzellii bambaka!\n"); if( girilen_yas > 30 && girilen_yas <= 50 ) printf("Hepsini boverin, olgunluk ortayata balar!\n"); return 0; }

Yukarda ki kodu if - else kullanarak daha efektif hale getirebiliriz:


/* if - else yapsyla daha efektif bir yap */ #include<stdio.h> int main( void ) { int girilen_yas; printf("Ltfen yanz giriniz> "); scanf("%d",&girilen_yas); if( girilen_yas < 18 ) printf("Daha ocuk yatasnz, hayatn bandasnz.\n"); else { if( girilen_yas >= 18 && girilen_yas <= 30 ) printf("Genliin, gzellii bambaka!\n"); else { if( girilen_yas > 30 && girilen_yas <= 50 ) printf("Hepsini boverin, olgunluk ortayata balar!\n"); } } return 0; }

Yukardaki program daha efektif bir yap sunmu olmasna ramen, eer kontrol ettiimiz aralklarn says ok fazla olsayd, tam bir babelas olacakt! nk if - else iinde, bir baka if - else blou ve onun iinde bir bakas... bu byle srp gidecekti. Ksacas performans olarak ok bir ey deimese de, kodu yazan ve/veya okuyacak olan iin tam bir eziyete dnecekti. te bu nedenlerle daha efektif yaplara ihtiya duyuyoruz.

if - else if Merdiveni
if - else if merdiveni yukarda verdiimiz rnekler iin biilmi kaftandr. if - else if merdiveni, doru bir ey bulduu zaman kontrolu orada keser ve dier koullar kontrol etmeden blok sonlandrlr. Aada if - else if yapsn ve ak diyagramn bulabilirsiniz: if - else if Yaps if - else if Ak Diyagram

if( koul 1 ) { komut(lar) } else if( koul 2 ) komut(lar) } . . . else if( koul n ) komut(lar) } else { komut(lar) }

1 { 2

{ n n

if - else if ile sylenebilecek son bir ey sonunda ki else'tir. else koymak zorunlu deildir. Ancak hibir koula uymayan bir durumla karlatnzda, else devreye girer. rnein yukarda anlatp, kodunu vermi olduumuz programda, belirtilen ya aralklarnda deer girilmezse, hibir ey ekrana bastrlmayacaktr. nk programa tannmayan ya aralnda ne yaplaca retilmemitir. imdi bu durumu da ierecek ekilde, programammz if - else if yapsyla tekrar yazalm:
#include<stdio.h> int main( void ) { int girilen_yas; printf("Ltfen yanz giriniz> "); scanf("%d",&girilen_yas); if( girilen_yas < 18 ) printf("Daha ocuk yatasnz, hayatn bandasnz.\n"); else if( girilen_yas >= 18 && girilen_yas <= 30 ) printf("Genliin, gzellii bambaka!\n"); else if( girilen_yas > 30 && girilen_yas <= 50 ) printf("Hepsini boverin, olgunluk ortayata balar!\n"); else

printf("HATA: Girilen ya tanml deildir!\n"); } return 0;

swicth - case ifadesi


switch - case, if - else if yapsna olduka benzer bir ifadedir. Ancak aralarnda iki fark vardr. Birincisi, switch - case yapsnda, aralk deeri girmezsiniz. Direkt olarak ifadelerin bir eylere eit olup olmadna bakarsnz. kinci farksa, switch - case yaplarnda, illa ki uygun koulun salanmasyla yapnn kesilmek zorunda olmaydr. 'break' komutu kullanmadnz takdirde, dier artlarn iindeki ilemleri de yapma imkannz olabilir. switch case en tepeden balayarak artlar tek tek kontrol eder. Uygun art yakalanrsa, bundan sonra ki ifadeleri kontrol etmeden doru kabul eder. Ve ayet siz break koymamsanz, eitlik uygun olsun olmasn, alt tarafta kalan case'lere ait komutlarda altrlacaktr. if - else if ise daha nce sylemi olduumuz gibi byle deildir. Uygun koul salandnda, yap darsna klr. switch case yapsnda ki durumu, aadaki tabloda grebilirsiniz: switch case Yaps switch case Ak Diyagram

switch( degisken ) { case sabit1: komut(lar) [break] case sabit2: komut(lar) [break] . . . case sabitN: komut(lar) [break] default: komut(lar); }

Sanrm gznze biraz farkl gzkt. Yap olarak imdiye kadar grm olduunuz if else gibi gzkmese de, bir rnekten sonra arasnda pek bir fark olmadn greceksiniz. Her komut sonunda koyduum break komutu, zorunlu deildir ve o nedenle keli parantezle belirtilmitir. break koyduuz takdirde, uygun koul salandktan sonra, daha fazla kontrol yaplmayacak ve aynen if - else if yapsnda olduu gibi program orada kesilecektir. Ama break koymazsanz, altnda kalan btn ilemler -bir daha ki break'e kadar- yaplacaktr. Kodun sonunda grdnz default komutu, if - else if yapsnda ki sonuncu else gibidir. Uygun hibir art bulunamazsa, default komutu alr. rendiimiz bilginin pekimesi iin biraz pratik yapalm. Bir not deerlendirme sistemi olsun. 100 - 90 aras A, 89 - 80 aras B, 79 - 70 aras C, 69 - 60 aras D, 59 ve altysa F olsun. Eer 100'den byk veya negatif bir say girilirse, o zaman program hatal bir giri yapldn konusunda bizleri uyarsn. Bunu imdiye kadar rendiiniz bilgilerle, if - else if yapsn kullanarak rahatlkla yantlayabilirsiniz. Ama u an konumuz switch case olduundan, cevabn yle verelim:
#include<stdio.h> int main( void ) { int not; printf("Ltfen notu giriniz> "); scanf("%d",&not); switch( not / 10 ) { case 10: case 9: printf("NOT: A\n"); break; case 8: printf("NOT: B\n"); break; case 7: printf("NOT: C\n"); break; case 6: printf("NOT: D\n"); break; case 5: case 4: case 3: case 2: case 1: case 0: printf("NOT: F\n"); break; default: printf("HATA: Bilinmeyen bir deer girdiniz!\n"); } return 0;

Algoritmaya bakalm: nce sayy alyor ve 10'a blyoruz. Yani girilen not, 57 ise 5.7 sonucunu elde ediyoruz. Ancak iki tam saynn sonucu bir virgll say veremez, tpk ileme giren deikenler gibi tam say olarak dner. Dolaysyla bilgisayarn elde edecei sonu, 5.7 deil, sadece 5'tir. switch case yapsnda koullar yukardan balayarak kontrol ediliyor. case 5'e gelindiinde eitlik salanyor. Ama break konmad iin, switch case'ten klmyor. Ve altnda kalan ilemlerde yaplyor. Altnda herhangi bir ilem veya break olmadndan case 0'a kadar bu byle sryor. Ve case 0'da ekrana bir kt alp switch case yaps break ile sonlandrlmaktadr. switch case, if - else if yapsnn sunduu esneklie sahip deildir. Daha ok men olarak sunulacak ilerde kullanlr. rnein Unix'in nl listeleme komutu ls iersinde, verilen parametrelerin kontrol switch case kullanlarak salanmtr. Open Solaris, FreeBSD veya Linux kodlarn incelerseniz bunun gibi yzlerce rnek bulabilirsiniz.

Arttrma (Increment) ve azaltma (decrement) ilemleri


Daha nceki derslerimizde, aritmetik ilemlerden bahsetmitik. Bunlarn dnda yapabileceimiz baka eylerde bulunmaktadr. Bunlardan biri de, arttrma ve azaltma ilemleridir. Eer i adnda bir deikenin deerini 1 arttrmak isterseniz, i = i + 1 olarak yazarsnz. Veya 1 azaltmak isterseniz, benzer ekilde i = i - 1 de yazabilirsiniz. Arttrma ve azaltma ilemleri bu olay daha basit bir forma sokmaktadr. i = i + 1 yazmak yerine i++ veya i = i - 1 yazmak yerine i-yazabilirsiniz. Arttrma ve azaltma ilemleri temelde iki eittir. Birinci yntemde yukarda yazdmz gibi, arttrma/azaltma sonradan yaplr. kinci yntemdeyse arttrma/azaltma ilk bata yaplr. Aadaki rneklere bakalm.
/* Bu programda, arttrma ve azaltma ilemleri nce yaplacaktr. */ #include<stdio.h> int main( void ) { int i = 10, j = 60; printf("i = %d ve j = %d\n", ++i, --j); return 0; }

Yukardaki program yazar ve altrsanz elde edeceiniz kt u ekilde grnecektir: i = 11 ve j = 59 nk arttrma ve azaltma ilemleri ekrana bastrmadan nce yaplm ve i ile j'nin deerleri deitirilmitir. imdi program deitirip yle yazalm:
/* Bu programda, arttrma ve azaltma ilemleri sonra yaplacaktr. */ #include<stdio.h> int main( void ) { int i = 10, j = 60; printf("i = %d ve j = %d\n", i++, j--); return 0; }

Bu sefer program kts yle olacaktr: i = 10 ve j = 60 Farkettiiniz zere hibir deiiklik yaplmam gibi duruyor. Aslnda deiiklik yapld ve program sonlanmadan nce i 10 olurken, j'de 59 oldu. Ama arttrma ve azaltma ilemleri printf komutu altrldktan sonra yapld iin, biz bir deiiklik gremedik. Ksacas nce arttrma (pre-increment) veya nce azaltma (pre-decrement) kullandnzda, ilgili komut satrnda alacak ilk ey bu komutlar olur. Ancak sonra arttrma (post increment) veya sonra azaltma kullanrsanz, o zaman bu ilemlerin etkileri ilgili komut satrndan sonra geerli olacaktr. Aadaki zel tabloya bakabilirsiniz: Form i++ ++i i---i Tip postfix prefix postfix prefix sim post-increment pre-increment post-decrement pre-decrement Aklama lem sonras arttrma lem ncesi arttrma lem sonras azaltma lem ncesi azaltma

Gelimi atama (Advanced Assignment) yntemleri


C'de yazm kolayl amacyla sunulmu bir baka konu da, gelimi aama yntemleridir. Biraz daha uzun yazacanz kodu, ksaltmanza yaramaktadr. degisken_1 = degisken_1 (operator) degisken_2 eklinde yazacanz ifadeleri, daha ksa yazabilmeniz iin, degisken_1 (operator) = degisken_2 eklinde ifade edebilirsiniz. Gelimi atamalarda sunulan genel formlar u ekildedir:
+= , -= , *= , /= , %=

Sanrm aadaki rneklere bakarsanz, konuyu ok daha net anlayacaksnz:


1-) j = j * ( 3 + x ) ==> j *= ( 3 + x ) 2-) a = a / ( 5 - z ) ==> a /= ( 5 - z ) 3-) x = x - 5 ==> x -= 5

Conditional Operator ( ? )
Trke karlk bulamadm bir baka C kavram da, Conditional Operator. Aslnda mot a mot eviri yaparsam, koullu operatr anlamna geliyor. Ama u ana kadar grdmz birok yapy da bu ekilde tanmlamak mmknken, koullu operatr ifadesini kullanmay pek tercih etmiyorum. Neyse laf uzatmayalm... Conditional Operator, if-else ile tamamen ayn yapdadr. Hibir fark yoktur. Tek fark koda bakldnda anlalmasnn biraz daha zor oluudur. Bir de if - else gibi yazyla ifade edilmez. Onun yerine soru iareti (?) ve iki nokta st ste ( : ) kullanarak yazarz. Aadaki tabloda if else yapsyla karlatrlmal olarak, Conditional Operator verilmitir: if-else Yaps
if( koul ) { if_komut(lar) } else {

Conditional Operator ( ? ) Yaps


koul?if_komut(lar):else_komutlar

else_komut(lar) }

Conditional Operator ( ? ) Ak Diyagram

imdi de ayn program, hem if-else, hem de conditional operator kullanarak yazalm:
/* Girilen tam saynn 10'dan byk olup olmadn gsteren program */ #include<stdio.h> int main( void ) { int sayi; printf("Ltfen bir say giriniz> "); scanf("%d",&sayi); if( sayi > 10 ) printf("Say 10'dan byktr\n"); else printf("Say 10'dan kktr veya 10'a eittir\n"); return 0; }

imdi de ayn program conditional operator kullanarak yazalm:


/* Girilen tam saynn 10'dan byk olup olmadn syleyen program */ #include<stdio.h> int main( void ) { int sayi; printf("Ltfen bir say giriniz> "); scanf("%d",&sayi); ( sayi > 10 ) ? printf("Say 10'dan byktr\n"): printf("Say 10'dan kktr veya 10'a eittir\n");

return 0;

Program grdnz gibi biraz daha ksald. Conditional Operator'ler pek kullanmay sevmediim bir yapdr. nk kodun ksa olmasndan ok, anlalabilir olmas nemli. Ve conditional operator kullanmak ne yazk ki, kodu daha karmak hale getiriyor. UNIX filozofisinde bir eyi akllca yapacanza, temiz/ak yapn diye bir yaklam mevcut. Belki bu yzden veya belki de tembellik, conditional operator'lere alamadm gitti... :) imdi rnek sorularmza gelelim... Soru 1: Aadaki kodu yorumlaynz: s = ( x < 0 ) ? -1 : x * x Soru 2: ki tam say alacak ve verilecek operatre gre (+, -, *, /, %) ilem yapacak bir program yaznz. Soru 3: Verilecek saydan en byn ekrana yazdracak bir program yaznz. Cevap1:
Eer x, 0'dan kk bir deerse, s deikenine, -1 deeri atanr. Eer x, 0'dan bykse, x'in karesi, s deikenine atanr. (Grdnz gibi ilk bakta kodu yorumlamak biraz skc olabiliyor. Sanrm yukarda ne demek istediimi anlamsnzdr.)

Cevap2:
#include<stdio.h> int main( void ) { int sayi_1, sayi_2; char operator_simgesi; printf("Ltfen ilem simgesi giriniz> "); scanf("%c",&operator_simgesi); printf("Ltfen birinci sayy giriniz> "); scanf("%d",&sayi_1); printf("Ltfen ikinci sayy giriniz> "); scanf("%d",&sayi_2); switch( operator_simgesi ) { case '+': printf("%d %c %d = %d\n",sayi_1,operator_simgesi, sayi_2, sayi_1 + sayi_2); break; case '-': printf("%d %c %d = %d\n",sayi_1,operator_simgesi, sayi_2, sayi_1 - sayi_2); break; case '%': printf("%d %c %d = %d\n",sayi_1,operator_simgesi, sayi_2, sayi_1 % sayi_2); break; case '*': printf("%d %c %d = %d\n",sayi_1,operator_simgesi, sayi_2, sayi_1 * sayi_2); break; case '/': printf("%d %c %d = %.2f\n",sayi_1,operator_simgesi, sayi_2, (float)sayi_1 / sayi_2);break; default: printf("HATA: Tanmsz bir operatr girdiniz!\n"); }

return 0;

Cevap3:
#include<stdio.h> int main( void ) { int sayi_1, sayi_2, sayi_3; printf(" say giriniz> "); scanf("%d %d %d", &sayi_1, &sayi_2, &sayi_3); if( sayi_1 >= sayi_2 && sayi_1 > sayi_3 ) printf("%d en byk saydr!\n", sayi_1); else if( sayi_2 >= sayi_1 && sayi_2 >= sayi_3 ) printf("%d en byk saydr!\n", sayi_2); else if( sayi_3 >= sayi_1 && sayi_3 >= sayi_1 ) printf("%d en byk saydr!\n", sayi_3); return 0; }

Dng Kavram
Programlama konusunda -hangi dil olursa olsun- en kritik yaplardan biri dnglerdir. Dngler, bir ii, belirlediiniz sayda yapan kod bloklar olarak dnlebilir. Ekrana 10 kere "Merhaba Dnya" yazan bir programda, "Merhaba Dnya" yazdran kodu aslnda tek bir defa yazarsnz, dng burada devreye girip, sizin iin bu kodu istediiniz sayda tekrarlar. Dngleri bu kadar kritik yapan unsur; iyi yazlp, optimize edilmedii takdirde, bilgisayarnzn ilem gcn gereksiz yere tketmesi ve harcanan zaman arttrmasdr. Benzer ekilde, iyi yazlm bir dng, programnz hzl altracaktr. Btn dngler temelde iki aamayla zetlenebilir. Aamalardan biri, dngnn devam edip etmeyeceine karar verilen mantksal sorgu ksmdr. rnein, ekrana 10 kere "Merhaba Dnya" yazdracaksanz, kanc seferde olduunu, koul ksmnda kontrol edersiniz. Dier aama, dngnn ne yapacan yazdnz ksmdr. Yani ekrana "Merhaba Dnya" yazlmas dngnn yapaca itir. Dngnn devam edip etmeyeceine karar verilen aamada, hatal bir mantk snamas koyarsanz, ya programnz hi almaz ya da sonsuza kadar alabilir. C programlama diline ait baz dngler; while, do while, for yaplardr. Bunlar dnda, goto dng eleman olmasna ramen, kullanlmas pek tavsiye edilmemektedir.

while Dngs
while dngs, en temel dng tipimizdir. Bir kontrol ifadesiyle dngnn devam edilip edilmeyecei kontrol edilirken, scope iinde ( yani ayra iaretleri arasnda ) kalan btn alan ileme sokulur. leme sokulan kod ksm dng yaplacak adet kadar tekrar eder. while dngsnn genel yapsn ve ak emasn aada grebilirsiniz:

while Yaps

while Ak Diyagram

while( koul ) { komut(lar) }

Yukarda 10 kere ekrana "Merhaba Dnya" yazan programdan bahsettik. Gelin bir anlama yapalm ve dnglerle alakal btn ilk rneklerimiz bu programn nasl yazlacan gstersin. while dngs kullanarak, ekrana 10 kere "Merhaba Dnya" yazan program aadaki gibidir:
/* Ekrana 10 kere "Merhaba Dnya" yazan program */ #include<stdio.h> int main( void ) { //i deikenine bir balang deeri atyoruz. //i'ye ilk deger atanmazsa, dngmz yanl alr. int i = 0; //i'nin degeri kontrol ileminden //sonra 1 artar. while( i++ < 10 ) { //2d bir tam saynn yazdrlaca //ancak bu say tek rakamdan olusa da //2 rakamlk yer ayrlmasn belirtir. printf("%2d: Merhaba Dnya\n",i); } return 0; }

Yukardaki program aslnda son derece basit. i deikenine ilk deer olarak 0 atyoruz. Daha sonra, while dngsne balyoruz. fadenin doruluu ( yani i'nin 10'dan kk olup olmad) kontrol ediliyor. Eer doruysa, dng iindeki kodlarn almas balatlyor. Elbette kodlarn balamasndan bir nceki admda, i deikeni arttrlyor. Bu yap toplamda 10 kere tekrar ediyor ve en sonunda i'nin degeri 10'a eit olunca, dng sonlandrlyor. Yandaki ilem basit bir toplama ifadesidir. Yanda grdmz ifade de, n deerini kullancdan alacamz dnerek bir program yazalm. Bu program, alaca n deerine gre, kendisine kadar olan saylarn karelerinin toplamn gsterecektir. Bu program yazarsak:
#include<stdio.h> int main( void ) { int i = 0, toplam_deger = 0; int n; printf("Ltfen n deerini giriniz> ");

scanf("%d",&n); while( i <= n ) { toplam_deger += i*i; i++; } printf("Sonu: %d\n",toplam_deger); return 0;

do while Dngs
Greceimiz ikinci dng eidi, do while dngsdr. Yapt i, while ile hemen hemen ayndr; verilen ii, dng koulu bozulana kadar srdrr. Ancak while'a gre nemli bir fark vardr. while dnglerinde, dng iersindeki ilem yaplmadan nce, sunulan koul kontrol edilir. ayet koul salanmyorsa, o while dngsnn hi almama ihtimali de bulunmaktadr. do while dnglerindeyse, durum byle deildir. lk almada koul kontrol yaplmaz. Dolaysyla, her ne artta olursa olsun, dngnz -en azndan bir kere- alacaktr. Baz durumlarda, dng blou iersindeki kodlarn en azndan bir kere almas gerektiinden, do while yaps kullanlr. do while ile ilgili genel yapy ve ak emasn aada bulabilirsiniz: do while Yaps do while Ak Diyagram

do { komut(lar) } while( koul );

nce Merhaba Dnya rneimizi yapalm:


#include<stdio.h> int main( void ) { int i = 0; do { //nce i'nin deeri arttrlyor //sonra ekrana Merhaba Dnya yazdrlyor. printf("%2d: Merhaba Dnya\n",++i); } while( i < 10 ); return 0; }

Grdnz gibi, bir nceki rneimize olduka benzer bir yapda, yazld. Tek fark i'nin deeri 0'da olsa, 1000'de olsa, en azndan bir kez Merhaba Dnya'nn yazlacak olmasdr. Ancak while'de kontrol nce yapld iin, hibir ey ekrana yazlmaz. imdi do while'in kullanlmasnn daha mantkl olaca bir program yapalm. Kullancdan iki say alnsn. Bu iki say toplandktan sonra, sonucu ekrana yazdrlsn. Yazdrma sonunda "Devam etmek istiyor musunuz?" sorusu sorulsun ve klavyeden 'E' veya 'e' karakterlerinden birisi girilirse, program

devam etsin. Yok farkl birey girilirse, program sonlandrlsn. rnek programmz aada bulabilirsiniz:
#include<stdio.h> int main( void ) { int sayi_1, sayi_2; char devam_mi; do { printf("Birinci sayy giriniz> "); scanf("%d",&sayi_1); printf("kinci sayy giriniz> "); scanf("%d",&sayi_2); printf("%d + %d = %d\n", sayi_1, sayi_2, sayi_1 + sayi_2); printf("Devam etmek ister misiniz? "); //C'de tek karakter okuma ilemi biraz skntl //olduundan, burada da bir do while kullandk. do { scanf("%c",&devam_mi); }while( devam_mi == '\n' ); printf("\n"); } while( devam_mi == 'E' || devam_mi == 'e' ); } return 0;

Program, kullancdan iki say alp, toplamn ekrana bastktan sonra, yeniden ilem yapp yapmak istemediimizi sormaktadr. Bu program while ile de yazabilirdik. Ancak while ile yazabilmek iin, devam_mi deikenine nceden 'E' deerini atamamz gerekmekteydi. do while dngsndeyse, bu zorunlulua gerek kalmamtr. Not: Yukardaki programda, farketmi olduunuz gibi karakter okumay biraz farkl yaptk. Normalde, scanf( ) fonksiyonunu kullanmak yeterliyken, burada, iin iine bir de, do while girdi. Aklayacak olursak, C'de karakter okumalar, biraz skntldr. Eer giri tampon belleinde (Buffer) veri bulunuyorsa, bu direkt karaktere atanr. Bundan kurtulmak iin birok yntem olduu gibi, uygulanabilecek bir yntem de, yukarda yazlm olan dng eklinde deer almaktr. nk siz daha bir ey girmeden, ilk deer '\n' geleceinden, dngnn ikinci almasnda, doru deer atanacaktr. lerki konularda, daha detayl ele alacamz bir problem olarak imdilik nemsemeyelim. Sadece karakter okuyacanz zaman problem karsa, yukardaki gibi bir yntem uygulanabileceini bilmeniz -imdilik- yeterli.

for Dngs
while ve do while dnda, nc bir dng tipi olarak, for yaps bulunmaktadr. Dier iki dngden farkl olarak, for yaps, yenilemeli-tekrarlamal (ngilizce iterative) yaplarda kullanma daha uygundur. Bunu performans anlamnda sylemiyorum. Demek istediim yazm teknii olarak, for dngsnn daha kullanl olmasdr. rnein birbirini, srekli tekrar eden ilemlerin yapld Nmerik Analiz gibi alanlar, for dngs iin iyi bir rnek olabilir. Ancak bu dediklerim sizi yanltmasn; for dngs sadece soyut alanlarda alsn diye yaratlm bir ey deildir. Programlarda, dier iki dngden ok daha fazla for kullanrsnz. nk for sadece matematiksel hesaplama ilemlerinde deil, diziler ( array ) gibi konularda srekli kullanlan bir yapdr. Yazm dierlerine nazaran daha sade olduundan, iteratif ilemlerde kullanlmas elbette ki tesadf olarak dnlemez. Aada for dngsnn genel yazmn ve ak diyagramn greceksiniz:

for Yaps

for Ak Diyagram

for( ilk_deger_atama; koul; arttrma/azaltma ){ komut(lar) }

lk atacamz adm; elbette ki ekrana 10 kere "Merhaba Dnya" yazdrmak olacak. ( Umarm bu Merhaba Dnya'larla sizi fazla skp, programlama iinden vazgeirmemiimdir. Programlama mantn kaptktan sonra, dnyay daha farkl grmeye balayacak ve Merhaba Dnyalar'n sebebini daha iyi anlayacaksnz. Ve inann btn bu eziyete deer... ) Buyrun programmz:
#include<stdio.h> int main( void ) { int i; for( i = 0 ; i < 10; i++ ) { printf("%2d: Merhaba Dnya\n",(i+1)); } return 0; }

Grdnz gibi ok daha sade ve ak gzkr bir kod oldu. for altnda tek satr komut olduundan, kme parantezleri koymamz opsiyoneldi ama ne yaptnz kartrmamak iin, her zaman koymanz neririm. for dngleriyle ilgili baz zel durumlarda vardr. for dngs iersine yazdnz ilk deer atama, kontrol ve arttrma ilemlerini tanmlama esnasnda yapmanz gerekmez. Aada verilen kod, yukardakiyle tamamen ayn ii yapar. Fark, i'nin daha nce tanmlanm olmas ve arttrma/azaltma iinin dng iinde yaplmasdr.
#include<stdio.h> int main( void ) { int i; i = 0; for( ; i < 10; ) { printf("%2d: Merhaba Dnya\n",(i+1)); i = i + 1; } return 0; }

break Komutu
Baz durumlarda, dngy aniden sonlandrmak isteriz. Bunun iin 'break' komutunu kullanrz. Dngy aniden sonlandrmak veya dngy krmak ilemini, zaten daha nce switch case'lerde kullanmtk. Bahsetmediimiz ey, bunun her dng iersinde kullanlabileceiydi. Aadaki program inceleyelim:
/* 0 ile 99 arasnda tesadfi saylar reten bir programn, kanc seferde 61 saysn bulacan yazan program aadadr. */ #include<stdio.h> int main( void ) { int i,tesadufi_sayi; int deneme_sayisi = 0; //while iinde 1 olduundan sonsuza kadar dng alr. while( 1 ){ //tesadufi_sayi deikenine, 0 ile 99 arasnda //her seferinde farkl bir say atanr. //rand( ) fonksiyonu tesadfi say atamaya yarar. //mod 100 ilemiyse, atanacak saynn 0 ile 99 //arasnda olmasn garantiler. tesadufi_sayi = rand() % 100; //Dngnn ka defa altn deneme_sayisi //deikeniyle buluruz. deneme_sayisi++; //Eer tesadufi say 61'e eit olursa, //dng krlp, sonlandrlr. if( tesadufi_sayi == 61 ) break; } printf("Toplam deneme says: %d\n",deneme_sayisi); return 0; }

Program iin koyulmu aklamalar ( comment ) zaten neyin n'olduunu aklyor. Ksaca bir eyler eklemek gerekirse, bitiinin nerede olacan bilmediimiz bir dngy ancak, break komutuyla sonlandrabiliriz. artlar salandnda, break komutu devreye girer ve dng sonlandrlr. Bunun gibi bir ok rnek yaratmak mmkndr.

continue Komutu
break komutunun, dngy krmak iin olduundan bahsetmitik. Bunun dnda ilem yapmadan dngy devam ettirmek gibi durumlara da ihtiyacmz vardr. Bunun iinde continue ( Trke: devam ) komutunu kullanrz.
/* Sadece tek saylar yazdran bir program */ #include<stdio.h> int main( void ) { int i; for( i = 0; i < 10; i++ ) { //i deikeninin 2'ye gre modu //0 sonucunu veriyorsa, bu onun //bir ift say olduunu gsterir. //Bu durumda ekrana yazdrlmamas //iin dng bir sonraki adma geer.

if( i%2 == 0 ) continue; printf("%2d\n",i); } return 0; }

0 ile 10 arasndaki tek saylar gsteren program rneini yukarda grebilirsiniz. Elbette ki bu ii daha farkl ve daha iyi yapan bir program yazabilirdik. Ama imdilik continue komutunun nasl kullanldn inceleyelim. Program bir for dngs altrmaktadr. Her defasnda i deikenin 2'ye gre modu alnr. Eer sonu 0'sa, bu saynn ift olduunu gsterir. Dolaysyla, bunun ekrana yazdrlmamas gerekir. Bu yzden, dng iersindeki ilemleri srdrmek yerine, altta kalan kodlar atlarz. Burada continue komutu kullanlr ve kullanld noktadan itibaren olan ilemler yaplmaz. Dng baa dner, ayn ilemleri yapar. Bu sefer i tek say olacandan continue komutu almaz ve sayy ekrana bastrrz.

goto Yaps
C programlama dilinde bulunan bir baka yap, goto deyimidir. Koyacanz etiketler sayesinde, programn bir noktasndan bir baka noktasna atlamanz salar. goto, bir dng deildir ancak dng olarak kullanlabilir. goto, alabilmek iin etiketlere ihtiya duyar. Etiketler, vereceiniz herhangi bir isme sahip olabilir. Etiket oluturmak iin btn yapmanz gereken; etiket adn belirleyip, sonuna iki nokta st ste eklemek ( : ) ve programn herhangi bir yerine bunu yazmaktr. goto deyimi kullanarak bu etiketleri arrsanz, etiketin altnda bulunan kodlardan devam edilir. goto ve etiketlere dair genel yapy, ak diyagramyla birlikte aada bulabilirsiniz: goto Yaps goto Ak Diyagram

label_name: . . . if( kosul ) { goto label_name } . . .

NOT: goto deyimi tek bana da kullanlabilir. Fakat mantksal bir snama olmadan, goto yapsn kullanmanz, sonsuz dngye neden olacaktr. imdi goto ifadesiyle basit bir dng rnei oluturalm. nceki seferlerde olduu gibi ekrana 10 defa "Merhaba Dnya" yazdralm:
#include<stdio.h> int main( void ) { int i = 0; // baslangic_noktasi adinda bir etiket koyuyoruz. // i degiskeni 10 degerine ulasmadigi surece,

// program buraya donecektir. baslangic_noktasi: printf( "Merhaba Dnya\n" ); // i degerini arttiriyoruz. i++; // i degeri kontrol ediliyor. Sayet 10'dan kucukse, // en basa donuyor. if( i<10 ) goto baslangic_noktasi; return 0; }

stediiniz sayda etiket koyup, goto kullanarak, programn herhangi bir noktasna ulaabilirsiniz. Programnz, etiket altnda kalan ksmdan itibaren alr. goto yapsyla gelen esneklik, ilk bakta olduka gzel grnyor. Ancak goto iin birok kaynak, "ya hi kullanmayn ya da olabildiince az kullann" demektedir. Okunup, anlalmas zor ve zerinde allmas g bir koddan, herkesin uzak durmas gerekir. ngilizce'de, karman orman koda, "spagetti kod" ad verilmitir. goto deyimi, kodunuzun spagetti koda dnmesine neden olur. nk program aknn takibini zorlatrp, kodun okunabilirliini azaltr. Diliyorsanz, goto deyimini kullanabilirsiniz. Ama zorunlu kalmadka kanmak en iyisi...

Say Tabanlar
Bilgisayar programlamayla, matematik arasnda ok gl bir iliki vardr. Gemie bakarsanz, bilgisayar alannda nemli admlarn, hep matematik kkenli insanlar tarafndan atldn grrsnz. Bir bilgisayar programcs iin, matematikten uzak durmak dnlemez. Bugn ki dersimizde, biraz matematik iersine gireceiz ve say sistemleriyle, Boole Cebiri (Boolean Algebra) konularn ele alacaz. Genel kabul grm say sistemleri vardr ve ilerinde en yaygn, hepimizin gndelik hayatta kulland 10'luk say sistemidir. Yazmas, okunmas ve ilem yapmas son derece kolay olduundan bunu daha ocuk yata renir ve bu ekilde srdrrz. Ancak bilgisayarlar bizim gibi ilem yapabilme yetisine sahip deildir. Onlar iin iki ihtimal vardr. Bir ey ya 1'dir ya da 0. Bunu ikilik say sistemi olarak adlandrrz. Yani bizim yazdmz btn saylar, btn harfler ve aklnza gelen-gelmeyen btn iaretler, bilgisayar iin 0 ve 1'in kombinasyonlarndan ibarettir. te bu yzden bizlerin, ikilik say sistemine hakim olmas gerekir. Say sistemlerini genel olarak aadaki gibi ifade edebiliriz:

Burada, N say tabanna gstermektedir. k saynn hangi hanesinde olduumuzu ifade ederken, dk ise, ilgili saydaki rakam temsil eder. imdi basit bir rnek yapalm ve ikilik tabandaki 10011 saysnn, 10 tabanndaki e deerini bulalm:
( d4d3d2d1d0 )2 = ( d0 . 20 ) + ( d1 . 21 ) + ( d2 . 22 ) + ( d3 . 23 ) + ( d4 . 24 ) ( 10011 )2 = ( 1 . 20 ) + ( 1 . 21 ) + ( 0 . 22 ) + ( 0 . 23 ) + ( 1 . 24 ) = 19

ikilik say sistemi dnda, 16'lk (Hexadecimal) say sistemi de olduka nemli bir baka tabandr. 16'lk say sisteminde, rakamlar ifade etmek iin 16 adet sembole gereksinim duyarz. Bu yzden 0 ile 9 arasnda olan 10 rakam kullandktan sonra, A, B, C, D, E ve F harflerini de rakam olarak

deerlendiririz. Decimal Hexadecimal : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 : 0 1 2 3 4 5 6 7 8 9 A B C D E 15 F

Hexadecimal/16'lk say tabanyla ilgili aadaki rneklere gz atalm:


( 3FC )16 = ( 3 . 162 ) + ( F . 161 ) + ( C . 160 ) = 768 + 240 + 12 = 1020 ( 1FA9 )16 = ( 1 . 163 ) + ( F . 162 ) + ( A . 161 ) + ( 9 . 160 ) = 4096 + 3840 + 160 + 9 = 8105 ( 75 )16 = ( 7 . 161 ) + ( 7 . 160 ) = 112 + 5 = 117

16'lk say sisteminin dier bir ismi Hexadecimal olduundan, baz yerlerde, bunu ifade etmek iin 16 yerine 'H' harfi de kullanlabilir: ( BA3 )16 = ( BA3 )H ; ( A1E )16 = ( A1E )H gibi... Tabanlar arasnda dntrme ilemi, zerinde duracamz bir baka konudur. Elinizde 16'lk say sisteminde bir say varsa ve bunu 2'lik say sistemiyle yazmak isterseniz nce 10'luk say sistemine evirip daha sonra 2'lik say sistemine dntrebilirsiniz. Ancak 16'lk ve 2'lik say sistemlerini ok daha kolay birbirine dntrmeniz mmkndr. Aadaki tabloda 16'lk say sistemindeki rakamlar ve bunun 2'lik say sistemindeki karl verilmitir: Hexadecimal Binary ( kilik ) : 0 1 2 3 4 5 6 7 8 9 A B C

: 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 11

Bu durumu bir rnekle yle gsterebiliriz: ( A3F1 )H : A 3 F : 1010 0011 1111 1 0001

16'lk tabandaki her rakamn, 2'lik tabandaki karln koyduumuzda yukardaki eitlii elde ediyoruz ve buna gre ( A3F1 ) = ( 1010 0011 1111 0001 )2 eitliini kurabiliyoruz. (2'lik tabandaki sayya ait boluklar, saynn daha rahat okunmas iin braklmtr.) Bu tarz dnmler, 2 ve 2'nin katnda olan say tabanlarnda rahatlkla yaplabilir. Hatrlarsanz, deiken tiplerinde, iaretli ve iaretsiz deiken tanmlamalarndan bahsetmitik. imdi olayn biraz daha derinine inelim. Bir char, 1 byte alan kaplar ve 1 byte, 8 bit'ten oluur. Aadaki kutularn her birini bir bit ve kutularn oluturduu btn bir byte olarak dnn: a7 a6 a5 a4 a3 a2 a1 a0

Yukardaki kutularn toplam olan bir byte, char deikeninin kaplad alan temsil etmektedir. Pozitif saylar ifade etmeyi zaten renmitik. Saynn karln, 2'lik tabanda yazarak, gerekli sonuca ularz. Ancak saymz Negatif deerliyse, iler biraz farkllar. Burada devreye iaret biti (sign bit) devreye girer. Yukardaki ekilde, dier kutulardan farkl renkte olan a7 iaret bitidir. zetle, a7 0 ise, say pozitiftir. Eer a7 1 ise, say negatiftir. kilik tabandaki iaretli bir saynn, 10'luk tabandaki karln u ekilde bulabiliriz:
( a7a6a5a4a3a2a1a0 )2 = ( a7 . -27 ) + ( a6 . 26 ) + ... + ( a1 . 21 ) + ( a0 . 20 )

kilik tabanda yazlm ( 10000011 )2 says, iaretsiz olarak dnlrse, 131'e eittir. Ancak iaretli bir say olduu dnlrse, karl, -125 olacaktr. Konunun pekimesi asndan aadaki rneklere gz atabilirsiniz:
* ( ( * ( ( * ( ( 1011 1011 1100 1100 0110 0110 1011 1011 1101 1101 1101 1101 )2 )2 )2 )2 )2 )2 = = = = = = -69 187 -51 205 109 109 (Say (Say (Say (Say (Say (Say iaretliyse) iaretsizse) iaretliyse) iaretsizse) iaretliyse) iaretsizse)

Negatif bir saynn 2'lik tabandaki karln bulmak iin, nce (i) sayy pozitif olarak ikilik tabanda yazarz. Daha sonra, (ii) ikilik tabanda yazlm saynn 1 yazan rakamlar 0, 0 yazan rakamlar 1'e evrilir. Son olarak (iii) kan sayya, 1 eklenir. Bu size istediiniz saynn ikilik tabanndaki eini verecektir. imdi bir uygulama yapalm ve -7 sayn ikilik tabana evirmeye alalm: i ) -7 ==> ( 7 )10 = ( 0000 0111 )2 ii ) ( 0000 0111 ) ==> ( 1111 1000 ) iii ) ( 1111 1000 ) + 1 = ( 1111 1001 ) ==> ( -7 )10 = ( 1111 1001 )2

Bit Baznda ( Bitwise ) Operatrler


Bit baznda operatrlerin, ngilizce'deki karl Bitwise Operators ( yani Bit bit Operatrler ) olarak gemektedir. Bit baznda operatrler, ikilik say tabannda yapabileceimiz ilemleri temsil eder. Kullanlan operatrleri aada inceleyeceiz.

AND ( & ) Operatr


AND operatr, kendisine verilen iki deikenin btn bitleri 1'e eit olduu takdirde, geriye 1 dndrr. Aksi halde -yani en ufak bir fark varsa- 0 deeri dnmektedir. p 0 0 1 1 x x q 0 1 0 1 0 1 p&q 0 0 0 1 0 x

imdi, AND ( & ) operatrn 25 ve 14 saylarn karlatrmak iin kullanalm:


25 ==> ( 0001 1001 )2 14 ==> ( 0000 1110 )2 & ---------------------------8 ==> ( 0000 1000)2

OR ( | ) Operatr
ki deikenden herhangi biri 1 ieriyorsa, geriye 1 dner. Eer her ikisi de 0 ieriyorsa, geriye 0 dnmektedir. p 0 0 1 1 x x q 0 1 0 1 0 1 p|q 0 1 1 1 x 1

Daha nce kullandmz 25 ve 14 saylar zerinde OR ( | ) ilemi kullanalm:


25 ==> ( 0001 1001 )2 14 ==> ( 0000 1110 )2 | ---------------------------31 ==> ( 0001 1111)2

NEML NOT: Bit baznda kullanlan, AND( & ) ve OR ( | ) operatrleri, koullu ifadelerde kullanlan, AND( && ) ve OR ( || ) ifadelerinden farkldr. ayet, & veya | bir koullu ifade gibi kullanmaya kalkarsanz, ilem yine yaplacaktr. Ancak bunu yapmanz tavsiye edilmez. lerki konularmzda neden uygun olmad, short-circuit ile ilgili bilgi verilirken aklanacaktr.

NOT ( ~ ) Operatr
NOT ( ~ ) Operatr, kendisine verilen sayya ait bit'leri tam tersine evirir. Yani 0 grd yeri 1; 1 grd yeri 0 yapar. p 0 1 ~p 1 0

~ ---------------------------230 ==> ( 1110 0110 )2

25 ==> ( 0001 1001 )2

XOR ( ^ ) Operatr
XOR ( Exclusive OR ) Operatr, sadece ve sadece karlatrma yaplan bitlerden biri, 1 deerine sahipse, geriye 1 dndrr. Eer karlatrma yaplan bit'lerden her ikisi de 0 veya 1'se, o zaman sonu 0 olarak kar.

p 0 0 1 1 x x

q 0 1 0 1 0 1

p^q 0 1 1 0 x ~x

25 ==> ( 0001 1001 )2 14 ==> ( 0000 1110 )2 ^ ---------------------------23 ==> ( 0001 0111 )2

Kaydrma ( Shift ) Operatrleri


Kaydrma operatrleri, zellikle Assembly ile uraanlara tandk gelecektir. Bunlar kullanarak son derece hzl arpma ve blme yaplabilir. C'deyse benzer amalarla kullanmanz elbette mmkndr. ki eit kaydrma operatr vardr: i) Sola Kaydrma - Shift Left ( << ) ii) Saa Kaydrma - Shift Right ( >> ) Her iki durumda da genel kullanm ekli aadaki gibidir: [ Tam Say ][ Operatr ][ Kaydrma Adm Says ] Aadaki rnek, sola kaydrma operatr kullanlarak yaplan bir ilemi gstermektedir. x deikeni, 10 tabannda 22 saysn tutmaktadr. 2 adm sola kaydrlmas sonucu, say 88 olmu ve y'ye atanmtr.
x = ( 0001 0110 )2 ==> 22 y = x << 2 y = ( 0101 1000 )2 ==> 88

Operatr ncelikleri
Hatrlarsanz, aritmetik ilemlerde nceliklerin olduunu ve rnein arpmann, toplamadan daha nce yaplacan anlatmtk. Benzer bir durum, operatrler iinde geerlidir. Altta bulunan tabloda, hangi operatrn daha nce ileme alndn bulabilirsiniz: DK | ^ & OPERATR NCELK SIRASI << >> + - * / % ! ~ - ++ -- ( ) YKSEK

Aada bulunan tablo, ilikisel ve mantksal operatrlerde ki ncelik srasn gstermektedir: LKSEL ve MANTIKSAL OPERATR NCELK SIRASI

DK

||

&&

== !=

> >= < <=

YKSEK

Yukardaki tablolarda, ayn hcrede olan operatrlerin ilem ncelikleri ayndr. nce hangisi yazlmsa, ilk olarak o dikkate alnr. Ama bunun dnda tannan bir ilem ncelii bulunmamaktadr. Aadaki rnek, operatr nceliklerini pekitirmek asndan incelenebilir:
7 & 13 ^ 11 % 4 * 2 << 14 / 4 ==> 7 & 13 ^ 6 << 3 ==> 5 ^ 48 = 53

imdi de benzer bir rnei, C program yazarak yapalm:


#include<stdio.h> int main( void ) { printf( "lem Sonucu: %d\n", 117 & 11 << 2 * 3 ); return 0; }

Yukardaki program, 64 sonucunu vermektedir. Program altrdnzda, ikilik dzeyde ilemler yaplacak ve 64 cevabna ulalacaktr. Siz de hesaplayarak, ayn yant bulabilirsiniz. Bir sonraki dersimizde, konu anlatm olmayacak. Onun yerine bol bol rnek yapp, imdiye kadar ilediimiz konularn zerinden geeceiz. Grmek zere...

rnek Sorular
imdiye kadar ilemi olduumuz dersleri pekitirmek iin, bu yazda rnek sorular zeceiz. Sorularn hazrlanmasnda, arkadam Sunay SNMEZ'in byk emei gemitir. Kendisine teekkr ederim. Soru 1.a: Aadaki programn kts nedir?
#include<stdio.h> int main( void ) { int i = 0; for( ; i < 12; i++ ) { if( ( i++ + 1 ) == 5 ) printf( "%d\n",i ); else if( i % 2 == 0 ) break; else if( i % 3 == 0) continue; else printf("%d\n", i ); } return 0; } 1 5 7 11

Soru 1.b: Aadaki program doru olarak y

#include<stdio.h> int main( void ) { int sum; float average; int weight_1, weight_2; printf( "1.agirlik> " ); scanf( "%d", &weight_1 ); sum += weight_1; printf( "2.agirlik> " ); scanf( "%d", weight_2 ); sum += weight_2; average = sum / 2; printf( "Ortalama: %.2f\n", a return 0; } #include<stdio.h> int main( void ) { int sum = 0; float average; int weight_1, weight_2; printf( "1.agirlik> " ); scanf( "%d", &weight_1 ); sum += weight_1; printf( "2.agirlik> " );

scanf( "%d",&weight_2 ); sum += weight_2; average = sum / 2.0; printf( "Ortalama: %.2f\n", a return 0;

Soru 2: Bir gende, iki kenarn toplam uzunluu, nc kenardan az olamaz. Ayrca iki kenarn birbirinden farknn mutlak deeri, nc kenardan byk olmamaldr. Bu bilgileri kullanarak, verilen kenar uzunluuna gre bir gen izilip izilmeyeceini gsteren program yaznz. Girilecek kenar uzunluklar tam say olacaktr. Cevap 2:
/* Girilen 3 tamsayinin bir ucgenin kenari olup olmadigi kontrol edilir */ #include<stdio.h> int main( void ) { int a, b, c; int temp; printf("Birinci kenar uzunlugu> "); scanf("%d", &a); printf("Ikinci kenar uzunlugu> "); scanf("%d", &b); printf("Ucuncu kenar uzunlugu> "); scanf("%d", &c); /* a ile b den buyuk olan a ya kucuk olan b ye atanir */ if(a < b) { temp = a; a = b; b = temp; } if( ((a + b) < c) || ((a - b) > c) ) printf("Bu kenar uzunluklarina sahip bir ucgen olamaz.\n"); else printf("Bu kenar uzunluklarina sahip bir ucgen cizilebilir.\n"); } return 0;

Soru 3: Klavyeden girilecek bir saynn asal say olup olmadn ekrana basan bir program yaznz. Cevap 3:
/* Bir saynn asal olup olmadn bulmak iin eitli metodlar vardr. Aada bu metodlardan basit bir tanesi yazlmtr. Eer saynn yarsna kadar kontrol etmek yerine, karekkne kadar olan saylar test ederseniz, yine ayn sonu kacaktr. Ancak anlalma konusunda sorun olmamas iin soru bu ekilde zlmtr. */ #include<stdio.h> int main( void )

int sayi, i; //Sayy ilk bata asal kabul ediyoruz. //asal_mi deikeni 1 ise, sayi asaldir. int asal_mi = 1; //Klavyeden, test edilmek zere bir say alnyor. printf( "Bir say giriniz> " ); scanf("%d",&sayi); //Girilen saynn, baka saylara gre srayla modunu //alyoruz. Bir saynn modunu aldnzda, kalan 0 ise //bu saynn blnebildiine ve dolaysyla //asal olmadna dair bilgi verir. Bu ilemi yapabilmek //iin 2'den balayarak, saynn yarsna kadar olan //btn deerler deneniyor. for( i = 2; i <= sayi/2; i++ ) { if( sayi%i == 0 ) { //Say i deikenine kalansz blnmektedir. //Dolaysyla, say asal deildir ve dngy //srdrmeye gerek yoktur. asal_mi = 0; break; } } //Saynn asal olup olmama durumuna gre, kt yazdrlyor. if( asal_mi == 1 ) printf( "%d says asaldr.\n", sayi ); else printf( "%d says asal deildir.\n", sayi ); return 0;

Soru 4: Klavyeden girilecek 0 ile 999 arasnda bir tam saynn, yazyla ifade eden ( rnein 49, 'krkdokuz' gibi ) bir program oluturunuz. Cevap 4:
/* Girilen saynn, nasl okunduunu ekrana yazdran programdr. Fonksiyon kullanmyla daha efektif olarak yazlabilir. Ancak henz ilenmeyen bir konu olduundan, basit bir ekilde yazlmtr. */ #include<stdio.h> int main( void ) { int sayi; //Klavyeden girilecek sayinin 0 ile 999 snrlarnda //olup olmad kontrol ediliyor. Eer deilse, //uyar verilip, yeni bir say isteniyor. Bu ilem //doru bir deer girilene kadar devam ediyor. do { printf( "Sayy giriniz> " ); scanf("%d",&sayi); if( sayi>999 || sayi<0 ) printf("Girdiiniz say uygun deildir.\n" "0 ile 999 arasnda olmaldr.\n"); else break;

}while( 1 ); printf( "%d says, '",sayi ); //Verilen sayy, yazyla ifade edebilmemiz iin, //yzler, onlar ve birler basamaklarna ayrmamz //gerekmektedir. //Saynn yzler basama ayrtrlyor. //Bunun iin sayy, 100'e blmek yeterli. //YZLER BASAMAI: switch( sayi/100 ) { case 9: printf( case 8: printf( case 7: printf( case 6: printf( case 5: printf( case 4: printf( case 3: printf( case 2: printf( case 1: printf( }

"dokuzyz" ); "sekizyz" ); "yediyz" ); "altyz" ); "beyz" ); "drtyz" ); "yz" ); "ikiyz" ); "yz" );

break; break; break; break; break; break; break; break; break;

//Onlar basaman bulmak iin, saynn //yze blmnden kalan deeri, 10'a //blyoruz. Yzler basaman bir nceki //admda ele aldmz iin, bu admda, //saynn yze blmn deil, blmnden //kalan kullandk. //ONLAR BASAMAI: switch ( (sayi%100)/10 ) { case 9: printf( "doksan" ); case 8: printf( "seksen" ); case 7: printf( "yetmi" ); case 6: printf( "altm" ); case 5: printf( "elli" ); case 4: printf( "krk" ); case 3: printf( "otuz" ); case 2: printf( "yirmi" ); case 1: printf( "on" ); }

break; break; break; break; break; break; break; break; break;

//Birler basaman bulabilmek iin, saynn //10'a blmnden kalana bakyoruz. //BRLER BASAMAI: switch ( (sayi%10) ) { case 9: printf( case 8: printf( case 7: printf( case 6: printf( case 5: printf( case 4: printf( case 3: printf( case 2: printf( case 1: printf( }

"dokuz" ); "sekiz" ); "yedi" ); "alt" ); "be" ); "drt" ); "" ); "iki" ); "bir" );

break; break; break; break; break; break; break; break; break;

//Eer say 0 ise, yukarda ki dzenee //uymayacandan, onu ayrca ele alyoruz. if( sayi == 0 ) printf( "sfr" );

printf( "' eklinde okunur.\n" ); return 0; }

Soru 5: Drt basamakl bir saynn rakamlar ters yazlp, 4 ile arplrsa, kan sonu, kendisiyle ayndr. Drt basamakl bu sayy bulunuz. Cevap 5:
/* Drt basamakl bir saynn rakamlar, ters yazlp, 4 ile arplrsa, saynn kendisine eit olmaktadr. Bu program, bahsedilen drt basamakl bu sayy bulmaktadr. */ #include<stdio.h> int main( void ) { //Drt basamakl bir saynn tersinin drt katna //eit olmasn hesaplamamz gerektiinden, her //basama ayr ayr dnmemiz gerekmektedir. //Bilinmeyen bu sayy, abcd olarak dnebiliriz. int a,b,c,d; int sayi, sayinin_tersi; for( a = 0; a < 10; a++ ) for( b = 0; b < 10; b++ ) for( c = 0; c < 10; c++ ) for( d = 0; d < 10; d++ ) { //Burada sayinin degeri bulunmaktadir. sayi = a * 1000 + b * 100 + c * 10 + d; hesaplanmaktadir. 10 + a; //Burada da sayinin tersi sayinin_tersi = d * 1000 + c * 100 + b * //Sayinin tersinin 4 katinin ilk sayiya //esit olup olmadigi kontrol ediliyor. //Ayrica sayinin 0 olmamasi gerekmektedir. 0 ) { gosterilir: sayi, sayinin_tersi ); fazla devam kullanilmistir. burada kesilir. sonlandirir. } } //return ifadesi programin daha //etmemesi icin burada //Program donguye devam etmez ve //return, main fonksiyonunu return 0; //Bu kontrol de yapilmaktadir. if( sayi == 4 * sayinin_tersi && sayi != //Sayi ve uygun olan tersi printf( "Say: %d, tersi: %d\n",

//Uygun bir sayi bulunamazsa, program burada sonlanacaktir. return 0; }

Soru 6: Fibonacci serisinin ilk iki eleman 0 ve 1'dir. Bundan sonra gelen saylar, kendisinden nceki iki saynn toplamyla bulunur. Yani seri elemanlar 0 1 1 2 3 5 8 13 21 ... eklinde gitmektedir. Verilecek adm saysna gre, Fibonnaci serisinin elemanlarn gsterecek bir program yaznz. Cevap 6:
/* Fibonacci sayilarini ekrana yazar */ #include<stdio.h>int main( void ) { int a = 0; /* a[n] */ int b = 1; /* a[n+1] */ int c; /* a[n+2] */ int n; int i; printf("Fibonacci serisi kacinci elemana kadar yazilsin> "); scanf("%d", &n); for( i = 1; i <= n ; i++ ) { printf( "%4d. Eleman: %d\n", i, a ); c = a + b; a = b; b = c; } } return 0;

Soru 7: Verilecek kenar uzunluuna gre, yldz (*) iareti kullanarak kare izen, bir program yaznz. Cevap 7:
/* '*'ler kullanarak kenar uzunlugu verilen kareyi cizer */ #include<stdio.h> int main( void ) { int kenar; int i; int j; printf("Karenin kenar uzunlugu: "); scanf("%d", &kenar); /* Gecerli bir deger mi */ while((kenar < 0) || (kenar > 20)) { printf("Lutfen 0 ile 20 arasinda bi deger giriniz."); printf("Karenin kenar uzunlugu"); scanf("%d", &kenar);

/* karenin cizilmesi */ for(i = 1; i <= kenar; i++) {

if(kenar == 0) break; /* alt ve st kenarlarin cizimi */ if((i == 1) || (i == kenar)) { for(j = 1; j <= kenar; j++) printf("*"); printf("\n"); continue; } /* if sonu */ /* sag ve sol kenarlarin cizimi */ for(j = 1; j <= kenar; j++) if((j == 1) || (j == kenar)) printf("*"); else printf(" "); printf("\n"); } /* for sonu */ } return 0;

Soru 8: Aadaki ekenar drtgen ktsn retecek bir program yaznz:


* *** ***** ******* ********* ******* ***** *** *

Cevap 8:
/* '*'ler yardimiyla eskenar dortgen cizer */ #include<stdio.h> int main( void ) { int i, j; for(i = 1; i <= 5; i++) { for(j = 1; j <= 9; j++) if((j <= (9 - (2*i - 1))/2) || (j > (i + 4))) printf(" "); else printf("*"); printf("\n"); } for(i = 4; i >= 1; i--){ for(j = 1; j <= 9; j++) if((j <= (9 - (2*i - 1))/2) || (j > (i + 4))) printf(" "); else printf("*");

} }

printf("\n");

return 0;

Soru 9: Hipotenus'u 500 birime kadar olan dik genlerin, kenar uzunluklarn gsteren bir program yaznz. Kenar uzunluklar, sadece tam say olacaktr. Cevap 9:
/* Hipotenusu 500'e kadar olan pisagor uclulerini ekrana yazar. */ #include<stdio.h> int main( void ) { int a; /* birinci dik kenar */ int b; /* ikinci dik kenar */ int hipotenus; for(a = 1; a < 500; a++) for(b = a; b < 500; b++) for(hipotenus = b+1; hipotenus <= 500; hipotenus++) if( (a*a + b*b) == hipotenus*hipotenus ) printf("%5d%5d%5d\n", a, b, hipotenus); return 0;

Ksa Devre Deerlendirme


Ksa devre deerlendirme, ne yazk ki pek iyi bir eviri olmad ve bu yzden hibir anlam ifade etmeyebilir. ngilizce'de, Short Circuit Evaluation olarak geen bu konu, mantksal ifadelerle ilgilidir. Hatrlarsanz, daha nce ki derslerimizde iki farkl AND ve OR operatr grmtk. Bu yaplardan biri AND iin && iaretini kullanyorken, dieri sadece tek & simgesini kullanyordu. Keza, OR ifadesi bir yerde, || eklinde gsteriliyorken, dier yerde, tek bir | simgesiyle ifade edilmekteydi. Bu iaretler, ayn sonucu retiyor gibi grnseler de, farkl ekilde alrlar. ift ekilde yazlan operatrler, ( yani && ve || ) ksa devre operatrleridir. ngilizce, Short Circuit Operator olarak isimlendirilirler. Tek sembolle yazlan operatrlerden fark, ilemleri ksaltmalardr. Bir koul iersinde AND ( && ) operatr kullandnzda, koulun sol taraf yanlsa, sa taraf kontrol edilmez. nk artk sa tarafn doru veya yanl olmasnn nemi yoktur; sonu her ekilde yanl olacaktr. Benzer bir mantk OR ( || ) operatr iinde geerlidir. Eer sol taraf doruysa, sa tarafn kontrol edilmesine gerek yoktur. nk OR operatrnde taraflardan birinin doru olmas durumunda, dierinin nemi kalmaz ve sonu doru dner. Aadaki rnekleri inceleyelim: && Operatr
#include<stdio.h> int main( void ) { #include<stdio.h> int main( void ) {

& Operatr

int i = j = if(

} else {

i, j; 0; 5; i == 1 && j++ ) { printf( "if iersine girdi\n" ); printf( "if iersine girmedi\n" ); printf( "i: %d, j: %d\n", i, j ); }

int i = j = if(

} else {

i, j; 0; 5; i == 1 & j++ ) { printf( "if iersine g

} return 0;

} return 0;

printf( "if iersine g printf( "i: %d, j: %d\

if iersine girmedi i: 0, j: 5

if iersine girmedi i: 0, j: 6

Grdnz gibi, program ktlar birbirinden farkldr. Bunun sebebi, ilk rnekte, i == 1 koulu yanl olduu iin, && operatrnn ifadenin sa tarafna bakmamasdr. kinci rnekteyse, & operatr, koulun her iki tarafna da bakar. Bu yzden, j deikenine ait deer deiir. Benzer bir uygulamay, OR iin || ve | kullanarak yapabilirsiniz. NEML NOT: zetle ilemlerinizi hzlandrmak istiyorsanz; AND kullanacanz zaman, && operatryle aln ve yanl olmas muhtemel olan koulu sol tarafa koyun. Eer OR operatr kullanacaksanz, doru olma ihtimali fazla olan koulu, ifadenin soluna koyun ve operatr olarak || ile aln. Bu ekillde yazlan bir program, ksa devre operatrleri sayesinde, gereksiz kontrolden kanarak ilemlerinizi hzlandracaktr. Elbette & veya | operatrlerinin kullanlmas gereken durumlarda olabilir. Her n'olursa olsun, koulun iki tarafnnda almasn istiyorsanz, o zaman & ve | operatrlerini kullanmanz gerekmektedir.

nilemci Komutlar
Bir program yazdnz dnn... Bu programda, PI deerini birok yerde kullanmanz gerekiyor. Siz de PI deeri olmas gereken her yere, 3.14 yazyorsunuz. Olduka skc bir i. leride PI'yi, 3.141592653 olarak deitirmek isterseniz daha da skc hle dnebilir. Veya cannz istedi, printf( ) fonksiyonu yerine ekrana_yazdir( ) kullanmaya niyetlendiniz... te bu gibi durumlarda, nilemci Komutlarn ( Preprocessor ) kullanrz. nilemci komutlarnn amac, bir eyi baka bir ekilde ifade etmektir. Konuya devam etmeden nce ufak bir uyar da bulunmakta yarar var. nilemci komutlarn, deikenler veya fonksiyonlarla kartrmamak gerekiyor. Deikenlerin ve fonksiyonlarn daha dinamik ve esnek bir yaplar varken, nilemci komutlar statiktir. Programnza direkt bir kod yazdnz dnn. Bu kod herhangi bir ey (sembol, program paras, say, karakter vs...) olabilir. rnein, her yerde PI'nin karl olarak 3.14 girmek yerine, PI diye bir sembol tanmlarz ve bunun grld her yere 3.14' koyulmasn isteriz. nilemci komutlar bu gibi ilerde, biilmi kaftandr.

#define nilemci Komutu


#define komutu, adndan da anlalabilecei gibi tanmlama ilemleri iin kullanlr. Tanmlama komutunun kullanm mant ok basittir. Btn yapmamz gereken, neyin yerine neyi yazacamza karar vermektir. Bunun iin #define yazp bir boluk braktkan sonra, nce kullanacamz bir isim verilir, ardndan da yerine geecei deer. Altta ki program, PI sembol olan her yere 3.14 koyacak ve ilemleri buna gre yapacaktr:
/* ember alann hesaplar */

#include<stdio.h> #define PI 3.14 int main( void ) { int yaricap; float alan; printf( "emberin yar apn giriniz> " ); scanf( "%d", &yaricap ); alan = PI * yaricap * yaricap; printf( "ember alan: %.2f\n", alan ); return 0; }

Grdnz gibi, PI bir deiken olarak tanmlanmamtr. Ancak #define komutu sayesinde, PI'nin aslnda 3.14 olduu derleyici (compiler) tarafndan kabul edilmitir. Sadece #define komutunu kullanarak baka eylerde yapmak mmkndr. rnein, daha nce dediimizi yapalm ve printf yerine, ekrana_yazdir; scanf yerine de, deger_al isimlerini kullanalm:
/* Yarapa gre daire alan hesaplar */ #include<stdio.h> #define PI 3.14 #define ekrana_yazdir printf #define deger_al scanf int main( void ) { int yaricap; float alan; ekrana_yazdir( "emberin yar apn giriniz> " ); deger_al( "%d", &yaricap ); alan = PI * yaricap * yaricap; ekrana_yazdir( "ember alan: %.2f\n", alan ); return 0; }

#define komutunun baka marifetleri de vardr. lerki konularmzda greceimiz fonksiyon yapsna benzer ekilde kullanm mmkndr. Elbette ki, fonksiyonlar ok daha gelimitir ve saladklar esneklii, #define tutamaz. Bu yzden #define ile yaplacaklarn snrn ok zorlamamak en iyisi. Ancak yine de bilginiz olmas asndan aada ki rnee gz atabilirsiniz:
/* Istenen sayida, "Merhaba" yazar */ #include<stdio.h> #define merhaba_yazdir( x ) int i; for ( i = 0; i < (x); i++ ) printf( "Merhaba\n" ); int main( void ) { int yazdirma_adedi; printf( "Ka defa yazdrlsn> " ); scanf( "%d", &yazdirma_adedi ); merhaba_yazdir( yazdirma_adedi ); return 0; }

#undef nilemci Komutu


Baz durumlarda, #define komutuyla tanmladmz eyleri, iptal etmek isteriz. Tanmlamay iptal etmek iin, #undef komutu kullanlr. rnein #undef PI yazdnz da, o noktadan itibaren PI tanmsz olacaktr. #define ile oluturduunuz sembolleri belirli noktalardan sonra geerliliini iptal

etmek veya yeniden tanmlamak iin #undef komutunu kullanabilirsiniz.

#ifdef ve #ifndef nilemci Komutlar


nilemci komutlarnda bir sembol veya simgenin daha nce tantlp tantlmadn kontrol etmek isteyebiliriz. Tantlmsa, yle yaplsn; yok tantlmadysa, byle olsun gibi farkl durumlarda ne olacan belirten yaplar gerekebilir. Bu a kapatmak iin #ifdef (if defined - ayet tanmlandysa) veya #ifndef (if not defined - ayet tanmlanmadysa) operatrleri kullanlr.
#include<stdio.h> #define PI 3.14 int main( void ) { // Tanml PI deeri, tanmsz hle getiriliyor. #undef PI int yaricap; float alan; printf( "emberin yar apn giriniz> " ); scanf( "%d", &yaricap ); // PI deerinin tanml olup olmad kontrol ediliyor. #ifdef PI //PI tanmlysa, daire alan hesaplanyor. alan = PI * yaricap * yaricap; printf( "ember alan: %.2f\n", alan ); #else //PI deeri tanmszsa, HATA mesaj veriliyor. printf("HATA: Alan deeri tanml deildir.\n"); #endif } return 0;

Yukardaki rnee bakacak olursak, nce PI deeri tanmlanyor ve sonrasnda tanm kaldrlyor. Biz de srprizlerle karlamak istemediimizden, PI deerinin tanm durumunu kontrol ediyoruz. Tek bana alan biri iin gereksiz bir ayrnt gibi gzkse de, ekip almalarnda, baz eylerin kontrol edilmesi ve istenmeyen durumlarda, ne yaplaca belirlenmelidir. Yukarda ki program yle de yazabilirdik:
#include<stdio.h> int main( void ) { int yaricap; float alan; printf( "emberin yar apn giriniz> " ); scanf( "%d", &yaricap ); // u noktaya kadar tanml bir PI deeri bulunmuyor. // #ifndef opertr bu durumu kontrol ediyor. // Eer tanmszsa, PI'nin tanmlanmas salanyor. #ifndef PI #define PI 3.14 #endif alan = PI * yaricap * yaricap; printf( "ember alan: %.2f\n", alan ); return 0; }

#if, #else, #endif, #elif nilemci Komutlar


Bazen bir deerin tanmlanp, tanmlanmadn bilmek yetmez. Baz deerler, bayrak (flag) olarak kullanlr. Yani eer doruysa, byle yaplmas lzm, aksi hlde byle olacak gibi... Baz programlar, nilemci komutlarndan yararlanr. Deiken yerine, nilemcileri kullanarak tanmlanan simgeler, bu programlarda flag grevi grr. Konumuza dnersek, #if, #else, #endif yaps daha nce ilemi olduumuz if-else yapsyla hemen hemen ayndr. if-elif yaps da if-else if yapsna benzer. Her ikisinin de genel yazm kural aada verilmitir: #if - #else Yaps:
#if koul komut(lar) #else komut(lar) #endif

#if - #elif Yaps:


#if koul 1 komut(lar) #elif koul 2 komut(lar) . . . #elif koul n-1 komut(lar) #else komut(lar) #endif 1 2

n-1 n

Bir program tasarlayalm. Bu programda, pi saysnnn virglden sonra ka basamann hesaba katlacana karar veren bir mekanizma olsun. Soruyu, u ana kadar grdmz, if - else gibi yaplarla rahata yapabiliriz. nilemci komutuyla ise, aadakine benzer bir sistem oluturulabilir:
/* Daire alann hesaplar */ #include<stdio.h> #define HASSASLIK_DERECESI 2 int main( void ) { int yaricap; float alan; printf( "emberin yar apn giriniz> " ); scanf( "%d", &yaricap ); // // // // Hassaslk derecesi, pi saysnn virglden ka basamak sonrasnn hesaba katlacan belirtir. Eer hassaslk derecesi bunlara uymuyorsa, alan deeri -1 yaplr.

#if ( HASSASLIK_DERECESI == 0 ) alan = 3 * yaricap * yaricap; #elif ( HASSASLIK_DERECESI == 1 ) alan = 3.1 * yaricap * yaricap; #elif ( HASSASLIK_DERECESI == 2 ) alan = 3.14 * yaricap * yaricap; #else alan = -1; #endif printf( "ember alan: %.2f\n", alan ); return 0;

#include nilemci Komutu


#include olduka tandk bir operatrdr. Her programmzda, #include nilemci komutunu kullanrz. ayet kullanmasak, printf( ) veya scanf( ) gibi fonksiyonlar tekrar tekrar yazmamz gerekirdi. #include komutu, programmza bir balk dosyasnn (header file) dhil edileceini belirtir. Bu balk dosyas, standart giri k ilemlerini ieren bir ktphane olabilecei gibi, kendimize ait fonksiyonlarn bulunduu bir dosya da olabilir. Eer sistem ktphanelerine ait bir balk dosyasn programnza dhil edeceksek, kktr ( < ) ve byktr ( > ) iaretlerini kullanrz. rnein stdio.h sisteme ait bir ktphane dosyasdr ve Linux'ta /usr/include/stdio.h adresinde bulunur. Dolaysyla stdio.h ktphanesini programmza eklerken, #include<stdio.h> eklinde yazarz. Kendi oluturduumuz balk dosyalar iinse, durum biraz daha farkldr. alma ortammzla ayn klasrde olan bir balk dosyasn, programmza eklemek iin #include "benim.h" eklinde yazarz. lerki derslerimizde, kendi balk dosyalarmz oluturmay greceiz. Ancak imdilik burada keselim...

nemli Noktalar...
Konuyu noktalarken, sylemek istediim baz eyler bulunuyor. Olabildiince, nilemci komutlarndan - #include komutu hari - uzak durun. nk bu komutlar, esnek bir yapya sahip deiller ve bu durum, bir noktadan sonra banz artacaktr. nilemci komutlaryla yazlm kodlar takip etmek olduka zordur ve debug edilemezler. Java gibi gelimi dillerde, #define komutu bulunmaz. Modern dillerde, bu yapdan uzaklalmaya balanmtr. Yukarda saydklarma ramen, baz durumlarda, nilemci komutlarn kullanmak uygun olabilir. Kald ki bu komutlarn kullanld birok yer bulunuyor ve biz kullanmasak bile, bilmeye mecbur durumdayz. Szn z; bu konuyu es gemek uygun deil. Ancak zerine dmek olduka gereksiz.

Fonksiyonlar
C gibi prosedrel dillerin nemli konularndan birisi fonksiyonlardr. Java veya C# gibi dillerde metot (method) ismini alrlar. Ad n'olursa olsun, grevi ayndr. Bir ilemi birden ok yaptnz dnn. Her seferinde ayn ilemi yapan kodu yazmak olduka zahmetli olurdu. Fonksiyonlar, bu soruna ynelik yaratlmtr. Sadece bir kereye mahsus yaplacak ilem tanmlanr. Ardndan dilediiniz kadar, bu fonksiyonu arrsnz. stelik fonksiyonlarn yarar bununla da snrl deildir. Fonksiyonlar, modlerlik salar. Saynn asalln test eden bir fonksiyon yazp, bunun yanl olduunu farkederseniz, btn program deitirmeniz gerekmez. Yanl fonksiyonu dzeltirsiniz ve artk programnz doru alacaktr. stelik yazdnz fonksiyonlara ait kodu, baka programlara tamanz olduka basittir. Fonksiyonlar, almay kolaylatrr. Diskten veri okuyup, ileyen; ardndan kullancya gsterilmek zere sonular grafik hline dntren; ve ilem sonucunu diske yazan bir program batan aa yazarsanz, okumas ok g olur. Yorum koyarak kodun anlalabilirliini, artrabilirsiniz. Ancak yine de yeterli deildir. zlenecek en iyi yntem, program fonksiyon paralarna blmektir. rnein, diskten okuma ilemini disten_oku( ) isimli bir fonksiyon yaparken; grafik izdirme iini grafik_ciz( ) fonksiyonu ve diske yazdrma grevini de diske_yaz( ) fonksiyonu yapabilir. Yarn br gn, yazdnz kodu birileri incelediinde, sadece ilgilendii yapya gz atarak, aradn ok daha rahat bulabilir. Binlerce satr iinde almaktansa, paralara ayrlm bir yap herkesin iine gelecektir.

Bu yazmzda, fonksiyonlar aklayacaz.

main( ) Fonksiyonu
imdiye kadar yazdmz btn kodlarda, main( ) eklinde bir notasyon kullandk. Bu kullandmz ifade, aslnda main( ) fonksiyonudur. C programlama dilinde, bir kodun almas main( ) fonksiyonun iersinde olup olmamasna baldr. Bir nevi balang noktas olarak dnebiliriz. Her programda sadece bir tane main( ) fonksiyonu bulunur. Baka fonksiyonlarn, ktphanelerin, kod paralarnn altrlmas main( ) iersinde direkt veya dolayl refere edilmesiyle alakaldr. main( ) fonksiyonuna dair bilgimizi pekitirmek iin bir program yazalm. Aadaki izimi inceleyip, C programlama diliyle bunu izen program oluturalm.
/ / /\ \ \ / \ ---------| | | | | | ----------

Ev veya kule benzeri bu ekli aadaki, kod yardmyla gsterebiliriz:


/* Ev sekli cizen program */ #include<stdio.h> int main( void ) { printf( " /\\ \n" printf( " / \\ \n" printf( " / \\ \n" printf( " / \\\n" printf( "----------\n" printf( "| |\n" printf( "| |\n" printf( "| |\n" printf( "----------\n" } return 0;

); ); ); ); ); ); ); ); );

Programn zel bir yan yok. '\' simgesi zel olduu iin bundan iki tane yazmamz gerekti. Bunu nceki derslerimizde ilemitik. Bunun dnda kodun herhangi bir zorluu olmad iin aklamaya girmiyorum. Dikkat etmeniz gereken tek ey, kodun main( ) fonksiyonuyla almas. Bilgilerimizi zetleyecek olursak; main( ) fonksiyonu zel bir yapdr. Hazrladmz program, main( ) fonksiyonuyla almaya balar. main( ) fonksiyonu iersinde yer almayan kodlar almaz.

Fonksiyon Oluturma
Kendinize ait fonksiyonlar oluturabilirsiniz. Oluturacanz fonksiyonlar, vereceiniz ilemi yapmakla grevlidir ve arldka tekrar tekrar alr. Yukardaki ev rneine geri dnelim. Her eyi main( ) iinde, tek bir yerde yazacamza, aty izen ayr, kat izen ayr birer fonksiyon yazsaydk daha rahat olmaz myd? Ya da birden ok kat izmemiz gerekirse, tek tek kat izmekle uramaktansa, fonksiyon adn armak daha akllca deil mi? Bu sorularn yant, bizi fonksiyon kullanmaya gtryor. imdi yukarda yazdmz

kodu, iki adet fonksiyon kullanarak yapalm:


/* Ev sekli cizen program */ #include<stdio.h> // Evin catisini cizen fonksiyon. void catiyi_ciz( void ) { printf( " /\\ \n" ); printf( " / \\ \n" ); printf( " / \\ \n" ); printf( " / \\\n" ); printf( "----------\n" ); } // Evin katini cizen fonksiyon. void kat_ciz( void ) { printf( "| |\n" ); printf( "| |\n" ); printf( "| |\n" ); printf( "----------\n" ); } // Programin calismasini saglayan // ana fonksiyon. int main( void ) { catiyi_ciz( ); kat_ciz( ); } return 0;

Yazdmz bu kod, ilk bata elde ettiimiz ktnn aynsn verir. Ama nemli bir fark ierir:. Bu programla birlikte ilk defa fonksiyon kullanm olduk! Fonksiyon kullanmann, ayn eyleri batan yazma zahmetinden kurtaracandan bahsetmitik. Diyelim ki bize birden ok kat gerekiyor. O zaman kat_ciz( ) fonksiyonunu gereken sayda armamz yeterlidir.
/* Ev sekli cizen program */ #include<stdio.h> // Evin catisini cizen fonksiyon. void catiyi_ciz( void ) { printf( " /\\ \n" ); printf( " / \\ \n" ); printf( " / \\ \n" ); printf( " / \\\n" ); printf( "----------\n" ); } // Evin katini cizen fonksiyon. void kat_ciz( void ) { printf( "| |\n" ); printf( "| |\n" ); printf( "| |\n" ); printf( "----------\n" ); } // Programin calismasini saglayan // ana fonksiyon. int main( void )

catiyi_ciz( ); // 3 adet kat ciziliyor. kat_ciz( ); kat_ciz( ); kat_ciz( ); return 0;

Yukarda yazl kod, bir stekinden pek farkl durmasa bile, bu sefer katl bir evin ktsn elde etmi olacaksnz. Yaptmz rneklerde, kullanlan void ifadesi dikkatinizi ekmi olabilir. ngilizce bir kelime olan void, bo/geersiz anlamndadr. C programlama dilinde de buna benzer bir anlam tar. kat_ciz( ); fonksiyonuna bakalm. Yapaca i iin herhangi bir deer almas gerekmiyor. rnein verilen saynn asalln test eden bir fonksiyon yazsaydk, bir deiken almamz gerekirdi. Ancak bu rnekte grdmz kat_ciz( ); fonksiyonu, dardan bir deere gerek duymaz. Eer bir fonksiyon, almak iin dardan gelecek bir deere ihtiya duymuyorsa, fonksiyon adn yazdktan sonra parantez iini bo brakabiliriz. Ya da void yazarak, fonksiyonun bir deer almayacan belirtiriz. ( Srekli olarak main( ) fonksiyonuna void koymamzn sebebi de bundandr; fonksiyon argman almaz. ) kinci yntem daha uygun olmakla birlikte, birinci yntemi kullanmann bir mahsuru yok. Aada bulunan iki fonksiyon ayn ekilde alr:
// Evin katini cizen fonksiyon. // void var void kat_ciz( void ) { printf( "| |\n" printf( "| |\n" printf( "| |\n" printf( "----------\n" } // Evin katini cizen fonksiyon. // void yok void kat_ciz( ) { printf( printf( printf( printf( }

); ); ); );

"| |\n" "| |\n" "| |\n" "----------\n"

); ); ); );

void ifadesinin, deer alnmayacan gstermek iin kullanldn grdnz. Bir de fonksiyonun deer dndrme durumu vardr. Yazdnz fonksiyon yapaca ilemler sonucunda, arld noktaya bir deer gnderebilir. Deer dndrme konusunu, daha sonra ileyeceiz. imdilik deer dndrmeme durumuna bakalm. Yukarda kullanlan fonksiyonlar, geriye bir deer dndrmemektedir. Bir fonksiyonun geriye deer dndrmeyeceini belirtmek iin, void ifadesini fonksiyon adndan nce yazarz. Byleyece geriye bir deer dnmeyecei belirtilir.

Argman Aktarm
Daha nce ki rneklerimiz de, fonksiyonlar dardan deer almyordu. Bu yzden parantez ilerini bo brakmay ya da void ifadesini kullanmay grmtk. Her zaman byle olmas gerekmez; fonksiyonlar dardan deer alabilirler. Fonksiyonu tanmlarken, fonksiyona nasl bir deerin gnderileceini belirtiriz. Gnderilecek deerin hangi deiken tipinde olduunu ve deiken adn yazarz. Fonksiyonu tanmlarken, yazdmz bu deikenlere 'parametre' (parameter) denir. Argman (argument) ise, parametrelere deer atamasnda kullandmz deerlerdir. Biraz karmak m geldi? O zaman bir rnekle aklayalm. Daha nce izdiimiz ev rneini biraz gelitirelim. Bu sefer, evin duvarlar dz izgi olmasn; kullanc istedii karakterlerle, evin duvarlarn izdirsin.

/* Ev sekli cizen program */ #include<stdio.h> // Evin catisini cizen fonksiyon. void catiyi_ciz( void ) { printf( " /\\ \n" ); printf( " / \\ \n" ); printf( " / \\ \n" ); printf( " / \\\n" ); printf( "----------\n" ); } // Evin katini cizen fonksiyon. // sol ve sag degiskenleri fonksiyon // parametreleridir. void kat_ciz( char sol, char sag ) { printf( "%c %c\n", sol, sag ); printf( "%c %c\n", sol, sag ); printf( "%c %c\n", sol, sag ); printf( "----------\n" ); } // Programin calismasini saglayan // ana fonksiyon. int main( void ) { char sol_duvar, sag_duvar; printf( "Kullanlacak karakterler> " ); scanf( "%c%c",&sol_duvar, &sag_duvar ); catiyi_ciz( ); // sol_duvar ve sag_duvar, fonksiyona // giden argumanlardir. kat_ciz( sol_duvar, sag_duvar ); kat_ciz( sol_duvar, sag_duvar ); kat_ciz( sol_duvar, sag_duvar ); } return 0;

Argmanlarn deer olduunu unutmamak gerekiyor. Yukardaki rneimizden, deiken olmas gerektii yanlgsna debilirsiniz. Ancak bir fonksiyona deer aktarrken, direkt olarak deeri de yazabilirsiniz. Program deitirip, sol_duvar ve sag_duvar deikenleri yerine, '*' simgesini koyun. eklin duvarlar, yldz iaretinden oluacaktr. Yazdmz kat_ciz( ) fonksiyonunu incelemek iin, aada bulunan grafie gz atabilirsiniz:

imdi de baka bir rnek yapalm ve verilen herhangi bir saynn tek mi yoksa ift mi olduuna karar veren bir fonksiyon oluturalm:

/* Saynn tek veya ift olmasn kontrol eder. */ #include<stdio.h> void tek_mi_cift_mi( int sayi ) { if( sayi%2 == 0 ) printf( "%d, ift bir saydr.\n", sayi ); else printf( "%d, tek bir saydr.\n", sayi ); } int main( void ) { int girilen_sayi; printf( "Ltfen bir say giriniz> " ); scanf( "%d",&girilen_sayi ); tek_mi_cift_mi( girilen_sayi ); return 0; }

Yerel ( Local ) ve Global Deikenler


Kendi oluturacanz fonksiyon iersinde, main( ) fonksiyonunda ki her eyi yapabilirsiniz. Deiken tanmlayabilir, fonksiyon iinden baka fonksiyonlar arabilir veya dilediiniz operatr kullanabilirsiniz. Ancak deiken tanmlamalaryla ilgili gz ard etmememiz gereken bir konu bulunuyor. Bir fonksiyon iersinde tanmladnz deikenler, sadece o fonksiyon iersinde tanmldr. main( ) veya kendinize ait fonksiyonlardan bu deikenlere ulamamz mmkn deildir. main( ) iinde tanmladnz a isimli deikenle, kendinize zg tanmladnz kup_hesapla( ) iersinde tanmlanm a isimli deiken, bellekte farkl adresleri iaret eder. Dolaysyla deikenlerin arasnda hibir iliki yoktur. kup_hesapla( ) iersinde geen a deikeninde yapacanz deiiklik, main( ) fonksiyonundakini etkilemez. Keza, tersi de geerlidir. u ana kadar yaptmz btn rneklerde, deikenleri yerel olarak tanmladmz belirtelim. Yerel deiken dnda, bir de global deiken tipi bulunur. Programn herhangi bir noktasndan eriebileceiniz ve nerede olursa olsun ayn bellek adresini iaret eden deikenler, global deikenlerdir. Hep ayn bellek adresi sz konusu olduun iin, programn herhangi bir noktasnda yapacanz deiiklik, global deikenin getii btn yerleri etkiler. Aadaki rnei inceleyelim:
#include<stdio.h> // Verilen sayinin karesini hesaplar void kare_hesapla( int sayi ) { // kare_hesapla fonksiyonunda // a degiskeni tanimliyoruz. int a; a = sayi * sayi; printf( "Saynn karesi\t: %d\n", a ); } // Verilen sayinin kupunu hesaplar void kup_hesapla( int sayi ) { // kup_hesapla fonksiyonunda // a degiskeni tanimliyoruz. int a; a = sayi * sayi * sayi; printf( "Saynn kp\t: %d\n", a ); }

int main( void ) { // main( ) fonksiyonunda // a degiskeni tanimliyoruz. int a; printf( "Say giriniz> "); scanf( "%d",&a ); printf( "Girdiiniz say\t: %d\n", a ); kare_hesapla( a ); // Eger a degiskeni lokal olmasaydi, // kare_hesapla fonksiyonundan sonra, // a'nin degeri bozulur ve kup yanlis // hesaplanirdi. kup_hesapla( a ); return 0; }

Kod arasna konulan yorumlarda grebileceiniz gibi, deikenler lokal olarak tanmlanmasa, a'nin deeri farkl olurdu. Saynn karesini bulduktan sonra, kpn yanl hesaplardk. Deikenler lokal olduu iin, her aamada farkl bir deiken tanmland ve sorun kartacak bir durum olmad. Benzer bir program global deikenler iin inceleyelim:
#include<stdio.h> int sonuc = 0; // Verilen sayinin karesini hesaplayip, // global 'sonuc' degiskenine yazar. void kare_hesapla( int sayi ) { sonuc = sayi * sayi; } int main( void ) { // main( ) fonksiyonunda // a degiskeni tanimliyoruz. int a; printf( "Say giriniz> "); scanf( "%d",&a ); printf( "Girdiiniz say\t: %d\n", a ); kare_hesapla( a ); printf("Saynn karesi\t: %d\n", sonuc ); return 0; }

Grdnz gibi, sonuc isimli deiken her iki fonksiyonun dnda bir alanda, programn en banda tanmlanyor. Bu sayede, fonksiyon bamsz bir deiken elde ediyoruz. Global deikenlerle ilgili dikkat etmemiz gereken bir iki ufak nokta bulunuyor: Global bir deikeni fonksiyonlarn dnda bir alanda tanmlarz. Tanmladmz noktann altnda kalan btn fonksiyonlar, bu deikeni tanr. Fakat tanmlanma noktasnn stnde kalan fonksiyonlar, deikeni grmez. Bu yzden, btn programda geerli olacak gerek anlamda global bir deiken istiyorsanz, #include ifadelerinin ardndan tanmlamay yapmanz gerekir. Ayn ismi tayan yerel ve global deikenleri ayn anda kullanyorsak, i birazck farkllar. Bir fonksiyon iersinde, Global deikenle ayn isimde, yerel bir deiken bulunduruyorsanz, bu durumda lokal deikenle ilem yaplr. Akcas, snrsz sayda deiken ismi vermek mmknken, global deikenle ayn ad vermenin uygun olduunu dnmyorum. Program akn takip etmeyi zorlatracandan, ortak isimlerden kanmak daha akllca. Lokal ve global deikenlere dair son bir not; lokal deikenlerin sadece fonksiyona zg olmas

gerekmez. Bir fonksiyon iersinde 'daha lokal' deikenleri tanmlayabilirsiniz. Internet'te bulduum aadaki program incelerseniz, konuyu anlamanz asndan yardmc olacaktr.
#include<stdio.h> int main( void ) { int i = 4; int j = 10; i++; if( j > 0 ){ printf("i : %d\n",i); degiskeni */ } if (j > 0){ int i=100; } degerini */ tasiyan } printf("i : %d\n",i); /* En basta tanimlanan ve 5 degerini 'i' degiskenine donuyoruz */ printf("i : %d\n",i); /* 'main' icinde tanmlanmis 'i'

/* 'i' sadece bu if blogunda gecerli olmak uzere tanimlaniyor. */ /* if blogunda tanimlanan ve 100 tasiyan 'i' degiskeni burada sonlaniyor.

return fadesi
Yazmzn st ksmlarnda fonksiyonlarn geriye deer dndrebileceinden bahsetmitik. Bir fonksiyonun geriye deer dndrp dndrmemesi, o fonksiyonu genel yap iersinde nasl kullanacanza baldr. Eer hazrlayacanz fonksiyonun, alp, retecei sonular baka yerlerde kullanmayacaksanz, fonksiyondan geriye deer dnmesi gerekmez. Ancak fonksiyonun rettii sonular, bir deikene atayp kullanacaksanz, o zaman fonksiyonun geriye deer dndrmesi gerekir. Bunun iin 'return' ifadesini kullanrz. Daha nce grdmz geriye deer dndrmeyen fonksiyonlar tanmlarken, bana void koyuyorduk. Geriye deer dndren fonksiyonlar iinse, hangi tipte deer dnecekse, onu fonksiyon adnn bana koyuyoruz. Diyelim ki fonksiyonumuz bir tamsay dndrecekse, int; bir karakter dndrecekse char diye belirtiyoruz. Fonksiyon iersinden neyin dneceine gelince, burada da return ifadesi devreye giriyor. Fonksiyonun neresinde olduu farketmez, return sonu dndrmek zere kullanlr. Dndrecei sonu, elle girilmi veya deikene ait bir deer olabilir. nemli olan dndrlecek deiken tipiyle, dndrlmesi vaad edilen deiken tipinin birbirinden farkl olmamasdr. Yani int kup_hesapla( ) eklinde bir tanmlama yaptysanz, double tipinde bir sonucu dndremezsiniz. Daha dorusu dndrebilirsiniz ama program yanl alr. Tip uyumazl genel hatalardan biri olduu iin, titiz davranmanz tlerim. imdi return ifadesini kullanabileceimiz, bir program yapalm. Kullancdan bir say girilmesi istensin; girilen say asal deilse, tekrar ve tekrar say girmesi gereksin:
#include<stdio.h> // Verilen sayinin asal olup olmadigina // bakar. Sayi asalsa, geriye 1 aksi hlde // 0 degeri doner.

int sayi_asal_mi( int sayi ) { int i; for( i = 2; i <= sayi/2; i++ ) { // Sayi asal degilse, i'ye tam olarak // bolunur. if( sayi%i == 0 ) return 0; } // Verilen sayi simdiye kadar hicbir // sayiya bolunmediyse, asaldir ve // geriye 1 doner. return 1; } // main fonksiyonu int main( void ) { int girilen_sayi; int test_sonucu; do{ printf( "Ltfen bir say giriniz> " ); scanf( "%d",&girilen_sayi ); test_sonucu = sayi_asal_mi( girilen_sayi ); if( !test_sonucu ) printf("Girilen say asal deildir!\n"); } while( !test_sonucu ); printf( "Girilen say asaldr!\n" ); } return 0;

Dikkat edilmesi gereken bir dier konu; return koyduunuz yerde, fonksiyonun derhl sonlanmasdr. Fonksiyonun kalan ksm almaz. Geriye deer dndrmeye fonksiyonlar iin de ayn durum geerlidir, onlarda da return ifadesini kullanabilirsiniz. Deer dndrsn, dndrmesin yazdnz fonksiyonda herhangi bir yere 'return;' yazn. Fonksiyonun bu noktadan itibaren almay kestiini farkedeceksiniz. Bu fonksiyonu altrmann uygun olmad artlarda, kullanabileceiniz bir yntemdir. Bir kontrol ekrannda, kullanc ad ve/veya ifresini yanl girildiinde, programn almasn annda kesmek isteyebilirsiniz. Byle bir durumda 'return;' kullanlabilir. Dersimizi burada tamamlayp rnek sorulara gemeden nce, fonksiyonlara ait genel yapy incelemenizi neririm.
donus_tipi fonksiyon_adi( alacagi_arguman[lar] ) { . . FONKSYON ER ( YAPILACAK LEMLER ) . . [return deger] }

NOT: Keli parantez grdnz yerler opsiyoneldir. Her fonksiyonda yazlmas gerekmez. Ancak oluturacanz fonksiyon yapsna bal olarak yazlmas artta olabilir. Mesela dn tipi olarak void dnda bir deiken tipi belirlediyseniz, return koymanz gerekir.

Baz Aritmetik Fonksiyonlar


Geen dersimizde, fonksiyonlar ve bunlar nasl kullanlacan grmtk. Ayrca ktphanelerin hazr fonksiyonlar ierdiinden bahsetmitik. Baz matematiksel ilemlerin kullanm ska gerekebilecei iin bunlar bir liste hlinde vermenin uygun olduuna inanyorum. Bylece var olan aritmetik fonksiyonlar tekrar tekrar tanmlayarak zaman kaybetmezsiniz. double ceil( double n ) : Virgll n saysn, kendisinden byk olan ilk tam sayya tamamlar. rnein ceil(51.4) ilemi, 52 sonucunu verir. double floor( double n ) : Virgll n saysnn, virglden sonrasn atarak, bir tam sayya evirir. floor(51.4) ilemi, 51 saysn dndrr. double fabs( double n ) : Verilen n saysnn mutlak deerini dndrr. fabs(-23.5), 23.5 deerini verir. double fmod( double a, double b ) : a saysnn b saysna blmnden kalan verir. (Daha nce grdmz modl (%) operatr, sadece tam saylarda kullanlrken, fmod fonksiyonu virgll saylarda da alr.) double pow( double a, double b ) : stel deer hesaplamak iin kullanlr; ab deerini verir. double sqrt( double a ) : a'nn karekkn hesaplar. Yukarda verilmi fonksiyonlar, matematik ktphanesi ( math.h ) altndadr. Bu fonksiyonlardan herhangi birini kullacanz zaman, program kodununun bana #include<math.h> yazmalsnz. Ayrca derleyici olarak gcc'yle alyorsanz, derlemek iin -lm parametresini eklemeniz gerekir. (rnein: "gcc test.c -lm" gibi...)

Bellek Yaps ve Adresler


imdiye kadar deiken tanmlamay grdk. Bir deiken tanmlandnda, arka plnda gerekleen olaylara ise deinmedik. Hafzay kk hcrelerden olumu bir blok olarak dnebilirsiniz. Bir deiken tanmladnzda, bellek bloundan gerekli miktarda hcre, ilgili deikene ayrlr. Gereken hcre adedi, deiken tipine gre deiir. imdi aadaki kod parasna bakalm:
#include<stdio.h> int main( void ) { // Degiskenler tanmlanyor: int num1, num2; float num3, num4; char i1, i2; // Degiskenlere atama yapiliyor: num1 = 5; num2 = 12; num3 = 67.09; num4 = 1.71; i1 = 'H'; i2 = 'p'; } return 0;

Yukarda bahsettiimiz hcrelerden oluan bellek yapsn, bu kod paras iin uygulayalm. Deiken tiplerinden int'in 2 byte, float'un 4 byte ve char'n 1 byte yer kapladn kabul edelim. Her bir hcre 1 byte'lk alan temsil etsin. Deikenler iin ayrlan hafza alan, 4300 adresinden balasn. imdi bunlar temsili bir ekle dkelim:

Bir deiken tanmladmzda, bellekte gereken alan onun adna rezerve edilir. rnein 'int num1' yazlmas, bellekte uygun bir yer bulunup, 2 byte'n, num1 deikeni adna tutulmasn salyor. Daha sonra num1 deikenine deer atarsak, ayrlan hafza alanna 5 says yazlyor. Aslnda, num1 ile ilgili yapacanz btn ilemler, 4300 adresiyle 4302 adresi arasndaki bellek hcrelerinin deimesiyle alakaldr. Deiken dediimiz; uygun bir bellek alannn, bir isme revize edilip, kullanlmasndan ibarettir. Bir parantez ap, kk bir uyar da bulunalm. eklimizin temsili olduunu unutmamak gerekiyor. Deikenlerin bellekteki yerleimi bu kadar 'uniform' olmayabilir. Ayrca balang adresini 4300 olarak belirlememiz keyfiydi. Saylar ve tutulan alanlar deiebilir. Ancak bellein yapsnn, aa yukar byle olduunu kabul edebilirsiniz.

Pointer Mekanizmas
Bir deikene deer atadmzda, aslnda bellek hcrelerini deitirdiimizi sylemitik. Bu doru bir tanm ama eksik bir noktas var. Bellek hcrelerini deitermemize ramen, bunu direkt yapamaz; deikenleri kullanrz. Bellek hcrelerine direkt mdahle Pointer'lar sayesinde gerekleir. Pointer, birok Trke kaynakta 'iareti' olarak geiyor. Direkt evirirseniz mantkl. Ancak terimlerin znde olduu gibi renilmesinin daha yararl olduunu dnyorum ve ben Pointer olarak anlatacam. Baz yerlerde iareti tanm grrseniz, bunun pointer ile ayn olduunu bilin. imdi gelelim Pointer'in ne olduuna... Deikenler bildiiniz gibi deer (say, karakter, vs...) tutar. Pointer'lar ise adres tutan deikenlerdir. Bellekten bahsetmitik; kk hcrelerin oluturduu hafza blounun adreslere ayrldn ve deikenlerin bellek hcrelerine yerletiini grdk. te pointer'lar bu bellek adreslerini tutarlar. Pointer tanmlamak olduka basittir. Sadece deiken adnn nne '*' iareti getiririz. Dikkat edilmesi gereken tek nokta; pointer' iaret edecei deiken tipine uygun tanmlamaktr. Yani float bir deikeni, int bir pointer ile iaretlemee almak yanltr! Aadaki rnee bakalm:
#include<stdio.h> int main( void ) { // int tipinde deiken // tanmlyoruz: int xyz = 10, k;

// int tipinde pointer // tanmlyoruz: int *p; // xyz deikeninin adresini // pointer'a atyoruz. // Bir deiken adresini '&' // iaretiyle alrz. p = &xyz; // k deikenine xyz'nin deeri // atanr. Pointer'lar deer tutmaz. // deer tutan deikenleri iaret // eder. Bana '*' koyulduunda, // iaret ettii deikenin deerini // gsterir. k = *p; } return 0;

Kod parasndaki yorumlar okuduunuzda, pointer ile ilgili fikriniz olacaktr. Pointer adres tutan deikenlerdir. imdiye kadar grdmz deikeninlerin saklayabildii deerleri tutamazlar. Sadece deikenleri iaret edebilirler. Herhangi bir deikenin adresini pointer iersine atamak isterseniz, deiken adnn nne '&' getirmeniz gerekir. Bundan sonra o pointer, ilgili deikeni iaret eder. Eer bahsettiimiz deikenin sahip olduu deeri pointer ile gstermek veya deiken deerini deitirmek isterseniz, pointer bana '*' getirerek ilemlerinizi yapabilirsiniz. Pointer bana '*' getirerek yapacanz her atama ilemi, deikeni de etkileyecektir. Daha kapsaml bir rnek yapalm:
#include<stdio.h> int main( void ) { int x, y, z; int *int_addr; x = 41; y = 12; // int_addr x degiskenini // isaret ediyor. int_addr = &x; // int_addr'in isaret ettigi // degiskenin sakladigi deger // aliniyor. (yani x'in degeri) z = *int_addr; printf( "z: %d\n", z ); // int_addr, artik y degiskenini // isaret ediyor. int_addr = &y; // int_addr'in isaret ettigi // degiskenin sakladigi deger // aliniyor. (yani y'nin degeri) z = *int_addr; printf( "z: %d\n" ,z ); return 0; }

Bir pointer'in iaret ettii deikeni program boyunca srekli deitirebilirsiniz. Yukardaki rnekte, int_addr pointer'i, nce x'i ve ardndan y'yi iaret etmitir. Bu yzden, z deikenine int_addr kullanarak yaptmz atamalar, her seferinde farkl sonular dourmutur. Pointer kullanarak, deikenlerin saklad deerleri de deitirebiliriz. imdi bununla ilgili bir rnek inceleyelim:

#include<stdio.h> int main( void ) { int x, y; int *int_addr; x = 41; y = 12; // int_addr x degiskenini // isaret ediyor int_addr = &x; // int_addr'in isaret ettigi // degiskenin degerini // degistiriyoruz *int_addr = 479; printf( "x: %d y: %d\n", x, y ); int_addr = &y; return 0; }

Kodu derleyip, altrdnzda, x'in deerinin deitiini greceksiniz. Pointer bana '*' getirip, pointer'a bir deer atarsanz; aslnda iaret ettii deikene deer atam olursunuz. Pointer ise hi deimeden, ayn adres bilgisini tutmaya devam edecektir.

Pointer tutan Pointer'lar


Pointer'lar, grdmz gibi deikenleri iaret ederler. Pointer'da bir deikendir ve onu da iaret edecek bir pointer yaps kullanlabilir. Geen sefer ki bildirimden fark, pointer deikenini iaret edecek bir deiken tanmlyorsanz; bana '**' getirmeniz gerekmesidir. Buradaki yldz says deiebilir. Eer, pointer iaret eden bir pointer'i iaret edecek bir pointer tanmlamak istiyorsanz, defa yldz ( *** ) yazmanz gerekir. Evet, cmle biraz karmak, ama kullanm olduka basit! Pointer iaret eden pointer'lar aadaki rnekte bulabilirsiniz:
#include<stdio.h> int main( void ) { int r = 50; int *p; int **k; int ***m; printf( "r: %d\n", r ); p = &r; k = &p; m = &k; ***m = 100; printf( "r: %d\n", r ); } return 0;

Yazm olduumuz kod iersinde kimin neyi gsterdiini grafikle daha iyi anlayabiliriz:

Birbirini gsteren Pointer'lar ilerki derslerimizde, zellikle dinamik bellek tahsis ederken ok ihtiya duyacamz bir yap. O yzden iyice renmek gerekiyor.

Referansla Argman Aktarm


Fonksiyonlara nasl argman aktaracamz biliyoruz. Hatrlayacanz gibi parametrelere deer atyorduk. Bu yntemde, kullandnz argmanlarn deeri deimiyordu. Fonksiyona parametre olarak yollanan argman hep ayn kalyordu. Fonksiyon iinde yaplan ilemlerin hibiri argman deikeni etkilemiyordu. Sadece deiken deerinin aktarld ve argmann etkilenmedii bu duruma, "call by value" veya "pass by value" ad verilir. Bu isimleri bilmiyor olsanz dahi, u ana kadar ki fonksiyon almalar byleydi. Geriye birden ok deer dnmesi gereken veya fonksiyonun iersinde yapacanz deiikliklerin, argman deikene yansmas gereken durumlar olabilir. te bu gibi zamanlarda, "call by reference" veya "pass by reference" olarak isimlendirilen yntem kullanlr. Argman deer olarak aktarlmaz; argman olan deikenin adres bilgisi fonksiyona aktarlr. Bu sayede fonksiyon iersinde yapacanz her trl deiiklik argman deikene de yansr. Sylediklerimizi uygulamaya dkelim ve kendisine verilen iki saynn yerlerini deitiren bir fonksiyon yazalm. Yani kendisine a ve b adnda iki deiken yollanyorsa, a'nn deerini b; b'nin deeriniyse a yapsn.
#include<stdio.h> // Kendisine verilen iki degiskenin // degerlerini degistirir. // Parametreleri tanimlarken baslarina // '*' koyuyoruz. void swap( int *x, int *y ) { int temp; temp = *x; *x = *y; *y = temp; } int main( void ) { int a, b; a = 12; b = 27; printf( "a: %d b: %d\n", a, b ); // Argumanlar aktarrken, baslarina // '&' koyuyoruz. swap(&a, &b); printf( "a: %d b: %d\n", a, b );

return 0;

Referans yoluyla aktarm olmasayd, iki deikenin deerlerini fonksiyon kullanarak deitiremezdik. Eer yazdnz fonksiyon birden ok deer dndrmek zorundaysa, referans yoluyla aktarm zorunlu hle geliyor. nk daha nce ilediimiz return ifadesiyle sadece tek bir deer dndrebiliriz. rnein bir blme ilemi yapp, blm sonucunu ve kalan syleyen bir fonksiyon yazacamz dnelim. Bu durumda, blnen ve blen fonksiyona gidecek argmanlar olurken; kalan ve blm geriye dnmelidir. return ifadesi geriye tek bir deer vereceinden, ikinci deeri alabilmek iin referans yntemi kullanmamz gerekir.
#include<stdio.h> int bolme_islemi( int bolunen, int bolen, int *kalan ) { *kalan = bolunen % bolen; return bolunen / bolen; } int main( void ) { int bolunen, bolen; int bolum, kalan; bolunen = 13; bolen = 4; bolum = bolme_islemi( bolunen, bolen, &kalan ); printf( "Blm: %d Kalan: %d\n", bolum, kalan ); } return 0;

Fonksiyon Prototipleri
Bildiiniz gibi fonksiyonlarmz, main( ) zerine yazyoruz. Tek ksa bir fonksiyon iin bu durum rahatsz etmez; ama uzun uzun 20 adet fonksiyon olduunu dnn. main( ) fonksiyonu sayfalar dolusu kodun altnda kalacak ve okunmas gleecektir. Fonksiyon prototipleri burada devreye girer. Bir stte yazdmz program tekrar yazalm. Ama bu sefer, fonksiyon prototipi yapsna uygun olarak bunu yapalm:
#include<stdio.h> int bolme_islemi( int, int, int * ); int main( void ) { int bolunen, bolen; int bolum, kalan; bolunen = 13; bolen = 4; bolum = bolme_islemi( bolunen, bolen, &kalan ); printf( "Blm: %d Kalan: %d\n", bolum, kalan ); return 0; } int bolme_islemi( int bolunen, int bolen, int *kalan ) { *kalan = bolunen % bolen; return bolunen / bolen; }

bolme_islemi( ) fonksiyonunu, main( ) fonksiyonundan nce yazmadk. Sadece byle bir fonksiyon olduunu ve alaca parametre tiplerini bildirdik. ( steseydik parametre adlarn da

yazabilirdik ama buna gerek yok. ) Daha sonra main( ) fonksiyonu altna inip, fonksiyonu yazdk. rendiklerimizi pekitirmek iin yeni bir program yazalm. Fonksiyonumuz, kendisine argman olarak gnderilen bir pointer'i alp; bu pointer'in bellekteki adresini, iaret ettii deikenin deerini ve bu deikenin adresini gstersin.
#include<stdio.h> void pointer_detayi_goster( int * ); int main( void ) { int sayi = 15; int *pointer; // Degisken isaret ediliyor. pointer = &sayi; // Zaten pointer oldugu icin '&' // isaretine gerek yoktur. Eger // bir degisken olsaydi, basina '&' // koymamiz gerekirdi. pointer_detayi_goster( pointer ); return 0; } void pointer_detayi_goster( int *p ) { // %p, bellek adreslerini gostermek icindir. // 16 tabaninda (Hexadecimal) sayilar icin kullanilir. // %p yerine, %x kullanmaniz mumkundur. printf( "Pointer adresi\t\t\t: %p\n", &p ); printf( "aret ettii deikenin adresi\t: %p\n", p ); printf( "aret ettii deikenin deeri\t: %d\n", *p ); }

Fonksiyon prototipi, "Function Prototype"dan geliyor. Bunun gzel bir eviri olduunu dnmyorum. Ama aklma daha uygun bir ey gelmedi. neriniz varsa deitirebiliriz.

Rekrsif Fonksiyonlar
Bir fonksiyon iersinden, bir dierini arabiliriz. Rekrsif fonksiyonlar, fonksiyon iersinden fonksiyon armann zel bir hlidir. Rekrsif fonksiyon bir baka fonksiyon yerine kendisini arr ve artlar uygun olduu srece bu tekrarlanr. Rekrsif, Recursive kelimesinden geliyor ve tekrarlamal, yinelemeli anlamn tayor. Kelimenin anlamyla, yapt i rtmekte. Rekrsif fonksiyonlar aklmzdan kartp, bildiimiz yntemle 1, 5, 9, 13 serisini oluturan bir fonksiyon yazalm:
#include<stdio.h> void seri_olustur( int ); int main( void ) { seri_olustur( 1 ); } void seri_olustur( int sayi ) { while( sayi <= 13 ) { printf("%d ", sayi ); sayi += 4; } }

Bu fonksiyonu yazmak olduka basitti. imdi ayn ii yapan rekrsif bir fonksiyon yazalm:
#include<stdio.h>

void seri_olustur( int ); int main( void ) { seri_olustur( 1 ); } void seri_olustur( int sayi ) { if( sayi <= 13 ) { printf("%d ", sayi ); sayi += 4; seri_olustur( sayi ); } }

Son yazdmz programla, bir nce yazdmz program ayn ktlar retir. Ama birbirlerinden farkl alrlar. kinci programn farkn ak diyagramna bakarak sizler de grebilirsiniz. Rekrsif kullanm, fonksiyonun tekrar tekrar arlmasn salamtr.

Daha nce faktriyel hesab yapan program yazmtk. imdi faktriyel hesaplayan fonksiyonu, rekrsif olarak yazalm:
#include<stdio.h> int faktoriyel( int ); int main( void ) { printf( "%d\n", faktoriyel(5) ); } int faktoriyel( int sayi ) { if( sayi > 1 ) return sayi * faktoriyel( sayi-1 ); return 1; }

Yukardaki programn detayl bir ekilde ak diyagramn vermeyeceim. Ancak faktriyel hesaplamas yaplrken, admlar grmenizi istiyorum. Adm olarak geen her kutu, fonksiyonun bir kez arlmasn temsil ediyor. Balang ksmn geerseniz fonksiyon toplamda 5 kere arlyor.

Rekrsif yaplar, olduka karmak olabilir. Fakat kullanl olduklar kesin. rnein silme komutlar rekrsif yaplardan yararlanr. Bir klasr altnda bulunan her eyle birlikte silmeniz gerekiyorsa, rekrsif fonksiyon kanlmazdr. Ya da baz matematiksel ilemlerde veya arama ( search ) yntemlerinde yine rekrsif fonksiyonlara bavururuz. Bunlarn dnda rekrsif fonksiyonlar, normal fonksiyonlara gre daha az kod kullanlarak yazlr. Bunlar rekrsif fonksiyonlarn olumlu ynleri... Ancak hibir ey mkemmel deildir. Rekrsif fonksiyon kullanmann bilgisayarnza binderecei yk daha fazladr. Faktoriyel rneine bakn; tam 5 kez ayn fonksiyonu aryoruz ve bu srada btn deerler bellekte tutuluyor. Eer ok sayda iterasyondan sz ediyorsak, belleiniz hzla tkenecektir. Rekrsif yaplar, bellekte ekstra yer kaplad gibi, normal fonksiyonlara gre daha yavatr. stelik ksa kod yazmna karn, rekrsif fonksiyonlarn daha karmak olduklarn syleyebiliriz. Anlamak zaman zaman sorun olabiliyor. Ksacas bir programda gerekten rekrsif yapya ihtiyacnz olmad srece, ondan kanmanz daha iyi!

rnek Sorular
Soru 1: Aadaki programa gre, a, b ve c'nin deerleri nedir?
#include<stdio.h> int main( void ) { float a, b, c; float *p; a = 15.4; b = 48.6; p = &a; c = b = *p = 151.52; printf( "a: %f, b: %f, c: %f\n", a, b, c ); return 0; }

Cevap 1:
a: 151.52, b: 151.52, c: 151.52

Soru 2: Fibonnacci serisinde herhangi bir seri elemann deerini bulmak iin f( n ) = f( n - 1 ) + f( n - 2 ) fonksiyonu kullanlr. Balang deeri olarak f( 0 ) = 0 ve f( 1 ) = 1'dir. Bu bilgiler nda, verilen n saysna gre, seride karlk den deeri bulan fonksiyonu rekrsif olarak yaznz. Cevap 2:
#include<stdio.h> int fibonacci( int ); int main( void )

int i; // Fibonacci serisinin ilk 10 elemani // yazilacaktir. for( i = 0; i < 10; i++ ) { printf( "f(%d)= %d\n", i, fibonacci( i ) ); } return 0;

} int fibonacci( int eleman_no ) { if( eleman_no > 1 ) { return fibonacci( eleman_no - 1 ) + fibonacci( eleman_no - 2 ) ; } else if( eleman_no == 1 ) return 1; else return 0; }

Diziler
Bir bilgisayar program yaptnz dnn. Kullancnn 100 deer girmesi isteniyor. Girilen btn bu saylarn farkl aamalardan geeceini ve bu yzden hepsini ayr bir deikende tutmamz gerektiini varsayalm. Bu durumda ne yapardnz? a0, a1, a2, ..., a99 eklinde 100 tane deiken tanmlamak elbette mmkn; ama olduka zahmetli olurdu. Srf deikenleri tanmlarken kaybedeceiniz zaman dnrseniz ne demek istediimi anlarsnz. Bunun iin alternatif bir zmn gerektii mutlak! ok sayda deikenin gerektii durumlarda, diziler imdadmza yetiir. (Dizi, ngilizce kaynaklarda array olarak geer.) 100 deiken tanmlamamzn gerektii yukardaki rnee dnelim. Tek tek a0, ..., a100 yaparak bunu nasl yazacanz zaten biliyorsunuz. imdi tek satrda dizi tanmlayarak, bunu nasl yapacamz grelim:
int a[100];

Yukardaki tek satr, bellek blounda 100 adet int deiken yeri ayrr. Tek satr kod elbette aklayc deil, o yzden bunu aadaki ekille aklayalm:

Her eyin banda dizideki elemanlarn deiken tipini yazyoruz; buradaki rneimizde tam say gerektii iin 'int' yazdk. Daha sonra diziye 'a' yazarak bir isim veriyoruz. Deikenleri nasl isimlendiriyorsak, ayn kurallar diziler iin de geerli... Son aamada bu dizinin ka eleman iereceini belirtiyoruz. Keli parantezler ( [ ] ) iinde yazdmz 100 says, 100 adet int tipinde deikenin oluturulmasn salyor. Bir deikene ularken, onun adn yazarz. Dizilerde de aa yukar byle saylr. Fakat ufak farklar vardr. Bir dizi, birden ok elemandan oluur. Bu yzden sadece dizi adn yazmaz, ulamak

istediimiz eleman da yer numarasn yazarak belirtiriz. rnein a dizisinin, 25.eleman gerekiyorsa, a[24] ile arlr. Sanrm 25 yerine 24 yazldn fark etmisinizdir. C programlama dilinde, dizilerin ilk eleman 0'dr. Diziler 0'dan balad iin, ulamak istenilen dizi eleman hangisiyse bir eksiini yazarz. Yani a dizisinin 25.eleman, a[24]; 100.eleman a[99] ile arrz. imdi basit bir rnek yapalm. Bu rnekte, her aya ait gneli gn says sorulsun ve sonunda yllk gneli gn says yazlsn.
#include<stdio.h> int main( void ) { // Aylari temsil etmesi icin // aylar adinda 12 elemanli // bir dizi olusturuyoruz. int aylar[ 12 ]; int toplam = 0; int i; // Birinci dongu, deger atamak icindir for( i = 0; i < 12; i++ ) { printf( "%2d.Ay: ", (i+1) ); // aylara deger atyoruz: scanf( "%d", &aylar[ i ] ); } // Az evvel girilen degerleri gostermek icin // ikinci bir dongu kurduk printf( "\nGRDNZ DEERLER\n\n" ); for( i = 0; i < 12; i++ ) { printf( "%2d.Ay iin %d girdiniz\n", (i+1), aylar[i] ); toplam += aylar[ i ]; } printf( "Toplam gneli gn says: %d\n", toplam ); return 0;

rneimizi inceleyelim. En bata 12 elemanl aylar dizisini, "int aylar[12]" yazarak tanmlyoruz. Her ay iin deer girilmesini gerekiyor. Klavyeden girilen saylarn okunmas iin elbette scanf( ) fonksiyonunu kullanacaz ama ufak bir farkla! Eer 'a' isimde bir deikene atama yapyor olsaydk, hepinizin bilecei ekilde "scanf("%d", &a )" yazardk. Fakat dizi elemanlarna atama yaplacandan komutu, "scanf( "%d", &aylar[ i ] )" eklinde yazmamz gerekiyor. Dng iindeki i deikeni, 0'dan 11'e kadar srasyla artyor. Bu sayede, dngnn her admnda farkl bir dizi elemanna deer atyabiliyoruz. ( i deikeni, bir nevi indis olarak dnlebilir. ) Klavyeden okunan deerlerin dizi elemanlarna atanmasndan sonra, ikinci dng balyor. Bu dngde girmi olduunuz deerler listelenip, ayn esnada toplam gneli gn says bulunuyor. Son aamada, hesaplanan toplam deerini yazdrp, program bitiriyoruz. Dikkat ederseniz, deerlerin alnmas veya okunmas gibi ilemler dngler araclyla yapld. Bunlar dngler aracl ile yapmak zorunda deildik. Mesela "scanf("%d", &aylar[5] )" yazp, 6.ayn deerini; "scanf("%d", &aylar[9] )" yazp, 10.ayn deerini klavyeden alabilirdik. Ancak byle yapmak, dng kullanmaktan daha zahmetlidir. Yanlgya dmemeniz iin dngleri kullanmann kural olmadn, sadece ileri kolaylatrdn hatrlatmak istedim. Gerek tek tek, gerekse rnekte yaptmz gibi dnglerle zm retebilirsiniz. Baka bir rnek yapalm. Kullancmz, float tipinde 10 adet deer girsin. nce bu deerlerin ortalamas bulunsun, ardndan ka adet elemann ortalamann altnda kald ve ka adet elemann ortalamann stnde olduu gsterilsin.
#include<stdio.h>

int main( void ) { // Degerleri tutacagimiz 'dizi' // adinda bir dizi olusturuyoruz. float dizi[ 10 ]; float ortalama, toplam = 0; int ortalama_ustu_adedi = 0; int ortalama_alti_adedi = 0; int i; // Kullanici dizinin elemanlarini giriyor: for( i = 0; i < 10; i++ ) { printf( "%2d. eleman giriniz> ", (i+1) ); scanf( "%f", &dizi[ i ] ); toplam += dizi[ i ]; } // dizinin ortalamasi hesaplaniyor. ortalama = toplam / 10.0; // ortalamadan kucuk ve buyuk elemanlarin // kac adet oldugu belirleniyor. for( i = 0; i < 10; i++ ) { if( dizi[ i ] < ortalama ) ortalama_alti_adedi++; else if( dizi[ i ] > ortalama ) ortalama_ustu_adedi++; } // raporlama yapiliyor. printf( "Ortalama: %.2f\n", ortalama ); printf( "Ortalamadan dk %d eleman vardr.\n", ortalama_alti_adedi ); printf( "Ortalamadan yksek %d eleman vardr.\n", ortalama_ustu_adedi ); } return 0;

Program pek karmak deil. Dizi elemanlarn alyor, ortalamalarn hesaplyor, elemanlar ortalamayla karlatrp, ortalamadan byk ve kk elemanlarn adedini veriyoruz. Anlalmas g bir ey bulacanz sanmyorum. Tek karmak gelecek nokta, ikinci dngde neden bir else olmad olabilir. Olduka geerli bir sebebi var ve if else-if yapsn iyice renenler byle braklmasn anlayacaklardr. Bilmeyenlere gelince... her eyi ben sylersem, iin tad tuzu kalmaz; eski konular gzden geirmelisiniz.

Dizilere lk Deer Atama


Deiken tanm yaparken, ilk deer atamay biliyoruz. rnein "int a = 5;" eklinde yazacanz bir kod, a deikenini oluturaca gibi, iine 5 deerini de atayacaktr. ( Bu deikene, tanmladktan sonra farkl deerler atayabilirsiniz. ) Benzer ekilde, bir diziyi tanmlarken, dizinin elemanlarna deer atayabilirsiniz. Aada bunu nasl yapabileceinizi grebilirsiniz:
int dizi1[ 6 ] = { 4, 8, 15, 16, 23, 42 }; float dizi2[ 5 ] = { 11.5, -1.6, 46.3, 5, 21.56 };

Kme parantezleri iinde grdnz her deer, srasyla bir elemana atanmtr. rnein dizi1'in ilk eleman 4 olurken, son eleman 42'dir. Yukardaki tanmlamalarda farkedeceiniz gibi dizi boyutlarn 6 ve 5 eklinde belirttik. lk deer atamas yapacamz durumlarda, dizinin boyutunu belirtmeniz gerekmez; dizi boyutunu yazp yazmamak size baldr. Dilerseniz dizi boyutunu belirtmeden aadaki gibi de yazabilirdiniz:

int dizi1[ ] = { 4, 8, 15, 16, 23, 42 }; float dizi2[ ] = { 11.5, -1.6, 46.3, 5, 21.56 };

Derleyici, atanmak istenen deer saysna bakar ve dizi1 ile dizi2'nin boyutunu buna gre belirler. dizi1 iin 6, dizi2 iin 5 tane deer belirtmiiz. Bu dizi1 dizisinin 6, dizi2 dizisinin 5 elemanl olacan iaret eder. Deer atamayla ilgili ufak bir bilgi daha aktarmak istiyorum. Aada iki farkl ilk deer atama yntemi bulunuyor. Yazm fark olmasna ramen, ikisi de ayn ii yapar.
int dizi[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 }; int dizi[ 7 ] = { 0 };

Bir diziyi tanmlayn ve hibir deer atamadan, dizinin elemanlarn printf( ) fonksiyonuyla yazdrn. Ortaya anlamsz saylar ktn greceksiniz. Bir dizi tanmlandnda, hafzada gerekli olan yer ayrlr. Fakat daha nce bu hafza alannda ne olup olmadyla ilgilenilmez. Ortaya kan anlamsz saylar bundan kaynaklanr. nceden hafzada bulunan deerlerin yansmasn grrsnz. Modern programlama dillerinin bir ounda, dizi tanmladnzda, dizinin btn elemanlar 0 deeriyle balar; sizin herhangi bir atama yapmanza gerek yoktur. C programlama dilindeyse, kendiliinden bir balang deeri atanmaz. Bunu yapp yapmamak size kalmtr. Ksacas ilerin daha kontrol gitmesini istiyorsanz, dizileri tanmlarken "dizi[ 7 ] = { 0 };" eklinde tanmlamalar yapabilirsiniz. lk deer atanmasyla ilgili bir rnek yapalm. 10 elemanl bir diziye atadmz ilk deerin maksimum ve minimum deerleri gsterilsin:
#include<stdio.h> int main( void ) { // dizi'yi tanitirken, ilk deger // atiyoruz int dizi[ ] = { 15, 54, 1, 44, 55, 40, 60, 4, 77, 45 }; int i, max, min; // Dizinin ilk elemanini, en kucuk // ve en buyuk deger kabul ediyoruz. // Bunun yanlis olmasi onemli degil; // sadece bir noktadan kontrole baslamamiz // gerektiginden boyle bir secim yaptik. min = dizi[ 0 ]; max = dizi[ 0 ]; for( i = 1; i < 10; i++ ) { // min'in degeri, dizi elemanindan // buyukse, min'in degerini degistiririz. // Kendisinden daha kucuk sayi oldugunu // gosterir. if( min > dizi[i] ) min = dizi[i]; // max'in degeri, dizi elemanindan // kucukse, max'in degerini degistiririz. // Kendisinden daha buyuk sayi oldugunu // gosterir. if( max < dizi[i] ) max = dizi[i]; } printf( "En Kk Deer: %d\n", min );

printf( "En Byk Deer: %d\n", max ); } return 0;

Dizilerin fonksiyonlara aktarm


Dizileri fonksiyonlara aktarmak, tpk deikenleri aktarmaya benzemektedir. Uzun uzadya anlatmak yerine, rnek stnden gitmenin daha fayda olacan dnyorum. Bir fonksiyon yazalm ve bu fonksiyon kendisine gnderilen dizinin elemanlarn ekrana yazsn.
#include<stdio.h> void elemanlari_goster( int [ 5 ] ); int main( void ) { int dizi[ 5 ] = { 55, 414, 7, 210, 15 }; elemanlari_goster( dizi ); return 0; } void elemanlari_goster( int gosterilecek_dizi[ 5 ] ) { int i; for( i = 0; i < 5; i++) printf( "%d\n", gosterilecek_dizi[ i ] ); }

Fonksiyon prototipini yazarken, dizinin tipini ve boyutunu belirttiimizi fark etmisinizdir. Fonksiyonu tanmlama aamasnda, bunlara ilaveten parametre olarak dizinin adn da yazyoruz. ( Bu isim herhangi bir ey olabilir, kendisine gnderilecek dizinin adyla ayn olmas gerekmez. ) Bir dizi yerine sradan bir deiken kullansaydk, benzer eyleri yapacaktk. Farkl olan tek nokta; dizi eleman saysn belirtmemiz. imdi main( ) fonksiyonuna dnelim ve elemanlari_goster( ); fonksiyonuna bakalm. Anlayacanz gibi, "dizi" ismindeki dizinin fonksiyona argman olarak gnderilmesi iin sadece adn yazmamz yeterli. Fonksiyonlarla ilgili bir baka rnek yapalm. Bu sefer fonksiyon oluturalm. Birinci fonksiyon kendisine gnderilen dizideki en byk deeri bulsun; ikinci fonksiyon, dizinin en kk deerini bulsun; nc fonksiyon ise elemanlarn ortalamasn dndrsn.
#include<stdio.h> float maksimum_bul( float [ 8 ] ); float minimum_bul( float [ 8 ] ); float ortalama_bul( float [ 8 ] ); int main( void ) { // 8 boyutlu bir dizi olusturup buna // keyfi degerler atiyoruz. float sayilar[ 8 ] = { 12.36, 4.715, 6.41, 13, 1.414, 1.732, 2.236, 2.645 }; float max, min, ortalama; // Ornek olmasi acisindan fonksiyonlar // kullaniliyor. max = maksimum_bul( sayilar ); min = minimum_bul( sayilar ); ortalama = ortalama_bul( sayilar ); printf( "Maksimum: %.2f\n", max ); printf( "Minimum: %.2f\n", min ); printf( "Ortalama: %.2f\n", ortalama ); return 0; } /* Dizi icindeki maksimum degeri bulur */

float maksimum_bul( float dizi[ 8 ] ) { int i, max; max = dizi[0]; for( i = 1; i < 8; i++ ) { if( max < dizi[ i ] ) max = dizi[ i ]; } return max; } /* Dizi icindeki minimum degeri bulur */ float minimum_bul( float dizi[ 8 ] ) { int i, min; min = dizi[ 0 ]; for( i = 1; i < 8; i++ ) { if( min > dizi[ i ] ) { min = dizi[ i ]; } } return min; } /* Dizi elemanlarinin ortalamasini bulur */ float ortalama_bul( float dizi[ 8 ] ) { int i, ortalama = 0; for( i = 0; i < 8; i++ ) ortalama += dizi[ i ]; return ortalama / 8.0; }

Yukardaki rneklerimizde, dizilerin boyutlarn bilerek fonksiyonlarmz yazdk. Ancak gerek hayat byle deildir; bir fonksiyona farkl farkl boyutlarda diziler gndermeniz gerekir. Mesela ortalama_bul( ) fonksiyonu hem 8 elemanl bir diziye hizmet edecek, hem de 800 elemanl bir baka diziye uyacak ekilde yazlmaldr. Son rneimizi her boyutta dizi iin kullanlabilecek hle getirelim ve ortalama_bul( ), minimum_bul( ) ve maksimum_bul( ) fonksiyonlarn biraz deitirelim.
#include<stdio.h> float maksimum_bul( float [ ], int ); float minimum_bul( float [ ], int ); float ortalama_bul( float [ ], int ); int main( void ) { // 8 boyutlu bir dizi olusturup buna // keyfi degerler atiyoruz. float sayilar[ 8 ] = { 12.36, 4.715, 6.41, 13, 1.414, 1.732, 2.236, 2.645 }; float max, min, ortalama; // Ornek olmasi acisindan fonksiyonlar // kullaniliyor. max = maksimum_bul( sayilar, 8 ); min = minimum_bul( sayilar, 8 ); ortalama = ortalama_bul( sayilar, 8 ); printf( "Maksimum: %.2f\n", max ); printf( "Minimum: %.2f\n", min ); printf( "Ortalama: %.2f\n", ortalama ); return 0; } /* Dizi icindeki maksimum degeri bulur */ float maksimum_bul( float dizi[ ], int eleman_sayisi )

int i, max; max = dizi[0]; for( i = 1; i < eleman_sayisi; i++ ) { if( max < dizi[ i ] ) max = dizi[ i ]; } return max;

} /* Dizi icindeki minimum degeri bulur */ float minimum_bul( float dizi[ ], int eleman_sayisi ) { int i, min; min = dizi[ 0 ]; for( i = 1; i < eleman_sayisi; i++ ) { if( min > dizi[ i ] ) { min = dizi[ i ]; } } return min; } /* Dizi elemanlarinin ortalamasini bulur */ float ortalama_bul( float dizi[ ], int eleman_sayisi ) { int i, ortalama = 0; for( i = 0; i < eleman_sayisi; i++ ) ortalama += dizi[ i ]; } return ortalama / 8.0;

Fonksiyonlara dikkatlice bakn. Geen sefer sadece dizi adn gnderirken, artk dizi adyla birlikte boyutunu da yolluyoruz. Bylece dizinin boyutu n'olursa olsun, fark etmiyor. Yeni bir parametre ap dizinin eleman saysn isterseniz, fonksiyon her dizi iin alabilir.

Dizilere Pointer ile Eriim


Pointer'larn deikenleri iaret etmesini geen dersimizde ilemitik. Benzer ekilde dizileri de iaret edebilirler. rnein, int dizi[6]; eklinde tanmlanm bir diziyi, pointer ile iaret etmek istersek, ptr = dizi; yazmamz yeterlidir. Deikenlerde, deiken adnn bana '&' iareti getiriyorduk, fakat dizilerde buna gerek yoktur. nk dizilerin kendisi de bir pointer'dr. Dizilerin hepsi hafza alannda bir balang noktas iaret eder. rnek olmas asndan bu noktaya 6066 diyelim. Siz "dizi[0]" dediiniz zaman 6066 ile 6068 arasnda kalan blgeyi kullanrsnz. Ya da "dizi[4]" dediiniz zaman 6074 ile 6076 hafza blgesi ileme alnr. Bir diziyi iaret eden pointer aynen dizi gibi kullanlabilir. Yani ptr = dizi; komutunu vermenizden sonra, ptr[0] ile dizi[0] birbirinin aynsdr. Eer *ptr yazarsanz, yine dizinin ilk eleman dizi[0]' iaret etmi olursunuz. Ancak dizi iaret eden pointer'lar genellikle, *( ptr + 0 ) eklinde kullanlr. Burada 0 yerine ne yazarsanz, dizinin o elemann elde ederseniz. Diyelim ki, 5.eleman ( yani dizi[ 4 ] ) kullanmak istiyorsunuz, o zaman *( ptr + 4 ) yazarsanz. Bir resim, bin szden iyidir... Aadaki resmi incelerseniz, durumu daha net anlayacanz dnyorum.

Grdnz gibi dizi, 6066 numaral hafza adresini iaret ediyor. ptr isimli pointer ise, dizi zerinden 6066 numaral adresi gsteriyor. Ksacas ikisi de ayn noktay iaret ediyorlar. imdi bunu koda dkelim:
#include<stdio.h> int main( void ) { int i; // dizi'yi tanimliyoruz. int dizi[ 6 ] = { 4, 8, 15, 16, 23, 42 }; // ptr adinda bir pointer tanimliyoruz. int *ptr; // ptr'nin dizi'yi isaret etmesini soyluyoruz. ptr = dizi; // ptr'in degerini artirip, dizi'nin butun // elemanlarini yazdiriyoruz. for( i = 0; i < 6; i++ ) printf( "%d\n", *( ptr + i ) ); return 0; }

Pointer'lar farkl ekillerde kullanlabilir. Her defasnda, dizinin balang elemann atamanz gerekmez. rnein, ptr = &dizi[ 2 ] eklinde bir komut kullanarak, dizinin 3.elemannn adresini pointer'a atayabilirsiniz. Pointer'larin deiik kullanm eitlerini aada grebilirsiniz:
#include<stdio.h> int main( void )

int int int ptr elm ptr ptr elm elm ptr elm elm

elm; month[ 12 ]; *ptr; = month; // month[0] adresini atar = ptr[ 3 ]; // elm = month[ 3 ] deerini atar = month + 3; // month[ 3 ] adresini atar = &month[ 3 ]; // month[ 3 ] adresini atar = ( ptr+2 )[ 2 ]; // elm = ptr[ 4 ] ( = month[ 7 ] )deeri atanr. = *( month + 3 ); = month; = *( ptr + 2 ); // elm = month[ 2 ] deerini atar = *( month + 1 ); // elm = month[ 1 ] deerini atar

return 0;

Dizilerin fonksiyonlara gnderilmesini grmtk. Parametre ksmna dizinin tipini ve boyutunu yazyorduk. Ancak bunun yerine pointer da kullanabiliriz. rnein aadaki iki komut satr birbirinin aynsdr.
int toplam_bul( int dizi[ ], int boyut ); int toplam_bul( int *dizi, int boyut );

Fonksiyondan Dizi Dndrmek


Fonksiyondan bir diziyi dndrmeden nce nemli bir konuyla balayalm. Hatrlarsanz fonksiyonlara iki ekilde argman yolluyorduk. Birinci yntemde, sadece deer gidiyordu ve deiken zerinde bir deiiklik olmuyordu. ( Call by Value ) kinci yntemdeyse, yollanlan deiken, fonksiyon iersinde yapacanz ilemlerden etkileniyordu. ( Call by Reference ) Dizilerin aktarlmas, referans yoluyla olur. Fonksiyon iersinde yapacanz bir deiiklik, dizinin aslnda da deiiklie sebep olur. Aadaki rnee bakalm:
#include<stdio.h> /* Kendisine verilen dizinin butun elemanlarinin karesini alir */ void karesine_donustur( int [ ], int ); int main( void ) { int i; int liste[ ] = { 1,2,3,4,5,6,7 }; for( i = 0; i < 7; i++ ) { printf( "%d ", liste[ i ] ); } printf("\n"); // Fonksiyonu cagiriyoruz. Fonksiyon geriye // herhangi bir deger dondurmuyor. Diziler // referans yontemiyle aktarildigi icin dizinin // degeri bu sekilde degismis oluyor. karesine_donustur( liste, 7 ); for( i = 0; i < 7; i++ ) { printf( "%d ", liste[ i ] ); } printf("\n"); return 0; } void karesine_donustur( int dizi[ ], int boyut ) { int i;

for( i = 0; i < boyut; i++ ) { dizi[ i ] = dizi[ i ] * dizi[ i ]; }

Grdnz gibi fonksiyon iersinde diziyle ilgili yaptmz deiikler, dizinin aslna da yansmtr. Srada, fonksiyondan dizi dndrmek var. Aslnda fonksiyondan dizi pek doru bir isimlendirme deil. Gerekte dndrdmz ey, dizinin kendisi deil, sadece balang adresi oluyor. Dolaysyla bir dizi dndrdmz sylemek yerine, Pointer dndrdmz syleyebiliriz. Basit bir fonksiyon hazrlayalm; bu fonksiyon kendisine gnderilen iki diziyi birletirip, tek bir dizi hline getirsin.
#include<stdio.h> /* Kendisine verilen iki diziyi birlestirip sonuclari ucuncu bir diziye atar */ int *dizileri_birlestir( int [], int, int [], int, int []); int main( void ) { // liste_1, 5 elemanli bir dizidir. int liste_1[5] = { 6, 7, 8, 9, 10 }; // liste_2, 7 elemanli bir dizidir. int liste_2[7] = {13, 7, 12, 9, 7, 1, 14 }; // sonuclarin toplanacagi toplam_sonuc dizisi int toplam_sonuc[13]; // sonucun dondurulmesi icin pointer tanimliyoruz int *ptr; int i; // fonksiyonu calistiriyoruz. ptr = dizileri_birlestir( liste_1, 5, liste_2, 7, toplam_sonuc ); // pointer uzerinden sonuclari yazdiriyoruz. for( i = 0; i < 12; i++ ) printf("%d ", *(ptr+i) ); printf("\n"); return 0; } int *dizileri_birlestir( int dizi_1[], int boyut_1, int dizi_2[], int boyut_2, int sonuc[] ) { int i, k; // Birinci dizinin degerleri ataniyor. for( i = 0; i < boyut_1; i++ ) sonuc[i] = dizi_1[i]; // Ikinci dizinin degerleri ataniyor. for( k = 0; k < boyut_2; i++, k++ ) { sonuc[i] = dizi_2[k]; } // Geriye sonuc dizisi gonderiliyor. return sonuc; }

Neyin nasl olduunu sanrm anlamsnzdr. Diziler referans yoluyla gnderilirken ve gnderdiimiz dizilerin boyutlar belliyken, neden bir de iin iine pointer'lar soktuumuzu

sorabilirsiniz. lerki konumuzda, dinamik yer ayrma konusunu ileyeceiz. imdilik ok lzumlu gzkmese de, n hazrlk olarak olarak bunlar renmeniz nemli!

Sralama
Sralama olduka nemli bir konudur. eit eit algoritmalar ( QuickSort, Insertion, Shell Sort, vs... ) bulunmaktadr. Ben sizlere en basit sralama yntemlerinden biri olan, "Bubble Sort" ("Kabarck Sralamas") metodundan bahsedeceim. Elinizde, {7, 3, 66, 3, -5, 22, -77, 2} elemanlarndan oluan bir dizi olduunu varsayn. Dizinin en sonuna gidiyorsunuz ve 8.elemanla ( dizi[ 7 ] ), 7.eleman ( dizi[ 6 ] ) karlatryorsunuz. Eer 8.eleman, 7.elemandan kkse bu ikisi yer deitiriyor; deilse, bir deiiklik yapmyorsunuz. Sonra 7.elemanla ( dizi[ 6 ] ) 6.eleman iin ayn ilemler yaplyor. Bu byle dizinin son elemanna ( dizi[ 0 ] ) kadar gidiyor. Buraya kadar yaptmz ilemlere birinci aama diyelim. kinci aamada da tamamen ayn ilemleri yapyorsunuz. Sadece sre dizinin son elemanna ( dizi[ 0 ] ) kadar deil, ondan bir nceki elemana kadar sryor. Ksacas her aamada, kontrol ettiiniz eleman saysn bir azaltyorsunuz. Aama says da, dizi eleman saysnn bir eksii oluyor. Yani bu rneimizde 7 aama gerekiyor Konu biraz karmak; tek seferde anlalmayabilir. Bu dediklerimizi algoritmaya dkelim:
#include<stdio.h> void dizi_goster( int [ ], int ); void kabarcik_siralamasi( int [ ], int ); int main( void ) { int i, j; int dizi[ 8 ] = { 7, 3, 66, 3, -5, 22, -77, 2 }; // Siralama islemi icin fonksiyonu // cagriyoruz. kabarcik_siralamasi( dizi, 8 ); // Sonucu gostermesi icin dizi_gosteri // calistiriyoruz. dizi_goster( dizi, 8 ); return 0; } // Dizi elemanlarini gostermek icin yazilmis // bir fonksiyondur. void dizi_goster( int dizi[ ], int boyut ) { int i; for( i = 0; i < boyut; i++ ) { printf("%d ",dizi[i]); } printf("\n"); } // Bubble Sort algoritmasina gore, siralama islemi // yapar. void kabarcik_siralamasi( int dizi[ ], int boyut ) { int i, j, temp; // Ilk dongu asama sayisini temsil ediyor. // Bu donguye gore, ornegin boyutu 8 olan // bir dizi icin 7 asama gerceklesir. for( i = 0; i < boyut-1; i++ ) { // Ikinci dongu, her asamada yapilan // islemi temsil eder. Dizinin elemanlari // en sondan baslayarak kontrol edilir. // Eger kendisinden once gelen elemandan

// kucuk bir degeri varsa, elemanlarin // degerleri yer degistirir. for( j = boyut - 1; j > i; j-- ) { if( dizi[ j ] < dizi[ j - 1 ] ) { temp = dizi[ j -1 ]; dizi[ j - 1 ] = dizi[ j ]; dizi[ j ] = temp; } } } }

rnek Sorular
Soru 1: Kendisine parametre olarak gelen bir diziyi, yine parametre olarak bir baka diziye ters evirip atayacak bir fonksiyon yaznz. Cevap 1:
#include<stdio.h> void diziyi_ters_cevir( int[], int[], int ); int main( void ) { int i; int liste_1[] = { 6, 7, 8, 9, 10 }; int liste_2[5]; diziyi_ters_cevir( liste_1, liste_2, 5 ); for( i = 0; i < 5; i++ ) { printf("%d ", liste_2[i]); } printf("\n");

} void diziyi_ters_cevir( int dizi_1[], int dizi_2[], int boyut ) { int i, k; for( i = 0, k = boyut - 1; i < boyut; i++, k-- ) dizi_2[k] = dizi_1[i]; }

Soru 2: Kendisine parametre olarak gelen bir dizinin btn elemanlarn, mutlak deeriyle deitiren program yaznz. Cevap 2:
#include<stdio.h> void dizi_mutlak_deger( int[], int ); int main( void ) { int i; int liste[] = { -16, 71, -18, -4, 10, 0 }; dizi_mutlak_deger( liste, 6 ); for( i = 0; i < 6; i++ ) { printf("%d ", liste[i]); }

printf("\n"); } void dizi_mutlak_deger( int dizi[], int boyut ) { int i; for( i = 0; i < boyut; i++ ) { if( dizi[i] < 0 ) dizi[i] *= -1; } }

Soru 3: int *ptr = &month[ 3 ] eklinde bir atama yaplyor. Buna gre, aadakilerden hangileri *ptr deerine eittir?
a) b) c) d) month; ptr[ 0 ]; ptr[ 1 ]; *( month + 3 ) e) ( month + 3 )[ 0 ]; f) ( month + 1 )[ 2 ]; g) *( month + 3 )[ 0 ];

Cevap3:
b, d, e ve f klar, *ptr'ye eittir.

ok Boyutlu Diziler
nceki derslerimizde dizileri grmtk. Ksaca zetleyecek olursak, belirlediimiz sayda deikeni bir sra iinde tutmamz, diziler sayesinde gerekleiyordu. Bu dersimizde, ok boyutlu dizileri inceleyip, ardndan dinamik bellek konularna gireceiz. imdiye kadar grdmz diziler, tek boyutluydu. Btn elemanlar tek boyutlu bir yapda saklyorduk. Ancak dizilerin tek boyutlu olmas gerekmez; istediiniz boyutta tanmlayabilirsiniz. rnein 3x4 bir matris iin 2 boyutlu bir dizi kullanrz. Ya da boyutlu klid uzayndaki x, y, z noktalarn saklamak iin 3 boyutlu bir diziyi tercih ederiz. Hemen bir baka rnek verelim. 5 kiilik bir renci grubu iin 8 adet test uygulansn. Bunlarn sonularn saklamak iin 2 boyutlu bir dizi kullanalm:
#include<stdio.h> int main( void ) { // 5 adet ogrenci icin 8 adet sinavi // temsil etmesi icin bir ogrenci tablosu // olusturuyoruz. Bunun icin 5x8 bir matris // yaratilmasi gerekiyor. int ogrenci_tablosu[ 5 ][ 8 ]; int i, j; for( i = 0; i < 5; i++ ) { for( j = 0; j < 8; j++ ) { printf( "%d no.'lu ogrencinin ", ( i + 1 ) ); printf( "%d no.'lu snav> ", ( j + 1 ) ); // Tek boyutlu dizilerdeki gibi deger // atiyoruz scanf( "%d", &ogrenci_tablosu[ i ][ j ] ); } } return 0; }

Bu program altrp, rencilere eitli deerler atadmz dnelim. Bunu grsel bir ekle sokarsak, aadaki gibi bir izelge oluur:

Tabloya bakarsak, 1.renci snavlardan, 80, 76, 58, 90, 27, 60, 85 ve 95 puan alm gzkyor. Ya da 5.rencinin, 6.snavndan 67 aldn anlyoruz. Benzer ekilde dier hcrelere gerekli deerler atanp, ilgili rencinin snav notlar hafzada tutuluyor.

ok Boyutlu Dizilere lk Deer Atama


ok boyutlu bir diziyi tanmlarken, eleman deerlerini atamak mmkndr. Aadaki rnei inceleyelim:
int tablo[3][4] = { 8, 16, 9, 52, 3, 15, 27, 6, 14, 25, 2, 10 };

Diziyi tanmlarken, yukardaki gibi bir ilk deer atama yaparsanz, elemanlarn deeri aadaki gibi olur: Satr 0 Satr 1 : : 8 3 16 15 9 27 52 6

Satr 2 : 14 25 2 10 ok boyutlu dizilerde ilk deer atama, tek boyutlu dizilerdekiyle ayndr. Girdiiniz deerler srasyla hcrelere atanr. Bunun nedeni de basittir. Bilgisayar, ok boyutlu dizileri sizin gibi dnmez; dizi elemanlarn hafzada arka arkaya gelen bellek hcreleri olarak deerlendirir. ok boyutlu dizilerde ilk deer atama yapacaksanz, deerleri kmelendirmek iyi bir yntemdir; karmakl nler. rnein yukarda yazm olduumuz ilk deer atama kodunu, aadaki gibi de yazabiliriz:
int tablo[3][4] = { {8, 16, 9, 52}, {3, 15, 27, 6}, {14, 25, 2, 10} };

Farkedeceiniz gibi elemanlar drderli gruba ayrdk. Bilgisayar asndan bir ey deimemi olsa da, kodu okuyacak kii asndan daha yararl oldu. Peki ya drt adet olmas gereken grubun elemanlarn, adet yazsaydk ya da bir-iki grubu hi yazmasaydk n'olurdu? Deneyelim...
int tablo[3][4] = { {8, 16}, {3, 15, 27} };

Tek boyutlu dizilerde ilk deer atamas yaparken, eleman saysndan az deer girerseniz, kalan

deerler 0 olarak kabul edilir. Ayn ey ok boyutlu diziler iin de geerlidir; olmas gerektii sayda eleman ya da grup girilmezse, bu deerlerin hepsi 0 olarak kabul edilir. Yani stte yazdmz kodun yarataca sonu, yle olacaktr: Satr 0 Satr 1 : : 8 3 16 15 0 27 0 0

Satr 2 : 0 0 0 0 Belirtmediimiz btn elemanlar 0 deerini almtr. Satr 2'ninse btn elemanlar direkt 0 olmutur; nk grup tanm hi yaplmamtr.

Fonksiyonlara 2 Boyutlu Dizileri Aktarmak


ki boyutlu bir diziyi fonksiyona parametre gndermek, tek boyutlu diziyi gndermekten farkl saylmaz. Tek fark dizinin iki boyutlu olduunu belirtmemiz ve ikinci boyutun elemann mutlaka yazmamzdr. Basit bir rnek yapalm; kendisine gnderilen iki boyutlu bir diziyi matris eklinde yazan bir fonksiyon oluturalm:
#include<stdio.h> /* Parametre tanimlamasi yaparken, iki boyutlu dizinin satir boyutunu girmemize gerek yoktur. Ancak sutun boyutunu girmek gerekir. */ void matris_yazdir( int [ ][ 4 ], int ); int main( void ) { // Ornek olmasi acisindan matrise keyfi // degerler atiyoruz. Matrisimiz 3 satir // ve 4 sutundan ( 3 x 4 ) olusuyor. int matris[ 3 ][ 4 ] = { {10, 15, 20, 25}, {30, 35, 40, 45}, {50, 55, 60, 65} }; // Matris elemanlarini yazdiran fonksiyonu // cagriyoruz. matris_yazdir( matris, 3 ); return 0; } void matris_yazdir( int dizi[ ][ 4 ], int satir_sayisi ) { int i, j; for( i = 0; i < satir_sayisi; i++ ) { for( j = 0; j < 4; j++ ) { printf( "%d ", dizi[ i ][ j ] ); } printf( "\n" ); } }

Kod iersinde bulunan yorumlar, iki boyutlu dizilerin fonksiyonlara nasl aktarldn gstermeye yetecektir. Yine de bir kez daha tekrar edelim... Fonksiyonu tanmlarken, ok boyutlu dizinin ilk boyutunu yazmak zorunda deilsiniz. Bizim rneimizde int dizi[ ][ 4 ] eklinde belirtmemiz bundan kaynaklanyor. ayet 7 x 6 x 4 boyutlarnda dizilerin kullanlaca bir fonksiyon yazsaydk tanmlamamz int dizi[ ][ 6 ][ 4 ] olarak deitirmemiz gerekirdi. Ksacas fonksiyonu tanmlarken dizi boyutlarna dair ilk deeri yazmamakta serbestsiniz; ancak dier boyutlarn yazlmas zorunlu! Bunun yararn merak ederseniz, stun says 4 olan her trl matrisi bu fonksiyona gnderebileceinizi hatrlatmak isterim. Yani fonksiyon her boyutta matrisi alabilir, tabii stun

says 4 olduu srece...

2 Boyutlu Dizilerin Hafza Yerleimi


Dizilerin ok boyutlu olmas sizi yanltmasn, bilgisayar hafzas tek boyutludur. ster tek boyutlu bir dizi, ister iki boyut ya da isterseniz 10 boyutlu bir dizi iersinde bulunan elemanlar, birbiri pei sra gelen bellek hcrelerinde tutulur. ki boyutlu bir dizide bulunan elemanlarn, hafzada nasl yerletirildiini aadaki grafikte grebilirsiniz.

Grld gibi elemanlarn hepsi srayla yerletirilmitir. Bir satrn bittii noktada ikinci satrn elemanlar devreye girer. Kapsaml bir rnekle hafza yerleimini ele alalm:
#include<stdio.h> void satir_goster( int satir[ ] ); int main( void ) { int tablo[5][4] = { {4, 3, 2, 1}, {1, 2, 3, 4}, {5, 6, 7, 8}, {2, 5, 7, 9}, {0, 5, 9, 0} }; int i, j; // Dizinin baslangic adresini yazdiriyoruz printf( "2 boyutlu tablo %p adresinden balar\n\n", tablo ); // Tablo icersinde bulunan dizi elemanlarinin adreslerini // ve degerlerini yazdiriyoruz. printf( "Tablo elemanlar ve hafza adresleri:\n"); for( i = 0; i < 5; i++ ) { for( j = 0; j < 4; j++ ) { printf( "%d (%p) ", tablo[i][j], &tablo[i][j] ); } printf( "\n" ); } // Cok boyutlu diziler birden fazla dizinin toplami olarak

// dusunulebilir ve her satir tek boyutlu bir dizi olarak // ele alinabilir. Once her satirin baslangic adresini // gosteriyoruz. Sonra satirlari tek boyutlu dizi seklinde // satir_goster( ) fonksiyonuna gonderiyoruz. printf( "\nTablo satrlarnn balang adresleri: \n"); for( i = 0; i < 5; i++ ) printf( "tablo[%d]'nin balang adresi %p\n", i, tablo[i] ); printf( "\nsatir_goster( ) fonksiyonuyla, " "tablo elemanlar ve hafza adresleri:\n"); for( i = 0; i < 5; i++ ) satir_goster( tablo[i] ); } // Kendisine gonderilen tek boyutlu bir dizinin // elemanlarini yazdirir. void satir_goster( int satir[ ] ) { int i; for( i = 0; i < 4; i++ ) { printf( "%d (%p) ", satir[i], &satir[i] ); } printf( "\n" ); }

rnekle ilgili en ok dikkat edilmesi gereken nokta, ok boyutlu dizilerin esasnda, tek boyutlu dizilerden olumu bir btn olduudur. Tablo isimli 2 boyutlu dizimiz 5 adet satrdan oluur ve bu satrlarn her biri kendi bana bir dizidir. Eer tablo[2] derseniz bu nc satr temsil eden bir diziyi ifade eder. satir_goster( ) fonksiyonunu ele alalm. Esasnda fonksiyon iersinde satr diye bir kavramn olmadn syleyebiliriz. Btn olan biten fonksiyona tek boyutlu bir dizi gnderilmesidir ve fonksiyon bu dizinin elemanlarn yazar. Dizi elemanlarnn hafzadaki ardk yerleimi bize baka imkanlar da sunar. ki boyutlu bir diziyi bir hamlede, tek boyutlu bir diziye dntrmek bunlardan biridir.
#include<stdio.h> int main( void ) { int i; int tablo[5][4] = { {4, {1, {5, {2, {0,

3, 2, 6, 5, 5,

2, 3, 7, 7, 9,

1}, 4}, 8}, 9}, 0} };

// Cok boyutlu dizinin baslangic // adresini bir pointer'a atiyoruz. int *p = tablo[0]; // p isimli pointer'i tek boyutlu // bir dizi gibi kullanabiliriz. // Ayni zamanda p uzerinde yapacagimiz // degisikler, tablo'yu da etkiler. for( i = 0; i < 5*4; i++ ) printf( "%d\n", p[i] ); } return 0;

Daha nce sralama konusunu ilemitik. Ancak bunu iki boyutlu dizilerde nasl yapacamz henz grmedik. Aslnda grmemize de gerek yok! ki boyutlu bir diziyi yukardaki gibi tek boyuta indirin ve sonrasnda sralayn. ok boyutlu dizileri, tek boyuta indirmemizin ufak bir faydas...

Pointer Dizileri
ok boyutlu dizilerin tek boyutlu dizilerin bir bileimi olduundan bahsetmitik. imdi anlatacamz konuda ok farkl deil. Dizilerin, adresi gstermeye yarayan Pointer'lardan pek farkl olmadn zaten biliyorsunuz. imdi de pointer dizilerini greceiz. Yani adres gsteren iareti saklayan dizileri...
#include<stdio.h> int main( void ) { int i, j; // Dizi isimleri keyfi secilmistir. // alfa, beta, gama gibi baska isimler de // verebilirdik. int Kanada[8]; int ABD[8]; int Meksika[8]; int Rusya[8]; int Japonya[8]; // Bir pointer dizisi tanimliyoruz. int *tablo[5]; // Yukarda tanimlanan dizilerin adreslerini // tablo'ya aktiriyoruz. tablo[0] = Kanada; tablo[1] = ABD; tablo[2] = Meksika; tablo[3] = Rusya; tablo[4] = Japonya; // Tablo elemanlarinin adreslerini gosteriyor // gibi gozukse de, gosterilen adresler Kanada, // ABD, Meksika, Rusya ve Japonya dizilerinin // eleman adresleridir. for( i = 0; i < 5; i++ ) { for( j = 0 ; j < 8; j++ ) printf( "%p\n", &tablo[i][j] ); } return 0;

lke isimlerini verdiimiz 5 adet dizi tanmladk. Bu dizileri daha sonra tabloya srayla atadk. Artk her diziyle tek tek uramak yerine tek bir diziden btn lkelere ulamak mmkn hle gelmitir. ki boyutlu tablo isimli matrise atamasn yaptmz ey deer veya bir eleman deildir; dizilerin balang adresleridir. Bu yzden tablo dizisi iersinde yapacamz herhangi bir deiiklik orijinal diziyi de (rnein Meksika) deitirir. Atama ilemini aadaki gibi tek seferde de yapabilirdik:
int *tablo[ ] = { Kanada, ABD, Meksika, Rusya, Japonya };

imdi de bir pointer dizisini fonksiyonlara nasl argman olarak gndereceimize bakalm.
#include<stdio.h> void adresleri_goster( int *[ ] ); int main( void ) { int Kanada[8]; int ABD[8]; int Meksika[8]; int Rusya[8]; int Japonya[8];

int *tablo[ ] = { Kanada, ABD, Meksika, Rusya, Japonya }; // Adresleri gostermesi icin adresleri_goster( ) // fonksiyonunu cagriyoruz. adresleri_goster( tablo ); return 0; } void adresleri_goster( int *dizi[ ] ) { int i, j; for( i = 0; i < 5; i++ ) { for( j = 0 ; j < 8; j++ ) printf( "%p\n", &dizi[ i ][ j ] ); } }

Dinamik Bellek Ynetimi


Dizileri etkin bir biimde kullanmay rendiinizi ya da reneceinizi umuyorum. Ancak dizilerle ilgili ilememiz gereken son bir konu var: Dinamik Bellek Ynetimi... imdiye kadar yazdmz programlarda ka eleman olaca nceden belliydi. Yani snf listesiyle ilgili bir program yazacaksak, snfn ka kii olduunu biliyormuuz gibi davranyorduk. Programn en banda ka elemanlk alana ihtiyacmz varsa, o kadar yer ayryorduk. Ama bu gerek dnyada karmza kacak problemler iin yeterli bir yaklam deildir. rnein bir snfta 100 renci varken, dier bir snfta 50 renci olabilir ve siz her ortamda alsn diye 200 kiilik bir st snr koyamazsnz. Bu, hem hafzann verimsiz kullanlmasna yol aar; hem de karma eitimlerin yapld baz fakltelerde say yetmeyebilir. Statik bir ekilde dizi tanmlayarak bu sorunlarn stesinden gelemezsiniz. zm dinamik bellek ynetimindedir. Dinamik bellek ynetiminde, dizilerin boyutlar nceden belirlenmez. Program aknda dizi boyutunu ayarlarz ve gereken bellek miktar, program alrken tahsis edilir. Dinamik bellek tahsisi iin calloc( ) ve malloc( ) olmak zere iki nemli fonksiyonumuz vardr. Bellekte yer ayrlmasn bu fonksiyonlarla salarz. Her iki fonksiyon da stdlib ktphanesinde bulunur. Bu yzden fonksiyonlardan herhangi birini kullanacanz zaman, programn bana #include<stdlib.h> yazlmas gerekir. calloc( ) fonksiyonu aadaki gibi kullanlr:
isaretci_adi = calloc( eleman_sayisi, her_elemanin_boyutu );

calloc( ) fonksiyonu eleman saysn, eleman boyutuyla arparak hafzada gereken bellek alann ayrr. Dinamik oluturduunuz dizi iersindeki her elemana, otomatik olarak ilk deer 0 atanr. malloc( ) fonksiyonu, calloc( ) gibi dinamik bellek ayrm iin kullanlr. calloc( ) fonksiyonundan farkl olarak ilk deer atamas yapmaz. Kullanmysa aadaki gibidir:
isaretci_adi = malloc( eleman_sayisi * her_elemanin_boyutu );

Bu kadar konumadan sonra ii pratie dkelim ve dinamik bellekle ilgili ilk programmz yazalm:
#include<stdio.h> #include<stdlib.h> int main( void ) { // Dinamik bir dizi yaratmak icin // pointer kullaniriz. int *dizi;

// Dizimizin kac elemanli olacagini // eleman_sayisi isimli degiskende // tutuyoruz. int eleman_sayisi; int i; // Kullanicidan eleman sayisini girmesini // istiyoruz. printf( "Eleman saysn giriniz> "); scanf( "%d", &eleman_sayisi ); // calloc( ) fonksiyonuyla dinamik olarak // dizimizi istedigimiz boyutta yaratiyoruz. dizi = calloc( eleman_sayisi, sizeof( int ) ); // Ornek olmasi acisindan dizinin elemanlarini // ekrana yazdiriliyor. Dizilerde yapabildiginiz // her seyi hicbir fark olmaksizin yapabilirsiniz. for( i = 0; i < eleman_sayisi; i++ ) printf( "%d\n", dizi[i] ); // Dinamik olan diziyi kullandiktan ve isinizi // tamamladiktan sonra free fonksiyonunu kullanip // hafizadan temizlemelisiniz. free( dizi ); return 0; }

Yazdnz programlarn bir sre sonra bilgisayar belleini korkun bir ekilde igal etmesini istemiyorsanz, free( ) fonksiyonunu kullanmanz gerekmektedir. Gelimi programlama dillerinde ( rnein, Java, C#, vb... ) kullanlmayan nesnelerin temizlenmesi otomatik olarak p toplayclarla ( Garbage Collector ) yaplmaktadr. Ne yazk ki C programlama dili iin bir p toplayc yoktur ve iyi programcyla, kt programc burada kendisini belli eder. Programnz bir kereliine altryorsanz ya da yazdnz program ok ufaksa, bo yere tketilen bellek miktarn farketmeyebilirsiniz. Ancak byk boyutta ve kapsaml bir program sz konusuysa, efektif bellek ynetiminin ne kadar nemli olduunu daha iyi anlarsnz. Gereksiz tketilen bellekten kanmak gerekmektedir. Bunun iin fazla bir ey yapmanz gerekmez; calloc( ) fonksiyonuyla tahsis ettiiniz alan, iiniz bittikten sonra free( ) fonksiyonuyla boaltmanz yeterlidir. Konu nemli olduu iin tekrar ediyorum; artk kullanmadnz bir dinamik dizi sz konusuysa onu free( ) fonksiyonuyla kaldrlabilir hle getirmelisiniz! Az evvel calloc( ) ile yazdmz programn aynsn imdi de malloc( ) fonksiyonunu kullanarak yazalm:
#include<stdio.h> #include<stdlib.h> int main( void ) { // Dinamik bir dizi yaratmak icin // pointer kullaniriz. int *dizi; // Dizimizin kac elemanli olacagini // eleman_sayisi isimli degiskende // tutuyoruz. int eleman_sayisi; int i; printf( "Eleman saysn giriniz> "); scanf( "%d", &eleman_sayisi );

// malloc( ) fonksiyonuyla dinamik olarak // dizimizi istedigimiz boyutta yaratiyoruz. dizi = malloc( eleman_sayisi * sizeof( int ) ); for( i = 0; i < eleman_sayisi; i++ ) printf( "%d\n", dizi[i] ); // Dinamik olan diziyi kullandiktan ve isinizi // tamamladiktan sonra free fonksiyonunu kullanip // hafizadan temizlemelisiniz. free( dizi ); return 0; }

Hafza alan ayrrken bazen bir problem kabilir. rnein bellekte yeterli alan olmayabilir ya da benzeri bir sknt olmutur. Bu tarz problemlerin sk olacan dnmeyin. Ancak hafzann gerekten ayrlp ayrlmadn kontrol edip, iinizi garantiye almak isterseniz, aadaki yntemi kullanabilirsiniz:
dizi = calloc( eleman_sayisi, sizeof( int ) ); // Eger hafiza dolmussa dizi pointer'i NULL'a // esit olacak ve asagidaki hata mesaji cikacaktir. if( dizi == NULL ) printf( "Yetersiz bellek!\n" );

Dinamik hafza kullanarak dizi yaratmay grdk. Ancak bu diziler tek boyutlu dizilerdi. Daha nce pointer iaret eden pointer'lar grmtk. imdi onlar kullanarak dinamik ok boyutlu dizi oluturacaz:
#include<stdio.h> #include<stdlib.h> int main( void ) { int **matris; int satir_sayisi, sutun_sayisi; int i, j; printf( "Satr says giriniz> " ); scanf( "%d", &satir_sayisi ); printf( "Stun says giriniz> " ); scanf( "%d", &sutun_sayisi ); // Once satir sayisina gore hafizada yer ayiriyoruz. // Eger gerekli miktar yoksa, uyari veriliyor. matris = (int **)malloc( satir_sayisi * sizeof(int) ); if( matris == NULL ) printf( "Yetersiz bellek!" ); // Daha sonra her satirda, sutun sayisi kadar hucrenin // ayrilmasini sagliyoruz. for( i = 0; i < satir_sayisi; i++ ) { matris[i] = malloc( sutun_sayisi * sizeof(int) ); if( matris[i] == NULL ) printf( "Yetersiz bellek!" ); } // Ornek olmasi acisindan matris degerleri // gosteriliyor. Dizilerde yaptiginiz butun // islemleri burada da yapabilirsiniz. for( i = 0; i < satir_sayisi; i++ ) { for( j = 0; j < sutun_sayisi; j++ ) printf( "%d ", matris[i][j] );

printf( "\n" );

// Bu noktada matris ile isimiz bittiginden // hafizayi bosaltmamiz gerekiyor. Oncelikle // satirlari bosaltiyoruz. for( i = 0; i < satir_sayisi; i++ ) { free( matris[i] ); } // Satirlar bosaldiktan sonra, matrisin // bos oldugunu isaretliyoruz. free( matris ); return 0; }

Yukardaki rnek karmak gelebilir; tek seferde zemeyebilirsiniz. Ancak bir iki kez zerinden geerseniz, temel yapnn aklnza yatacan dnyorum. Kodun koyu yazlm yerlerini rendiiniz takdirde, sorun kalmayacaktr.

rnek Sorular
Soru 1: Kendisine gnderilen iki diziyi birletirip geriye tek bir dizi dndren fonksiyonu yaznz. Cevap 1:
#include<stdio.h> #include<stdlib.h> /* Kendisine verilen iki diziyi birlestirip sonuc dizisini geriye dondurur */ int *dizileri_birlestir( int [], int, int [], int ); int main( void ) { int i; // liste_1, 5 elemanli bir dizidir. int liste_1[5] = { 6, 7, 8, 9, 10 }; // liste_2, 7 elemanli bir dizidir. int liste_2[7] = {13, 7, 12, 9, 7, 1, 14 }; // sonuclarin toplanacagi toplam_sonuc dizisi // sonucun dondurulmesi icin pointer tanimliyoruz int *ptr; // fonksiyonu calistiriyoruz. ptr = dizileri_birlestir( liste_1, 5, liste_2, 7 ); // ptr isimli pointer'i bir dizi olarak dusunebiliriz for( i = 0; i < 12; i++ ) printf("%d ", ptr[i] ); printf("\n"); return 0; } int *dizileri_birlestir( int dizi_1[], int boyut_1, int dizi_2[], int boyut_2 ) { int *sonuc = calloc( boyut_1+boyut_2, sizeof(int) ); int i, k; // Birinci dizinin degerleri ataniyor. for( i = 0; i < boyut_1; i++ ) sonuc[i] = dizi_1[i]; // Ikinci dizinin degerleri ataniyor.

for( k = 0; k < boyut_2; i++, k++ ) { sonuc[i] = dizi_2[k]; } // Geriye sonuc dizisi gonderiliyor. return sonuc; }

Soru 2: Sol aada bulunan 4x4 boyutundaki matrisi saat ynnde 90o dndrecek fonksiyonu yaznz. ( Sol matris dndrld zaman sa matrise eit olmaldr. )
12 88 90 38 34 54 91 39 22 67 92 40 98 11 93 41 38 39 40 41 90 91 92 93 88 54 67 11 12 34 22 98

>>>

Cevap 2:
#include<stdio.h> void elemanlari_goster( int [][4] ); void saat_yonunde_cevir( int [][4] ); int main( void ) { int matris[4][4] = { {12, 34, 22, 98}, {88, 54, 67, 11}, {90, 91, 92, 93}, {38, 39, 40, 41} }; elemanlari_goster( matris ); printf("\n"); saat_yonunde_cevir( matris ); } void elemanlari_goster( int dizi[][4] ) { int i, j; for( i = 0; i < 4; i++ ) { for( j = 0; j < 4; j++ ) printf( "%d ", dizi[i][j] ); printf( "\n" ); } } void saat_yonunde_cevir( int dizi[][4] ) { int i, j; for( i = 0; i < 4; i++ ) { for( j = 0; j < 4 ; j++ ) printf( "%d ", dizi[3-j][i] ); printf( "\n" ); } }

Katarlar ( String )
Dizileri ve ok boyutlu dizileri grdk. Katar dediimiz ey de aslnda bir dizidir. Deiken tipi char yani karakter olan diziler, 'katar' ya da ngilizce adyla 'string' olarak isimlendirilirler. Katarlar, imdiye kadar grdmz dizilerden ayran, onlar farkl klan zellikleri yoktur. rnein bir tam say ( int ) dizisinde, tam saylar saklarken; bir karakter dizisinde -yani katardakarakterleri ( char ) saklarz. Bunun dnda bir fark bulunmaz. Ancak sk kullanlmalarna paralel olarak, katarlara ayr bir nem vermek gerekir. Yaptnz ilemler bilimsel ve hesaplama arlkl

deilse, hangi dili kullanrsanz kullann, en ok ili dl olacanz dizi tipi, karakter dizileridir. simler, adresler, kullanc adlar, telefonlar vs... szle ifade edilebilecek her ey iin karakter dizilerini kullanrz. Katarlar ite bu yzden nemlidir! Karakter dizilerine ngilizce'de String dendiini belirtmitik. String; ip, ba, kordon gibi anlamlar tayor. lk olarak katar adn kim mnasip grd bilmiyorum. Muhtemelen bellek hcrelerine pei sra dizilen karakterlerin, vagonlara benzetilmesiyle, String deiken tipi Trke'ye katar olarak evrildi. ( Arapa kkenli Trke bir kelime olan katar, 'tren' anlamna gelmektedir. ) Daha uygun bir isim verilebilirdi ya da sadece 'karakter dizisi' de diyebilirdik. Fakat madem genel kabul grm bir terim var; yazmz iersinde biz de buna uyacaz. String, katar ya da karakter dizisi hi farketmez; hepsi ayn kapya kyor: Deiken tipi karakter olan dizi...

Katarlarda printf( ) ve scanf( ) Kullanm


Katarlarla, daha nce grdmz diziler arasnda bir farkn olmadn sylemtitik. Bu szmz, teorik olarak doru olsa da, pratikte ufak tefek farklar kapsam d brakyor. Hatrlayacaksnz, dizilerde elemanlara deer atama ya da onlardan deer okuma adm adm yaplan bir ilemdi. Genellikle bir dng iersinde, her dizi eleman iin scanf( ) veya printf( ) fonksiyonunu armamz gerekiyordu. Katarlar iin byle bir mecburiyet bulunmuyor. Tek bir kelimeyi, tek bir scanf( ) fonksiyonuyla okutabilir ve elemanlara otomatik deer atayabilirsiniz. Yani "Merhaba" eklinde bir girdi-input gelirse, 3.dizi eleman 'r' olurken; 6.dizi eleman 'b' olur. nceki dizilerde grdmzn aksine, eleman atamalar kendiliinden gerekleir. Aadaki rnei inceleyelim:
#include<stdio.h> int main( void ) { char isim[30]; printf( "sim giriniz> "); scanf( "%s", isim ); printf( "Girdiiniz isim: %s\n", isim ); return 0; }

rneimizde 30 karakterlik bir karakter dizisi tanmlayarak ie baladk. Bunun anlam girdileri saklayacamz 'isim' katarnn 30 karakter boyutunda olacadr. Ancak bu katara en fazla 29 karakterlik bir kelime atanabilir. nk katarlarda, kelime bitiminden sonra en az bir hcre bo braklmaldr. Bu hcre 'Bo Karakter' ( NULL Character ) tutmak iindir. Bo karakter "\0" eklinde ifade edilir. C programlama dilinde, kelimelerin bittiini bo karakterlerle anlarz. Herhangi bir katar bo karakterle sonlandrmaya, 'null-terminated' denmektedir. Bu arada katarlara deer atarken ya da katarlardan deer okurken, sadece katar adn yazmamzn yettiini farketmisinizdir. Yani scanf( ) fonksiyonu iersine & iareti koymamz gerekmiyor. nk scanf( ), katarn ilk adresinden balayarak aaya doru harfleri tek tek atamas gerektiini biliyor. ( Aslnda biliyor demek yerine, fonksiyonun o ekilde yazldn sylememiz daha doru olur. ) Katarlarn, esasnda bir dizi olduundan bahsetmitik. imdi bunun uygulamasn yapalm. Katara deer atamak iin yine ayn kodu kullanrken; katardan deer okumak iin kodumuzu biraz deitirelim:
#include<stdio.h> int main( void ) { char isim[30]; int i; printf( "sim giriniz> "); scanf( "%s", isim );

printf( "Girdiiniz isim: "); for( i = 0; isim[i]!='\0'; i++ ) printf( "%c", isim[i] ); printf("\n"); return 0; }

Daha nce tek bir printf( ) fonksiyonuyla btn katar yazdrabilirken, bu sefer katar elemanlarn tek tek, karakter karakter yazdrmay tercih ettik. kan sonu ayn olacaktr fakat gidi yolu biraz farkllat. zellikle for dngs iersinde bulunan " isim[i]!='\0' " kouluna dikkat etmek gerekiyor. steseydik, " i < 30 " yazar ve katarn btn hcrelerini birer birer yazdrabilirdik. Fakat bu mantkl deil! 30 karakterlik bir dizi olsa bile, kullanc 10 harften oluan bir isim girebilir. Dolaysyla kalan 20 karakteri yazdrmaya gerek yoktur. Kelimenin nerede sonlandn belirlemek iin "isim[i]!='\0'" koulunu kullanyoruz. Bunun anlam; isim katarnn elemanlar, "\0" yani bo karakterere ( NULL Character ) eit olmad srece yazdrmaya devam edilmesidir. Ne zaman ki kelime biter, sradaki elemann deeri "\0" olur; ite o vakit dngy sonlandrmamz gerektiini biliriz. Yukardaki rneimize birden ok kelime girdiyseniz, sadece ilk kelimenin alndn farketmisinizidir. Yani "Bugn hava ok gzel." eklinde bir cmle girdiiniz zaman, katara sadece "Bugn" kelimesi atanr. Eer ayn anda birden fazla kelime almak istiyorsanz, ayr ayr belirtilmesi gerekir.
#include<stdio.h> int main( void ) { char isim[25], printf( "Ad ve scanf( "%s%s", printf( "Sayn return 0; }

soyad[30]; soyad giriniz> "); isim, soyad ); %s %s, ho geldiniz!\n", isim, soyad );

gets( ) ve puts( ) Fonksiyonlar


Grdnz gibi ayn anda iki farkl kelime alp, ikisini birden yazdrdk. Fakat scanf( ) fonksiyonu "Bugn hava ok gzel." cmlesini tek bir katara alp, atamak iin hlen yetersizdir. nk boluk grd noktada, veriyi almay keser ve sadece "Bugn" kelimesinin atamasn yapar. Boluk ieren bu tarz cmleler iin puts( ) ve gets( ) fonksiyonlar kullanlmaktadr. Aadaki rnek program, 40 harfi gemeyecek her cmleyi kabul edecektir:
#include<stdio.h> int main( void ) { char cumle[40]; printf( "Cmle giriniz> "); gets( cumle ); printf( "Girdiiniz cmle:\n" ); puts( cumle ); return 0; }

gets( ) isminden anlayacanz ( get string ) gibi katara deer atamak iin kullanlr. puts( ) ( put string ) ise, bir katarn ieriini ekrana yazdrmaya yarar. gets( ) atayaca deerin ayrmn yapabilmek iin '\n' aramaktadr. Yani klavyeden Enter'a baslana kadar girilen her eyi, tek bir katara atayacaktr. puts( ) fonksiyonuysa, printf( ) ile benzer alr. Bo karakter ( NULL Character ) yani '\0' ulaana kadar katar yazdrr; printf( ) fonksiyonundan farkl olarak sonuna '\n'

koyarak bir alt satra geer. Olduka ak ve basit kullanmlara sahip olduklarndan, kendiniz de baka rnekler deneyebilirsiniz.

Katarlara lk Deer Atama


Bir katar tanm yaptnz anda, katarn btn elemanlar otomatik olarak '\0' ile doldurulur. Yani katarn btn elemanlarna bo karakter (NULL Character) atanr. Dilerseniz, katar yaratrken iine farkl deerler atayabilirsiniz. Katarlarda ilk deer atamas iki ekilde yaplr. Birinci yntemle deer atamas yapacaksanz, istediiniz kelimeyi bir btn olarak yazarsnz:
#include<stdio.h> int main( void ) { // Her iki katarada ilk deger // atamasi yapiliyor. Ancak // isim katarinda, boyut // belirtilmezken, soyad katarinda // boyutu ayrica belirtiyoruz. char isim[] = "CAGATAY"; char soyad[5] = "CEBI"; printf( "%s %s\n", isim, soyad ); } return 0;

kinci yntemdeyse, kelime btn olarak yazlmaz. Bunun yerine harf harf yazlr ve sonlandrmak iin en sonuna bo karakter ( NULL ) eklenir:
#include<stdio.h> int main( void ) { char isim[] = { 'C', 'A', 'G', 'A', 'T', 'A', 'Y', '\0' }; char soyad[5] = { 'C', 'E', 'B', 'I', '\0' }; printf( "%s %s\n", isim, soyad ); return 0; }

Ben ilk deer atamas yapacam durumlarda, ilk yolu tercih ediyorum. kinci yntem, daha uzun ve zahmeti...

Biimlendirilmi ( Formatl ) Gsterim


Daha nce float tipindeki bir saynn, noktadan sonra iki basaman gstermek trnden eyler yapmtk. rnein printf( ) fonksiyonu iersinde, sayy %.2f eklinde ifade ederseniz, saynn virglden sonra sadece iki basama gsterilir. Yada %5d yazarak tam saylar gsterdiiniz bir durumda, say tek bir rakamdan dahi olusa, onun iin 5 rakamlk gsterim yeri ayrlr. Ayn ekilde biimlendirilmi ( formatl ) gsterim, katarlarda da yaplmaktadr. Katarlar biimlendirilmi ekilde gstermeyi, rnek zerinden anlatmak daha uygun olacaktr:
#include<stdio.h> int main( void ) { char cumle[20] = "Denemeler"; // Cumleyi aynen yazar: printf( "%s\n", cumle ); // 20 karakterlik alan ayirir

// ve en saga dayali sekilde yazar. printf( "%20s\n", cumle ); // 20 karakterlik alan ayirir // ve en saga dayali sekilde, // katarin ilk bes kelimesini // yazar printf( "%20.5s\n", cumle ); // 5 karakterlik alan ayirir // ve en saga dayali sekilde yazar. // Eger girilen kelime 5 karakterden // buyukse, kelimenin hepsi yazilir. printf( "%5s\n", cumle ); // 20 karakterlik alan ayirir // ve sola dayali sekilde yazar. // Sola dayali yazilmasi icin // yuzde isaretinden sonra, // (eksi) isareti konulur. printf( "%-20s\n", cumle ); } return 0;

rneimizde bulunan formatlama biimlerini gzden geirirsek: %20s, ekranda 20 karakter alan ayrlaca anlamna gelir. Katar, en saa dayanr ve "Denemeler" yazlr. %.5s olursa 5 karakterlik boluk ayrlr. Yzde iaretinden sonra nokta olduu iin katarn sadece ilk be harfi yazdrlr. Yani sonu "Denem" olacaktr. %20.5s yazldnda, 20 karakterlik boluk ayrlmas istenmi ancak katarn sadece ilk 5 harfi bu boluklara yazlmtr. %5s kullanrsanz, yine 5 karakterlik boluk ayrlacaktr. Ancak yzdeden sonra nokta olmad iin, katarn hepsi yazlr. Belirtilen boyutu aan durumlarda, eer noktayla snr konmamsa, katar tamamen gsterilir. Dolaysyla kt, "Denemeler" eklinde olacaktr. Anlattklarmzn hepsi, saa dayal ekilde kt retir. Eer sola dayal bir kt isterseniz, yzde iaretinden sonra '-' (eksi) iareti koymanz gerekir. rnein %-20.5s eklinde bir format belirlerseniz, 20 karakterlik boluk ayarlandktan sonra, sola dayal olarak katarn ilk 5 harfi yazdrlacaktr. mle ( cursor ), sa ynde 20 karakter sonrasna decektir.

Standart Katar Fonksiyonlar


Katarlarla daha kolay alabilmek iin, baz hazr ktphane fonksiyonlarndan bahsedeceiz. Bu fonkisyonlar, string ktphanesinde bulunuyor. Bu yzden, programnzn bana, #include<string.h> eklemeniz gerekiyor. * strlen( ) fonksiyonuyla katar boyutu bulma Dizi boyutuyla, katar uzunluunun farkl eyler olduundan bahsetmitik. Dizi boyutu, 40 karakter olacak ekilde ayarlanmken, dizi iinde sadece 7 karakterlik "Merhaba" kelimesi tutulabilir. Bu durumda, dizi boyutu 40 olmasna ramen, katar boyutu yalnzca 7'dir. Katarlarn boyutunu saptamak iin, bo karakter ( NULL Character ) iaretinin yani "\0" simgesinin konumuna baklr. Her seferinde arama yapmanza gerek kalmasn diye strlen( ) fonksiyonu gelitirilmitir. strlen( ) kendisine argman olarak gnderilen bir katarn boyutunu geri dndrr. Aadaki gibi kullanlmaktadr:
#include<stdio.h>

#include<string.h> int main( void ) { printf( "Katar Uzunluu: %d\n", strlen("Merhaba") ); return 0; }

* strcpy( ) ve strncpy( ) ile katar kopyalama Bir katar, bir baka katara kopyalamak iin strcpy( ) fonksiyonunu kullanrz. Katarlar ayn boyutta olmak zorunda deildir. Ancak kopya olacak katar, kendisine gelecek kelimeyi alacak boyuta sahip olmaldr. Fonksiyon prototipi aadaki gibidir, geriye pointer dner.
char *strcpy( char[ ], char[ ] );

strcpy( ) fonksiyonunu bir rnekle grelim:


#include<stdio.h> #include<string.h> int main( void ) { char kaynak[40]="Merhaba Dnya"; char kopya[30] = ""; strcpy( kopya, kaynak ); printf( "%s\n", kopya ); } return 0;

strncpy( ) fonksiyonu, yine kopyalamak iindir. Fakat emsalinden farkl olarak, ka karakterin kopyalanaca belirtilir. Protopi aada verilmitir:
char *strncpy( char[ ], char[ ], int );

Yukardaki rnei strncpy( ) fonksiyonuyla tekrar edelim:


#include<stdio.h> #include<string.h> int main( void ) { char kaynak[40]="Merhaba Dnya"; char kopya[30] = ""; strncpy( kopya, kaynak, 9 ); printf( "%s\n", kopya ); } return 0;

Yukardaki program altrrsanz, kopya isimli katara sadece 9 karakterin aktarldn ve ekrana yazdrlan yaznn "Merhaba D" olduunu grebilirsiniz. * strcmp( ) ve strncmp( ) ile katar karlatrma strcmp( ) fonksiyonu, kendisine verilen iki katar birbiriyle karlatrr. Katarlar birbirine eitse, geriye 0 dner. Eer ilk katar alfabetik olarak ikinciden bykse, geriye pozitif deer dndrr. ayet alfabetik srada ikinci katar birinciden bykse, geriye negatif deer dnmektedir. Bu dediklerimizi, daha iyi anlalmas iin bir tabloya dntrelim: Dnen Deer Aklama <0 Katar1, Katar2'den kktr.

0 >0

Katar1 ve Katar2 birbirine eittir. Katar1, Katar2'den byktr.

strncmp( ) iin de ayn kurallar geerlidir. Tek fark, karlatrlacak karakter saysn girmemizdir. strcmp( ) fonksiyonunda iki katar, null karakter iareti kana kadar karlatrlr. Fakat strncmp( ) fonksiyonunda, balangtan itibaren ka karakterin karlatrlacana siz karar verirsiniz. Her iki fonksiyonu da kapsayan aadaki rnei inceleyelim:
#include<stdio.h> #include<string.h> int main( void ) { int sonuc; char ilk_katar[40]="Maymun"; char ikinci_katar[40]="Maytap"; sonuc = strcmp( ilk_katar, ikinci_katar ); printf( "%d\n", sonuc ); sonuc = strncmp( ilk_katar, ikinci_katar, 3 ); printf( "%d\n", sonuc ); } return 0;

lk nce arlan strcmp( ), null karakterini grene kadar btn karakterleri karlatracak ve geriye negatif bir deer dndrecektir. nk "Maymum" kelimesi alfabede "Maytap" kelimesinden nce gelir; dolaysyla kktr. Fakat ikinci olarak ardmz strncmp( ) geriye 0 deeri verecektir. Her iki katarn ilk harfi ayndr ve fonksiyonda sadece ilk harfin karlatrlmasn istediimizi belirttik. Dolaysyla karlatrmann sonucunda 0 dndrlmesi normaldir. * strcat( ) ve strncat( ) ile katar birletirme strcat( ) ve strncat( ) fonksiyonlar, bir katar bir baka katarla birletirmeye yarar. Fonksiyon adlarnda bulunan cat, ngilizce bir kelime olan ve birletirme anlamna gelen 'concatenate'den gelmitir. strcat( ) kendisine verilen katarlar tamamen birletirirken, strncat( ) belirli bir eleman saysna kadar birletirir. strcat ile ilgili basit bir rnek yapalm.
#include<stdio.h> #include<string.h> int main( void ) { char ad[30], soyad[20]; char isim_soyad[50]; printf( "Ad ve soyadnz giriniz> " ); scanf( "%s%s", ad, soyad ); // isim_soyad <-- ad strcat( isim_soyad, ad ); // isim_soyad <-- ad + " " strcat( isim_soyad, " " ); // isim_soyad <-- ad + " " + soyad strcat( isim_soyad, soyad ); printf( "Tam sim: %s\n", isim_soyad ); return 0; }

Dilerseniz, strncat( ) fonksiyonunu da siz deneyebilirsiniz.

* strstr( ) fonksiyonuyla katar ii arama yapma Bir katar iinde, bir baka katar aradnz durumlarda, strstr( ) fonksiyonu yardmnza yetiir. strstr( ) fonksiyonu, bir katar iinde aradnz bir katar bulduu takdirde bunun bellekteki adresini geriye dndrr. Yani dnen deer eidi bir pointer'dr. Eer herhangi bir eleme olmazsa geriye bir sonu dnmez ve pointer null olarak kalr. Elbette insanlar iin hafza adreslerinin veya pointer deerlerinin pek bir anlam olmuyor. Bir katar iinde arama yapyorsanz, aradnz yapnn katarn neresinde olduunu tespit etmek iin aadaki kodu kullanabilirsiniz:
/* strstr( ) fonksiyon ornegi */ #include<stdio.h> #include<string.h> int main( void ) { char adres[] = "Esentepe Caddesi Mecidiyekoy Istanbul"; char *ptr; // 'adres' katari icinde, 'koy' kelimesini // ariyoruz. Bu amacla strstr( ) fonksiyonunu // kullaniyoruz. Fonksiyon buyuk-kucuk harf // duyarlidir. Eger birden fazla eslesme varsa, // ilk adres degeri doner. Hic eslesme olmazsa, // pointer degeri NULL olur. ptr = strstr( adres, "koy" ); if( ptr != NULL ) printf( "Balang notkas: %d\n", ptr - adres ); else printf( "Eleme bulunamad.\n" ); return 0; }

* strchr( ) ve strrchr( ) fonksiyonlar strchr( ) ve strrchr( ) fonksiyonlar, tpk strstr( ) gibi arama iin kullanlr. Ancak strstr( ) fonksiyonu katar iinde bir baka katar arayabilirken, strchr( ) ve strrchr( ) fonksiyonlar katar iinde tek bir karakter aramak iin kullanlr. strchr( ), karakterin katar iindeki ilk konumunu gsterirken; strrchr( ) fonksiyonu, ilgili karakterin son kez getii adresi verir.
#include<stdio.h> #include<string.h> int main( void ) { char adres[] = "Esentepe Caddesi Mecidiyekoy Istanbul"; char *ilk_nokta, *son_nokta; ilk_nokta = strchr( adres, 'e' ); son_nokta = strrchr( adres, 'e' ); if( ilk_nokta != NULL ) { printf( "Ilk gorundugu konum: %d\n", ilk_nokta - adres ); printf( "Son gorundugu konum: %d\n", son_nokta - adres ); } else printf( "Eleme bulunamad.\n" ); return 0; }

* atoi( ) ve atof( ) ile katar dnm Verilen katar, sayya evirmek gerekebilir. Eer elinizdeki metni, bir tam sayya ( int ) evirecekseniz, atoi( ) fonksiyonunu kullanmanz gerekir. ayet dnm sonunda elde etmek istediiniz deiken tipi, virgll say ise ( float ), atof( ) fonksiyonu kullanlr. Her iki fonksiyon stdlib.h ktphanesi iindedir. Bu fonksiyonlar kullanrken, #include<stdlib.h> komutunu program

balangcna yazmalsnz.
#include<stdio.h> #include<stdlib.h> int main( void ) { char kok_iki[] = "1.414213"; char pi[] = "3.14"; char tam_bir_sayi[] = "156"; char hayatin_anlami[] = "42 is the answer"; printf( "%d\n", printf( "%d\n", printf( "%f\n", printf( "%f\n", return 0; } atoi( atoi( atof( atof( tam_bir_sayi ) ); hayatin_anlami ) ); kok_iki ) ); pi ) );

Her iki fonksiyonda rakam harici bir ey grene kadar alr. Eer nmerik ifadeler dnda bir karakter karsa, fonksiyon o noktada almay keser.

main( ) Fonksiyonuna Argman Aktarm


lediimiz btn derslerde main( ) fonksiyonu vard. main( ) fonksiyonuyla ilgili incelememizi de, fonksiyonlarla ilgili dokuzuncu dersimizde yapmtk. Ancak main( ) fonksiyonuna hibir zaman parametre aktarmadk; aksine parametre almayacan garantilemek iin srekli olarak main( void ) eklinde yazmtk. Artk main( ) fonksiyonuna nasl parametre verileceini greceiz. Aadaki kod, parametresi olan bir main( ) fonksiyonunu gstermektedir:
#include<stdio.h> int main( int argc, int *arg[] ) { int i; for( i = 0; i < argc; i++ ) { printf( "%d. argman: %s\n", i, arg[i] ); } return 0; }

Bu kodu yazp, "yeni_komut.c" adyla kaydedin. Ardndan eer Linux ve gcc kullanyrsanz, aadaki komutu kullanarak kodun derlemesini yapn.
$ gcc yeni_komut.c -o yeni_komut

Yukardaki komut, "yeni_komut" adnda altrlabilir bir program dosyas oluturacak. Windows ve Dev-C++ kullanyorsanz byle bir komuta gerek yok. Kodu kaydedip, derlediiniz zaman, alma klasrnzde "yeni_komut.exe" adnda bir dosya zaten oluacaktr. kinci aamada, programa parametre gndererek altracaz. Bunun iin gerek Linux gerekse Windows kullanclarnn yapaca ey birbirine ok benziyor. Linux kullanclar aadaki gibi bir komut girecekler:
$ ./yeni_komut Merhaba Dnya Hello World

Windows kullanclarnnsa, DOS komut istemini ap, programn kaytl olduu klasre gelmeleri gerekiyor. Diyelim ki, "yeni_komut.exe" "C:\Belgelerim" iinde kaytl... O hlde aadaki komutu giriyoruz:
C:\Belgelerim> yeni_komut Merhaba Dnya Hello World

Her iki iletim sisteminde elde edeceiniz sonu ayn olacaktr:


0. 1. 2. 3. 4. argman: argman: argman: argman: argman: ./yeni_komut Merhaba Dnya Hello World

Dardan gelen argmanla alan bir baka main( ) fonksiyonu oluturalm. Toplama ve kartma ilemini alaca argmanlara gre yapan bir program aada bulabilirsiniz:
#include<stdio.h> #include<stdlib.h> #include<string.h> int main( int argc, char *arg[] ) { // Eger eksik arguman soz konusuysa, // program calismamalidir. if( argc < 4 ) { printf( "Hata: Eksik argman!\n"); return; } float sayi_1, sayi_2; char islem_tipi[2]; sayi_1 = atof( arg[1] ); strcpy( islem_tipi, arg[2] ); sayi_2 = atof( arg[3] ); // Verilen sembolun neye esit oldugu asagidaki // if-else if merdiveniyle saptaniyor. if( !strcmp( islem_tipi, "+" ) ) printf( "Toplam: %.2f\n", sayi_1 + sayi_2 ); else if( !strcmp( islem_tipi, "-" ) ) printf( "Fark: %.2f\n", sayi_1 - sayi_2 ); else printf( "Hatal ilem!\n" ); return 0;

Program altrmak iin u tarz bir komut verdiimizi dnelim:


$ ./hesapla 4 + 12

Program bu ekilde altrdnz zaman argmanlarn, parametrelere atanmas aadaki gibi olur: arg[ 0 ] ./hesapla arg[ 1 ] arg[ 2 ] 4 + arg[ 3 ] 12

Btn fonksiyonlara, program iersinden argman aktarm yaparken; main( ) fonksiyonuna program dndan deer gnderebiliyoruz. Unix komutlarnn hemen hemen hepsi bu ekildedir. DOS komutlarnn birou da byle yazlmtr. main( ) fonksiyonun parametre alp almamas gerektiine, ihtiyacnza gre sizin karar vermeniz gerekir.

rnek Sorular
Soru 1: Kendisine verilen bir katarn boyutunu bulan fonksiyonu yaznz. ( zm iin strlen( ) fonksiyonunu kullanmaynz. ) Cevap 1:

#include<stdio.h> #include<string.h> int katar_boyutu_bul( char [] ); int main( void ) { char test_katari[50]; strcpy( test_katari, "ABCDEF" ); printf( "Katar boyutu: %d\n", katar_boyutu_bul( test_katari ) ); return 0; } int katar_boyutu_bul( char katar[] ) { int i; for( i = 0; katar[ i ]!='\0'; i++ ); return i; }

Soru 2: Tersinden de ayn ekilde okunabilen kelime, cmle veya msraya 'palindrome' denmektedir. Ad palindrome( ) olan ve verilen katarn tersinin kendisine eit olduu durumda geriye 1; aksi hlde 0 dndren fonksiyonu yaznz. Cevap 2:
#include<stdio.h> #include<string.h> int palindrome( char [] ); int main( void ) { char test_katari[50]; strcpy( test_katari, "ABBA" ); printf( "%d\n", palindrome( test_katari ) ); return 0; } int palindrome( char katar[] ) { int boyut =0 , i; // Once katar boyutu bulunuyor for( boyut = 0; katar[ boyut ]!='\0'; boyut++ ); for( i = 0; i < boyut/2; i++ ) { if( katar[i] != katar[ boyut - i - 1 ] ) return 0; } return 1; }

Soru 3: Aadaki gibi alp, kt retebilecek "ters_cevir" programn oluturunuz.


$ ./ters_cevir Merhaba Dunya Nasilsin? abahreM aynuD ?nislisaN

Cevap 3:
#include<stdio.h> #include<string.h> void ters_cevir( char [] ); int main( int argc, int arg[] ) { int i; for( i = 1; i < argc; i++ ) { ters_cevir( arg[i] ); }

printf("\n"); return 0; } void ters_cevir( char katar[] ) { int i, boyut; for( boyut = 0; katar[ boyut ]!='\0'; boyut++ ); for( i = 0; i < boyut; i++ ) printf("%c", katar[ boyut - 1 - i ] ); printf(" ");

Yeni Deiken Tipi Oluturma


Kullandmz birok deiken tipi oldu. Tam saylar, karakterleri, virgll saylar, katarlar grdk. Ancak kullanabileceimiz deiken tipleri bunlarla snrl deildir. Kendi deiken tiplerimizi, yaratabiliriz. rnein boolean diye yeni bir tip yaratarak, bunun alabilecei deerleri true ve false olarak belirleyebiliriz; nc bir ihtimal olmaz. Ya da mevsimler diye bir deiken tipi belirleyip, alabilecei deerleri aylar olarak kstlayabiliriz. te bu tarz ilemleri yapmak iin enum kullanlr. enum kelimesi, enumerator yani 'sayc', 'numaralandrmac'dan gelmektedir. Hayat, rakamlarla ifade edilebilir. Bunun en bariz uygulamalarn programlama yaparken grrsnz. Bir karakter olan A harfi, ASCII Tablo'da 65 saysna denk der; byk B harfiyse 66'dr ve bu byle devam eder. Bilgisayarnz iaretlerden, sembollerden, karakterlerden anlamaz. Onun iin tek gereklik saylardr. te enum bu felsefeye hizmet ediyor. rnein doruyu gstermek iin 1, yanl iinse 0' seersek; yeni bir deiken tipi belirlemi oluruz. Bilgisayar dorunun ya da yanln ne olduunu bilmez, onun iin sadece 0 ve 1 vardr. Ancak insanlarn yararna, okunurluu artan programlar ortaya kar. sterseniz, boolean diye tabir ettiimiz deiken tipini oluturalm:
#include<stdio.h> int main( void ) { // Degisken tipinin nasil olacagini tanimliyoruz enum boolean { false = 0, true = 1 }; // Simdi de 'dogru_mu' adinda bir degisken // tanimliyoruz enum boolean dogru_mu; // Tanimladigimiz 'dogru_mu' degiskenine // deger atayip, bir alt satirda da // kontrol yapiyoruz. dogru_mu = true; if( dogru_mu == true ) printf( "Doru\n" ); return 0; }

Daha nce boolean diye bir veri tipi bulunmuyordu. imdiyse, iki farkl deeri olabilen, doru ve yanllar gstermekte kullanabileceimiz yeni bir deiken tipi oluturduk. Yanl gstermek iin 0; doruyu ifade etmek iinse 1 rakamlar kullandk. Yanln ve dorunun karln belirtmemiz gerekmiyordu; boolean veri tipini tanmlarken, 0 ve 1 yazmadan sadece false ya da true da yazabilirdik. Programnz derlenirken, karlk girilmeyen deerlere srayla deer atanmaktadr. lla ki sizin bir eitlik oluturmanz gerekmez. Mesela ana rengi ( Krmz, Sar ve Mavi )alabilecek ana_renkler veri tipini oluturalm:

#include<stdio.h> int main( void ) { // Degisken tipinin nasil olacagini tanimliyoruz enum ana_renkler { Kirmizi, Mavi, Sari }; // Degiskeni tanimliyoruz. enum ana_renkler piksel; // Degisken degerini Mavi olarak belirliyoruz. // Dilersek Sari ve Kirmizi da girebiliriz. piksel = Mavi; // Degisken degeri karsilastiriliyor. if( piksel == Kirmizi ) printf( "Krmz piksel\n" ); else if( piksel == Mavi ) printf( "Mavi piksel\n" ); else printf( "Sar piksel\n" ); return 0;

Kirmizi, Mavi ya da Sari'nin nmerik deerini bilmiyoruz; muhtemelen birden balam ve srayla e kadar devam etmilerdir. Deerlerin nmerik karln bilmesek bile, bu onlarla ilem yapmamz engellemiyor. Bir nceki rnekte olduu gibi rahata kullanabiliyoruz. Oluturduumuz yeni veri tiplerinden, deiken tanmlarken her defasnda enum koyduumuzu grmsnzdr. Bunu defalarca yazmak yerine iki alternatif biim bulunuyor. Birincisi yeni veri tipini olutururken, deikeni tanmlamak eklinde... boolean rneimize geri dnp, farkl ekilde nasl tanmlama yapabileceimizi grelim:
#include<stdio.h> int main( void ) { // Yeni veri tipini olusturuyoruz // Ayrica yeni veri tipinden, // bir degisken tanimliyoruz. enum boolean { false = 0, true = 1 } dogru_mu; dogru_mu = true; if( dogru_mu == true ) printf( "Doru\n" ); return 0; }

Yukarda grdnz yntem, yeni veri tipini oluturduunuz anda, bu veri tipinden bir deiken tanmlamanz salar. Her seferinde enum yazmanzdan kurtaracak dier yntemse, typedef kullanmaktan geer. typedef kullanm u ekildedir:
typedef veri_tipi_eski_adi veri_tipi_yeni_adi

Kullanacanz typedef ile herhangi bir deiken tipini, bir baka isimle adlandrabilirsiniz. rnein yazacanz "typedef int tam_sayi;" komutuyla, deiken tanmlarken int yerine tam_sayi da yazabilirsiniz. Bunun enum iin uygulamasna bakalm:

#include<stdio.h> int main( void ) { // Yeni veri tipini olusturuyoruz // Ayrica yeni veri tipinden, // bir degisken tanimliyoruz. enum boolean { false = 0, true = 1 }; // Alttaki komut sayesinde, boolean // veri tipini tek adimda yaratabiliyoruz. typedef enum boolean bool; bool dogru_mu; dogru_mu = true; if( dogru_mu == true ) printf( "Doru\n" ); return 0; }

zel Deiken Tipleri ve Fonksiyonlar


enum konusu geniletilebilir. rnein enum tanmlamasn, global olarak yaparsanz, fonksiyon parametresi olarak kullanabilirsiniz. ok basit bir fonksiyon oluturalm. Alaca deiken bilgisine gre, ekrana ona dair bilgi yazdrlsn:
#include<stdio.h> // Ay listesini olusturuyoruz. Ocak // ayi 1 olacak sekilde, aylar sirayla // numerik degerler aliyor. enum ay_listesi { ocak = 1, subat, mart, nisan, mayis, haziran, temmuz, agustos, eylul, ekim, kasim, aralik }; // Degisken tanimlamasini kolaylastirmak // icin typedef kullaniliyoruz. aylar diyerek // tanimlama yapmak mumkun hale geliyor. typedef enum ay_listesi aylar; void ay_ismini_yazdir( aylar ); int main( void ) { // aylar tipinde bir degisken // yaratip, 'kasim' degerini atiyoruz. aylar bu_ay = kasim; // kasim, numerik olarak 11'i ifade edecektir. printf( "%d. ay: ", bu_ay ); // fonksiyonumuzu cagiriyoruz. ay_ismini_yazdir( bu_ay ); return 0; } // Kendisine verilen aylar tipindeki degiskene gore // hangi ayin oldugunu ekrana yazmaktadir. void ay_ismini_yazdir( aylar ay_adi ) { switch( ay_adi ) { case ocak: printf( "Ocak\n" );break; case subat: printf( "ubat\n" );break; case mart: printf( "Mart\n" );break;

} }

case case case case case case case case case

nisan: printf( "Nisan\n" );break; mayis: printf( "Mays\n" );break; haziran: printf( "Haziran\n" );break; temmuz: printf( "Temmuz\n" );break; agustos: printf( "Austos\n" );break; eylul: printf( "Eyll\n" );break; ekim: printf( "Ekim\n" );break; kasim: printf( "Kasm\n" );break; aralik: printf( "Aralk\n" );break;

Grdnz gibi enum ile oluturacanz zel veri tiplerini fonksiyonlara aktarmak mmkn. enum aracl ile yeni bir deiken tipi yaratmak, birok konuda iinizi basit hle getirir. zellikle gruplandrlmas/tasnif edilmesi gereken veriler varsa, enum kullanmak yararldr. rnek olmas asndan aada enum ile tanmlanm baz veri tiplerini bulabilirsiniz:
enum medeni_durum { bekar, evli, dul }; enum medeni_durum ayse = bekar; enum egitim_durumu { ilkokul, ortaokul, lise, universite, master }; enum egitim_durumu ogrenci; enum cinsiyet { erkek, kadin }; enum cinsiyet kisi;

Yaplar ( Structures )
Yaplar ( structures ); tam say, karakter vb. veri tiplerini gruplayp, tek bir at altnda toplar. Bu gruplandrma iinde ayn ya da farkl veri tipinden dilediiniz sayda eleman olabilir. Yaplar, nesne tabanl programlama ( Object Oriented Programming ) dilleri iin nemli bir konudur. Eer Java, C# gibi modern dillerle almay dnyorsanz, bu konuya daha bir nem vermeniz gerekir. Vakit kaybetmeden bir rnekle konumuza girelim. Doum gn bilgisi isteyip, bunu ekrana yazdran bir program oluturalm:
#include<stdio.h> int main( void ) { struct { int yil; int ay; int gun; } dogum_gunu; printf( "Doum gnnz " ); printf( "GG-AA-YYYY olarak giriniz> "); scanf( "%d-%d-%d", &dogum_gunu.gun, &dogum_gunu.ay, &dogum_gunu.yil ); printf( "Doum gnnz: " ); printf( "%d/%d/%d\n", dogum_gunu.gun, dogum_gunu.ay, dogum_gunu.yil ); return 0; }

Bir kullancnn doum gnn sorup, gn, ay ve yl bilgilerini farkl int deiken iersinde tutabilirdik. Ancak gruplandrmak her zaman daha iyidir. Hem yaptnz ilerin takibi kolaylar, hem de hata yapma riskinizi azaltr. Bunu daha iyi anlatmak iin ayn anda sizin ve iki kardeinizin

doum gnlerini soran bir program yazalm:


#include<stdio.h> int main( void ) { struct { int yil; int ay; int gun; } siz, kiz_kardes, erkek_kardes; printf( "Doum gnnz giriniz> "); scanf( "%d-%d-%d", &siz.gun, &siz.ay, &siz.yil ); printf( "Kz kardeiniz> " ); scanf( "%d-%d-%d", &kiz_kardes.gun, &kiz_kardes.ay, &kiz_kardes.yil ); printf( "Erkek kardeiniz> " ); scanf( "%d-%d-%d", &erkek_kardes.gun, &erkek_kardes.ay, &erkek_kardes.yil ); return 0; }

Eer yaplardan ( structures ) yararlanmasaydk; kiinin doum gn bilgilerini tutmak iin toplamda 9 adet farkl deiken tanmlamak gerekecekti. Tanmlama zahmeti bir yana, deikenlerin kartrlma ihtimali de ayr bir sknt yaratacakt. Sadece deiken olarak dnmeyelim; nfus czdan bilgilerini soracamz bir program, yirminin zerinde deikene ihtiya duyar. Bu kadar ok deiken barndrp, yaplar kullanmadan hazrlanacak bir program grmek bile istemezsiniz. Yaplar kullanmann bir dier avantaj, kopyalama konusundadr. rnein, sizin bilgilerinizi, erkek kardeinize kopyalamak iin tek yapmanz gereken, "erkek_kardes = siz" yazmaktr. Bu basit ilem ilgili btn deikenlerin kopyalamasn yapar.

e Yaplar
Bir yap iersine tpk bir deiken koyar gibi, bir baka yap da koyulabilir. rnein kullanc bilgisi alan bir programda, isim, boy ve doum tarihi bilgilerini ayn yap altna toplayabilirsiniz. Ancak doum tarihi bilgilerini daha alt bir yap iersinde tutmak yararl olabilir. Bunu koda dkersek yle olur:
#include<stdio.h> int main( void ) { struct { char isim[40]; int boy; struct { int yil; int ay; int gun; } dogum_bilgileri; } kisi; printf( "Adnz: " ); scanf( "%s", kisi.isim ); printf( "Boyunuz: " ); scanf( "%d", &kisi.boy );

printf( "Doum tarihi: "); scanf( "%d-%d-%d", &kisi.dogum_bilgileri.gun, &kisi.dogum_bilgileri.ay, &kisi.dogum_bilgileri.yil ); printf( printf( printf( printf( "Girilen bilgiler:\n" ); "sim: %s\n", kisi.isim ); "Boy: %d\n", kisi.boy ); "Doum tarihi: %d/%d/%d\n",

return 0; }

kisi.dogum_bilgileri.gun, kisi.dogum_bilgileri.ay, kisi.dogum_bilgileri.yil );

Alt yapya ulamak iin nokta kullanp, ardndan yapnn adn yazdmz gryorsunuz. Yaplar kullanarak, bir arada durmas yararl olan deikenleri gruplarz. ie yaplar kullanaraksa, bu gruplandrmay daha da ufak boyutlara indirgemekteyiz. Ksacas her ey, daha derli toplu alma iin yaplyor. Yoksa programn temelinde deien bir ey yok.

Yap Etiketleri
Yaplara etiket koyabilir ve etiketleri kullanarak ilgili yapy temel alan deikenler tanmlayabilirsiniz. Az evvel yaptmza benzer bir rnek yapalm:
#include<stdio.h> #include<string.h> int main( void ) { // sahis_bilgileri, yapimizin // etiketidir. struct sahis_bilgileri { char isim[40]; int boy; }; // Yapidan iki adet degisken // tanimliyoruz. struct sahis_bilgileri kisi_1; struct sahis_bilgileri kisi_2; // Birinci sahsin bilgilerini // kaydediyoruz. strcpy( kisi_1.isim, "AHMET" ); kisi_1.boy = 170; // Ikinci sahsin bilgilerini // kaydediyoruz. strcpy( kisi_2.isim, "MEHMET" ); kisi_2.boy = 176; } return 0;

Yaplarn etiket konarak tanmlanmas, daha mantkldr. Aksi hlde sadece yapy olutururken tanmlama yaparsnz. Etiket koyduunuz zamansa, programn herhangi bir yerinde istediiniz kadar yap deikeni tanmlayabilirsiniz. nemli bir noktay belirtmek isterim: yaplarda etiket kullandnz zaman elinizde sadece bir ablon vardr. O etiketi kullanarak yapdan bir deiken yaratana kadar, zerinde ilem yapabileceiniz bir ey olmaz. Yap ( structure ) bir kalptr; bu kalbn etiketini kullanarak deiken tanmlamanz gerekir.

Yaplarda lk Deer Atama


Yaplarda da ilk deer atamas yapabilirsiniz. Aadaki rnek etiket kullanmadan oluturduunuz yaplarda, ilk deer atamasnn nasl olduunu gstermektedir. 'kisi' isimli yap iersinde bulunan isim ve boy deikenlerine srasyla Ali ve 167 deerleri atanmaktadr.
#include<stdio.h> int main( void ) { // kisi adinda bir yapi olusturulup // baslangic degerleri 'Ali' ve '167' // olacak sekilde atanir. struct { char isim[40]; int boy; } kisi = { "Ali", 167 }; return 0; }

Etiket kullanarak oluturduunuz yaplarda, ilk deer atamas deikenlerin tanmlanmas aamasnda gerekleir. nce yapy kurar ve ardndan deiken tanmlarken, ilk deerleri atarsnz. Kullanm aadaki kod iersinde grlmektedir:
#include<stdio.h> int main( void ) { // sahis_bilgileri adinda bir yapi // olusturuyoruz struct sahis_bilgileri { char isim[40]; int boy; }; // sahis_bilgileri yapisindan kisi adinda // bir degisken tanimliyoruz. Tanimlama // esnasinda atanacak ilk degerler belirleniyor. struct sahis_bilgileri kisi = { "Ali", 167 }; return 0; }

Bir yap deikenine, ilk deer atamas yapyorsanz sra nemlidir. Atayacanz deerlerin sras, ilgili deikenlere gre olmaldr. Yani ilk yazacanz deer, ilk yap ii deikene; ikinci yazacanz deer, ikinci yap ii deikene atanr. Sray armadnz srece bir problem yaamazsnz. Aksi durumda, yanl deer yanl deikene atanacaktr. Sray armak iin, ekstra ayra iaretleri kullanabilirsiniz. rnein { "Mehmet", 160, 23, 3, 1980 } yerine { "Mehmet", 160, {23, 3, 1980} } yazmakta mmkndr.

Yap Dizileri
Veri tiplerine ait dizileri nasl oluturacamz biliyoruz. Bir tam say dizisi, bir karakter dizisi rahatlkla oluturabiliriz. Benzer ekilde yap ( structure ) dizileri de tanmlanabilir. 3 kiilik bir personel listesi tutacamz dnp, ona gre bir program oluturalm. Her eleman iin ayr ayr deiken tanmlamaya gerek yoktur; yaplardan oluan bir dizi yaratabiliriz.
#include<stdio.h> int main( void ) { int i; // Dogum tarihi tutmak icin

// 'dogum_tarihi' adinda bir yapi // olusturuyoruz struct dogum_tarihi { int gun; int ay; int yil; }; // Kisiye ait bilgileri tutmak // icin 'sahis_bilgileri' adinda // bir yapi kuruluyor. struct sahis_bilgileri { char isim[40]; int boy; // Yapi icinde bir baska yapiyi // kullanmak mumkundur. dogum_tarihi // yapisindan 'tarih' adinda bir // degisken tanimlaniyor. struct dogum_tarihi tarih; }; // Dizi elemanlarina ilk deger atamasi yapiyoruz. Dilerseniz // klavyeden deger girmeyi tercih edebilirsiniz. struct sahis_bilgileri kisi[3] = { "Ali", 170, { 17, 2, 1976 }, "Veli", 178, { 14, 4, 1980 }, "Cenk", 176, { 4, 11, 1983 } }; // Yapi dizisi yazdiriliyor: for( i = 0; i < 3; i++ ) { printf( "Kayt no.: %d\n", ( i + 1 ) ); printf( "Ad: %s\n", kisi[i].isim ); printf( "Boy: %d\n", kisi[i].boy ); printf( "Doum Tarihi: %d/%d/%d\n\n", kisi[i].tarih.gun, kisi[i].tarih.ay, kisi[i].tarih.yil ); } return 0; }

Tek bir yap deikeniyle, bir yap dizisi arasnda byk fark bulunmuyor. Sadece keli parantezlerle eleman indisini belirtmek yetiyor. Yoksa, deer okuma, deer yazma... bunlarn hepsi tpatp ayn. Bu yzden ayrca detaya inmiyorum.

Yap Dizilerine Pointer ile Eriim


Kambersiz dn olmaz. Ayn ekilde, dizilerden bahsettiimiz bir yerde pointer'lardan bahsetmemek mmkn deil. Bir yap dizisinin balang adresini pointer'a atadnz takdirde, elemanlara bu iareti zerinde de ulaabilirsiniz. Bir stteki rneimizi pointer'larla kullanalm:
#include<stdio.h> int main( void ) { int i; // Dogum tarihi tutmak icin // 'dogum_tarihi' adinda bir yapi // olusturuyoruz struct dogum_tarihi { int gun; int ay; int yil; };

// Kisiye ait bilgileri tutmak // icin 'sahis_bilgileri' adinda // bir yapi kuruluyor. struct sahis_bilgileri { char isim[40]; int boy; // Yapi icinde bir baska yapiyi // kullanmak mumkundur. dogum_tarihi // yapisindan 'tarih' adinda bir // degisken tanimlaniyor. struct dogum_tarihi tarih; }; struct sahis_bilgileri *ptr; // Dizi elemanlarina ilk deger atamasi yapiyoruz. Dilerseniz // klavyeden deger girmeyi tercih edebilirsiniz. struct sahis_bilgileri kisi[3] = { "Ali", 170, { 17, 2, 1976 }, "Veli", 178, { 14, 4, 1980 }, "Cenk", 176, { 4, 11, 1983 } }; // Yapi dizisi yazdiriliyor: for( i = 0, ptr = &kisi[0]; ptr <= &kisi[2]; ptr++, i++ ) { printf( "Kayt no.: %d\n", ( i + 1 ) ); printf( "Ad: %s\n", ptr->isim ); printf( "Boy: %d\n", ptr->boy ); printf( "Doum Tarihi: %d/%d/%d\n\n", ptr->tarih.gun, ptr->tarih.ay, ptr->tarih.yil ); } } return 0;

Pointer'n tanmlamasn yaparken, 'sahis_bilgileri' ablonundan tretilen deikenlerin iaret edileceini bildirmemiz gerekiyor. Yazm olduumuz "struct sahis_bilgileri *ptr;" kodu bundan kaynaklanmaktadr. for dngsne gelirsek, kisi isimli yap dizisinin ilk elemannn adresini, ptr iaretisine atadmz grmsnzdr. Her seferinde de, ptr deeri bir adres blou kadar artmaktadr. Dngnn devam, adresin son dizi elemanndan kk olmasna baldr. Kullandmz -> operatryse, pointer ile dizi elemanlarn gstermemizi salar. Bu cmleler size muhtemelen kark gelecektir -ki bu kesinlike normal... nanyorum ki kodu incelerseniz, durumu daha basit kavrarsnz.

Yaplar ve Fonksiyonlar
enum ile yarattmz deiken tiplerini, fonksiyonlarda kullanmak iin global olarak tanmlyorduk. Yaplar, fonksiyonlarda kullanlmak iin izlenecek yntem ayndr; yine global tanmlanmas gerekir. ok basit bir rnekle yaplarn fonksiyonlarla kullanmn grelim:
#include<stdio.h> #include<string.h> struct sahis_bilgileri { char isim[40]; int boy; }; struct sahis_bilgileri bilgileri_al( void ); void bilgileri_goster( struct sahis_bilgileri ); int main( void )

struct sahis_bilgileri kisi; kisi = bilgileri_al( ); bilgileri_goster( kisi );

return 0; } struct sahis_bilgileri bilgileri_al( void ) { struct sahis_bilgileri sahis; printf( "sim> " ); gets( sahis.isim ); printf( "Boy> " ); scanf( "%d", &sahis.boy ); return sahis; } void bilgileri_goster( struct sahis_bilgileri sahis ) { printf( "Ad: %s\n", sahis.isim ); printf( "Boy: %d\n", sahis.boy ); }

Dinamik Yaplar
Dinamik bellek tahsis etmenin ne olduunu, niin bunu kullandmz aklamaya gerek duymuyorum. Daha nceki derslerimizde bu konuya yer vermitik. ok basit bir rnekle dinamik yaplarn kullanm gstermek yeterli olacaktr:
struct sahis_bilgileri *ptr; ptr = calloc( 1, sizeof( struct sahis_bilgileri ) ); free( ptr );

admda, yaplar dinamik kullanmay gryorsunuz. En bata ptr adnda bir pointer tanmlyoruz. kinci aamada, bellek ayrm yaplyor. Bu rnekte, sadece tek deikenlik yer ayrlyor. ptr ile iimiz bittikten sonra, free( ) fonksiyonuyla, bellei boaltyoruz. Sadece temel admla, yaplarda dinamik bellek kullanmn salayabilirsiniz. Yalnz calloc( ) ( ya da malloc( ) ) fonksiyonunun stdlib.h altnda olduunu unutmayn. ( Bu yzden kodun bana #include<stdlib.h> yazmak gerekmektedir. )

Yaplarda typedef Kullanm


enum konusuna tekrar dnyoruz. Hatrlayacanz zere, typedef orada da gemiti. typedef kullanarak her seferinde fazladan enum yazma zahmetinden kurtuluyorduk. typedef, yaplar iin de kullanlmaktadr. Her defasnda tekrar tekrar struct yazmak yerine, bir kereye mahsus typedef kullanarak bu zahmetten kurtulabilirsiniz. Aadaki gibi yazacanz kodla, tekrar tekrar struct kelimesi kullanmanza gerek kalmayacaktr.
typedef struct sahis_bilgileri kisi_bilgileri;

Noktalarken...
C programlama diline dair anlatmlarmz burada bitiyor. Bu demek deildir ki; C zerine her eyi anlattk; aksine daha birok konu bulunuyor. ( rnein dosya ilemleri, union kullanm vb... konulara hi deinilmedi. ) Ancak imdiye kadar rendikleriniz, bundan sonrasn renebilmeniz iin size temel tekil edecektir. Programlama dili renmek, yabanc dil renmekle hemen hemen ayndr. ngilizce zerine dersler aldnzda, kimse Shakespeare olacanz syleyemez. Ama ok alp kendinizi gelitirmek size baldr. Programlama dilleri de aynen byle... Burada ya da bir

baka kaynakta anlatlanlarla iin duayeni olamazsnz; fakat ii anlar duruma gelirsiniz. Bundan sonras sizin elinizdedir... Ltfen bol bol pratik yapp, olabildiince ok algoritma kurun. Sizlere temel programlama gramerini vermeye altm; umarm sonunda hepiniz birer "Macbeth" yazarsnz!

You might also like