Kod Dünyası

cpp Programlama etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
cpp Programlama etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

23 Ocak 2015 Cuma

Programın içinde sıkça yinelenmesi gerekebilecek küçük kod parçaları makrolar yardımıyla gerçeklenebilir. Örnekte kare alma işlemini yapmak üzere bir makro yazılmıştır. Makrolar da değişmez tanımlarına benzer şekilde #define sözcüğüyle yapılırlar. İşleyişleri de yine değişmez tanımlarına benzer şekilde olur, yani makronun adının geçtiği yere açılımı konur. Örnekteki
area = PI * sqr(radius);
komutu görülünce makro tanımında x yerine radius sözcüğü konarak kod
area = PI * ((radius) * (radius));
şekline getirilir (programcı kendisi bu şekilde yazmış gibi).
Bu işlem bir sözcük ya da sözcük grubunun yerine başka bir sözcük ya da sözcük grubunun yerleştirilmesi şeklinde yürüdüğünden kullanımına dikkat etmek gerekir. Örnekteki makro
#define sqr(x) x * x
şeklinde tanımlansa ve programda
sqr(radius + 1)
şeklinde kullanılsaydı yerine geçecek (yanlış) kod şu şekilde olurdu:
radius + 1 * radius + 1

22 Ocak 2015 Perşembe

system() Fonksiyonu
Bu kısımda standart bir derleyicinde bulunan, stdlib.h kütüphanesindeki system() fonksiyonu anlatılacaktır. Bu fonksiyon kendisine parametre olarak gelen ifadeyi UNIX, Linux veya MS-DOS komut satırına yazar ve çalıştırır. system() fonksiyonu ile, bilgisayarın tüm dosya ve çevre birimleri, küçük program parçaları sayesinde kontrol edilebilir. Genel yazım biçimi:
      system("işletim_sistemi_komutu");
Örneğin,
Windows dizininde bulunan tüm dosyaları listelemek için
      system("dir c:\\windows");
Bu fonksiyon Linux İşletim sisteminde de kullanımı aynıdır. Örneğin /root/bingul/www dizinindeki dosya ve alt dizinleri listelemek için
      system("ls -asl /root/bingul/www");
Program 19.1 D: sürücüsünde bulunan tüm dosyaları gizli ve salt okunur hale getirmek için kullanılır. Son olarak derleyicinin EXE kodu üreteceğini unutmayın. Bu EXE kodu her bilgisayarda çalışır.
Program 19.1 : D: sürücüsünde bulunan bütün dosyaları gizli ve salt-okunur hale getirir
1:  /* D: sürücüsündeki bütün dosyaları gizli ve salt-okunur hale getirir */
2:  #include <stdlib.h>
3:  main()
4:  {
5:     system("attrib d:\\*.* +h+r");
6:  }
Program 19.2 proramında autoexec.bat dosyasına DOSKEYin nasıl yükleneceği gösterilmiştir. Bunun için >> yönlendirme operatörü kullanılmıştır. Bu operatör MSDOS işletim siteminde olduğu gibi Linux işletim sisteminde de kullanımı aynıdır.
Program 19.2 : Bilgisayar açılışında DOSKEY in yüklenmesi
1:  /* autoexec.bat dosyasına 'doskey /insert' yazar */
2:  #include <stdio.h>
3:  #include <stdlib.h>
4:
5:  main()
6:  {
7:     system("echo. >> c:\\autoexec.bat");
8:     system("echo doskey /insert >> c:\\autoexec.bat");
9:     printf("DOSKEY açılışa yüklendi...\n");
10: }
DOSKEY açılışa yüklendi...
main() Fonksiyonuna Paremetre Aktarımı
Fonksiyon inşasına dayanan bir C programında, ana programın kendisi, main(), de bir fonksiyondur. Ana programa parametre aktarımı, derlenmiş bir program komut satırından (işletim sistemi ortamından) ilk çalıştırılacağı zaman yapılır. Aktarılacak parametreler, programın adı yazılıp bir boşluk bırakıldıktan hemen sonra yazılır. Parametreler, komut satırından sayısal olarak girilse bile program içinde karakter topluluğu (string) olarak gelir. Bu durumda, string ifadeleri sayısal değerlere çeviren fonksiyonlar (atoi(), atol(), atof(),...) kullanılmalıdır. Genel kullanım biçimi:
          ...
          main(arguman_sayisi,arguman_vektoru)
          int  arguman_sayısı;
          char *arguman_vektoru[];
          {
             .
             .
             .
             if(arguman_sayisi < ...){
                printf("Eksik parametre !\n");
                exit(0);
             }
             if(arguman_sayisi > ...){
                 printf("Çok fazla parametre !\n");
                 exit(0);
             }
             .
             ... arguman_vectoru[0] ... /* 1. eleman program adı  */
             ... arguman_vectoru[1] ... /* 2. eleman 1. parametre */
             ... arguman_vectoru[2] ... /* 3. eleman 2. parametre */
             .
         }
Program 19.3 i dikkatle inceleyin.
Program 19.3 : komut satırından girilen iki sayının toplamını hesaplar
1:  #include <stdio.h>
2:  #include <stdlib.h>
3:
4:  main(int argsay, char *argvek[])
5:  {
6:     int toplam;
7:
8:     if(argsay < 3){
9:       printf("Eksik parametre !\n");
10:      exit(0);
11:    }
12:    if(arguman_sayisi > 3){
13:       printf("Çok fazla parametre !\n");
14:       exit(1);
15:    }
16:
17:    toplam = atoi(argvec[1])+atoi(argvec[2]);
18:    printf("Toplamları %d\n",toplam);
19:
20:  }
Program 19.3 in derlendikten sonra MS DOS ve Linux ortamında çalıştırılması şöyledir:
MS DOS                      | UNIX / Linux
----------------------------+-----------------------
c:\>topla 1 2               |$ topla 1 2
Toplamları 3                |Toplamları 3
                            |
C:\>topla 9 5 8             |$ topla 9 5 8
Çok fazla parametre !       |Çok fazla parametre !
                            |
C:\>topla 5                 |C:\>topla 5
Eksik parametre !           |Eksik parametre !
                            |
Komut satırında yazılan dosya adı dahil toplam parametre sayısı 3 tür. Bunlar:
argsay = 3

      1            2            3
    -----        -----        -----
             
    topla          58           34

      ^            ^            ^
      |            |            |
   argvek[0]    argvek[1]    argvek[2]
şeklindedir.

21 Ocak 2015 Çarşamba

Port Kavramı
Bu kısıma başlamadan önce port kavramları konusunda giriş seviyesinde bilgi sahibi olmak gerekir. Bunun için burayı tıklayın. Eğer port kavramı konusunda yeterli bilgiye sahip olduğunuzu düşünüyorsanız bu kısmı atlayabilirsiniz.
Portların Kontrolü
Geliştirilen bir program içerisinden donanımsal öğelere erişmek veya onları kullanmak için birçok yol vardır. En yalını, ki sistem mimarisi buna izin veriyorsa, bu gibi birimlere aynı bellek gözüne erişilmiyormuş gibi işaretçi değişkenler kullanılmıştır; ancak bu durum sistem mimarisinden dolayı her zaman mümkün olmayabilir. Bu durumda, ilgili birimlere erişmek için derleyicilerin sahip olduğu hazır kütüphane fonksiyonları kullanılır.
Port Giriş/Çıkış Fonksiyonları
Bir bilgisayarın portlarına erişmek için (outport()intport() gibi) birçok fonksiyon vardır. Bunlar, sistemin sahip olduğu donanımsal öğelere port üzerinden erişilmesi imkanını sunar. Sistemin donanımsal öğelerine erişmek için derleyiciler birçok fonksiyona sahiptir; tüm listesi için kullanılan derleyicinin başvuru kitabına bakılmalıdır. Tablo 18.1 de, Turbo C derleyicisinde bululunan ve bu konu ile ilgili birkaç fonksiyon tanıtılmıştır (bunlar dışında birçok fonksiyon da vardır!).
Tablo 18.1 : Turbo C derleyicisine ait bazı port fonksiyonları
Port FonksiyonuAçıklama
void outp(int port_adresi,int bayt_degeri);Porta bir baytlık veri yazar
void outport(int port_adresi,int deger);Porta bir kelime* yazar
void outportb(int port_adresi,unsigned char deger);Porta bir baytlık veri yazar
int inp(int port_adresi);Porttan bir baytlık veri okur
int inport(int port_adresi);Porttan bir kelime okur
char inportb(int port_adresi);Porttan bir baytlık veri okur
int peek(unsigned segment, unsigned offset);segment:offset ile belirlenen bellek alanındaki kelimeyi çağırır
char peekb(unsigned segment, unsigned offset);segment:offset ile belirlenen bellek alanından bir baytlık veriyi çağırır
void poke(unsigned segment, unsigned offset,int deger);segment:offset ile belirlenen bellek alanına bir tamsayı değeri yazar
void pokeb(unsigned segment,unsigned offset, char deger);segment:offset ile belirlenen bellek alanına bir baytlık veri yazar
(*) kelime(word) : Porta yazılacak veya porttan okunacak, bir tamsayının bellekte kaplayacağı alanı temsil eder. (Bu alan sizeof() operatörü ile öğrenilebilir)
Port foksiyonlarının kullanımı, örnek programlar üzerinde, bir sonraki bölümde incelenmiştir. Örnekler, programlaması kolay olduğu için, PC paralel portu üzerinde yoğunlaştırılmıştır. Programların çıktıları hemen ilgili progam kodunun altında verilmiştir.
Porta Veri Yazma ve Porttan Veri Okuma
Bir önceki bölümde verilen port fonksiyonları, bir PC nin bağlantı noktalarına erişmek veya bellek gözündeki port adreslerine erişmek için kullanılır. Aşağıda bu fonksiyonları daha iyi anlamak için 10 tane örnek program sunulmuştur. (Bütün programlar Turbo C derleyicisinde denemiştir. Eger bu derleyiciye sahip degilseniz, buradan inderbilirsiniz).
Not : Turbo C derleyicisinde port fonksiyonları kullanılırken dos.h başlık dosyası programın başına ilave edilmelidir.
Program 18.1 : outp fonksiyonunun kulanımı
1:  /* outp örneği */
2:  #include <stdio.h>
3:  #include <dos.h.h> /* port fonksiyonları için */
4:
5:  #define DATA  0x0378
6:
7:  int main(void)
8:  {
9:     int deger = 25;
10:
11:    outp(DATA,deger);
12:    printf("\n%X nolu adrese %d değeri yazıldı.",DATA,deger);
13:    return 0;
14: }
378 adresine 25 değeri yazıldı.
Program 18.1 de 5. satırda tanımlanan porta, 11.satırda 25 değeri yazılmaktadır. Bu değer PC paralel portunun DATA uçlarına yazılır. Bu sebeple 25 değeri binary olarak 8 e bölünür, yani 25 = 00011001 şekinde DATA portuna yazılır.
Porta yazılmak veya porttan okunmak istenen veriyi binay olarak görüntülemek mümkündür. PortPrg02 bu amaçla yazılımıştır. Bu işlemin gerçekleşmesi için Programa ayrıca CevFonks.c programı da ilave edilmelidir.
Program 18.2 : outportb fonksiyonun kullanımı
1:  #include <stdio.h>
2:  #include <dos.h>
3:  #include "CvrFonks.c"
4:
5:  #define DATA 0x0378
6:
7:  main()
8:  {
9:     int deger;
10:
11:    deger = 0x19; /* deger = 25 */
12:
13:     outportb(DATA,deger);
14:
15:     printf("\nDATA portuna gönderilen değer %Xh ",deger);
16:     cevir(deger);
17:
18:   return 0;
19: }
Porta gönderilen değer 19h 00011001
3. satıda CvrFonks.c programa eklenmiştir. 11. satırda tanımlanan değer, 5. satırdaki porta, 13. satırda elirtilen outportb fonksiyonu ile yazılmıştır. 16. satırdaki cevir fonksiyonu, porta yazılan değeri sadece 8 bite çevirir ve ekrana yazar. cevir fonksiyonu CevFonks.c fonksiyonunda daha önce tanımlanmıştır. outp ve outportb fonksiyonlarının kullanımının aynı olduğuna dikkat ediniz.
inp ve inportb fonksiyonları, PC bağlantı noktalarından bir baytlık veri okumak mümkündür. PortPrg03 bu fonksiyonlar ile nasıl veri okunacağına dair iyi bir fikir verir. Ayrıca bu iki fonksiyonun kullanımının aynı olduğuna dikkat ediniz.
Program 18.3 : inp ve inportb fonksiyonlarının kulanımı
1:  /* inp ve inportb fonksiyonlarıyla ile paralel porta atanan varsayılan değerleri öğrenme */
2:  #include <dos.h>
3:  #include <stdio.h>
4:
5:  #define DATA    0x0378
6:  #define STATUS  DATA+1
7:  #define CONTROL DATA+2
8:
9:  main()
10: {
11:    int  veri;
12:
13:    puts("Paralel porta atanan varsayılan değerler (Hex):");
14:
15:    veri = inp(DATA);
16:    printf( "Data portu    : %X\n",veri );
17:
18:    veri = inp(STATUS);
19:    printf( "Status portu  : %X\n",veri );
20:
21:    veri = inportb(CONTROL);
22:    printf( "Kontrol portu : %X\n",veri );
23:
24:    return 0;
25: }
Paralel porta atanan varsayılan değerler (Hex):
Data portu    : 4
Status portu  : 7F
Kontrol portu : CC
Port adresleri 5. 6. ve 7. satırlarda tanımlanmıştır. inp ve inportb foksiyonları ile okunanan değerle (sırasıyla DATA,STATUS ve CONTROL) veri değişkenine aktarılmış ve ekrana yazıldırılmıştır. Bu değerler porta hiç bir müdehale olmadan elde edilmiştir ve her bilgisayarda başka bir sonuç verebilir. Bu fonksiyonların tek parameteresi olduğuna dikkat ediniz.
Bir porta her hangi bir veri yazıldıktan sonra, bu veri o portun saklayıcısına (register) yazılır ve yeni bilgi yazılmadıkça orada veri kalır. PortPrg05 CONTROL portuna ouportb ile yazılan bir verinin inportb fonksiyonu ile okunması gösterilmiştir.
Program 18.4 : inportb ve outportb fonksiyonlarının kullanımı
1:  /* inportb ve outportb örneği */
2:  #include <stdio.h>
3:  #include <dos.h>
4:  #define PORT 0x037A  /* kontrol portu */
5:
6:  main()
7:  {
8:     int deger;
9:
10:    deger = inportb(PORT);  /* varsayılan deger */
11:    printf("\nPorta veri yazılmadan önceki değer : %X",deger);
12:
13:    deger = 0x0A;   /* deger = 10 */
14:    outportb(PORT,deger);
15:
16:    deger = inportb(PORT);
17:    printf("\nPorta veri yazdıktan sonraki değer : %X",deger);
18: }
Porta veri yazılmadan önceki değer : CC
Porta veri yazdıktan sonraki değer : CA
4. satırda belirtilen porta, A değeri 14. satırdaki outportb fonksiyonu ile yazılmıştır. Yazılan değer CONTROL portunun saklayıcısında saklanmaktadır. Daha sonra bu saklayıcıdan aynı veri 16. satırdaki inport fonksiyonu ile okunmaktadır. Program çıktısı incelendiğinde, portta varsayılan değerin CC, veri yazıldıktan sonraki değerin CA olduğu görülmektedir.
Not: CONTROL portunun ilk ilk dört bitine müdehale edilebilir. Yani birinci C değeri değiştirilemez.
Bazen paralel porttan istenen çıkış 8 bitten fazla olabilir. Bu durumda DATA portuna ek olarak CONTROL portunun kullanılması gerekir. DATA portunun 8 bitlik çıkışına, CONTROL portunun 4 bitlik çıkışları da ilave edilirse toplam 12 bitlik çıkış almak mümkün olur. PortPrg05 12 bitlik veri çıkışının nasıl yapılabilceğini göstermektedir. Kullanılan yöntem özetle şöyledir:
  • Veri 3 basamaklı Hex olarak ifade edilir. Çünkü 3 basamaklı Hex veri 12 bitlik binary veriye denktir.
    Örneğin A2F = 101000101111
  • Sağdan ilk 8 bit DATA portuna son 4 bit CONTROL portuna yazılır. Yani veri, veriC ve veriD olarak iki kısma bölünür.
    örneğin A2F = 1010 00101111
  • Soldan ilk 4 bit CONTROL portuna yazılması için, veri bitleri 8 basamak sağa kaydırılır.
    veriC = A2f >> 8 = 000000001010 = A
  • Daha sonra veri bitleri 4 sola ardından 4 sağa kaydırılır.
    A2F << 4 = 001011110000 = 2F0
    2F0 >> 4 = 000000101111 = 2F
    veriD = 2F
  • Böylece veri iki kısma ayrılmış olur.
Program 18.5 : PC Paralel portundan 12 bitlik veri çıkışı
1:  /*
2:     PC Paralel portundan 12 bitlik veri çıkışı:
3:     veri değişkeni bit düzeyinde işlem yapan operatörlerle
4:     iki kısma ayrılır.
5:          veri = veriC + veriD
6:  */
7:
8:  #include <stdio.h>
9:  #include <dos.h>
10:
11: #define DATA    0x0378
12: #define CONTROL DATA+2
13:
14: main()
15: {
16:
17:    int veri,veriC,veriD;
18:
19:    veri = 0xF48;  /* 3-dijit Hex sayı = 12 bit binary sayı */
20:
21:    veriC = veri >> 8; /* CONTROL portuna yazılack veri */
22:
23:    veri <<= 4;
24:    veri >>= 4;
25:
26:    veriD = veri;        /* DATA Portuna yazılacak veri */
27:
28:    outportb(DATA,veriD);
29:    outportb(CONTROL,veriC);
30:
31:    printf("\n12 bitlik veri              : %X%X",veriC,veriD);
32:    printf("\nCONTROL portuna yazılan veri: %X",veriC);
33:    printf("\nDATA    portuna vazılan veri: %X",veriD);
34:
35: return 0;
36: }
12 bitlik veri              : F48
CONTROL portuna yazılan veri: F
DATA    portuna vazılan veri: 48
19. satırdaki veri 21. satırdaki işlemle veriC değişkenine aktarılmıştır. 23. ve 24. satırdaki işlemlerle veri bitlerinden F değeri silinmiş olur. Elde eldilen yeni veri, 26. satırda veriD değişkenine aktarılmıştır. 28. ve 29. satıda veriC ve veriD değerleri sırasıyla CONTROL ve DATA portlarına yazılmıştır.
Paralel porttan belli bir formatla veri çıkış almak mümkündür. Örneğin format DATA uçlarına belli zaman aralıklarıyla sırasıyla 1 değeri göndemek olsun. Bu işlem bit düzeyinde işlem yapan operatörler ve ve basit bir döngü yardımıyla PortPrg06 programında incelenmiştir. Programda kullanılan delay fonksiyonu ile zaman aralıkları seçilmiştir. dos.h kütüphanesinde bulunan bu fonksiyon, kendisine parametre olarak gelen değeri mili saniye olarak kabul eder ve bekletir.
Program 18.6 : DATA-port uclarına sırasıyla 1 değerini gönderme
1:  /* DATA-port uclarına sırasıyla 1 değerini gönderir */
2:  #include <stdio.h>
3:  #include <dos.h>
4:
5:  #define DATA 0x0378
6:
7:  main()
8:  {
9:     int veri,sayac;
10:
11:    sayac = 0;  /* döngü sayacı */
12:    veri  = 1;
13:
14:    while( sayac<8 )
15:    {
16:        outportb(DATA,veri);  /* DATA portuna int veri yaz */
17:        printf("\nPorta yazılan veri : %d",veri);
18:
19:        veri <<= 1; /* veriyi binary olarak birer-birer sola kaydır */
20:
21:        delay(500); /* 500 ms bekle */
22:        sayac++;
23:    }
24: }
Porta yazılan veri : 1
Porta yazılan veri : 2
Porta yazılan veri : 4
Porta yazılan veri : 8
Porta yazılan veri : 16
Porta yazılan veri : 32
Porta yazılan veri : 64
Porta yazılan veri : 128
12. satırda veri değişkenine dögüye girmeden önce 1 (00000001) değeri atanmıştır. Dögü koşulu sınandıktan sonra 16. satırda veri DATA portuna yazılmıştır. 19. satırda verinin içeriği 1 bit sola kaydırılrak DATA portunun sadece bir sonraki ucuna 1 değeri gönderilmiştir. 21. satırda bu verinin DATA portunun saklayıcısında 500 ms saklanmış ve ardından bir sonraki çevrime girilmiştir. Bütün verilerin ekran çıktısı incelendiğinde 2 saysının kuvvetleri olduğu görülür.
Şimdiye kadar paralel portun taban adresini 378h olarak kabul edildi. Bu adres bazı makinalarda farklı olabilir. Fakat şu bir gerçektir ki taban adresleri PCde herzaman belli bir alanlarda(register) yazılıdır. Bu alanlarsegment:offset olarak adlandırılan bölgede saklıdır. segment ve offset değerleri bir değişkeninin (veya bir çevre biriminin) bellekteki (genellikle RAM) adreslerini gösterir. Bu adresler dört çift heksadesimal değerden oluşur. Örneğin segment:offset => 23FB:0017 gibi. segment ve offset adres çiftinin belirli bir kombinasyonu ana bellekteki kesin adresleri belirler. Bu belirlemenin hesaplanışı şu şekildedir:
   segmet:offset => 2083:0100
segment adresinin sağına 0 rakamı ilave edilip offset adresi ile toplanır:
   20830h + 00100h = 20930h (= 133424 desimal olarak)
Çıkan netice ana belleğin 133424. adresini işaret eder. Segmet/Offset yapısı bilgisayarın giriş/çıkış bağlantı noktalarına atanan adresleri öğrenmek ve programlamak için de kullanılabilir. Örneğin paralel portun taban adresi 0000:0408 (yada 0040:0008) şeklinde belirlenen segment:offset adresi ile bellidir. PortPrg07 programında peek fonksiyonu ile paralel port adreslerinin nasıl öğrenileceği gösterilmiştir.
Program 18.7 : peek fonksiyonu ile paralel port adreslerinin öğrenilmesi
1:  /* peek fonksiyonu ile paralel port adreslerinin öğrenilmesi */
2:
3:  #include <dos.h>
4:  #include <stdio.h>
5:
6:  main()
7:  {
8:     unsigned int DATA,STATUS,CONTROL;
9:
10:    DATA    = peek(0x0000,0x0408); /* segmet:offset - 0000:0408 */
11:    STATUS  = DATA + 1;
12:    CONTROL = DATA + 2;
13:
14:    puts("Paralel Port Adresleri (Hex):");
15:
16:    printf("DATA    : %X\n",DATA);
17:    printf("STATUS  : %X\n",STATUS);
18:    printf("CONTROL : %X\n",CONTROL);
19:
20:    return 0;
21: }
Paralel Port Adresleri (Hex):
DATA    : 378
STATUS  : 379
CONTROL : 37A
10. satırdaki peek fonksiyonu ile 0000:0408 adres gözünden alınan değer DATA değişkenine aktarılmıştır. Bu değer 378h dir ve paralel portun taban adresini işaret eder. PortPrg07 ile elde edilen sonuç bir çok makine için geçerlidir. Fakat bazı makinelerde bu değer farklı olabilir. PortPrg08 daha genel amaçlı bir rogramdır ve bütün makinelerde kullanılabilir.
Program 18.8 : Genel amaçlı paralel port programı
1:  /* peek ile elde edilen değer ile porta ver yazma */
2:  #include <dos.h>
3:  #include <stdio.h>
4:  main()
5:  {
6:     unsigned int port;
7:
8:     port = peek(0x0040,0x0008);  /* 0x0000,0x0408 anlamında */
9:     outportb(port,22);
10:
11: }
8. satırdaki port değişkenine peek fonksiyonunun sonucu aktarılmıştır. 9. satırda port ile belirtilen porta (DATA portu) 22 değeri yazılmıştır.
Son olarak peek ve poke fonksiyonlarının kullanımı PortPrg09 ve PortPrg10 da birer örnekle gösterilmiştir. Bu örnekler klavyedeki Num Lock, Caps Lock ve Scroll Lock durumları için hazırlanmış iyi bir örnekdir.
Program 18.9 : Klavyedeki Num Lock, Caps Lock ve Scroll Lock durumlarını inceleme
1:  /* peek ile klavye kontrolü */
2:  #include <stdio.h>
3:  #include <dos.h>
4:
5:  int main(void)
6:  {
7:     int deger;
8:
9:     puts("Klavyedeki Num Lock, Caps Lock ve Scroll Lock durumları:");
10:    deger = peek(0x0040, 0x0017);
12:
13:    if (deger & 16)   puts("Scroll Lock açık");
14:    else              puts("Scroll Lock kapalı");
15:
16:    if (deger & 32)   puts("Num Lock açık");
17:    else              puts("Num Lock kapalı");
18:
19:    if (deger & 64)   puts("Caps Lock açık");
20:    else              puts("Caps Lock kapalı");
21:
22:    return 0;
23: }
Program 18.10 : Scroll Lock tusunu aktifleştirir
1:  #include <stdio.h>
2:  #include <dos.h>
3:
4:  int main(void)
5:  {
6:    printf("Scroll Lock tuşunun kapalı olduğundan emin olup ENTER tuşuna basın\n");
7:    getchar();
8:    poke(0x0000,0x0417,16);  /* scroll lock açılıyor... */
9:    printf("scroll lock şimdi açık\n");
10:   return 0;
11: }


EK: CvrFonks.c

/*
   Bu fonksiyon 10 tabanındaki bir sayıyı
   8 bit olarak 2 tabanına çevirir
*/

void cevir(int x)
{
    int i=0,Binary[8];
    /* x değeri alınıp 2 tabanına çevriliyor ...*/
    while( x>0 )
    {
       Binary[i++] = x%2;
       x /= 2;
    }
    /* x in binary değerleri ekrana yazdırılıyor...*/
    for(i=7;i>=0;i--)
    {
      if( Binary[i]>1 || Binary[i]<0 )
      Binary[i]=0;

      printf("%d",Binary[i]);
    }
}

20 Ocak 2015 Salı

Grafik sistemine geçmek için, initgraph() fonksiyonunu kullanmak gerekir. Tüm çizimler sadece DOS ortamında çalışır. Grafik fonksiyonlarının kullanılması için graphics.h başlık dosyası programın başına ilave edilmelidir. Grafik işlemleri için temel işlemler:
          #include <graphics.h>
          ...
          int surucu=DETECT,grmod;        /* DETECT grafik surucusunu otomatik secer */
          initgraph(&surucu,&grmod,"");   /* grafik ekranını başlatır */ 
          ...
          closegraph();                   /* grafik ekranını kapatır */
şeklindedir.
Bazı Grafik Fonksiyonları
Bu bölümde Turbo C grafik fonksiyonlarının bazıları tanıtılmıştır. Bunların dışında biçok fonsiyon vardır. Bu fonksiyonlar derleyicinin başvuru kitabından öğrenilebilir.
renkler : 0-15 arasında (0-Siyah,15-mor) renk kodları ile (yada ingilizce isimleri örneğin YELLOW gibi) tanımlıdır.
moveto(x,y);Son noktayı (x,y) noktasına taşır
lineto(x,y);Son noktadan (x,y) noktasına düz bir çizgi çizer.
line(x1,y1,x2,y2);(x1,y1) noktasından (x2,y2) noktasına düz bir çizgi çizer.
circle(x,y,r);Merkezi (x,y) olmak üzere yarıçapı r olan bir çember çizer.
arc(x,y,baş_açı,bit_açı,r);Merkezi (x,y) noktasında ve yarıçapı r olan, baş_açı açısından dan başlayıp bit_açı açısına kadar bir yay çizer.
ellipse(x,y,baş_açı,bit_açı,xr,yr);Elipsin bir parçası olan yayı, merkezi (x,y) ve yarıçapları xr, yr olacak biçimde baş_açı açısındandan başlayarak bit_açı açısına kadar bir yay çizer.
putpixel(x,y,renk);(x,y) noktasına verilen renkte bir nokta çizer.
rectangle(sol,üst,sağ,alt);Sol üst köşesi (sol,üst) ve sağ alt köşesi (sağ,alt) koordinatlarında olacak şekilde bir dikdörtgen çizer.
bar(sol,üst,sağ,alt);İki boyutlu ve taralı bir bar çizer.
bar3d(sol,üst,sağ,alt,derinlik,şapka);Üç boyutlu ön yüzeyi taralı bar çizer. Şapka 0 ise barın üst kısmı çizilmez.
setcolor(renk);Çizilen olan şeklin rengini belirler
setbkcolor(renk);Arka alanın rengini belirler.
outtext(*yazılacak ifade);Yazılacak bir ifadenin grafik ekranında yazdırmak için kullanılır.
outtextxy(x,y,*yazılacak ifade);Grafik ekranında yazılacak bir ifadeyi (x,y) ile belirlenen noktadan başlayarak yazar.
settextstyle(font,yazı yönü,yazı boyutu);Ekranda yazılacak olan bir karakterin font'unu, yönünü ve boyutunu belirler. Yön:0 ise yatay, 1 ise dikey yazar.
cleardevice();Ekranı temizler. DOS taki CLS komutu gibi.
closegraph();Grafik ekranını kapatıp normal yazı ekranına döner. (DOS ekranı).
Örnekler
Burada Bir önceki kısımda verilen fonksiyonların, bir kaç uygulaması verilmiştir.
Program 17.1 : Grafik ekranında; bir çizgi, bir çember, bir yay, bir dikdörtgen ve bir elips çizer
1: /* grafik1.c
2:    Bu program, bir çizgi, bir çember, 
3:    bir yay, bir dikdörtgen ve bir elips çizer.
4: */
5: #include <stdio.h>
6: #include <grphics.h>
7:
8: main(){
9:      int sur=DETECT,gmode;
10:      initgraph(&sur,&gmode,"");
11:  
12:      line(12,12,298,198);
13:      circle(200,100,75)  
14:      arc(200,100,90,180,50);
15:      rectangle(10,10,300,200);
16:      ellipse(320,240,0,180,50,70);  
17:
18:      getchar();
19:      closegraph();
20: return 0;  
21: }

Program 17.2 : Ekranda yatay ve dikey iki yazı yazar ve farklı kalınlıkta iki çizgi çizer
1: /* grafik2.c 
2:    Bu program ekranda yatay ve dikey iki yazı yazar ve
3:    farklı kalınlıkta iki çizgi çizer.
4: */
5: #include <graphics.h>
6: main(){
7:       int sur=DETECT,grmode;
8:       initgraph(&sur,&grmde,"");
9:
10:      outtext("Merhaba C.");   
11:      outtextxy(30,40,"Bu yazi YATAY");
13:
14:      settextstyle(2,1,5);   
15:      outtextxy(50,60,"Bu yazi DIKEY");
16:
17:      setlinestyle(0,0,3);
18:      line(320,240,500,350);
19:
20:      setlinestyle(1,1,3);
21:      circle(320,240,100);
23: }

Program 17.3 : y=f(x) ile belirlenen bir fonksiyonu çizer
1:  /* grafik3.c
2:     Bu program, [-20,+20] aralığında sin(x) 
3:     fonksiyonunun grafiğini çizer. 22: satırdaki fonksiyonu
4:     değiştirerek, başka fonksiyonlar da çizilebilir.
5:  */
6:
7:  #include <graphics.h>
8:  #include <math.h>
9:
10:  main(){       
11:      int sur=DETECT,grmode;
12:       float x,y,X,Y,olcek;
13:       initgraph(&sur,&grmde,"");
14:
15:       putpixel(320,240,5);
16:       line(0,240,640,240);
17:       line(320,0,320,480);
18:
19:       olcek=40.0;                    /* Ölçek değiştirilerek zoom yapılabilir.  */
20:
21:       setcolor(YELLOW);              /* Fonksiyonun rengi sarı                  */
22:
23:       for(X=-20.0;X<=20;X+=0.01){    /* X değerleri [-20,20] aralığında         */
24:           Y=sin(X);                  /* sin(x) fonksiyonu                       */
25:           x=320+X*olcek;             /* Dönüşüm denklemleri                     */
26:           y=240-Y*olcek;            
27:           line(x,y,x,y);             /* Fonksiyon çiziliyor...                  */
28:        }
29:
30:    getchar();
31:    closegraph();
32:    return 0;
33:  }

19 Ocak 2015 Pazartesi

C, kullanıcının kendi veri tipini tanımlamasına müsaade eder. Bu kısımda böyle veritiplerinin nasıl oluşturulacağı anlatılacaktır.
enum
Bu tip, değişkenin alabileceği değerlerin belli(sabit) olduğu durumlarda programı daha okunabilir hale getirmek için kullanılır. enum örnekleri Program 13.1 ve Program 13.2 de gösterilmiştir. Genel yazım biçimi:
          enum TipAdı{değer1,değer2,...,değerN}DeğişkenAdı;
TipAdı programcı tarafından verilen tip ismidir. DeğişkenAdı ise program içinde kullanılacak olan değişkenin adıdır. Eğer kullanılmazsa program içinde daha sonra enum ile birlikte kullanılır. Örneğin:
          enum bolumler{programcilik, donanim, muhasebe, motor};
tanımı ile derleyici programcilik için 0, donanim için 1, muhasebe için 2 ve motor için 3 değerini kabul ederek atamaları buna göre yapar. Değişken adı bildirilirse daha sonra enum kullanmaya gerek kalmaz.
          enum renkler{kirmizi,mavi,sari} renk;
          enum gunler{pazartesi,sali,carsamba,persembe,cuma,cumartesi,pazar};
Şimdi istenirse tanımlanan bu tipler program içinde kullanılabilir.
          enum bolumler bolum;
          enum gunler gun;

          bolum = muhasebe /* bolum = 2 anlaminda */
          gun   = cuma;    /* gun = 4 anlaminda   */
          renk  = kirmizi; /* renk = 0 anlaminda  */
Program 13.1 : 3 sabit renk için enum kullanımı
1:  /* enum1.c */
2:  enum renkler{kirmizi,sari,mavi};
3:
4:  main(){
5:       enum renkler renk;
6:       renk = sari;
7:       printf("\n%d",renk);
8:  }
Program 13.2 : 5 sabit bölüm için enum kullanımı
1:  /* enum2.c */
2:  enum bolumler{
3:    programcilik, donanim,   muhasebe, motor, buro
4:  }bolum;
5:
6:  main(){
7:     bolum = donanim;
8:     printf("\n%d",bolum);
9:     bolum +=2;  /* bolum=motor */
10:    printf("\n%d",bolum);
11: }
stuct
C dilinde standart tipler kullanılarak kendi tipinizi üretebilirsiniz. (struct örnekleri Program 13.3 , Program 13.4 ve Program 13.5 te gösterilmiştir). Bu yapının kullanımı:
          struct TipAdı{
       tip deg_ismi;
       tip deg_ismi;
       ...
          };
enum ile sabit bildirimi yapılırken struct ile değişken bildirimi yapılır. Bu yapının faydası, örneğin bir öğrenciye ait bilgileri bir çatı altında toplamak için:
          struct ogrenci{
       char  ad[10],soyad[20];
       long  no;
              short sinif;
          };
Bu tipte bir değişken tanımlama:
           struct ogrenci ogr1,ogr2;
şeklinde olmalıdır. ogr1 değişkeni ile tanımlanan 1. öğrencinin numarasına bir değer atama işlemi:
           ogr1.no = 2012597;
veya
           ogr1->no = 2012597;
şeklinde yapılır.
Program 13.3 : Bir öğrenciye ait bilgilerin tek bir çatı altında toplanması
1:  /* struct1.c */
2:  #include <stdio.h>
3:
4:  struct ogrenci{
5:      char ad[10],soyad[20];
6:      long no;
7:      int  sinif;
8:  }
9:
10: main(){
11:   struct ogrenci ogr;
12:   printf("Ogrenci nosu :");
13:   scanf("%ld",&ogr.no);
14:   if( ogr.no == 2248 )
15:   {
16:      ogr.no    = 2248;
17:      strcpy(ogr.ad,"Ahmet");
18:      strcpy(ogr.soyad,"Bingul");
19:      ogr.sinif = 1;
20:   }
21:   printf("\nNo    : %ld",ogr.no);
22:   printf("\nAdı   : %s ",ogr.ad);
23:   printf("\nSoyadı: %s ",ogr.soyad);
24:   printf("\nSınıfı: %d ",ogr.sinif);
25: }
Program 13.4 : Bir öğrenciye ait bilgilerin tek bir çatı altında toplanması
/* struct2.c */
#include <stdio.h>
struct ogrenci{
    char ad[10],soyad[20];
    long no;
    int  sinif;
}ogr;

main(){
   printf("Ogrenci nosu :");
   scanf("%ld",&ogr->no);
   if( ogr.no == 2248 )
   {
      ogr.no    = 2248;
      strcpy(ogr.ad,"Ahmet");
      strcpy(ogr.soyad,"Bingul");
      ogr.sinif = 1;
   }
   printf("\nNo    : %ld",ogr.no);
   printf("\nAdı   : %s ",ogr.ad);
   printf("\nSoyadı: %s ",ogr.soyad);
   printf("\nSınıfı: %d ",ogr.sinif);
}
Program 13.5 : bir topun x-y düzlemindeki zamana bağlı hareketi
1:  /* struct3.c */
2:  #include <stdio.h>
3:  #include <math.h>
4:
5:  struct koordinat{
6:    float x,y;
7:  }top;
8:
9:  main(){
10:   int i;
11:   float t;
12:
13:   for(t=0.0;t<10.0;t+=0.1){
14:     top->x = 10 - 9*cos(t);
15:     top->y = 5  + 2*sin(t);
16:     printf("%f\t%f",top->x,top->y);
17:   }
18:
19: }
tpyedef
struct ile oluşturulan yapıda typedef deyimi kullanılırsa, bu yapıdan değişken tanımlamak için tekrar struct deyiminin kullanılmasına gerek kalmaz.
         typedef struct kayit{
         char  ad[10],soyad[20];
         long  no;
         short sinif;
         }ogr1,ogr2;
bu kullanımın diğerlerinden farkı yoktur.
Bu deyimin başka kullanımı da vardır. C dilinde program kodları bu deyimle tamamen türkçeleştirilebilir. Örneğin:
          typedef int tamsayi;
şeklinde kullanılırsa programda daha sonra int tipinde bir değişken tanımlarken şu biçimde kullanılmasına izin verilir.
          tamsayi x,y; /* int x,y anlaminda */
union
Bir programda veya fonksiyonda değişkenlerin aynı bellek alanını paylaşması için ortaklık bildirimi union deyimi ile yapılır. Bu da belleğin daha verimli kullanılmasına imkan verir. Bu tipte bildirim yapılırken struct yerine union yazılır.
          union paylas{
                float f;
                int   i;
                char  kr;
          };
Dikkat: Yukarıdaki bildirim yapıldığında, bellekte bir yer ayrılmaz. Değişken bildirimi:
          union paylas bir,iki;
şeklinde yapılır. Üyelere erişmek aşağıdaki gibi olur:
          bir.kr= 'A';
          iki.f = 3.14;
          bir.i = 2000;
Program 13.6 : union x ve y nin aynı bellek alanını işgal ettiğinin kanıtı
1:  /* union1 */
2:  #include <stdio.h>
3:
4:  union paylas{
5:       int x;
6:       int y;
7:  }z;
8:
9:  main()
10: {
11:   int *X,*Y;
12:
13:    z.x = 10;
14:    X = &z.x;
15:    printf("\nTamsayı(x) : %d - bellek adresi %X",z.x,X);
16:
17:    z.y = 20;
18:    Y = &z.y;
20:    printf("\nTamsayı(y) : %d - bellek adresi %X",z.y,Y);
21: }
Tamsayı(x) : 10 - bellek adresi DF23
Tamsayı(y) : 20 - bellek adresi DF23

Çoğu programda, bazı verilerin disk üzerinde saklanmasına gerek duyulur. C programlama dilinde, disk dosyasına erişme (okuma ve yazma için) iki farklı yöntemle yapılır. Bunlar üst düzey ve alt düzey olarak adlandırılır. Bunlardan üst düzey G/Ç yöntemi ANSI tarafından desteklenmektedir. Alt düzey G/Ç ANSI tarafından desteklenmemektedir. Bu yüzden, burada Üst düzey G/Ç konu edilecektir.
Dosya Açma ve Kapama
Bir dosyaya okuma/yazma yapmak için onun açılması gerekir. Bunun için fopen() fonksiyonu kullanılır. Açılan dosya fclose() ile tekrar kapatılmalıdır. Genel olarak:
          ...
          FILE *dosya;
          ...
          dosya = fopen(dosya_adı,mod);
          ...
          fclose(dosya);
          ...
mod ile açılacak olan dosyanın ne amaçla açılacağı belirlenir. Bunlar:
          r    (read only) yalnızca okuma için açar. 
          w    (write only) yalnızca yazma için açar.
          a    (append) ekleme yapmak için açar.
          r+   Okuma/yazma için açar.
          w+   Okuma/yazma için açar.
          a+   Okuma/yazma için açar.
deneme.txt adlı bir dosyanın, yazmak için açılıp açılmadığını test etmek için aşağıdaki kod kullanılır:
          #include <stdio.h>
          ...
          FILE *yaz; /* dosya işaretçisi */
          ...
          yaz = fopen("deneme.txt","w");

          if( yaz == NULL)
          {
                 puts("bu dosya acilmiyor...");
                 exit();
          }

          /* açılırsa! dosya işlemleri */
         ...
         fclose(yaz);
         ...
Dosya Fonksiyonları
  Fonksiyon     Görevi
  fopen()       Dosya oluşturur, açar
  fclose()      Dosyayı kapatır
  putc()        Dosyaya karakter yazar
  getc()        Dosyadan karakter okur
  feof()        Dosya sonuna gelindiğini sorgular
  fprintf()     Dosyaya formatlı veri yazar
  fscanf()      Dosyadan formatlı veri okur
  fputs()       Dosyaya katar yazar
  fgets()       Dosyadan katar okur
  fwrite()      Dosyaya dizi yazar
  fread()       Dosyadan dizi okur
Örnekler
Program 12.1 : Bu program klavyeden girilen iki tamsayı ve toplamını deneme.txt adlı bir dosyaya yazar.
1:/* dosya1.c */
2: #include <stdio.h>
3:
4: main()
5: {
6: FILE *yaz;
7: int x,y,z;
8:
9: yaz = fopen("deneme.txt","w");
10: if( yaz== NULL)
11: {
12:  puts("Dosya acilamiyor...\a\n");
13:  exit();
14: }
15:
16: printf("Toplanacak iki sayı girin : ");
17: scanf("%d %d",&x,&y);
18: z = x+y;
19:
20: fputs( "Bu dosya iki sayının toplamsını gösterir!\n",yaz );
21: fprintf(yaz,"%d + %d = %d",x,y,z);
22: fclose(yaz);
23:
24: puts("Bilgiler kaydedildi. Devam etmek için ENTER tuşuna basın.");
25: getchar();
26: }
Toplanacak iki sayı girin : 5 6
Bilgiler kaydedildi. Devam etmek için ENTER tuşuna basın.

+-----------------------------------------------
| Bu dosya iki sayının toplamsını gösterir!
| 5 + 6 = 11
|
Not: deneme.txt dosyası daha önce oluşturulmuşsa Program 12.1 önceki verileri silip yerine yeni verileri yazacaktır. Ekleme yapmak için fopen() fonksiyonunu 'a' modu ile kullanılmalıdır.

Bilgisayarın c:\deneme dizininde bulunan tipler.dat adlı bir dosyaya sahip olduğumuzu varsayalım, ve bu dosyanın içeriği aşağıdaki gibi olsun.
+-------------------------------
|Ahmet
|d
|1256
|65489878
|0.822
|
Buradaki veri tipleri sırasıyla katar, karakter, tamsayı, uzun tamsayı ve reel sayı şeklindedir. dosya2.c programı bu verilerin nasıl okunacağını göstermektedir.
Program 12.2 : Bu program bir dosyaya formatlı yazılmış olan verileri okur ve ekrana basar
1: /* dosya2.c */
2: #include <stdio.h>
3: main()
4: {
5: FILE  *oku;
6: char  ktr[10],kr;
7: int   tam;
8: long  uzun_tam;
9: float reel;
10:
11: if( (oku=fopen("c:\\deneme\\tipler.dat","r")==NULL ){
12:  puts("Dosya açılmadı !\n");
13:  exit();
14: }
15:
16: fscanf(oku,"%s\n%c\n%d\n%ld\n\%f",
17:     ktr,&kr,&tam,&uzun_tam,&reel);
18:  fclose(oku);
19:
20: puts("Dosyadan okunan veriler sırasıyla:");
21: printf(%s\n%c\n%d\n%ld\n\%f",ktr,kr,tam,uzun_tam,reel);
22: 
23: }
Dosyadan okunan veriler sırasıyla:
Ahmet
d
1256
65489878
0.822

Elimizde aşağıdaki gibi bir dosya olsun. Bu dosyadan istediğimiz bir öğrencinin numarasını girerek ona ait bilgilere ulaşılmak istensin. Program 12.3 basit bir veritabanı uygulamasıdır. Bu program öğrencilere ait bilgilerin bulunduğu bir dosyadan veri okur. 16. satırda Öğrencinin numarası istenir. Eğer böyle bir numara varsa öğrenciye ait bilgiler ekrana basılır. Aksi durumda "Kayıt bulunamadı" şelinde bir ileti ekrana basılır.
+------------------------------------------------
|NO     ADI     SOYADI  mt1     mt2     fin
|---    ------- ------  ---     ---     ---
|251 Ahmet   Bingul 100 100     100
|597    Meltem  Bingul  100 100     100
|569    Metin   Celen   54      65      89
|987    Teoman Burak   45      87      65
|
Program 12.3 : Basit bir veritabanı
1: /* dosya3.c */
2: #include <stdio.h>
3:
4: main()
5: {
6: FILE  *notlar;
7: int   i,numara,no,mt1,mt2,final;
8: char  gecici[10],ad[10],soyad[10];
9:
10: if( (notlar=fopen("notlar.js","r")==NULL ){
11:  puts("Dosya açılmadı !\n");
12:  exit(0);
13: }
14:
15: printf("Numara girin: ");
16: scanf("%d",&numara);
17:
18: for(i=0;i<12;i++)
18:  fscanf(notlar,"%s",gecici);
19: 
20: no = 0;
21:
22: while( !feof(notlar) )
23: {
24:  fscanf(notlar,"%d\t%s\t%s\%d\t%d\t%d\n",
25:         &no,ad,soyad,&mt1,&mt2,&final);
26:  if( no==numara ) break;
27: }
28: fclose(oku);
29: if( no ){
30:  puts("Öğrenci Bilgileri:");
31:  printf("Numarası : %d",no);
32:  printf("Adı      : %s",ad);
33:  printf("Soyadı   : %d",soyad);
34:  printf("1.Vize   : %d",mt1);
35:  printf("2.Vize   : %d",mt2);
36:   printf("2.Vize   : %d",mt3);
37: }
38: else
39:  puts("Kayıt bulunamadı");
40:
41: }/*main*/

Bazı uygulamalarda, daha önce bir şekilde hazırlanmış olan bir dosyanın içeriğini değiştirmek gerekebilir. Program 12.4 , eski.dat dosyasındaki verileri yeni.dat dosyasına aşağıdaki çevirir. Program kodları bir dosyadan diger bir dosyaya, bir verinin nasıl taşınacağına dair bir örnek teşkil eder.
    dosya 1                    dosya 2
 _______________           ________________
|X-degerleri    |         |                |
|1.0            |         |X      Y        |
|2.0            |         |1.0    0.0      |
|3.0            |         |2.0    2.5      |
|4.0            |         |3.0    4.9      |
|5.0            |  --->   |4.0    3.2      |
|Y-degerleri    |         |5.0    1.8      |
|0.0            |         |                |
|2.5            |         |                |
|4.9            |         |                |
|3.2            |         |                |
|1.8            |         |                |
|_______________|         |________________|
Program 12.4 : dosya1 in içindeki alt alta olarak yazılmış olan verileri, dosya2 ye şekildeki gibi yan yana yazar
1: /* dosya4.c */
2: #include <stdio.h>
3:
4: main()
5: {
6:       FILE  *oku,*yaz;
7:       float x[5],y[5];
8:       char  dosya1[12],dosya2[12],gecici[10];
9:       int   i;
10:
11:        printf("Verilerin okunacağı dosyanın adı");
12:        scanf("%s",dosya1);
13:        if( (oku==fopen(dosya1,"r"))==NULL ){
14:                printf("%s dosyası acilamiyor...",dosya1);
15:                exit();
16:        }
17:
18:        printf("Verilerin yazılacağı dosyanın adı");
19:        scanf("%s",dosya2);
20:        if( (yaz==fopen(dosya1,"w"))==NULL ){
21:  printf("%s dosyası acilamiyor...",dosya2);
22:  exit();
23:         }
24:
25:     /*dosya1 den verileri oku, bu verileri x[] ve y[] dizilerine sakla */
26:        fscanf(oku,"%s",gecici);  /* rakamlarin disindaki degerleri okumak icin */
27:
28:        for(i=0;i<5;i++)  fscanf(oku,"%f\n",&x[i]);
29:
30:        fscanf(oku,"%s",gecici);
31:
32:        for(i=0;i<5;i++)  fscanf(oku,"%f\n",&y[i]);
33:
34:      fclose(oku); /* verilerin bulundugu dosyayi kapat */
35:
36:      /* dizileri dosya2 ye yaz */
37: fprintf(yaz,"X\tY");
38: for(i=0;i<5;i++)
39:             fprintf(yaz,"%f\t%f",x[i],y[i]);
40:      fclose(yaz); /* verilerin yazildigi dosyayi kapat */
41:
42:        printf("%s --> %s dönüştürme işlemi gerçekleşti.",dosya1,dosya2);
43:
44: return 0;
45:}


Katar bir char tipinde bildirilen karakter dizisidir. Stringler, içeriği harfler, rakamlar, veya bazı semboller olan text bilgilerini tutmak(saklamak) için kullanılır. C dilinde string bildirimi için bir tip deyimi yoktur. Bu yüzden, bir stringe bir dizi gözüyle bakılır. Genel olarak bir string'in bildirimi:
          char string_adı[eleman_sayısı];
şeklindedir. Örneğin 10 elemanlı bir isim bilgisi OgrenciAdi adlı bir string ile tutulmak istenirse:
          char OgrenciAdi[10];
şeklinde programın başında bildirilmelidir.
Stringlere Başlangıç Değeri Atama
Diğer dizi bildirimlerinde olduğu gibi, karakter dizilerine başlangıç değeri verilebilir. Örneğin aşağıda verilen iki bildirim aynı anlamdadır:
          char ktr[5]={'a','h','m','e','t','\0'};
          char ktr[5]="ahmet";
birinci satırdaki bildirimde '\0' (NULL) sembolü karakter dizisinin sonlandığını gösterir. Eğer bir karakter dizisinin kaç elemandan oluşacağı belirtilmezse, başlangıçta bildirilen karakter sayısı kaç tane ise dizinin eleman sayı o kadar olduğu varsayılır.
          char ktr[]="ahmet"; /* 5 elemanlı */
Stringler bazen bir pointer ile gösterilebilir.
          char *ktr="ahmet";
Her dört örnekteki ktr stringinin eleman sayısı 5 tir.
String Üzerinde İşlem Yapan Standart G/Ç Fonksiyonları
printf(); ve scanf();
Bu fonksiyonlar diğer tiplerde olduğu gibi formatlı okuma/yazma amaçlı kullanılır. String formatı %s dir. Aşağıda verilen programları iyice inceleyin. Bu öenekler basitten karmaşığa doğru sunulmuştur. Gerekli açıklamalar program üzerinde gösterilmiştir.
Program 11.1 : Bir stringin ekrana yazılması
1:  main()
2:  {
3:     char ktr[20]="Ahmet";
4:     printf("%s",ktr);
5:  }
Program 11.2 : iki stringin ekrana yazılması
1:  main(){
2:      char *ileti = "Selam dostum";
3:      char isim[] ={'A','l','i','\0'};
4:      printf("%s %s",ileti,isim);
5:  }
Program 11.3 : klavyeden okunan stringin ekrana yazılması
1:  main(){
2:      char ktr[20];
3:      printf("\nBir seyler yazin:");
4:      scanf("%s",ktr);    printf("%s yazdiniz.",ktr);
5:  }
Program 11.4 : Bir stringin formatlı yazılması
1:  main(){
2:       char ad[5]="ahmet";
3:       printf("%10s",ad);
4:  }
Program 11.5 : Bir stringin printf ile yazılması
1:  main(){
2:      char *isim = "ahmet";
3:      printf(isim);
4:  }
Program 11.6 : bir stringin içindeki m karakterinin sayısını öğrenme
1:  main(){
2:      char ktr[20];
3:      int i,sayac = 0;
4:      printf("\nBir seyler yazin :");
5:      scanf("%s",ktr);
6:      for(i=0;ktr[i];i++)
7:      if( ktr[i]=='m' ) sayac++;
8:      printf("yazilanlarin icinde %d tane m harfi var",sayac);
9:  }
puts(); ve gets();
Bu fonksiyonlar sadece stringler üzerinde işlem yapar. printf(); ve scanf(); fonksiyonları gibi klavyeden veri okuma/ekrana bilgi yazma amaçlı kullanılır.
Program 11.7 : puts ve gets fonksiyonları
1:  main(){
2:      char ktr[20];
3:      printf("\nBir seyler yazin: ");
4:      gets(ktr);    puts(ktr);
5:  }
Program 11.8 : bir siringin ilk karkareini yazdırma
1:  main(){
2:     char ad[10],soyad[20];
3:     printf("ADI    : ");
4:     gets(ad);
5:     printf("SOYADI : ");
6:     gets(soyad);
7:     printf("%c. %s",ad[0],soyad);
8:  }
Program 11.9 : puts,gets ve malloc fonksiyonları
1:  main(){
2:      char *ktr;
3:      ktr = (char *) malloc(20);
4:      printf("\nBir seyler yazin: ");
5:      gets(ktr);
6:      puts(ktr);
7:  }
Program 11.10 : bir stringin kaç karkaterden oluştuğunu hesaplar
1:  main(){
2:      char ktr[200];
3:      int  i;
4:       puts("Bir seyler yazin");
5:       gets(ktr);
6:       for(i=0;ktr[i];i++); /* kosul ktr[i]!='\0' anlamindadir*/    
7:       printf("yazilan %d harfdir",i);
8:  }
Bazı String Fonksiyonları
Bu fonksiyonlar standart C dilinde iki stringi karşılaştırmak, bir stringin içeriğini diğerine kopyalamak ve stringin uzunluğunu bulmak vb işlemler için tanımlı fonksiyonlardır. Bu ve benzeri fonksiyonlar kullanılırken string.hkütüphanesi programın başına ilave edilmelidir. Burada sadece bunlardan bir kaçı Tablo 11.1 de verilmiştir.
strstr1 ve str2 birer string ve kr bir karakter olmak üzere:
Tablo 11.1 : string.h kütüphanesine ait, bazı string fonksiyonları
strcmp( str1,str2 );str1 ve str2 yi karşlaştırır
strcpy( str1,str2 );str2 yi str1 e kopyalar
strcat( str1,str2 );str2 yi str1 e ekler
strrev( str );str yi ters çevirir
strlen( str );str nin kaç karakterden oluştuğunu hesaplar
strchr( str,kr );kr ile verilen karakterin str içindeki soldan itibaren yerini verir
Program 11.11 : İki stringin karşılaştırılması
1:  #include <string.h>
2:  main(){
3:     char ktr1[10],ktr2[10];
4:     int sonuc;
5:     printf("1. katar:");gets(ktr1);
6:     printf("2. katar:");gets(ktr2);
7:     sonuc = strcmp(ktr1,ktr2);
8:     if(sonuc>0)        puts("2. 1.den büyük");
9:     else if(sonuc<0)   puts("2. 1.den küçük");
10:    else               puts("2. 1. eşit");
11: }
Program 11.12 : basit bir şifre programı
1:  #include <string.h>
2:  main(){
3:     char sifre[20];
4:     printf("SIFRE : ");
5:     scanf("%s",sifre);
6:    if( strcmp(sifre,"deneme")==0 )
7:        puts("sifre dogru girildi");
8:     else
9:        puts("sifre yanlis!");
10: }
Program 11.13 : Bir stringi diğerine kopyalama
1:  #include <string.h>
2:  main(){
2:     char *str1="ahmet", str2[10];
4:  /* once */
5:     puts(str2);
6:     strcpy(str2,str1);
7: /* sonra */
8:     puts(str2);
9: }
Program 11.14 : bir stringi diğerine ekleme
1:  #include <string.h>
2:  main(){
3:    char *a="ahmet            ";
4:    char *b="bingul";
5:    strcat(a,b);
6:    printf(a);
7:  }
Program 11.15 : strinin uzunluğunu hesaplar
1:  #include <string.h>
2:  main(){
3:     char ktr[100];
4:     puts("Birseyler yazin:");
5:     gets(ktr);
6:     printf("%s %d karakterden oluşmuştur.",ktr,strlen(ktr));
7:  }
Bilgisayarın ana belleği (RAM) sıralı kaydetme bölgelerinden(gözlerinden) oluşmuştur. Her göze bir adres atanmıştır. Bu adreslerin değerleri 0 ila RAMe bağlı olarak MAX arasında değerler alabilir.
Programlama dillerinde bir değişken tanımlandığında, o değişkene tipine bağlı olarak RAMden bir bölge ayrılır. Örneğin rate adlı bir değişken tanımladığımızı varsayalım. Bu değişken bellekte Şekil 10.1 deki bir yere yazılır.
Bir değişkenin bellek gözündeki yeri
Şekil 10.1 : rate adlı değişkenin bellekteki adresi
Pointer(işaretçi), bellek alanındaki bir gözün adresinin saklandığı değişkendir. Pointerlara, veriler(yani değişkenlerin içeriği) değil de, o verilerin bellekte saklı olduğu bellek gözlerinin başlangıç adresleri atanır. Bir pointer, diğer değişkenler gibi, sayısal bir değişkendir. Bu sebeple kullanılmadan önde program içinde bildirilmelidir. Pointer değişkenler şöyle tanımlanır:
          tipadı *ptradı;
Burada tipadı herhangi bir C tip adı olabilir. Değişkenin önüne konan * karakteri indirection operatörü olarak adlandırılır ve tipadı ile bildirilen ptradı değişkenini işaret eder. Örneğin:
          char *kr1;          /* karakter için */
          int *x;             /* tamsayı için */
          float *deger,sonuc; /* deger pointer tipinde sonuc sıradan bir reel değişkenler */
Yukarıda bildirilen pointer değişkenlerden; kr bir karakterin, x bir tamsayının ve deger bir gerçel sayının bellekte saklı olduğu yerlerin adreslerini tutar. Fakat sonuc adlı float değişken sıradan bir gerçel sayıdır.
Bir pointera, bir değişkenin adresini atamak için & adres-operatörü kullanılır. Bu operatör bir değişkenin önüne konursa, o değişkenin içeriği ile değilde adresi ile ilgileniliyor anlamına gelir. Örneğin karakter tipindeki rate adlı bir değişken ve p_rate ise pointer tipinde, rate değişkenini işaret eden bir değişken olsun. Bu durum Şekil 10.2 de gösterilmektedir:
Bir değişken ve onun işaterçisi
Şekil 10.2 : rate adlı sıradan bir değişken ve onu işaret eden p_rate adlı pionter değişkeninin bellekteki dizilimi
Derleyicide şöyle ifade edilir:
          char rate;
          char *p_rate;
          ...
          p_rate = &rate;
Yani p_rate pointeri rate değişkeninin saklandığı adresi işaret etmektedir. Program Program 10.1 pointer kavramını anlamak için oldukça önemli bir örnektir.
Program 10.1 : ilk Pointer programı
/*ptr01.c*/
1: main()
2: {
3:  int x, *isaret;
4:
5:  x = 888;
6: isaret = &x;
7:
8: printf("x in degeri = %d\n",x);
9: printf("x in adresi = %x\n",isaret);
10: printf("x in değeri = %d\n",*isaret);
11: printf("x in adresi = %x\n",&x);
12: }
x in degeri = 888
x in adresi = ffde
x in degeri = 888
x in adresi = ffde
Özetle, eğer ptr adında bir pointera, deg adlı bir değişkene sahipseniz ve ptr = & deg; şeklinde bir atama yapmışsanız:
  • *ptr ve deg, deg adlı değişkenin içeriği ile ilgilidir.
  • ptr ve & deg, deg adlı değişkenin adresi ile ilgilidir.
  • * indirection opreratörü olarak adlandırılır.
  • & adres operatörüdür.
Dinamik Diziler
Bir dizi daha önce anlatıldığı gibi, programın başında kaç elemanlı olduğu belirtilerek bildirilirse, derleyici o dizi için gerekli bellek alanını program sonlandırılıncaya kadar saklı tutar ve o alan başka amaçlar için kullanılmaz. Dizilerde dinamik çalışma, programın çaklıştırılması sırasında gerekli bellek alanının işletim sisteminden istenmesi ve işi bittiğinde bu alanın geri verilmesidir. Bu amaçla standart kütüphanede malloc(), calloc(), realloc() ve free() fonksiyonları vardır. Bu şekilde dizileri kullanmak için:
          ...
          tip *ptr;
          ...
          ptr = malloc(50); /* herbiri 8 bit olan 50 elemanlık yer isteniyor */
          .
          .                 /* kullanılıyor */
          .
          free(ptr);        /* geri veiliyor */
          ...
Program 10.2 ile basit olarak dinamik bir dizinin kullanımı gösterilmiştir.
Program 10.2 : Dinamik bir dizinin kullanımı
1:  #include <stdio.h>
2:  #include <stdlib.h>
3:
4:  main(){
5:          int *x,i,N,toplam=0;
6:          float ortalama;
7:
8:         printf("Eleman sayısı ");
9:         scanf("%d",&N);
10:
11:        x = (int *) malloc(N*sizeof(int)); /* N tane int gözü 
12:                                              isteniyor (Nx2 byte) */
13:
14:         puts("Elemanları girin:");
15:         for(i=0;i<N;i++){
16:           printf("%d.eleman = ",i+1);
17:           scanf("%d",&x[i]);  /* x[i] ile *(x+i) aynı anlamda !... */
18:           toplam += x[i];
19:         }
20:
21:         free(x);  /* ayrılan yer boşaltılıyor... */
22:
23:         ortalama = (float) toplam/N;
24:
25:         printf("Bu %d sayının ortlaması %f dir\n",N,ortalama);         
26:
27: }
5. satırda x değişkeni pointer tipinde tanımlanmıştır. N sayısı 9. satırda klavyeden okutlmuştur. 11. satırda x pointeri için malloc() fonksiyonu ile bellekten N tane int tipinde bellek gözü istenmiştir. malloc() fonksiyonu bellekten istenen yerin başlangıç adresini x değişkenine aktarır. N tane yer istendiğine göre, x, artık N elemanlı bir dizidir. Buna göre x[0] ayrılan bölgenin ilk adresindeki değişkeni temsil eder. Benzer olarak diğer elemanlar da, bellekte peşpeşe sıralanır. Bu yüzden, x 17. satırda bir dizi gibi okutulmuştur. Eğer x bir dizi gibi ifade edilmek istenmiyorsa i. eleman x[i]*(x+i) şeklinde de kullanılabilir. x in elemanların toplamı toplam adlı değişkene 18. satırda aktarılmaktadır. 21. satırda x için ayrılan bellek alanı free fonksiyonu ile serbest bırakılmıştır.
Program 10.2 sıradan bellek kullanımından oldukça farklıdır. Eğer x bir pointer değil de, sıradan bir dizi gibi bildirilseydi, programın başında x in eleman sayısı mutlaka belirtilmesi gerekirdi. Bu bize, pointer kullanımın ne kadar önemli olduğunu gösterir.
Pointer Tipindeki Fonksiyonlar
Bir fonksiyon tanımlanırken, parametreleri pointer olabileceği gibi, tipi de pointer olabilir. Bu, o fonksiyonun kendisini çağırana bir adres göndereceği anlamına gelir. Bu tip uygulamalar özellikle string uygulamalarında sık kullanılır.
Program 10.3 de, geri dönüş değeri int tipinde olan bir pointer fonksiyon örneği verilmiştir. Bu fonksiyon iki sayının toplamının saklandığı toplam adlı değişkenin adresini, çağırılan yere gönderir.
Program 10.4 : Geri dönüş değeri, pointer olan bir fonksiyon
1:  #include <stdio.h>
2:
3:  int *topla(int,int);
4:
5:  main(){
6:    int a,b;
7:    int *p;
8:
9:    a = 2;
10:   b = 4;
11:
12:   p = topla(a,b);
13:
14:  printf("Toplam : %d (adresi %p)\n",*p,p);
15: }
16:
17: int *topla(int x,int y)
18: {
19:   int *ptr,toplam;
20:
21:   toplam = x+y;
22:   ptr = &toplam;
23:
24:   return ptr;
25: }
Toplamları 6 (adresi 0xbbb7fc4)


Dizi bir kümedir. Aynı tipte verilere tek bir isimle erişmek için kullanılır. Bir dizinin bütün elemanları bellekte peşpeşe saklanır.
Dizi Tipi             Genel bildirimi                                  Örnek
Tek boyutlu diziler   tip ad[eleman_sayısı]                            int veri[10];
İki boyutlu diziler   tip ad[satir_say][sutun_say]                float mat[5][4];
Çok boyutlu diziler   tip ad[boyut_1][boyut_2][boyut_3]...[ boyut_n]   double x[2][4][2];
Aşağıda dizilerin kullanımı il ilgili 10 adet örnek sunulmuştur. Örnekleri dikkatle inceleyin.
Program 9.1 : Dizi elamanlarına erişim.
1:  main(){
2:     int i,x[5];
3:     x[0]=5;
4:     x[1]=25;
5:     x[2]=-40;
6:     for(i=0;i<3;i++)
7:       printf("%d\n",x[i]);
8:  }
Program 9.2 : Dizilere başlangıç değeri verme
1:  main(){
2:     int i,x[5]={5,0,6};
3:     int y[]={1,5,9};
4:     puts("X  Y");
5:     for(i=0;i<3;i++)
6:       printf("%d  %d\n",x[i],y[i]);
7:  }
Program 9.3 : Karakter dizisi (String)
1:  main(){
2:     int   i;
3:     char  ad[][15]  ={"Ahmet",
4:                       "Mehmet","Can"};
5:     int   kilo[]={70,60,52};
6:     float boy[] ={1.70,1.85,1.45};
7:     puts("\nISIM\tKILO\tBOY");
8:     for(i=0;i<3;i++)
9:        printf("%s\t%d\t%1.3f\n",ad[i],kilo[i],boy[i]);
10: }
Program 9.4 : Beş sayının ortalama hesabı
1:  main(){
2:      int   i,x[5],toplam =0;
3:      float ort;
4:      for(i=0;i<5;i++){
5:        printf("%d. eleman : ",i+1);
6:        scanf("%d",&x[i]);
7:        toplam += x[i];
8:      }
9:      ort = (float) toplam/5;
10:     printf("ortalamalari : %f",ort);
11: }
Program 9.5 : Dizilerin fonksiyonla kullanma
1:  void yaz(int x[]);
2:  main(){
3:      int x[10];
4:      yaz(x);
5: }
6:
7:  void yaz(int x[]){
8:     int i;
9:     for(i=0;i<10;i++)
10:      printf("%d\n",x[i]);
11: }
12:
Program 9.6 : Dizinin bellekte kapladığı alan
1:  main(){
2:     char   dizi1[10];
3:     int    dizi2[10];
4:     float  dizi3[10];
5:     double dizi4[10];
6:     printf( "%d\n",sizeof(dizi1) );
7:     printf( "%d\n",sizeof(dizi2) );
8:     printf( "%d\n",sizeof(dizi3) );
9:     printf( "%d\n",sizeof(dizi4) );
10: }
Program 9.7 : On elemanlı bir diziye ait elamanların sırlanaması
1:  main(){
2:    int x[10],i,j,gec;
3:    puts("5 tane sayi gir:");
4:    for(i=0;i<5;i++)
5:    {
6:      printf("%d.sayi : ",i);
7:      scanf("%d",&x[i]);
8:    }
10:
11:   for(i=0;i<4;i++)
12:   {
13:       for(j=i+1;j<5;j++)
14:       {
15:    if( x[j]<x[i] )
16:       {
17:          gec = x[i];
18:          x[i] = x[j];
19:          x[j] = gec;
20:  }
21:   }
22: }
23:
24:
25:   for(i=0;i<5;i++)
26:    printf("\n%d",x[i]);
27:
28:  }
Program 9.8 : İki matrisin toplamı
1:  main(){
2:     int i,j,A[3][3],B[3][3],C[3][3];
3:     puts("iki matrisin toplami:");
4:     puts("A matrisinin elemanlarini girin:");
5:     for(i=0;i<3;i++){
6:        for(j=0;j<3;j++){
7:           printf("A(%d,%d)=",i+1,j+1);
8:      scanf("%d",&A[i][j]);
9:        }
10:   }
11:
12:   puts("B matrisinin elemanlarini girin:");
13:   for(i=0;i<3;i++){
14:      for(j=0;j<3;j++){
15:         printf("B(%d,%d)=",i+1,j+1);
16:      scanf("%d",&B[i][j]);
17:      }
18:   }
19:
20:   puts("A+B matrisinin elemanlari:");
21:   for(i=0;i<3;i++){
22:      for(j=0;j<3;j++){
23:         C[i][j] = A[i][j] + B[i][j];
24:         printf("C(%d,%d)=%d\n",i+1,j+1,C[i][j]);
25:      }
26:   }
27:
28: }
Program 9.9 : Elemanları (0,100) arsında olan rasgele dizi
1:  #include <time.h>
2:  #include <stdlib.h>
3:  main(){
4:     int i,x[10];
5:     randomize();    /* rasgele sayı üretecini başlatır */
6:     for(i=0;i<10;i++)
7:     {
8:       x[i]=random(100);       /* 0-100 arasında rasgele sayı seçiliyor */
9:       printf("%d\n",x[i]);
10:    }
11: }
Program 9.10 : Dizi elemanlarının bellekteki sıralanış adresleri
1:  main(){
2:    int i,x[10];
3:    puts("x dizisinin elemanlarının sıralanışı");
4:    for(i=0;i<10;i++)
5:     printf("%p\n",&x[i]);
6:  }