Yazılım ve Program Dillerinin Sınıflandırılması

YAZILIMIN SINIFLANDIRILMASI -Bilimsel MühendislikYazılımlar -Görüntüsel Yazılımlar -Mesleki ve Ticari Yazlımlar -Sistem Yazılımları --ĠĢletim Sistemleri --Derleyiciler --Editörler --Debug programları -Yapay Zekâ Yazılımları PROGRAMLAMA DĠLLERĠNĠN SINIFLANDIRILMASI -Seviyelerine göre -Uygulama alanlarına göre 1)Seviyelerine Göre Programlama dilinin insan anlayıĢına yakınlığı… Ġnsana yakın Çok yüksek programlama dilleri(Dbase,Clipper,Vbasic,Paradox,Access) Yüksek seviyeli programlama dilleri(Fortran,Basic,Pascal,Cobol) Orta seviyeli programlama dilleri( C ) Sembolik makina dilleri(Assembler)

Makinaya yakın 2)Uygulama Alanlarına Göre -Bilimsel ve mühendislik dilleri(Fortran,C,Pascal) -Sistem programlama dilleri(C,Assembler) -Veri tabanı dilleri(Dbase,Clipper) -Yapay zekâ dilleri(Prolog, LISP) -Genel amaçlı(C,Pascal, Basic)

2

Programlama Dillerinin Değerlendirilmesi -TaĢınabilirlik -Verimlilik -Veri yapıları ve türleri -Alt programlama yeteneği: --Avantajları: ---Kodu küçültür ---Algıyı kolaylaĢtıtır ---Test imkânını arttırır ---Yeniden kullanılabilirliliği arttırır -Esneklik -Yapısallık -Nesne yönelimlilik -Öğrenme kolaylığı TEMEL KAVRAMLAR -ĠĢletim sistemi -Derleyiciler

C kaynak kodu Derleyici

makine dili(0,1) [amac program] Derleyicinin Hata Mesajları

1)Uyarılar(warning) 2)Gerçek hatalar(error) 3)Fatal error: Derleme iĢleminin bitirilmesini engelleyecek büyüklükteki hatalar. Derleyici .OBJ .C Linker .EXE SAYI SĠSTEMLERĠ VE ĠKĠLĠK SĠSTEM Ġkilik sistemde yezılmıĢ sayının her basamağına 1 bit denir.Bilgisayarda heseplamalar 2‟lik sistemde yapılır ve öyle kaydedilir. 1 byte=8 bit 1 kilobyte=1024 byte 1 byte içerisindeki tüm dizilimlerin sayısı 2*2*2*2*2*2*2*2=256‟dır. 00000000 ………... ………...

3

11111111 Sayısal olarak 0-255 arası. Bilgisayarda makina komutları da yazılar da sayılar da 1ve 0‟lar olarak korunur… Tamsayıların 2‟lik Sistemde Tutulması -ĠĢaretsiz sistem -ĠĢaretli sistem Tam sayılar iĢaretli veya iĢaretsiz sistemde tutulabilirler.ĠĢaretsiz sistemde sayılar hep pozitif kabul edilirler..ĠĢaretli sistem (genellikle bu kullanılır) pozitif ve negatif sayıların yazılabildiği sitemdir.. ĠĢaretli Sistemde Sayıların Gösterimi Negatif bir sayı bilgisayarda -1100 gibi tutulmaz.nagatiflik için de 1 ve 0‟larla gösterilir.Bu konuda 3 sistem önerilmiĢtir.. 1.Sistem X0101101=> x=1 ise negatif x=0 ise pozitif Bu sistemde yazılabilecek en büyük sayı 01111111=+127 en küçük sayı ise 11111111=-127.Bu sistemde iki tane 0 vardır. 00000000 ve 10000000 Toplamada da sorunları vardır.. +10= 00001010 10= 10001010 00001010 + 10001010 = 10010100 = -20 Bu sistemde +n ile –n toplandığında –2n yapar..

2.Sistem(1‟e tümleme) 0=>+ 1=>1‟e tümleme sayı içindeki 1‟lerin 0, 0‟ların 1 yapılmasıdır.Pozitif ve negatif sayılar birbirlerinin 1‟e tümleyenleridir.. +10=00001010 -10=11110101 Bu sistemde negatif bir sayı yazmamız istenirse önce sayının pazitifini yazar sonra !2 tümleriz.Bu sistemde yazılabilecek en büyük sayı 011111111, en küçük sayı 100000000.1.sistemde olduğu gibi 2 tane 0 var(00000000,111111111)

4

Toplama hatası yok. 3.Sistem(2‟ye tümleme) Sayının 1‟e tümleyenine 1 eklenerek sayının 2‟ye tümleyeni bulunmuĢ olur.. 101011010101001001010011 Ya da sayının sağından soluna doğrı ilk 1‟i görene kadar (ilk 1 dahil) aynısı ilk 1‟den sonra 0‟ları 1 1‟leri 0 yapılabilir. Bu sistemde de problemli bir sayı vardır.: 10000000Bu sayının 2‟ye tümleyeni alınamaz.Problemli olan bu sayıya –128 değeri verilmiĢtir. (C‟de en büyük pozitif sayıya 1 eklenirse en küçük negatif tam sayı elde edilir.127+1=-128) 16‟lık Sayı Sistemi(Hexadecimal) 0 0000 1 0001 ikiliğe 2 0010 3 0011 4 0100 5 0101 6 0110 7 0111 8 1000 9 1001 A 1010 B 1011 C 1100 D 1101 E 1110 F 1111 8‟lik Sistem 0 000 1 001 2 010 3 011 4 100 5 101 6 110 7 111

1A13=3+1*16+10*16*16+1*16*16*16 16‟lık sistemdeki herbir digite 4 bit karĢılık düĢer.16‟lıktan dönüĢüm kolaydır. FC18=1111 1100 0001 1000

5

Yazıların Bellekte Tutulması Her karakter ascii tablosunda 8 bitlik bir dizilim olaraka tutulmaktadır.Ascii tablusu 256 giriĢli bir tablodur.Yani karakterler 1 byte‟lık sayılardır.C‟de örneğin bir karakter aritmetik iĢlemlere sokulabilir. Bu durumda karakterin ascii numarası iĢleme sokulmaktadır.(„A‟+1=66) C'NĠN YAZIM KURALLARI BoĢluk Karakterleri SPACE,TAB,ENTER 1)Atomlar arasında yazım kuralları Ġstenildiği kadar boĢluk bırakılabilir(#'li satırlar hariç) ÖRNEK: #include <stdio.h> main ( { )

printf ; }

(

"merhaba c\n"

)

2)Atomlar istenildiği kadar bileĢik yazılabilir... ÖRNEK: #include <stdio.h> main(){printf("merhaba c\n");} C'nin VERĠ ve NESNE TÜRLERĠ Her değiĢken ve sabitin bir türü olmak zorundadır.Tür bilgisi ile derleyici 2 Ģeyi anlar: 1)O nesne için kaç byte ayıracaktır. 2)O nesne içindeki 1 ve 0'lar nasıl yorumlanacaktır(iĢaretli,iĢaretsiz,tam,reel)

6

BĠLDĠRĠM ve TANIMLAMA Programlama dillerinin çoğunda bir nesne kullanılmadan önce nesnenin özelliklerinin derleyiciye açıklanması gerekir.Bu iĢleme bildirim denir... Nesne özellikleri: -Ġsmi -Türü -Faaliyet alanı -Ömrü -Diğer Bildirim ĠĢleminin Genel Biçimi <tür belirtne anahtar sözcük> <değiĢken ismi> ÖRNEK: int a; unsigned long b; double weight; int a,b; DeğiĢken Ġsimlendirme Kuralları -DeğiĢken ismi numerik bir karakterle baĢlayamaz... -DeğiĢken ismi boĢluk içeremez...(BoĢluk yerine "_" kullanılır) -Ġsimlendirme karakteri olarak ingilizce karakterler kullanılabilir.(Türkçe karakterler kullanılamaz) -DeğiĢkenin karakter uzunluğu konusunda belirli bir standart yoktur ancak 32 sayısı kullanılmaktadır.. -Case sensitive'dir.Büyük küçük harf kullanımı değiĢkenleri farklılaĢtırır...C'nin bütün anahtar sözcükleri küçük harftir.. Bildirim ĠĢlemi Nerede Yapılmalıdır? 1-Blokların baĢlarında 2-Tüm blokların dıĢında 3-Fonksiyon parametresi olarak parantezin içinde 1.a)Blokların baĢında yapılan bildirimler

7

Fonksiyon ana bloğu içerisinde istenildiği kadar iç içe ya da ayrık blok açılabilir.Tabi bloklar birbirini kesemez.Blok baĢı demekle küme parantezinin hemen sonrası denilmektedir.. (C++'da yerel değiĢkenler bloğun her yerinde tanımlanabilir) Tanımlama Kavramı Bir bildirimde belekte yer ayrılıyorsa tanımlamadır..Özellikle belirtilmediyse her bildirim iĢlemi de tanımlama iĢlemidir. ÖRNEK: #include <stdio.h> main () { int x; x=10; } Sabitler Doğrudan yazılmıĢ sayılara sabit denir. C'de sabitlerin de türleri vardır. Bir sabitin türü nitelikle ya da sayının sonuna getirilen eklerle belirtilir.. -Signed Int Sabitler ĠĢaretli int sınırları içerisinde kalan ve sonuna ek almamıĢ sayılar otomatik olarak signed int sabiti olarak belirlenirler -40000 =>Dos'ta int değil ama unix'te int -Signed Long Int Sabitler 1- 10L =>Signed long int olarak belirtilmiĢtir. 2- Int sınırını aĢmıĢ sayılar otomatik olarak sonunda L veya l olsun olmasın long sabiti olarak kabul edilirler.. (0 (sıfır) C'de her tür sabit anlamına gelmektedir ve istisnadır) ÖNCEDEN TANIMLANMIġ KARAKTER SABĠTLERĠ '\a' => 7 nolu ASCII çan sesi çıkarır '\b' => 8 nolu ASCII backspace '\f' => feedform '\r' => enter '\n' => line feed

8

'\t' => 9 nolu ASCII tab karakteri '\0' => 0 nolu ASCII null karakter HEX SĠSTEMDE YAZILMIġĠ KARAKTER SABĠTLERĠ '\xhh' , '\x13' ,'\x1' ... Önce bir \ sonra x sonra da iki haneli bir hex sayı yazılırsa o hex sayıya karsılık gelen karakter sabiti elde edilmiĢ olunur. '\x61' = 'a' OKTAL SĠSTEMDE YAZILMIġ KARAKTER SABĠTLERĠ '\0ooo' , '\0117' , '\010' ... Uyarı '\' geçersiz bir karakter sabitidir..ekrana \ basılmak isteniyorsa '\\' karakter sabiti uygulanmalıdır. SIGNED SHORT SABĠTLER C'de short türünden bir sabit yoktur. FLOAT SABĠTLER c'de bir sayı nokta içerirse ve sonunda "f" varsa bu sabit float olarak nitelendiririlir. DOUBLE SABĠTLER Bir sayı nokta içeriyorsa ve sonunda f veya F yoksa double olarak düĢünülür. LONG DOUBLE SABĠTLER Sayı nokta içeriyorsa ve sonuna l veya L içeriyorsa long double düĢünülür. ĠġARETSĠZTAMSAYI SABĠTLER Sayının sonuna u veya U getirilirse sayı aynı türün unsigned'ı olarak anlaĢılır. 10u => unsigned integer 100L => long intereger 100LU =>unsigned long integer (bunun yerine 100UL de aynı anlama gelirdi..) C'de unsigned tipinde bir sabit yoktur. C'de sağ taraf ve sol taraf değerleri farklı türlerden olabilir. printf FONKSĠYONUNUN KULLANIMI

9

printf fonksiyonu ile değiĢkenlerin içindeki değerler ekrana yazdırılabilir. printf(.....); #include <stdio.h> main() { int a; a = 10; printf("a=%d\n",a); /* burada %d ",'den sonraki a deiĢkeninin /*değerinin ekrana yazılacağını gösteriyor*/ } FORMAT KARAKTERLERĠ %d => int türünü 10'luk sistemde %x => int türünü 16'lık sistemde %l => long türünü 10'luk sistemde %lx => long türünü 16'lık sistemde %f => float ve double türünü %lf => double türünü %c => karakter görüntüsünü %s => string görüntüsünü yazdırmaya yarar. TANIMLAMA SIRASINDA DEĞĠġKENLERE ĠLK DEĞER VERĠLMESĠ int i = 200; int a, b = 10, c; TAMSAYI SABĠTLERĠNĠN 10'LUK 16'LIK VE 8'LĠK SĠSTEMLERDE GÖSTERĠLĠġĠ a = 123; 10'luk a = 0x123; 16'lık a = 0123; 8'lik sistemde.... Hexadesimal sistemde yazılmıĢ bir sayının iĢareti (-,+'lığı) bitleriyle zaten bellidir. 0xFF13 = (1111 1111 0001 0021) en baĢtaki 1 zaten negatif olduğunu anlatıyor. Bu sabitin kaçlık sistemde yazıldığıyla hangi türden olduğu arasında bir iliĢki yoktur. Belirtilmesi gerekliyse yukarıda anlatıldığı gibi davranılmalıdır. sayısal */

10

0xFF13L => long int gibi.. GERÇEK SAYI SABĠTLERĠNĠN ÜSTEL BĠÇĠMDE GÖSTERĠMĠ 3.2E+23 => 3.2*10^23 1.2e-17 => 1.2*10^-17 Üstel formda yazılan sayı ya float ya da double olmalıdır. FONKSĠYONLAR [geri dönüĢ değeri] <fonksiyon ismi>([paramatre]) { ANABLOK } Her fonksiyon ard arda tanımlanır.Ġç içe fonksiyon tanımlanamaz... YanlıĢ fonksiyon kullanımına örnek: main() { fonk() { } } Olması gereken: main() { } fonk() { } Hiçbir fonksiyon 1'den fazla tanımlanamaz.En azından aynı isme sahip olmaz. Fonksiyonlara örnek: #include <stdio.h>

11

main() { printf("Ben main'im\n"); fonk1(); fonk2(); } fonk1() { printf("Ben 1.fonksiyonum\n"); } fonk2() { printf("Ben 2. fonksiyonum\n"); fonk3(); } fonk3() { printf("Ben 3. fonksiyonum\n"); } FONKSĠYONLARIN GERĠ DÖNÜġ DEĞERLERĠ(RETURN VALUE) int x; x = fonk(); Bir fonksiyonun çalıĢması bittikten sonra onu çağıran fonksiyona gönderdii değere geri dönüĢ değeri denir. Fonksiyonların geri dönüĢ değerleri aritmetik iĢlemlere sokulabilir. x = fonk() + a; gibi.. GERĠ DÖNÜġ DEĞERĠ OLUġTURULMASI VE return ANAHTAR SÖZCÜĞÜ fonk() { printf("Ben fonk'um\"); return 100; } main()

12

{ int a; a = fonk(); printf("fonk'un geri dönüĢ değeri=%d\n",a); } return anahtar sözcüğünün iki iĢlevi vardır: 1-Fonksiyonun çalıĢmasını bitirir.Bu durumda akıĢ, onu çalıĢtıran fonksiyonda devam edecektir. 2-Geri dönüĢ değeri oluĢturur. Kullanım biçimi => return [ifade] return ĠFADESĠ NASIL OLUġTURULUR? return'ün yanındaki ifade önce derleyici yarafından programcının eriĢemediği geçici bir bölgeye alınır,oradan kullanılır.Örneğin a = fonk(); iĢleminde Ģunlar yapılır: temp = fonk(); a = temp; Bu iĢlem bize aksettirilmez. Fonksiyonun geri dönüĢ türü aslında geçici bölgenin türünü gösterir.return ifadesinin oluĢturulması da geçici bölgeye yapılan gizli bir atamadır. long fonk() { printf("Ben fonk'um\"); return 123000L; } main() { long a; a = fonk(); printf("%ld\n",a); } return anahtar sözcüğü kullnılmıĢsa fonksiyon ana bloğu bittiğinde sonlanır.Fonksiyonda return ile belirli bir değer veilmemiĢse rastgele bir geri dönüĢ değeri verilecektir. Bir fonksiyonun geri dönüĢ değerine sahip olması kullanılmasını gerektirmez. Fonksiyon baĢında void yazılırsa foksiyonun geri dönüĢ değerinin olmadığı analtılır. void fonk() {

13

} Böyle fonksiyonlarda return anahtar sözcüğü fonksiyonu sonlandırmak için kullanılır.void bir fonksiyonun geri dönüĢ değeri olmadığı için geri dönüĢ değeri kullanımaya çalıĢılmamalıdır. void fonk() { printf("selam\n"); return; } main() { int a; a = fonk();/*bu kullanım tamamen yanlıĢ*/ printf("%d\n",a);/*bu kullanım tamamen yanlıĢ*/ } void FONKSĠYONA NEDEN ĠHTĠYAÇ VARDIR? 1-void anahtar sözcüğü okunabilirliği arttırır. 2-Geri dönüĢ değerine sahip olmayan fonksiyonları void olarak tanımlarsak yeni derleyiclerin vereceği uyarılardan kurtuluruz. Parametre yerine void koyarsak fonksiyonun parametre almadığını gösteririz. main fonksiyonunun da bir geri dönüĢ değeri vardır.main'e geri dönüĢ değeri çıkĢ kodu olarak(exit code) gönderilir.Bu değer iĢletim sisteminden daha sonra istenebilir.Ancak böyle bir bilgiye seyrek olarak ihtiyaç duyulur. KLAVYEDEN KARAKTER ALAN STANDART C FONKSĠYONLARI 1-getchar fonksiyonu #include <stdio.h> void main(void) { char ch; ch = getchar(); printf("%d %c\n", a, a); } Bu fonksiyon bir tuĢa ve ardından enter'a basılana kadar bekler. Basılan tuĢun ASCII sıra numarasıyla geri döner.

14

2-getche fonksiyonu Enter'a gereksinim duymaz.Bir tuĢa basıldığı anda görüntülenme sağlanabilir. #include <stdio.h> void main(void) { char ch; ch = getche(); printf("%d %c\n", ch, ch); } 3-getch fonksiyonu Bu fonksiyon da tuĢa basar basmaz alır ama basılan tuĢu göstermez.Basılan tuĢu görmek için printf ile yazırmak gerekir. Bu fonksiyon daha çok programın bir tuĢ alınana kadar bekletilmesini sağlamak için kullanılır. KLAVYEDEN HER TÜRLÜ BĠLGĠ ALAN FONKSĠYON(scanf) scanf fonksiyonu printf fonksiyonu gibi format karakterleri alır. Ancak bu karakterler klavyeden yapılan giriĢi belirlemekte kullanılır. #include <stdio.h> void main(void) { int a; printf("sayı="); scanf("%d", &a); printf("%d", a); } scanf fonksiyonunun string kısmında format karakterleri dıĢında hiçbirĢey konulmamalıdır.Buraya konulacak boĢluk bile farklı anlama gelir. scanf fonksiyonunun diğer parametrelerinin önünde ampersan(&) operatörü bulunur. scanf ile birden fazla değiĢken giriĢi yapılabilir. #include <stdio.h>

15

void main(void) { int a; long b; printf("sayılar="); scanf("%d %ld", &a, &b); printf("%d %ld\n", a, b); } NESNELERĠN FAALĠYET ALANLARI VE ÖMÜRLERĠ Faaliyet alanları: Bir nesnenin derleyici tarafından tanınabildiği program aralığını gösterir.3 tür faaliyet alanı vardı. 1-Blok faaliyet alanı:Yalnızca bir blokta tanınır. 2-Fonksiyon faaliyet alanı:Bir fonksiyonun her yerinde tanınır. 3-Dosya faaliyet alanı:Programın her tarafında tanınır. NESNELERĠN FAALĠYET ALANLARINA GÖRE SINIFLANDIRILMASI 1-Yerel değiĢkenler: Blokların baĢlarında tanımlanmıĢ değiĢkenler yerel değiĢkenlerdir. Bunlar tanımlandıkları blokta kullanılırlar.(blok faaliyet alanı) void main(void) { int a; { int b; } } Burda a main fonksiyonunun tamamında b ise sadeec içteki blok'ta geçerlidir.Farklı faaliyet alanlarına sahip değiĢkenler aynı ada sahip olabilir. main() { int a = 10; { int a = 20; } }

16

Farklı faaliyet alanlarına iliĢkin aynı isimli nesneler için farklı yerler ayrılır.Bir blok içierisinde aynı isimli birden fazla değiĢken faaliyet gösteriyorsa, o blok içerisinde değiĢken kullanıldığında dar faaliyet alanı olan kullanılır. 2-Global değiĢkenler Tüm blokların dıĢında tanımlanan değiĢkenlere global değiĢkenler denir.Dosya faaliyet alanı kuralına uyar.Kaynak kodun her yerinde tanınır. #include <stdio.h> int a; void fonk(void) { a = 20; } void main(void) { a = 10; fonk(); printf("%d\n", a);/*ekrana 20 değeri basılır*/ } #include <stdio.h> int a;/*global*/ void fonk(void) { a = 20;/*global a'ya atanan değer*/ } void main(void) { int a;/*yerel*/ a = 10;/*yerel a'ya atanan değer*/ printf("%d\n", a);/*ekrana 10 değeri basılır*/ } Global değiĢkenler herhangi bir yerde tanımlanabilir,ancak tanımlandıkları yerden daha yukarda derleyici tarafından etspit edilemezler.Bu durumda global değiĢkenler için en iyi tanımlama yeri programın tepesidir.yani include dosyalarının hemen altıdır.

17

3-Parametre değiĢkenleri Bir fonksiyon parametre alabilir.Bunun için parametre değiĢkenlerinin tanımlanması gerekir.Ġki ayrı yöntemel parametre bildirimi yapılır. a.Eski biçim: void fonk(a,b) int a; long b; { } b.Yeni biçim void fonk(int a,long b) { } Bu biçimde parametre değiĢkenlerĢ aralarına virgül konularak tanımlanır. void fonk(int a,b)/*YANLIġ TANIMLAMA*/ Bu değiĢkenler fonksiyon faaliyet alanı kuralına uyarlar.Parametre değiĢkenine sahip bir fonksiyon aynı sayıda değiĢkenle çağırılmalıdır. PARAMETRE AKTARIM KURALI Parametreli bir fonksiyon çağırıldığında derleyici önce parametrelerden parametre değerlerine karĢılık atama yapar, daha sonra programın akıĢı fonksiyona geçirilir. #include <stdio.h> int add(int a, ,int b) { return a + b; } void main(void) { int x = 10, y = 20, z; z = add(x, y); printf("%d\n", z);

18

} Fonksiyonlar sabitlerle de çağırılabilrler. fonk(10, 20); gibi.. BAZI MATEMATĠK FONKSĠYONLAR #include <stdio.h> #include <math.h> sqrt fonksiyonu double olarak aldığı bir sayıyı kare kökü olarak geri döndürür. sin, cos, tan, atan hepsinin parametresi ve geri dönüĢ değeri double #include <stdio.h> int kare(int x); { return x * x; } void main(void) { printf("%d\n", kare(10)); } Bir fonksiyonun parametresi bir diğerinin geri dönüĢ değeri olabilir. NESNELERĠN ÖMÜRLERĠ Ömür:Nesnenin bellekte yer kapladığı zaman aralığına ömür denir. Nesnelerin ömürleri 2 gruba ayrılır. 1-Statik ömürlü nesneler:Bu nesneler programın belleğe yüklenmesiyle yaratılırlar.Program bitince hafızadan atılır. 2-Dinamik ömürli nesneler:Programın belli bir aĢamasında yaratılırlar, belirli bir süre faaliyet gösterdiktensonra kaybedilirler. YEREL DEĞĠġKENLERĠN ÖMÜRLERĠ Dinamik ömürlüdürler.Programın akıĢı bloğa girdiğinde yaratılırlar, bloğun çalıĢması bittiğinde bellekten çıkarılırlar. GLOBAL DEĞĠġKENLERĠN ÖMÜRLERĠ Statik ömürlüdürler.Programın baĢından sonuna kadar bellekta kalırlar.

19

PARAMETRE DEĞĠġKENLERĠNĠN ÖMÜRLERĠ Dinamik ömürlüdürler.Fonksiyon çağırıldığında yaratılırlar, fonksiyon çalıĢması bittiğinde bellekten silinirler.Parametreli bir fonksiyonun çağırılmasında Ģunlar olmaktadır. 1-Parametre değiĢkeni yaratılır. 2-Değer ataması yapılır 3-Programın akıĢı fonksiyona yönledirilir. Ömürle faaliyet alanı arasındaki iliĢki programın faaliyet alanına girdiğinde değiĢken yaratılır, faaliyet alanından çıktığında değiĢken sonlandırılır. Ġçerisine değer verilmemiĢ yerel değiĢkenlerin içinde rastgele değerler vardır.Bir değer atanmamıĢ global değiĢkenlerin içerisinde ise 0 değeri vardır.Parametre değiĢkenlerine değer atanmaması söz konusu değildir. OPERATÖRLER Bir iĢleme yol açan, iĢlem sonucunda belirli bir değer üretilmesini sağlayan atomlara operatör denir. OPERATÖRLERĠN SINIFLANDIRILMASI 1-ĠĢlevlerine göre a.Aritmetik operatörler(+,*,/...) b.ĠliĢkisel operatörler(<,<,<=,...) c.Mantıksal operatörler(AND,OR,NOT,XOR,..) d.Bit operaörleri(belli bir sayının kaçıncı bitinin kaç olduğu hakkında bilgi verir) e.Gösterici operatörleri f.Özel amaçlı operatörler 2-Operand sayılarına göre a.Ġki operand alanlar (binary) b.tek operand alanlar (unary) c.Üç opernd alanlar (ternary) 3-Operatörün konumuna göre yapılan sınıflandırma a.Ara ek operatörler (infix) b.Ön ek operatörle (prefix) c.Son ek operatörleri (postfix) C'nin bütün iki operand alan operatörleri infix'tir.Bir operatörün teknik olarak tanımlanması için bütün bu gruplardaki yerinin belirtilmesi gerekir.Örneğin 4 binary infix aritmetik operatördür. OPERATÖRLER ARASI ÖNCELĠK ĠLĠġKĠSĠ Bir operatörün diğerinegöre bir öncelil sırası vardır.Bu sıra operatörlerin öncelik tablosu denilen bir tabloyla belirtilir.

20

Tabloda üstteki satrda bulunanlar attakilerden daha önceliklidir. Aynı satırda bulunanlar eĢit önceliklidir.Aynı öncelikli operatörlerle soldan sağa ya da sağdan sola iĢlem yapılır. ARĠTMETĠK OPEARATÖRLER +, -, *, / binary, infix % OPEARÖRÜ Binary infix bir operatördür.Bölüm iĢlemideki kalanı hesaplar. ++ VE -- OPERATÖRLERĠ ++ arttırma -- eksiltme operatörüdür. Ġkisi de unary operatörlerdir.Postfix ve prefix olarak kullanılabilir. Postfix ve prefiz kullanımda fark vardır. ++a => a = a + 1; Bu operatörler baĢka hiçbir operatör olmadan tek baĢlarına kullanılmıĢsa aralarında fark olmaz. void main(void) { int a = 10; ++a; printf("%d\n", a);/*11*/ --a; printf("%d\n", a);/*10*/ a++; printf("%d\n", a);/*11*/ a--; printf("%d\n", a);/*10*/ } Eğer baĢka operatörlerle beraber kullanılıyorlarsa prefix durumda tabloda belirtilen öncelikle iĢlemler yapılır.Eğer postfix durumda kullanılmıĢsa bütün iĢlemler yapıldıktan sonra yani ifadenin son iĢlemi olacak biçimde arttırma ya da eksiltme yapılır. void main(void) { int b, a = 10; b = ++a; printf("a=%d b=%d", a, b);/*a=11 b=11*/ b = a++; printf("a=%d b=%D", a, b);/*a=12 b=11*/

21

} void main(void) { int a = 10, b = 20, c; c = a++ * b++; printf("c=%d b=%d a=%d", c, b, a);/*c=30 b=21 a=11*/ } ġÜPHELĠ KODLAR ++ veya -- operatörlerinin bilinçsizce ve kötü kullanımları derleyiciler arasında yorum farklııklarına yol açarak taĢınabilirliği bozar.Böyle kolardan kaçınmk gerekir. 1-Üç tane + operatörü boĢluk olmaksızın yanyana getirilmemelidir.(+++) 2-Bir değiĢken ++ veya -- ile kullanılmıĢsa bir daha aynı ifade içerisinde ++ veya -operatörleriyle gözükmemelidir.(hata: b = ++a + ++a;) 3int multiply(int a, int b) { return a * b; } void main(void) { int a, b = 10; a = multiply(b, ++b);/*hata:derleyicinin parametreleri ne sırayla*/ /*aktardığı derleyiciye göre değiĢir.*/ printf("%d\n", a); } Bir fonksiyon çağırılırken parametrelerden birinde ++ veya -- kullanılmıĢsa diğer parametrelerde aynı değiĢken kullanılmamalı, çünkü parametre aktarım sayısı her sistemde aynı olmayabilir. fonk(++a);/*Doğru:önce a arttırılır sonra yeni a değeriyle fonk çağırılır*/ fonk(a++);/*Doğru:önce fonk çagırılır sonra a arttırılır*/ ĠLĠġKĠSEL OPERATÖRLER < > <= >= == != C'de 6 iliĢkisel operatör vardır.Hepsi binary infix operatörlerdir. Aritmetik operatörlerden daha düĢük önceliklilerdir. ĠliĢkisel operatörlerin ürettiği değer önerme doğruysa 1 yanlıĢsa 0'dır

22

void main(void) { int a; a =10 > 5; printf("a=%d\n", a);/*a=1*/ } Bu operatörlerden elde edilen değerler baĢka operatörlerle iĢleme sokulabilir. MANTIKSAL OPERATÖRLER(&&) C'de 3 tane mantıksal operatör vardır. AND && OR || NOT ! AND OPERATÖRÜ A | B | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | A&&B 0 0 0 1

Mantıksal operatörlerin hepsi önce operandlarını doğru ya da yanlıĢ olarak yorumlar, eğer sonuç doğruysa 1, yanlıĢsa 0 sayısal değerini üretir. Yorumlamada kural:eğer operand 0 dıĢı bir değerse doğru olarak, 0 ise yanlıĢ olarak yorumlanır.Uygulama da iliĢkisel operatörlerle birlikte kullanılırlar. && operatörünün önce sol tarafı tam olarak bitirilir.Daha sonra sağ tarafı yapılır ve bitirilir.Eğer sol tarafın sayısal değeri 0 ise sağ tarafın yapılmasına gerek kalmaz. Örneğin x > 10 && fonk() burada x 10'dan küçükse fonk hiç çağırılmayacaktır. OR OPERATÖRÜ(||) OR iĢlemi iki operand da yanlıĢsa yanlıĢ,operandlardan en az birisi doğruysa doğru sonucunu üretir. a 0 0 1 1 | | | | | b 0 1 0 1 | | | | | a||b 0 1 1 1

Bu operatör de 1 ya da 0 tamsayı değerini üretir.

23

void main(void) { int x,y; scanf("%d",&y); x = y < 10 || y > 50; printf("%d\n",x);/*girilen y değeri 10'dan küçük veya 50'den*/ /*büyükse ekrana 1 değeri basılacaktır.*/ } OR operatörünün önce sol tarafı yapılır.Eğer sol taraf değeri 0 dıĢı bir değerse sağ tarafın yapılmasına gerek kalmaz. NOT OPERATÖR(!) Bu operatör unary prefixtir.Zaten öncelik tablosunun ikinci düzeyi tamamen unary operatörlere ayrılmıĢtır. a | !a 0 | 1 1 | 0 Yani bu operatör operand 0 ise 1 , 0 dıĢı herhangibir değerse 0 yapar. void main(void) { int x,a = 10; x = !!a; printf("%d\n", x);/*a = 10, !a = 0, !(!a) = 1, ekrana 1 basılır*/ } ATAMA OPERATÖRÜ(=) Bu operatçr binary, infix bir operatördür.Atama operatörünün sol tarafındaki operandın nesne olması gerekir. Buradan hareketle ++ ve -- operatörlerinin operandlarının da nesne olması gerekir. Atama operatöründe elde edilen değer sağ taraftaki operandın sayısal değeridir. void fonk(int n) { printf("%d\n", n); } void main (void)

24

{ int x = 10, y; fonk(y = x); } z = y = x = 10; ifadesi doğru olduğu gibi, z = (y = 10) + 2; ifadesi de doğru ve geçerlidir. ĠġLEMLĠ ATAMAM OPERATÖRLERĠ(+=, -=, *=, /=) Öncelik sırasında atama operatörüylesağdan sola eĢit öncelik sırasında bulunurlar. void main (void) { int x = 12; x += 5;/*x=x+5(sonuc 17)*/ x -= 5;/*x=x-5(sonuç 17)*/ x /= 3;/*x=x/3(sonuç 4)*/ } Bu operatörlerin de sol tarafındaki operandları nesne olmalıdır. VĠRGÜL OPERATÖRÜ(,) Binary, infiz bir operatördür ve en düĢük önceliğe sahiptir.Ġki ifadeyi birleĢtirir.Önce sol taraf yapılır sonra sağındaki ifade yapılır. void main(void) { int x,y; x = 10, y = 20; printf("%d %d\n", x, y);/*x=10 y=20*/ } , operatörü sağ tarafındaki ifadenin sayısal değerini üretir. Ġstenilen operatörler parantez kullanılarak virgül dıĢına çıkarılabilirler. z = (x = 3,y = 4) + 2;/*iĢ1:x=3, iĢ2:y=4,iĢ3: ,=4 ,iĢ4:4+2=6, iĢ5:z=6*/ Her virgül virgül operatörü değildir.Örneğim fonk(a, b); buradaki virgül fonksiyon parametre ayıracıdır. fonk((a, b));buradaki , ise virgül operatörüdür. NOKTALI VĠRGÜLÜN ĠġLEVĠ

25

a = b + c;/*iĢ1=b+c, iĢ2=a=iĢ1*/ ; bir iĢlemin sonlandırıldığını anlatmak için kullanılır.Yani iki ; arasındaki kısım bağımsız olarak iĢlem sırasına göre yapılacaktır.Eğer ; unutulursa derleyici iki ifadeyi tek bir ifade zanneder.Bu da bir syntax error oluĢmasına neden olur.(Error:Statement missing ; in function...) #include <stdio.h> void main(void) { int x, y = 10; x = y +2 =>Statement missing ; in funciton main z = 10 + x; printf("%d %d\n", x, y); } OKUNABĠLĠRLĠĞE ĠLĠġKĠN KURALLAR 1-Ġki space üst üste kullanılmaz,bir space'in yetmediği yerde bir tab kullanılır.Tab ayarının 4 yapılması uygundur. 2-Bütün fonksiyonlar ilk sütuna dayalı olarak yazılır.Fonksiyonlar arasında bir satır boĢluk bırakılır.include satırlarından sonra da bir boĢluk bırakılır. 3-Her bloğun için bir tab içeriden yazılır. 4-Binary operatörlerle operandlar arasında boĢluk bırakılır(a = b). Bildirimden sonra bir satır boĢluk bırakılır. int a; a = 10; 5-Unary operatörlerle operandlar arasında boĢluk bırakılmaz. 6-Mümkün olduğunca her satıra bir ifade yazılır. 7-Virgülden sonra bir boĢluk bırakılır(önce değil). 8-Parantezlerden önce ya da sonra boĢluk bırakılmaz. 9-Noktalı virgül bitiĢik yazılır IF DEYĠMĠ Bir ifadenin sonuna noktalı virgül konursa, buna deyim denir. Deyimler gruplara ayrılabilir. 1-Yalın deyimler: ifade; biçimindekiler.. 2-BirleĢik deyimler: { ifade1; ifade2;

26

} Bir bloğun içerisinde 1 ya da birden fazla deyim varsa ona bileĢik deyim denir. 3-Bildirim deyimleri 4-Kontrol deyimleri if (...) { } Program akıĢı üzerinde etkili olan if gibi for, while gibi deyimlerdir. 5-BoĢ deyimler Solunda ifade olmadan konulan ;'e boĢ deyim denir. x = 10; ; ; son iki noktalı virgül boĢ deyimdir. BoĢ deyim görüldüğünde derleyici hiçbir Ģey yapmaz. IF DEYĠMĠNĠN GENEL BĠÇĠMĠ 1if (ifade) ifade; else ifade; 2if (ifade) { ifade1; ifade2; } else { ifade3; ifade4; } If Nasıl ÇalıĢır? Derleyici if deyimindeki ifadenin sayısal değerini hesaplar.Bu değer 0 dıĢı bir değer ise if kısmı,ifadenin değeri 0 ise ifadenin else kısmı yapılır. void main(void) { int a; printf("Sayı="); scanf("%d", &a); if (a >= 10 && a <=20) printf("%d sayısı 10 ile 20 arasındadır\n", a); else printf("değildir\n");

27

} Örnek:Klavyeden alınan iki sayının toplamının 100'den küçük olup olmadığını test eden programın yazılması: void main(void) { int a, b, c; printf("Ġki sayı giriniz:"); scanf("%d %d", &a, &b); c = a + b; if (c < 100) printf("%d 100'den küçüktür\n", c); else printf("%d 100'den büyüktür"\n", c); } KARAKTER TEST FONKSĠYONLARI C'de ismi "isxxxx" ile baĢlayan, geri dönüĢ değeri int, parametresi char olan bir grup fonksiyon vardır. x = isalpha('a');/*isalpha=alfanumerik mi?*//*x<>0*/ x = isupper('a');/*isupper=büyük harf mi?*//*x=0*/ Bu fonksiyonlar parametresiyle girilen karakterleri test ederler.Test olumluysa 0 dıĢı herhangi bir sayı ile geri dönerler, olumsuzsa 0 değerine geri dönerler. Bu fonksiyonları kullanabilmek için ctype.h'ın include edilmesi gerekir.(#include <ctype.h>) #include <stdio.h> #include <ctype.h> void main(void) { char ch; ch = getchar(); if (isupper(ch)) printf("%c büyük harf\n", ch); else printf("%c küçük harf\n", ch); }

28

Örnek:isupper fonksiyonunun Türkçe veriyonunun istrkupper biçiminde yazılması. #include <stdio.h> #include <ctype.h> int istrkupper(char ch)/*baĢtaki int geri dönüĢ değerini gösteriyor*/ { if (ch == 'Ç' || ch == 'ġ' || ch == 'Ġ' || ch == 'Ö' || ch == 'Ü' || ch == 'Ğ') return 1; else return isupper(ch); } void main(void) { char ch; ch = getchar(); if (istrkupper(ch)) printf("%c büyük harf", c); else printf"%c küçük harf", c); } Else kısmı olmayan if deyimi if (ifade) { Ġfade1; Ġfade2; } ifade3; if‟i yanlıĢlıkla boĢ deyimle kapatmak sıkça yapılan bir hatadır. BoĢ deyimle kapatılan if‟ten sonraki deyim dolayısıyla if‟in dıĢında düĢünülür. Ġç Ġçe if deyimler Bir if‟in doğruysa ya da yanlıĢsa kısmında baĢka bir if bulunabilir. Bir if doğruysa ya da yanlıĢsa kısmıyla birlikte dıĢarıdan bakıldığında tek bir deyim olarak ele alınır. if(ifade1){ if(ifade2){ ifade3; ifade4;

29

} else ifade5; ifade6; } else ifade7; ifade8; Ġki if‟den sonra gelen else içteki if‟e aittir. if(ifade1) if(ifade2) ifade3; else ifade4; ifade5; Eğer bu else‟in dıĢtaki if‟in olması isteniyorsa bilinçli blok açılmalıdır. if(ifade1){ if(ifade2) ifade3; } else ifade5; ifade5; Else-if durumları if(ch == ‟a‟) printf(“a\n”); if(ch == „b‟) printf(“b\n”); if(ch == „a‟) printf(“a\n”); else if(ch == „b‟) printf(“b\n”); Else if durumları özellikle bir olasılık gerçekleĢtiğinde baĢka bir olasılığın gerçekleĢme olasılığı mümkün olmadığı durumlarda karĢılaĢtırma sayısını azaltmak için kullanılır. ĠF DEYĠMĠNDE BOġ DEYĠMĠN KULLANILMASI: If deyiminin sonuna ; konulursa buradaki ; boĢ deyim demektir ve bütün if deyiminin biçimi değiĢebilir. BÜYÜK KÜÇÜK HARF DEĞĠġTĠRMESĠ YAPAN FONKSĠYONLAR: "char toupper(chr chr)"

30

toupper fonksiyonu parametresi ile belirtilen karakter küçük harf ise onun büyük harf karĢılığı ile geri döner ; değil ise değiĢiklik yapmadan aynısı ile döner.Bu fonksyon kullanılırken "#include <ctype.h>" yapılmalıdır. tolower parametresi ile belirtilen karakter büyük harf ise geri dönüĢ olarak onun küçük harf karĢılığını verir. Değilse aynı karakter ile geri döner. putchar FONKSĠYONU: Bu fonksiyon parametresi ile belirtilen fonksiyonun görüntüsünü ekrana basar. eĢdeğeri : printf("%c",ch) dır. DÖNGÜLER Döngü bir programın belirli bir kısmının yinelemeli olarak çalıĢtırılmasını sağlayan kontrol deyimlerine döngü denir. C'de döngüler ikiye ayrılır: 1--> while döngüleri 1-a-> kontrolun baĢta yapıldığı while döngüleri 1-b-> kontrolun sonda yapıldığı whilw döngüleri 2--> for döngüleri Kontrolun baĢta yapıldığı while döngüleri: "genel biçim" 1> while (ifade) ifade1; 2> while (ifade) { ifade1; ifade2; } while döngüsünün çalıĢma biçimi: Derleyici while paranteszi içindeki ifadenin sayısal değerini hesaplar eğer bu nonzero ise döngünün devamına karar verilir ve döngü deyimleri çalıĢtırılır. eğer ifadenin sayısal değeri 0 ise döngini çalıĢması sonlandırılır, programın çalıĢması döngü dıĢındaki ilk deyimle devam eder. eğer while parantezinden sonra bloklama yapılmıĢ ise tüm blok döngü içindedir yapılmamıĢ ise yanlızca ilk deyim döngü içindedir. Sınıf çalıĢması: Birden 100'e kadar (100 dahil) sayılarının toplamını döngü yoluyla hesaplayan bir program yazınız. while döngüsü içinde virgül operatörüde sıklıkla kullanılır.

31

Bazı döngülerden while ifadesi ile çıkıĢ mümkün olmayabilir. Bunlara "infinite loop" denir. BREAK anahtar sözcüğü: Kullanımı: break; Programın akıĢı brewak anahtar sözcüğünü gördüğünde döngü kırılarak akıĢ döngü dıĢındaki ilk deyimle devam eder. Break anahtar sözüğü için bir döngünün içinde olmak gerekir dıĢarıda kullanılamaz. While para bntezi içinde postpix bi iĢlem varsa arttırım(aynı Ģekilde eksiltim) önce döngünün devam etme veya etmeme kararı verilir sonra arttırım veya azaltım yapılır. Kontrolun sonda yapıldığı : 1--> do ifade1; while (ifade2); 2--> do { ifade1; ifade2; ..... } while (ifade); Bu tür while döngülerine ender olarak rastlanır.kontrol yapılana kadar döngü deyimleri en az bir kere çalıĢtırılır. While döngülerinde boĢ deyimlerin kullanılması: genellikle while döngüleri yanlıĢlıkla boĢ deyimle kapatılır. while (++i<10); <-- hatalı bazen while döngüsü bilinçli olarak boĢ deyimle kapatılabilir, bu durumda ; bir tab içeriden yazılmalıdır FOR DÖNGÜLERĠ: Genel Biçim: 1-->for (ifade1; ifade2; ifade3) ifade4; 2-->for (ifade1; ifade2; ifade3;) { ifade4; ifade5; .... }

32

Derleyicinin for anahtar sözcüğünden sonra bir parantez açılmasını ve parantez içerisinde iki noktalı virgül bulunmasını bekler. Bu iki ; for deyimini 3'e ayırır. Bu kısımlar ifade1 , ifade2 , ifade3 ile gösterilir. For parantezinden sonra blok varsa bloğun içindekiler yoksa ilk deyim döngü içerisindedir. For döngüsünün ilk kısmı döngüye ilk giriĢte bir defa yapılır, bir daha iĢlem görmez. Ġkinci kısmı ilk giriĢte ve her yinelemede döngünün devam edip etmeyeceğine karar verir. For döngüleri ikinci kısmın değeri 0 dıĢı bir değer olduğu sürece devam eder. Üçüncü kısım döngü deyimleri çalıĢtırıldıktan sonra dönüĢte çalıĢtırılır. for(ilk değer; koĢul; iĢlem) { …. …. .… }

Örnek:0‟dan 99‟a kadar olan sayıların görüntülenmesi. void main(void) { int i; for(i = 0; i < 100; ++i) printf(“%d\n”, i); /*99‟a kadar olan sayıları basar*/ printf(“Son değere=%d\n”, i);/*100 değerini ekrana basacak*/ } Örnek:1‟den 100‟e kadar olan sayıların toplamı. void main(void) { int i, total = 0; for (i = 0; i < 100; ++i) total = total + i; printf(“Toplam=%d”, total); } Örnek: void main(void) { double i;

33

for(i = 0; i < 6.28; i = i + 0.01) printf(“%lf\n”, i); } Örnek: void main(void) { char ch; for(ch = getch(); ch != „q‟; ch = getch()) putchar(ch); } Örnek: void main(void) { for(printf(“Birinci kısım\n”); printf(Ġkinci kısım\n”), getch !=‟q‟; printf(“üçüncü kısım\n”)); } Sınıf çalıĢması:Birden 100‟e kadar olan tek ve çift sayıların toplamını bulduracak program. void main(void) { int i, odd_sum = 0, even_sum = 0; for(i = 1; i < 100; ++i) if ((i % 2) == 0) even_sum += i; else odd_sum += i; printf("Tek sayılar=%d\n", odd_sum); printf("Çift sayılar=%d\n", even_sum); } i = 1; for( ; i <100; ++i){ } for(;;){ } /*ifadesi tamamen geçerlidir*/

/*sonsuz döngü*/

ĠÇ ĠÇE DÖNGÜLER void main(void)

34

{ int i, k; for(k = 0; k < 10; ++k) for(i = 0; i < 10; ++i) printf(“%d %d\n”, i, k); } SWITCH DEYĠMĠ: bu deyim bir ifadenin çeĢitli sayısal değerlerine karĢı farklı iĢlemlerin yapılabilmesi için kullanılır. Genel biçim: switch (ifade) { case <s1>: case <s2>: case <s3>: ...... [default:] } switch deyiminin çalıĢma biçimi Ģöyledir:derleyici switch parantezi içindeki ifadenin sayısal değerini hesaplar, eğer bu sayısal değere uygun bir case ifadesi varsa program akıĢı oraya yönlendirilir, yoksa default (varsa Ģart değil) yönlendirilir. Eğer yoksa programın akıoĢıo switch dıĢındaki ilk deyimle devam eder. SABĠT ĠFADESĠ(CONSTANT EXPERSSĠON) Yanlızca sabitlerden ve operatörlerden oluĢan ifadelere denir, yani değiĢken yoktur. 6 6/3 7+2 3+x(bu değil) sabit ifadelerinin sayısal değeri derleme aĢamasında belirlenir ve programın çalıĢması ile değiĢmez. C'de pek çok yerde ve durumda sabit ifadesine gereksinim duyulur. Örneğin "case" ifadeleri sabit ifadeleri olmak durumundadır. case x+2 "olmaz" case 3+5 "olur" case 3/8 "olur" BREAK anahtar sözcüğünün switch içindeki kullanımı: Break anahtar sözcüğü switch içindede kullanılabilir bu durumda programın akıĢı switch dıĢındaki ilk deyime atlar. her case ifadesi break ile sonlandırılırsa her durumda yalnızca bir case yapılmıĢ olur.

35

case ifadelerinin okunabilir yazımı Ģöyledir eğer ifade çok küçük ise hepsi aynı satıra yazılabilir değil ise aĢağıdaki satırdan ve bir tab içeriden yazılır. Switch deyimi olmasa idi aynı Ģey en ekonomik else iflerle yapılabilirdi. Ancak tipik switch kullanımlarını kaçırmamak gerekir. Case ifadelerin sırlaı gitmesi yada defaultun sonda olması zorunlu değil ama hoca sonda olsa iyi olur diyoo.case ifadeleri tam sayı türünden olmak zorundadır gerçek sayı türleri olmuyooo.çünkü yuvarlama hatasına göre iki sayı birbirine çok yakın olabilir ama eĢit değildir bu durum programlamacıyı ĢaĢırtabilir Bir switch ifadesinde bir baĢka switch olabilir. KOġUL OPERATÖRÜ (CONDĠTĠONAL OPERATOR) KoĢul operatörü if deyimi gibi çalıĢan bir operatördür. Ġki sembolden oluĢur ?: (C'deki tek üç değiĢken alan operatör) bu operatör Ģöyle çalıĢır.... 1-->önce soru iĢaretinin solundaki ifade tam olarak yapılırburadan bir sayısal değer hesaplanır bu değer 0 dıĢı ise ? ile : arasındaki ifade değilse : dan sonraki ifade yapılır. KoĢul operatörü bir operatör oldğu için bir değer üretir. Ürettiği değer baĢka bir değiĢkene atanabilir yada iĢlemlerde kullanılabilir. bu operatörün ürettiği değer koĢul ifadesinin durumuna göre ? : arasındaki ifade yada : dan sonraki ifadenin sayısal değeridir.(koĢul operatörü ile yapılan herĢey if deyimi ile de yapılabilir.) Bu operatör öncelik tablosunda atama operatörünün hemen yukarısında bulunur. derleyiciye göre koĢul operatörünün tamamı tek operatördür. aĢağıdaki ifadede iki operatör vardır. b= a>0 ? 10+20 : 20+50 KOġUL OPERATRÖRÜNÜN OPERANTLARININ AYRIġTIRILMASI derleyici ? dan sola doğru koĢul operatöründen daha düĢük öncelikli operatör görene kadar ilerler (bu operatör ya atamadır yada iĢlemlisidir atama operatörünün) o kısma kadarki ifade 1. operandı oluĢturur. ? ile : arasındaki ifade 2. operant olarak ele alınır. derleyici : dan sağa doğru koĢul operatöründen daha düĢük öncelikli operatörü görene kadar ilerler o kısım 3. kısımdı b= a>0 ? x : y =z burada 3 operatör var iki tane atama ve birdane de koĢul ancak parantez kullnılarak operantlar bilinçli olarak ayrıĢtırılabilir. koĢul operatörü ile yapılan herĢey if deyimi ile karĢılanabilir. koĢul operatörü üzellikle bir ifadenin sayısal değerinin karĢılaĢtırma sonunda bir değiĢkene atanması gerektiği durumlarda okunabilirlik açısından tercih edilmelidir.KoĢul operatörünün kullanılmasının tavsiye edildiği 3 durum vardır 1--> bir karĢılaĢtırmanın sonucunun bir değiĢkene atandığı durumlar b= a>10 ? 20 : 30 if eĢdeğeri if (a>10) b=20 else b=30 2--> koĢul operatörü return ile beraber kullanılabilir

36

return (a%3==0)? 1:0; 3--> bir fonksyon çağırılırken parametre yerinekoĢul operatörüde konulabilir. fonk (a%3==0 ? 10 : 20) GOTO DEYĠMĠ goto kullanım biçimi: goto <etiket> . . etiket goto özellikle karmaĢık ifadeleri basitleĢtirmek için kullanılır. en tipik kullanımı içiçe döngülerden çıkmak yada döngü içinde switch varsa hem switch hem döngüden çıkmak için kullanılır. Örnek: void main(void) { char ch; for(;;){ ch = getch(); switch(ch){ case „x‟: putchar(„?‟);break; case „q‟: goro EXIT; default: } } EXIT: printf(“Program sonu..\n”); } FONKSĠYON PROTOTĠPLERĠ C‟de bir fonksiyonun çağırıldığını gören derleyici, çağırılma noktasına gelene kadar o fonksiyonun geri dönüĢ değerini tespit etmelidir. Çağırılma noktasına kadar geri dönüĢ değeri tespit edilmemiĢse C derleyicileri bu fonksiyonun geri dönüĢ değerinin int türünden olduğunu varsayarlar. Eğer çağrılan fonksiyon çağıran fonksiyonun daha yukarısında tanımlanmıĢsa derleyici derleme yönüne göre önce çağırılanı göreceği için çağırılma noktasına gelindiğinde çağırılan fonksiyonun geri dönüĢ değerini tespit etmiĢ olacaktır. Eğer çağırılan çağıranın daha altında tanımlanmıĢ ise ve çağırılan fonksiyonun geri dönüĢ değeri int dıĢında bir değerse derleyici error verecektir. void main(void) {

37

long x; x = fonk(); printf("%ld", x); } long fonk(void) { return 100000; }

/*derleyici “type mismatch in redeclaration in fonk” error mesajını verir*/

Bir fonksiyonun geri dönüĢ değerini derleyiciye bildirim yolu fonksiyon prototipleridir. Fonksiyon prototipleri bir bildirim iĢlemidir. Yani derleyiciye bilgi verilmiĢ olur. Tanım yapılmamıĢtır henüz. [geri dönüĢ değeri] <fonksiyon ismi> ([parametreler]); Prototipler için en iyi bildirim yeri include satırlarının sonrasıdır. Bir önceki örnekteki hatanın düzeltilmesi:

#include <stdio.h> long fonk(void); void main(void) { long x; x = fonk(); printf("%ld", x); } long fonk(void) { return 100000; } STANDART C FONKSĠYONLARININ PROTOTĠPLERĠ Standart C fonksiyonlarının prototiplerinin mutlaka bildirilmeleri gerekir. Yoksa derleyici geri dönüĢ değerini int varsayar ve hata verir. Standart C fonksiyonlarını prototiplerini yazmak yerine o fonksiyonların prototiplerini bulunduran dosyaların include edilmesi yeterli olur. stdio.h /*fonk fonksiyonun prototipi*/

38

conio.h math.h stdlib.h TÜR DÖNÜġTÜRMELERĠ: Farklı türlerin birbirine atanması: bu konu 4 baĢlıkta incelenebilir: 1-->Büyük tamsayı türünün küçük tamsayı türüne atanması 2-->Küçük tamsayının büyuük tam sayı türüne atanması 3-->Gerçek sayıdan tam sayı türlerine yapıolan atamalar 4-->Tamsayı türlerinden gerçek sayı türlerine atamalar. Büyük tamsayı türlerinden küçük tamsayı türlerine atamalar: int=long chr=int gibi durumlar incelenecektir. büyük tür küçük tüğre atanırken sayının yüksek anlamlı byte değerleri atılır, düĢük anlamlısı atanır yani bilgi kaybı sözkonusudur.(uyarı gerektirmez normal iĢlem olarak görülür.) Sayının yüksek anlamlı byte'ları kaybedildiği zaman sayı ilki ile ilgisiz hatta iĢaret değiĢtirmiĢ bile olabilir. Küçük tamsayı türünün büyük tamsayı türüne atanması: long =int int=char gibi durumlar Böyle bir atamada bilgi kaybı sözkonusu olmaz. Ancak tabi sayının iĢareti korunarak atanmaktadır. Eksi atıyorsak yüksek anlamlı bytelar ffff ile doldurulur. Pozitif atanıyor ise büyük türün yüksek anlamlı byteları 0000 ile doldurulur. Gerçek sayı türlerinden tam sayı türlerine yapılan atamalar: int=float long double Sayının noktadan sonraki kısmı atılır geri kalanı atanır. gerçek sayıu nokta kısmı atıldıktan sonra atanankısma yine sığmıyorsa bir dönüĢtürme daha yapılır.(örneğin 116517.3) Tam sayı türlerinden gerçek sayı türlerine yapılan atamalar: float=long Bu durumda sayı .0 biçiminde atanır.

39

ĠġLEM ÖNCESĠ OTOMATĠK TÜR DÖNÜġTÜRMELERĠ:(acaip önemli imiĢ) C derleyicileri bir operatör ile karĢılaĢtığında önce operantların türlerini araĢtırır, eğer ikiside aynı ise iĢlem doğrudan yapılır; eğer farklı türlerden ise önce operantlar aynı türe dönüĢtürülür sonra iĢlem yapılır. Özet olarak küçük tür büyük türe dönüĢtürülür. Küçük türün büyük türe dönüĢümünde yukarıdaki kural uygulanır, yani bilgi kaybı yoktur ve iĢareti korunur. c de iki operantda tam sayı türlerine iliĢkin ise bölmenin sonucu tam sayı çıkar. at5 te bilgi kaybı var. iĢlemin sonucu negatif çıkıyor çünkü long int'e atanıyor . ĠĢlem öncesi tür dönüĢtürmeleri yalnızca aritmetik operatörlerle değil iliĢkisel operatörlerlede yapılmaktadır. at4 de FC yi inte dönüĢtürürken fffc olarak dönüĢütürülür.ama unsignedchar olarak dönüĢütürürsek 00fc olarak dönüĢür. TÜR DÖNÜġTÜRME OPERATÖRÜ: Unary prefix bir operatördür ve aĢağıdaki gibi kullanılır. (tür) operant Bu operatör öncelik tabvlosund ikinci düzeyde sağdan sola bulunur DönüĢtürme iĢlemi bir iĢlemlik yapılıyordur. (long)(a*b)--> burada a*b ddönüĢütürülüyor. Küçük türün büyük türe dönüĢtürülme olayının istisnaları: 1--> Integral promotion: Char ve/veya short iĢlemlerinde heriki operantta int'e dönüĢütürülür. sonuç int türünden çıkar. char + char --->int oluyor (char) char+char ---> char'a bilinçli dönüĢtürülüyor. 2--> Aynı türün iĢaretli ve iĢaretsiz versiyonların iĢleme sokulur ise sonuç iĢaretsiz çıkar(bilgi kaybı oluĢmaması için). int + unsigned int --> unsigned int olur unsigned int + long---> long olur. 3--> Float ve long arasındaki iĢlemlerde floata doğru dönüĢütürme yapılır. 4--> ĠĢaretli bir tür iĢaretsiz bir türe dönüĢtürülürse sayının bit durumları değiĢmez. En yüksek anlamlı bit iĢaret biti olmaktan çıkar ve sayıyı oluĢturan bir bit haline gelir. Benzer biçimde iĢaretsiz bir tür iĢaretli bir türe dönüĢtürülürse en yüksek anlamlı bit iĢaret biti olarak yorumlanır. 5-->

40

ĠĢaret dönüĢtürmek için kullanılan + - ler unary prefix operatördürler. - operatörü -1 ile çarpılıyormuĢ gibi bir etki yaratır. ÖNĠġLEMCĠ KAVRAMI VE SEMBOLĠK SABĠTLER: Derleyiciler iki modülden oluĢur;ÖniĢlemci modülü ve derleme modülü; Derleme iĢleminin tüm iĢlemleri derleme modülü tarafından yapılır. ÖniĢlemci kaynak kodu üzewrinde çeĢitli değiĢiklikler ve düzenlemeler yapan derleyicinin ön bir modülüdür. C'de # ile baĢlayan satırlar öniĢlemciye aittir yani ÖĠ sadece # ile baĢlayan saturlarla ilgilenir.# den sonra bir ÖĠ komutu bulunur. bu komut ÖĠ ye yapması gerekenleri anlatır.(#include ve #define ele alınacaktır) #INCLUDE komutu: komutun yanında açısal parantez yada ""içinde bir dosya ismi vardır.ÖĠ ilgili dosyayı diskte bulur komutun yazılı olduğu yere kopyalar, program derleme modülüne geldiğinde burada artık o dosya vardır. bu komut kaynak kodun herhangi bir yerine yerleĢtirilebilir nereye yerleĢtirilirse oraya açılır.Dosya açısal parantezler içinde ise ilgili dosya yalnızca derleyici tarafından belirlenen dizinde aranır orada yoksa yoktur bu dizin pek çok compilerde değiĢtirilebilir options\directories\include directories de bulunur. C standart baĢlık dosyaları açısal parantezler ile ifade edilirler. eğer uyguın dosya yoksa ön iĢlemci bunu error mesajı ile bildirir. Eğer dosya ismi iki tırnak ile belirtilmiĢ ise ÖĠ önce dosyayı bulunulan dizinde arar burada bulamazsa bu kezde derleyici tarafından belirlenen dizinde bakar. geleneksel olarak programcının yarattığı dosyalar "" içerisinde belirtilirler. Bir dosyanıın include olması için h uzantılı olması gerekmez. ÖĠ açtığı dosyadan hareket ederek oradaki ÖĠ komutlarını da yapar. /*--x1.c--*/ #include <stdio.h> #include "X2.c" void main(void) { clrscr(); printf("%d\n",add(10,20)); printf("%d\n",multiply(10,20)); } /*----*/ /*--x2.c--*/ #include "X3.c" int add(int a,int b) {

41

return a + b; } /*-----*/ #define KOMUTU #define str1 str2 Bu komut tıpkı text editörlerdeki bul ve değiĢtir özelliğinde olduğu gibi bir yazıyı baĢka bir yazı ile yerdeğiĢtirir. Hesaplama yapmaz. ÖĠ define anahtar sözcüğünden sonraki ilk boĢluksuz karakter kümesini alır, buna str1 diyelim, daha sonra satır sonuna kadarki tyüm karakterlerin kümesini alır , buna str2 diyelim, kaynak kodda str1 gördüğü yere str2 yazısını yerleĢtirir. Bir yazıya karĢılık bir sayı getirilmesi durumuna sembolik sabit tanımlama denir. define edilmiĢ bir sembolik sabit baĢka define ifadelerinde kullanılabilir. #define ile operatör vs. değiĢtirilemez yalnızca anahtar sözcükler ve değiĢkenler değiĢtirilebilir #define + - ERROR #define 300 200 ERROR değiĢtirme iĢleminde büyük küçük harf duyarlılığı vardır. Sembolik sabitler genellikle büyük harflerle yazılırlar bu durum onların program içinde kolay farkedilmesini sağlar. #define komutu include dosyaların içinde de bulunabilir. Okunabilir formu: define dan sonra boĢluk ve sonrada yeterince tab sembolik sabitin yazılmıĢ olması kullanımını zorunlu kılmaz. bazı standart sembolik sabitler belirtilmiĢrtir örneğin math.h içinde pek çok matematiksel sabit vardır tabi bu sabitlerin kullanımı için math.h ın include edilmesi gerekir. En ünlü sembolik sabit #define NULL 0 dır(stdio.h içinde). 2. string yazılmamıĢ ise bu durum birincisinin silineceği(yerine boĢluk atar) anlamına gelir. Sembolik sabitler neden kullanılır: 1--> Okunabilirlik arttırmak için sayılar yerine onları anlatan yazıların kullanılması kodun daha iyi anlamlandırılmasını sağlar. 2--> Bir sabit programın pek çok yerinde kullanılıyorsa sabitin değiĢtirilmesi tek yerden yapılabilir. !!!!!! DĠZĠLER !!!!!!

ADRES KAVRAMI: Bellek byteların peĢisıra dizilmesinde oluĢur. Donanımsal olarak her byte ın bir fiziksel adres numarası vardır.En tepedeki byte 0 olmak üzere her byte ın artan sırada bir adres numarası vardır. Fiziksel adres numaraları 16'lık sisitemde belirtilirler. Yazılımsal olarak adres bilgisinin bileĢenleri: 1-->(Fiziksel adres numarası) sayısal bileĢen

42

2-->Tür bileĢeni Sayısal bileĢen ilgili bölgenin fiziksel adres numarasını belirtir. Tür bileĢeni sayısal bileĢnle belirtilen bellek bölgesindeki bilginin hangi türden yorumlanacağını anlatır. Örneğin sayısal bileĢeĢn 1FC0 tür bileĢeni char ise burada Ģu anlaĢılır: 1FC0 fiziksel adres numarasındaki bilgi karakter olarak yorumlanacaktır. Adres bilgisi c'de ayrı bir veri türüdür. bu durumda c'deki veri türleri 3'e ayrılır. 1--> tam sayı türleri 2--> gerçek sayı türleri 3--> adres bilgisi C'de her değiĢkenin bir adresi söz konusudur. Bir byte tan uzun olan değiĢkenlerinin adreslerinin sayısal bileĢenleri onları düĢük anlamlı byte'larının fiziksel adres numarası ile belirtilir. ADRES SABĠTLERĠ: Adres türünden sabitler yazılabilir genel biçim : (int *) 0x1FC0 DĠZĠLER Elemanları aynı türden olan bellekte ardaĢıl bir biçimde bulunan veri yapılarına dizi denir. Dizi bildiriminin yapılması: genel biçim: <tür>dizi ismi [uzunluk]; chr s[10]; s 10 elemanlı bir karakter dizisidir. int sample[24]; float t[40]; t 40 elemanlı bir float dizisidir. dizinin istenen elemanına ulaĢmak için "dizi ismi[index]" Bir dizi bildirimi ile karĢılaĢan derleyici dizinin tüm elemanlarını tutacak uzunlukta bellekte yer ayırır. Dizinin her elemanı diğerlerinden bağımsız bir nesne imiĢ gibi kullanılabilir. Ġndex ifade tanımına uyan herĢey olabilir.dizinin ilk elemanın indisi 0 dır. Bir dizinin en önemli kullanım gerekçesi bir indĢis yardımı ile bir döngü içerisine dizinin tüm elemanlarının taranmasıdır. Eger yerel bi dizinin içerisine değerler atanmamıĢ ise o dizinin içerisinde rastgele değerler bulunur. Dizilere ilk değer verilmesi: int a[10]={1,2,3,4,5,80,90,100,4,7}; Ģeklinde verilebilir tür dizi ismi[uzunluk]={0,2,.....}; dizi elemanlarına ilk değer küme parantezleri içerisinde elemanlar arasına , konularak verilir bu durumda derleyici küme parantezi içerisindeki sayıları sırası ile dizi elemanları içine yerleĢtiriler.

43

bir dizinin az sayıda elemanına ilk değer verilebilir bu durumda diğğer elemanlar dizi yerelse rastgele global ise 0 alırlar. bir diziye uzunluk belirtmeden ilk değer verilebilir bu durumda derleyici verilen ilk değerlerin sayısını bulur ve dizinin o uzunlukta açılmıĢ olduğunu varsayar. int a[]={1,5,45,96} derleyici bir dizinin uzunluğunu o dizi için kaç byte yer ayıracağını tespit etmek için derleme sırasında bilmek zorundadır. o nedenle c de dizi uzunlukları sabit ifadesi biçiminde verilmek zorundadır. Bir dizinin en büyük ve en küçük elemanının bulunması: Bu iĢlem için önce dizinin ilk elemanı en büyük yada en küçük kabul edilip değiĢken içerisinde sakalnır. sonra dizinin tüm elemanları bir döngü içerisinde taranır. daha büyük veya daha küçük görüldükçe bu değiĢkenin içerisindeki değer değiĢtirilir. Dizilerin sıraya dizilmesi:(sortinng) Dizilerin sıraya dizilmesinde pek çok algoritmik yöntem vardır. hız ve performans dizinin dağılımı ile iliĢkilidir ancak rastsal bir dağılım sözkonusu ise en iyi performansı quick sort yönteminin gösterdiği söylenebilir. Bubble Sort: bu algoritmada yanyana iki eleman karĢılaĢtırılır eğer koĢul sağlanıyor ise yerdeğiĢtirilir. bubble sort algoritması içiçe n-1 defa dönen döngü biçiminde tasarlayabiliriz #include<stdio.h> #define SIZE 10 void main (void) { int a[SIZE] = {3, 8, 6, 41, 16, -7, 25, 63, 57, 45}; int temp,i,k; clrscr(); for (i = 0;i < SIZE -1;++i) for (k = 0;k < SIZE - 1 - i;++k) if (a[ k] > a[k + 1]) { temp = a[k]; a[k] = a[k + 1]; a[k+1] = temp; } for (i = 0;i < SIZE;i++) printf("%d\n", a[i]); }

44

Selection Sort: bu yöntemde duruma göre en büyük yada en küçük eleman bulunur bu eleman ilk elemanla yerdeğiĢtirilir bu iĢlem dizi daraltılarak yinelenir. #include <stdio.h> #define SIZE 10 void main (void) { int a[SIZE] = {3, 8, 6, 41, 16, -7, 25, 63, 57, 45}; int min,indis,i,k; clrscr(); for (i = 0;i < SIZE - 1;++i) { min = a[i]; indis = i; for (k = i + 1;k < SIZE;++k) if (a[ k] < min) { min = a[k]; indis = k; } a[indis] = a[i]; a[i] = min; } for (i = 0;i < SIZE;++i) printf("%d\n", a[i]); } sınıf çalıĢması : klavyeden bir sayı isteyen bu sayıyı 10 elemanlık bir int dizi içerisinde arayan bulursa bulduğu yerin indisini yazdıran bulamazsa bulamadığını belirten bir program yazınız. #include <stdio.h> #define SIZE 10 void main (void) { int a[10] = { 3,8,6,41,25,18,-7,65,57,45}; int i,k; clrscr(); printf("bir sayi giriniz:=>");

45

scanf("%d",&k); for(i = 0;i<SIZE;++i) if (k == a[i]) { printf("%d sayisini %d numarali indiste yani %d . eleman olarak buldum",k,i,i+1); return; } printf("bi daha dene.. "); } C'de bir dizi bildirirken sabit ifadesi ile bildirmek gerekir. Derleme aĢamasında dizinin uzunluğunun ne kadar olduğunun bilinmesi gerekir. Dizi uzunluğuna göre derleyici yer ayırmalıdır. Karakter Dizileri Her elemanı karakter olan dizilerdir(NULL karakteri = '\0'). Karakter dizileri sayısal ya da yazısal amaçlarla kullanılabilir. Eğer yazısal amaçla kullanılacaksa dizinin her elemanına yazının bir karakteri yerleĢtirilir. Böylece karakter dizisi bir yazıyı tutar hale gelir. Ancak dizi içerisindeki yazının da nerede sonlandığı belirlenmelidir. Bunun için C'de yazının sonuna NULL karakteri yerleĢtirilir. NULL karakteri ASCII tablosunun sıfırıncı elemanıdır ve değeri sıfırdır. Bu durumda C'de n elemanlı bir dizinin içerisine sonuna NULL karaktre konulması gerektiği için en fazla (n1) eleman yerleĢtirilebilir.

Karakter Dizilerine Ġlk Değer Verilmesi char s[50] = {'A', 'n', 'k', 'a', 'r', 'a', '\0'}; Ġlk değer verirken mutlaka en son karakter NULL karakter olmalıdır. char s[5] = "Ankara"; Bu durumda derleyici çift tırmak içerisindeki karaktreleri sırasıyla dizi içerisine yerleĢtirir ve sonuna NULL karakter koyar. char s[] = "Van"; Bu durumda derleyici 4 elemanlı bir dizi açar. char s[5] = "Ġstanbul"; /* Derleyici hata verir. */

Dizinin eleman sayısı atanan değeri eleman sayısından küçük ise hata oluĢur. Ama eĢit olursa hata vermez.

46

char s[3] = "Van"; Bu durumda, yani sayılar eĢit olduğunda dizinin sonuna NULL karakteri konmaz ve derleyici uyarı vermez. Klavyeden Bir Karakter Dizisinin Okunması gets(dizi_ismi); Bu fonksiyon enter tuĢuna basılana kadar girilen tüm karakterleri sırasıyla diziye yerleĢirir ve sonuna NULL karakterini yerleĢtirir. get fonksiyonunun kullanıĢında okutulan n elemanlı dizi için (n-1) eleman girilmelidir. Çünkü gets fonksiyonu yazının sonuna NULL karakteri koyacaktır. Okutulan n elemanlı dizi için (n-1)'den fazla eleman girilirse oluĢacal duruma dizi taĢması denir. Karakter Dizilerinin Ekrana Yazılması puts(dizi_ismi); Bu fonksiyon karakter dizisini ekrana NULL karakter görene kadar yazar, NULL karakterini görünce durur. Eğer NULL karakter bir Ģekilde ezilmiĢ ise puts istenilen yerde durmaz. Bu fonksiyonun iĢi printf fonksiyonu %s parametresiye çağırılarak da yapılabilir. Tek farkı puts farklı cursor'ı alt satıra geçirir.

DĠZĠ ĠSĠMLERĠ (CHAR *) 0X1FC0 Dizi elemanları bellekte ardaĢıl bir biçimde bulunurlar yani iki eleman arasında hiç boĢluk yoktur. dizi isimleri nesne değil ADRES SABĠTĠ belirtir. Bir dizi ismi yazıldığında derleyici sayısal bileĢeni dizininn bellekteki baĢlangıç adresi olan tür bileĢeni ise dizinin türü ile aynı olan bir adres sabiti yazar. Yani dizi isimleri derleyici tarafından adres sabitlerine dönüĢtürülür. Bir adresin sayısal bileĢeni printf fonksyonu ile " %p "formatında yazdırılır. POINTERS (GÖSTERĠCĠLER) 10 --> int a; 20L --> long b; 3.2 --> double c; (char*)0x1FC0 Ġçlerine adres bilgilerinin yerleĢtirildiği değiĢkenlere "gösterici" denir. :Gösterici bildirimlerinin genel biçimi: <tür>*<gösterici ismi>;

47

örnekler int *p; ----> p int türünden bir göstericidir. float *abc; ----> abc float türünden bir göstericidir. .... okunabilir formu * ile gösterici isminin birleĢik yazılmasıdır. int *p,a,*c ----> aynı satırda birden çok bildirim yapılabilir. int *p p=(int*)0x1BC3 char *p; p=(int*)0x1A13; doğru:: gösterim. hata:: gösterici ile adres bilgisi farklı türlerden.

char *p; p=0x1234; hata:: adres ataması bile yapılmamıĢ. Bir göstericiye aynı türden bir adres bilgisi konulmalıdır. Bir göstericiye adres bilgisi atandığında göstericiye adresein yalnızca sayısal bileĢeni yerleĢtirilir. Bir dizinin ismi aynı türden bir göstericiye atanabilir. Çünkü dizi isimleri aynı türden bir adres sabiti belirtmektedir. char *p; char s[100]; p=s; s yerine (char*)0x1A00

char *p; p=(char*)0x1F10; *p='a' bir gösterici * operatörü ile kullanılabilir.*p ='a' gibi bir iĢlemde *p ifadesi p'yi değil p göstericisinin içerisindeki adresteki bilgiyi temsil eder. * unary prefix bir gösterici operatörüdür. p bir gösterici olmak üzere *p bir nesnedir. her nesnenin bir türü vardır. *p nesnesinin türü bildirimde açıkça belirtilmiĢtir. AĢağıdaki gibi bir gösterici bildiriminden iki Ģey anlaĢılır: 1--> p karakter türünden bir göstericidir. 2--> p göstericisinin * operatörü ile kullanımında "*p" karakter türündendir. gösterici içerisine bir adres yerleĢtirilirse belleğin istediğimiz bir yerindeki bilgiye eriĢip okuyabiliriz. GÖSTERĠCĠ OPERATÖRLERĠ: c'de adresler üzerine iĢlem yapan operatörlere gösterici operatörü denir. c'de 3 tane gösterici operatör vardır. * --> indirection & --> address of

48

[n] --> index * OPERATÖRÜ unary prefix bir operatördür. operantının mutlaka ve mutlaka adres bilgisi olması gerekir. Yani * operatörü : 1--> Doğrudan adre .... *p * 10 * gösterici operatörünün operantı c nin normal türlerine iliĢkin bir bilgi olmaz adres bilgisi olmak zorundadır. & OPERATÖRÜ BU operatörde unary prefix bir operatördür.bir değiĢkenin bellekteki yerleĢim adresini elde etmek için kullanılır. BU operatör ile elde edilen adresin sayısal bileĢeni operant olarak alınan adresin fiziksel adres numarası tür bileĢeni ise nesnenin türü ile aynı olan türdür.Bir nesnenin adresi bu operatör ile alınıp bir göstericiye konulursa daha sonra bu gösterici * operatörü ile kullanıldığında daha sonra bu nesneye eriĢilmiĢ olur.

[] INDEX OPERATÖRÜ Unary postfix bir operatördür. Öncelik tablosunun en üst düzeyindedir. Kullanımı: köĢeli parantez içindeki ifade int türüne dönüĢtürülür otomatik olarak. Bu operatörün operantının bir adres bilgisi olması gerekir. yani operant 1- >bir gösterici olabilir. 2- >dizi ismi olabilir. 3- >adres sabiti olabilir. *(p+n)=p[n] ile tamamen eĢdeğerdir. bu operatör bir adresten n ilerinin içeriğini almakta kullanılır. FONKSYON PARAMETRESĠ OLARAK GÖSTERĠCĠLERĠN KULLANIMI: bir fonksyonun parametre değiĢkeni gösterici türünden olabilir.böyle fonksyonlar birer adres bilgisi ile çağırılmalıdır. Bu durumda derleyici fonksyon çağırıldığında adres bilgisini otomatik olarak göstercinin içine yerleĢtirir. C'de bir yerel değiĢkenin içeriğinin baĢka bir fonk tarafından değiĢtirilebilmesi ancak Ģöyle mümkündür:

49

Fonk yerel değiĢken adresi ile çağırılır, fonk parametre değiĢkeni aynı türden bir göstericidir. bu gösterici * ile kullanılırsa yerel değiĢkene eriĢilmiĢ olur. [ Bir göstericinin içerisine aynı türden bir adres bilgisi konulabilir bunun tersi de doğrudur yani bir adres bilgisinin atanacağı değiĢken aynı türden gösterici olmak zorundadır.] DĠZĠLERĠN FONKSYONLARA PARAMETRE OLARAK GEÇĠRĠLMESĠ diziler bellekte sürekli ardaĢıl bir biçiimde bulunduklarına göre onların baĢlangıç adreslerini geçirerek bir fonk diziye eriĢmesini sağlayabiliriz. karakter dizilerinin baĢlangıç adresi yeterlidir. çünkü dizinin baĢlangıç adresini alan fonksyon null karakter görene kadar ilerlerse dizi içindeki yazının hepsine eriĢebilir. karakter dıĢındaki türlere iliĢkin dizilerin baĢlangıç adreslerinin yanısıra birde uzunluklarının geçirilmesi gerekir. örneğin puts fonksyonu aslında dizinin baĢlangıç adresini parametre olarak almaktadır bu durumda puts fonk parametre değiĢkeni karakter türünden gösterici olmak zorundadır. bu durumda fonksyon dizinin baĢlangıç adresi ile yani dizinin ismi ile çağrılır. fonk parametre değiĢkeni aynı türden bir gösterici olmalıdır. ADRESLERĠN ARTTIRILMASI VE EKSĠLTĠLMESĠ: bir adres bilgisini bir artırdığımızda adresin sayısal bileĢeni adresin türünün uzunluğu kadar artar. yani int bir göstericiyi 1 artırdığımızda dos'ta adresin sayısal değeri 2 artacaktır. bir adres bilgisine int türden bir sayı ile toplarsakda elde edilen adresin sayısal bileĢeni adresin türünün uzunluğu kadar artacaktır. örneğin p[n] ifadesi p adresinden n byte ilerinin içeriği değil "p adresinden n*p'nin türünün uzunluğu kadar ilerinin içeriği anlamına gelir."

#include <stdio.h> void main(void) { int a[5] = {100, 200, 300, 400, 500}; int *p; clrscr(); p=a; printf("%d\n", p[2]); } GÖSTERĠCĠLER VE DĠZĠLERĠN BENZERLĠKLERĠ VE FARKLILIKLARI 1--> Göstericide dizi ismide adres bilgisidir. gösterici kullanıldığında göstericinin içerisindeki adres kullanılır dizi ismi kullanıldığında dizinin baĢlangıç adresi sabit olarak kullanılır. 2--> Gösterici bir nesnedir yani içerisine bir bilgi atanabilir oysa dizi ismi dizinin baĢlangıç adresine ait bir sabittir.yani diiznin ismi diiznin ilk elemanının adresi gibi bir anlamdadır.

50

3--> bir gösterici tanımlandığında yalnızca kendisi için yer ayrılır. ayrılan alan dosta 2 veya 4 byte; unix ve win32 de her zaman 4 byte yer ayrılmaktadır. bir gösterici için ayrılan alanın göstericinin tür ile hiç bir ilgisi yoktur. göstericinin türü göstericinin gösterdiği yer ile ilgilidir. ÖRNEK:Bir int dizinin baĢlangıc adresinmi ve uzunluğunu alarak dizinin en büyük elemanına geri dönen bir fonksyonun tasarımı: #include <stdio.h> int c=0; int MaxVal(int *p, int n) { int max = p[0]; int i; for (i = 1; i < n; ++i) if (max < p[i]) { max = p[i]; c=i; } return max; } void main(void) { int a[]={10,20,30,40,50,60,70,80,90,50}; int m; clrscr(); m = MaxVal(a,10); printf("%d %d\n",m,c); } ÖRNEK:n elemanlı bir int diziyi sıraya sokan sort isimli bir fonksiyon yazınız...prototipi sort(a,10); a = dizi ismi 10 = uzunluk void sort(int *p,int n) { int deis,i,j; for (i = 0; i < n - 1; ++i) for (j = 0; j < n - 1; ++j) if (p[j] > p[j + 1]) {

51

deis = p[j]; p[j] = p[j + 1]; p[j + 1] = deis; } } void main (void) { int a[]={1, 8, 9, 17, 6, 4, 41, -7, 20, 40}; int k; clrscr(); sort(a,10); for (k = 0; k < 10; ++k) printf("%d\n",a[k]); } :String Fonksyonları: standart c de baĢı str ile baĢlayan bir karakter dizisinin baĢlangıç adresini parametre alarak dizi içerisindeki yazı üzerinde çeĢitlli iĢlemler yapan bir grup fonksyon vardır. bunlara string fonksyonları denir ve prototoipleri string.h içerisindedir.

strlen fonksyonu: int strlen (char *str); bu fonksyon parametre olarak aldığı adresten baĢlayarak null karakter görene kadar yazı içerisinde kaç karakter bulunduğunu hesaplar ve bu değerle geri döner. int mystrlen(char *str) { int i = 0; while (*str != '\0') { ++str; ++i; } return i; }

int mystrlen(char *str)

52

{ int i = 0; while (str[i] != '\0') ++i; return i; }

int mystrlen(char *str) { int i; for (i = 0;str[i] != '\0';++i) ; return i; }

Geri dönüĢ değeri adres olan fonksyonlar: bir fonksyon herhangi türden bir adrese geri dönebilir. böyle fonksyonlar tanımlanırken geri dönüĢ değeri türü yerine <tür>* yazılmalıdır. int *fonk(void) yıldız olmasa int anlaĢılacaktu ama * varken int türünden adres sabiti. okuynablirlik gereği *ile fonksyon bitiĢik yazılır. böyle fonksyonların geri dönüĢ değerleri aynı türden bir göstericiye atanmalıdır. STRCHR fonksyonu: bu fonksyon bir yazı içerisinde bir karakteri aramakta kullanılır. prototipi: char *strchr(char *str,char ch) fonksyonun birinci parametresi aramanın yapılacağı yazının baĢlangıç adresine yönelik göstericidir. ikinci parametre aranacak karakteri belirtir. C'DE 0 ADRESĠ GEÇERLĠ BĠR ADRES DEĞERĠ DEĞĠLDĠR. Bu fonksyon karakteri yazı içerisinde bulursa bulduğu yerin adresi ile bulamazsa 0 ile geri döner. Bu bir baĢarısızlık iĢaretidir . 0 adresine null gösterici denilmektedir. SINIF ÇALIġMASI:Bir yazı içerisindeki belli bir karakterli baĢka bir karakterle değiĢtiren replace fonksiyonunu yazınız. prototipi:=> void replace(char *str,char a,char b) Bu fonksiyon strchr fonksiyonu yardımıyla yazılacaktır. #include <stdio.h>

53

#include <string.h> /* BaĢka bir replace /*void replace(char *str,char a,char b) /*{ /* int c,i; /* /* c = strlen(str); /* for (i = 0;i < c;++i) /* *strchr(str,a) = b; /*} /* /* BaĢka bir replace /*void replace(char *str,char a,char b) /*{ /* for (;;) { /* str=strchr(str,a); /* if (str == NULL) /* break; /* *str = b; /* } /* ++str; /*} /* void replace(char *str,char a,char b) { int c,i; while (strchr(str,a) != NULL) *strchr(str,a) = b; } */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */

void main (void) { char s[] = "Bu bir denemedir"; clrscr(); replace(s,'e','x'); puts(s); } STRCPY fonksiyonu:

54

Bu fonksiyon bir karakter dizisi içindeki yazıyı baĢka bir karakter dizisine kopyalamak için kullanılmaktadır. Prototipi:=> char *strcpy(char dest,char source); Ġkinci parametresinden baĢlayarak null karaktere kadar (null karakter dahil) olan tüm karakterleri ilk parametredeki adresten baĢlayarak yerleĢtirir. Fonksiyon birinci parametresiyle belirtilen yani kopyalamanın yapıldığı adresin kendisine geri döner.Geri dönüĢ değeri nadiren kullanılır.Bunun amacı: printf("%s\n",strcpy(d,s)); Ģeklinde kullanılsın.. STRRCHR fonksiyonu: Prototip:=>char *strrchar(char *str,char ch); Bu fonksiyon yazı içerisinde karakteri ararken son bulduğu yerin adresiyle geri döner.Oysa strchr ilk bulduğu adresle geri dönmektedir.strchr ve strrchr fonksiyonları ile NULL krakterin kendisi de aranabilir. p=strchr(s,'\0'); p karakter türünden bir gösterici olmak üzere p'nin null karaktere ötelenmesi aĢĢağıdaki 3 biçimde yapılabilir. 1-while(*p !='\0') ++p; 2-p += strlen(p); 3-p = strchr(p,'\0'); 1 ve 3 iyi 1 hızlı... STRCAT FONKSYONU: Bu fonksyon bir ayzının sonuna baĢka bir yazıyı eklemek amacı ile kullanılır. char *strcat(char *dest, char *source) bu fonksyon ikinci parametresinde belirtilen adresyen baĢlayarak null karakter görene kadar (dahil) tüm karakterleri birinci parametresinde belirtilen yazının sonuna kopyalar. Kopyalamanın yapıldığı yani birnci parametresi ile belirtilen adresin kendisine geri döner ancak geri dönüĢ değeri nadiren kullanılır. #include <stdio.h> #include <string.h> void main (void) { char s[50] = "ankara"; char d[50] = "istanbul";

55

strcat(d, s); printf("%s\n", d); } char *mystrcat (char *dest, char *source) { char *temp; temp=dest; while(*dest != '\0') ++dest; strcpy(dest,source); return(temp); } STRCMP FONKSYONU: bu fonksyon iki yazıyı karĢılaĢtırmakta kullanılır. int strcmp(char *s1, char *s2); bu fonksyon iki yazının da baĢlangıç adreslerinin kopyalandığı iki gösterici parametresi alır birincisi büyükse pozitif küçükse negatif herhangi bir değere eĢitse 0 a geri döner. #include <stdio.h> #include <string.h> void main (void) { int result; char passwrd[] = "mavi ay"; char s[50]; printf("enter password:"); gets(s); if (!strcmp(s, passwrd)) printf("OK....\n"); else printf("invalid password...\n"); }

56

SINIF ÇALIġMASI: kullanıcıdan en fazla 3 kere password isteyen 3ündede yanlıĢsa invalid password yazan doğru girilmiĢse OK yazısını çıkartan programı yazınız. her hatalı giriĢte password doesnot match enter password yazısı tekrar çıkacak. #include <stdio.h> #include <string.h> #define TRYNUM 3 void main (void) { int i, j = 0; char password[] = "mavi ay"; char s[50]; clrscr(); for(i = 0; i < TRYNUM; ++i){ if (j == -1) printf("Password does not match\n"); else if(j == 1) break; printf("Enter password:"); gets(s); if (!strcmp(s, password)) j = 1; else j = -1; } if (j == 1) printf("OK..\n"); else printf("Invalid password\n"); } standart olmamakla birlikte library içinde stricmp isminde büyük küçük harf duyarlılığı olmadan karĢılaĢtırma yapan bir fonksyon da vardır bu fonksyon derleyicilerin çoğu tarafında destekler. STRUPR ve STRLWR FONKSYONLARI: char *strupr(char *str); char *strlwr(char *lwr);

57

bu iki fonksyon null karakter görene kadar bir yazı içindeki tüm karakterleri büyük yada küçük harfe çevirir. #include <stdio.h> #include <string.h> void main (void) { char s[50]; gets(s); strlwr(s); puts(s); strupr(s); puts(s); } STRNCPY FONKSYONU: char *strncpy(char *dest,char *source, int n); bu fonksyon ikinci parametresi ile belirtilen adresten baĢlayaral birinci parametresinde belirtilen adrese doğru 3. parametresi iĢle belirtilen sayıda karakteri kopyalar.geri dönüĢ değeri 1. parametresi ile belirtilen adresin aynısıdır. bu fonksyon normal olarak null karakteri kopyalamazbir ayzının belli bir kısmını baĢka bir yazı ile değiĢtirmek amacı ile kullanılır. eğer n sayısı kopyalaacak yazının uzunluğundan daha büyük ise null karakterde kopyalanır ve iĢlem sonlandırılır. #include <stdio.h> #include <string.h> void main (void) { char d[50]="EskiĢehir"; char s[50]="yenisahra"; clrscr(); strncpy(d,s,4); printf("%s\n",d); } STRNCAT FONKSYONU

58

bu fonksyon bir yazının ilk n karakterini baĢka bir dizinin sonuna eklemeye yarar. null karakter her zaman yazının sonuna kopyalanır.

#include <stdio.h> #include <string.h> void main (void) { char d[50]="EskiĢehir"; char s[50]="yenisahra"; clrscr(); strncat(d,s,4); printf("%s\n",d); } STRNCMP FONKSYONU: int strncmp(char *s1,char *s2, int n); iki yazının ilk n karakterini karĢılaĢtırır. fonksyon n sayısı yaızlardan birinin uzunluğundan daha büyükse null karakteri görünce iĢlemini bitirir. #include <stdio.h> #include <string.h> void main (void) { char d[100] = "eskiĢehir"; char s[100] = "eskihisar"; if (!strncmp(d, s, 4)) printf("evet\n"); else printf("hayır\n"); } ALFABETĠK SAYISAL DÖNÜġÜM YAPAN FONKSYONLAR: stdlip.h içerisinde çok kullanılan karma fonksyonların prototipleri bulunur. ATOI (alfabetic to integer) FONKSYONU: int atoi( char *str);

59

bu fonksyon ascii karakterleri ile oluĢturulmuĢ yani bir yazı biçiminde bulunan sayısal bilginin baĢlangıç adresini bir parametre olarak alır. Onu int türüne dönüĢtürerek geri dönüĢ değeri olarak verir. #include <stdio.h> #include <stdlib.h> void main (void) { char s[] = "1234"; int n; n = atoi(s); printf("%d\n",n); } ilk sayısal olmayan yada null karakteri gördüğünde iĢlemi sonlandırır. SAYISAL ALFABETĠK DÖNÜġÜM YAPAN FONKSYONLAR ITOA FONKSYONU: char *itoa(int n, char *str, int base); 1. parametre yerleĢtirlecek sayıyı belirtir 2. parametre yerleĢtirilmenin yapılcağı adrestir 3. parametre kaçlık sistemde yerleĢtirileceği bu 2. parametredeki değerine geri döner LTOA FONKSYONU: itoa fonksiyonunun long türü için olanıdır. ATOF FONKSĠYONU:alfabetic to float #include <stdio.h> #include <stdlib.h> void main (void) { char s[]="127.560"; printf("%lf\n",atof(s)); } SPRINTF FONKSĠYONU:

60

Bu fonksiyon her turlu bilgiyi karakter biçimine dönüĢtüren genel amaçlı bir fonksiyondur.Kullanımı printf fonksiyonunun aynısıdır.Ancak ilk parametresi karakter türünden bir göstericidir. sprintf(char *str,.......); Bu fonksiyon sonuçları ekran yerine birinci parametresiyle belirtilmiĢ olan adrese yazar ve sonun null karakteri ekler. #include <stdio.h> #include <stdlib.h> void main(void) { char s[500]; int a=123; long b=5000000; sprintf(s, "a=%d b=%ld", a, b) puts(s); } sprintf(s,"%lf",x); GÖSTERĠCĠLERE ĠLK DEĞER VERĠLMESĠ: char *p=(char *)0X1FC0; Bir göstericiye tanımlar tanımlamaz ilk değer verilebilir. GÖSTERİCİ HATALARI Derleyicinin hafızada bizim kullanımımız için ayırdığı bölgelere güvenli bölge denir.Bir gösterici kullanılarak bellekte istenilen bir bölgeye eriĢilebilir.Ancak herhangi bir bölgeye gösterici yoluyla veri aktarmak orada çalıĢan programların bütünlüğünü bozacağı için beklenmeyen sonuçların çıkmasına neden olabilir.Bellekte kimin tarafından kullanıldığı belli olmayan bölgelere veri aktarılması gösterici hatasıdır.Ġçeriği programcı tarafından bilinmeyen bölgelere güvenli olmayan bölge denir.Gösterici hatası derleme sırasında değil run time sırasında etkisini gösterir.Böyle hataları derleyici anlayamaz.Göstericilerle ancak tanımlama yoluyla tahsis edilmiĢ olan alanlara veri aktarılabilir. GÖSTERĠCĠ HATALARININ ORTAYA ÇIKIġ BĠÇĠMLERĠ

61

1-ilk değer verilmemiĢ göstericilerin yol açtığı hatalar Bir pointer rast gele bir adresi ifade ederken onun içine değer verilmesi hatadır. void main(void) { char *p; *p='a'; } void main(void) { char *p; gets(p); } void main(void) { char *p; char s[]="ali"; strcpy(p,s); } p=strchr(s,'a'); *p='b'; eger a karakteri bulunmazsa strchr NULL adrei ile geri döner.Bu durumda b karakteri NULL adresine konulmaya çalıĢılır ki,tanımsız bir adrestir. 2-Dizi taĢmalarında kaynaklanan gösterici hataları { int a[10]; int i; for (i=0;i<=10;++i) a[i]=0; } { char s[10]; gets(s); /*burada ancak 9 karakter girilebilir.yoksa null karakter /*11. karakter olarak konulabilir... */ */ /* a<10 olmalı yoksa dizi taĢması...*/

62

{ char d[]="ali"; /*tanımlamada d'ye daha büyük bir aralık verilmeli */ char s[]="veli"; /*d[50] gibi */ strcpy(d,s); } { char d[10]="adana"; char s[10]="istanbul"; strcat(d,s); /*strcat d'nin sonuna s'yi eklediği için taĢma olur*/ } { char d[10]; char s[10]="ali"; char t[]="veli"; strcat(d,s); /*d'nin içinde rastgele değerler olduğu için ilk önce */ strcat(d,t); /*strcpy(d,s) yapılması daha doğru olur */ } Çok iĢlemli iĢletim sistemlerinde bir programcının yaptığı gösterici hatalarından baĢka bir programcı etkilenebilir.Ancak böyle birĢeyin güvenlik açısından engellenmesi gerekir.Böyle sistemlerde kullanılan mikro iĢlemcilerin koruma mekanizmaları vardır.Böyle sistemlerde bir program kendi alanı dıĢına eriĢtiğinde bu durum iĢlemci tarafından tespit edilir,iĢlemci bu durumu iĢletim sistemine bildirir,iĢletim sistemi de programı sonlandırır.

RASTGELE SAYI TÜRETME RASTGELE(random): Sayıların rastgeleliği istatistik hesaplamalarla bulunabilir.Her sayının gelme olasılığının eĢit olduğu sisteme düzgün dağılmıĢ rastgele sistem denir. Borland ve microsoft derleyicilerinde rastgele sayı üretilmesini sağlayan fonksiyonlar bölümden elde edilen kalan sistemini kullanırlar.Bu sisteme göre bir sayının bir sayıya bölümünden kalan rastgeledir.Ritchie'nin "The C Programming Language" kitabında bu tür fonksiyonların tasarımı açıklanmıĢtır. C'nin srand ve rand isimli rastgele sayı üretilmesini sağlayan iki türlü fonksiyonu vardır.Ġkisi de stdlib.h'ta bulunur. rand fonksiyonu 0-32765 arası bir tam sayı verir[prototipi=>int rans(void);]

63

#include <stdio.h> #include <stdlib.h> void main(void) { int i; for (i=0;i<10;++i) printf("%d\n",rand()); } Bu fonksiyon her defasında aynı sayıları üretir.Bu fonksiyon ile herhangi bir aralıkta rastgele sayı üretilebilir.=> rand()%n+k [:=>k ile n arası] 0-1 arasında noktalı rastgele sayı üretimi için stdlib.h içerisinde RAND_MAX isimli bir sembolik sabit de vardır. rand fonksiyonunun algoritması : unsigned long int next=1; int rand(void) { next=next * 1103515245 + 12345; return (next / 65536) % 32767; } Burada next global değiĢkeni sabit olduğuna göre program her çalıĢtığında bir dizi aynı rastgele sayılar elde edilir.

srand standart olarak next global değiĢkenine bir değer yüklemek için kullanılır. void srand(unsigned int seed) { next=seed; } Programın her çalıĢmasında farklı bir dizilimin elde edilmesi isteniyorsa srand fonksiyonunun parametresinin de rastgele bir değer alınması gerekir. Prototipi time.h içerisinde tanımlanmıĢ olan time fonksiyonu kullanılır.time fonksiyonu 1-1-1970 'ten kullanıldığı ana kadar geçmiĢ saniye sayısını bulur.Parametre için 0 girilmelidir.Yani programın baĢında srand(time(0)); çağırması

64

yapılırsa her seferinde farklı sayılar bulunur.Borland derleyicilerinde stdlib.h dosyası içerisinde aynı çağrmayı yapan bir #define vardır.. /* #define randomize() srand(time(0)) */

void Göstericiler Bir göstericinin türü void olabilir. Böyle göstericilerin içieriisnde bulunan adresi türü belli değildir. Void gösterici arttırılamaz ve azaltılamaz. Void göstericiler * veya [] operatörleriyle de kullanılamaz. Böyle göstericiler adres bilgilerinin geçici olarak tutulmasında kullanılırlar. Bir Göstericiye Farklı Türden Bir Adresin Atanması void main(void) { int *p; char s[10]; p = s; /*warning:suspicious pointer conversion*/ } C'de bir göstericiye farklı türden bir adres bilgisi atanırsa bir uyarı söz konusu olur. Çünkü derleyici bu iĢlemin yanlıĢlıkla yapıldığını düĢünür. Bu uyarıya karĢın adresin sayısal bileĢeni göstericiye atanmaktadır. void main(void) { int *p; char s[10]; p = (int *)s; } Bir Göstericiye Adres Olmayan Bilginin Atanması void main(void) { int *p; p = 0x1FC0; /*warning non-portable pointer assignment...*/ } Bir göstericiye adres olmayan bir bilgi atanırsa derleyici bunu da programcının yanlıĢ yaptığı bi4r iĢlem olarak alır ve uyarı verir. Bu durumda da uyarıyı kesmek için bilinçli tür dönüĢümü yapmak gerekir. Bu yapılırsa zaten ifade adres sabitine dönüĢür. /*Bilinçli tür dönüĢtürme yapıldığında warning olmaz*/

65

void main(void) { int *p; p = (int *)0x1FC0; } Bu atama iĢlemleri fonksiyon çağırılması sırasında gizli bir biçimde de yapılır. void fonk(int *p) { *p = 10; } void main(void) { char s[] = "Ankara"; fonk(s); } Standart C fonksiyonlarının kendileri kütüphane dosyalarında, prototipleri baĢlık dosyalarında olduğuna göre parametresi gösterici olan standart C fonksiyonlarındaki uyuĢmazlıklar da tespit edilir. void main(void) { int p[] = {1, 2, 3}; puts(p); } Normal Bir Türe Adres Bilgisinin Atanması Durumu void main(void) { int a; char s[] = "Ankara"; a = s; /*warning Non-portable pointer assignment in function ... */ } Bir adres bilgisi C'nin normal bir türüne atanmaya çalıĢılırs, derleyici bunu da Ģüpheyle karĢılar ve uyarı verir. Bu uyarıdan kurtulmak için normal türe bilinçli dönüĢtürme yapılabilir. /*warning:suspicious pointer assignment..*/

66

void main(void) { int a; char s[] = "ankara"; a = (int ) s; } Genel Sonuçlar 1. Bir göstericiye aynı türden bir adres bilgisi atanmalıdır ve bir adres bilgisi de ancak aynı türden bir göstericiye atanabilir. Bu kurala uyulmazsa C derleyicileri uyarı verir. 2. Uyumsuzluk nedeniyle ortaya çıkan uyarılar bilinçli tür dönüĢümüyle giderilebilir. Void Göstericilerle Ġlgili Atama ĠĢlemleri void göstericiye hangi türden adres atarsak atayalım bir uyarı söz konusu olmaz. Ancak void bir adres herhangi bir türden göstericiye atanırsa bu durum eski dereiyicilerde bir probleme yol açmasa da yeni derleyicilerde uyarı olarak ele alınır. void * = int * ; int * = void * ; /*warning yok*/ /*warning var*/

void adresin bir göstericiye atanması gerektiği durumlarda bilinçli tür dönüĢtürmesi uygulanırsa hiçbir derleyicide problem ortaya çıkmaz. { char *p; int *t; p = (char *) t; /*warning yok*/ } void Göstericilerin Kullanım Amacı void göstericiler türden bağımsız iĢlemlerin yapılması için genellikle fonksiyon parametresi kullanırlar. memcpy isimli fonksiyon bir adresten bir adrese koĢulsuz n byte kopyalar. Bu fonksiyon herhangi bir türden dizinin içeriğinin kopyalanması amacıyla kullanılır. Bu iĢlem strncpy fonksiyonu ile yapılamaz bu fonksiyon 0 sayısını gördüğü anda bunu NULL karakter zanneder ve iĢlemi sonlandırır. Bu fonksiyonun ilk parametresi kopyalamanın yapılacağı adres, ikinci parametresi kopyalanacak adres, üçüncü parametresi ise kopyalanacak byte sayısıdır. Bu fonksiyonun prototipi string.h içerisindedir.

67

memcpy(dest, source, n); memcpy fonksiyonu madem her türden adres bilgisiyle çağırılmaktadır o halde bu fonksiyonun ilk iki parametresi void türden gösterici olmalıdır. memcpy(void *dest, void *source, int n); void Gösterici Parametresine Sahip Olan Fonksiyonların Yazımı void göstericiler * ve [] ile kullanılamadığına ve arttırılıp azaltılamadığına göre hemen blok giriĢinde tür dönüĢümü yapılarak türü belirli bir göstericiye atanmalıdır. void mymemcpy(void *dest, void *source, int n) { char *d = (char *) dest; char *s = (char *) source; int i; for (i = 0; i < n; ++i) d[i] = s[i]; } memset Fonskiyonu void memset(void *p, char ch,int n); Bu fonksiyon bir adresten baĢlayarak n tane byte'ı belirle bir değerle doldurmak için kullanılır. Bu fonksiyon örneğin bir diziyi 0'lamak için kullanılabilir. #nclude <stdio.h> #include <string.h> void main(void) { char s[50]; memset(s, 'x', 20); s[20] = '\0'; puts(s); } void main(void) { char a[] = "Ali"; char b[50];

68

memcpy(b, a, strlen(a) + 1); puts(b); } Bir fonksiyon void bir adresle geri dönebilir. Böyle bir fonksiyonun geri dönüĢ değeri tür dönüĢtürmesi yapılarak herhangi bir türden göstericiye atanmalıdır. Stringler C'de çift tırnak içerisine yazılan ifadelere çift tırnak ile beraber string denir. Derleyici bir stringle karĢılaĢtığında önce string içerisindeki karakterler belleğin güvenli bir bölgesine yerleĢtirir. Sonuna NULL karakteri ekler. String yerine yerleĢtirildiği yerin adresini koyar. Yani stringler karakter türünden adres sabiti gibi iĢlem görürler. void main(void) { char *p; p = "Ankara"; puts(p); } p=> A n k a r a '\0' 1A00 1A00 1A01 1A02 1A03 1A04 1A05 1A06

Stringler karakter türünden bir göstericiye atanabilirler. Bir diziye ilk değer verirken kullanılan çift tırnak içerisindeki deyim string değildir. Yani derleyici oradaki çift tırnak yerine bir adres yerleĢtirmez. char s[100] = "Ali"; /*string değil*/

Bu iĢlem çift tırnak içerisindeki karakterlerin dizi içerisine tek tek yerleĢtirilmesi anlamındadır. { char s[100]; s = "Ali"; } /*error: Lvalue required in function...*/

69

Bir karakter dizisinin içerisine bir yazı 3 Ģekilde yerleĢtirilebilir. 1. Ġlk değer verilerek: char s[] = "Ali"; 2. Tek tek değer verme: char s[10]; s[0] = 'A'; s[1] = 'l'; s[2] = 'i'; s[3] = '\0'; 3. strcpy fonksiyonu kullanılarak: char s[10]; strcpy(s, "Ali"); (12-9-1998)

70