C Programlama Dilinde En Sık Yapılan 10 Hata

source-code-583537_1280

C programlama dilinin tarihi 70’li yıllara dayansa da günümüzde hala yaygın olarak kullanılan dillerden birisi. Özellikle gömülü sistemlerde en çok kullanılan dil olma özelliğini koruyor. Oldukça esnek yapısıyla assembly’de yazılmış programlara yakın performanslı programlar yazılmasını sağlıyor. Ancak bu esneklik bütün sorumluluğu programcıya bıraktığından birçok hatanın yapılmasına da yol açabiliyor. Zaman zaman birçok güvenlik açığının sebebi de olabilen C programlama diline yapılan hatalardan en yaygın olan 10 tanesini burada paylaşacağım.

  1. Noktalı virgülü kullanılmaması gereken yerde kullanmak
    C’de zaman zaman karıştırılan durumlardan birisi de noktalı virgülün (;) kullanımıyla ilgili. Hemen hemen bütün ifadelerin sonuna konulduğu halde if, for, while gibi ifadelerin sonlarında noktalı virgül olmaması gerektiği bazen unutulabiliyor. O zaman da aşağıdaki koddaki gibi durumlar ortaya çıkabiliyor.

    for( x = 1; x<10; x++ );
    {
    printf( "%d\n", x )
    }

    Yukarıdaki örnekte for ifadesi ile 1’den 9’a kadar olan sayıların yazdırılması amaçlanıyor. Ancak for ifadesi sonundaki noktalı virgün yüzünden for ifadesinin sonrasında “boş” bir ifade varmış gibi işlem yapılıyor ve prinf() fonksiyonu 1 kere çağırılıp devam ediliyor.

  2. Süslü parantez kullanılmayan if ifadeleri
    if ( degisken == 12) 
    fonk1();
    fonk2();

    if gibi kontrol yapılarından sonra eğer tek satırlık bir ifadenin çalıştırılmasını istiyorsak süslü parantez kullanmamıza gerek yok. Ancak sonrasında yeni ifadeler eklenip süslü parantez açılması unutulabiliyor. Dolayısıyla yukarıdaki kodlara ilk sefer bakıldığında if içerisindeki şart sağlandığında her iki fonksiyonun da işletileceği düşünülebilir. Ancak fonk1 fonksiyonu şarta bağlı olarak çalıştırıldığı halde fonk2 fonksiyonu her zaman çalışacaktır. Bu hatanın en önemli örneklerinden birisi geçtiğimiz aylarda web sayfalarında güvenli bağlantılar sağlamakta yaygın olarak kullanılan SSL kütüphanelerinde ortaya çıktı.

  3. Değer atanmamış değişken kullanımı
    Stack’te oluşturulan otomatik değişkenlere başlangıçta bir değer atanmaz dolayısıyla kendiniz bir değer atamadığınız sürece “çöp” değerler alırlar. Eğer programınızda bu değişkenlere başlangıç değeri atamadan kullanırsanız programınız düzgün olarak çalışmayacaktır. Tanımladığınız bütün değişkenlere başlangıç değeri vermeyi alışkanlık haline getirmekte fayda var.
  4. Değişken tip dönüşümleri
    C’de işaretli (signed) ve işaretsiz (unsigned) değişkenleri bir arada kullandığınızda otomatik olarak tip dönüşümleri uygulanabilir (integer promotion). Bu nedenle çoğu zaman hatalı durumlar oluşacaktır. İşaretli değerler genelde işaretsiz değerlere dönüştürüldüğünde negatif bir sayı, pozitif çok büyük bir sayıya dönüşebilir.

    unsigned int a = 12;
    int b = -3;
     
    if ( b < a) {
    fonk1();
    }

    Yukarıdaki karşılaştırma ifadelerinde işaretli ve işaretsiz değişkenler bir arada kullanıldığından işaretli değişken otomatik olarak işaretsiz hale çevrilerek işlem yapılır. Bu nedenle işaretli olarak düşük bir sayısal değere sahip olan değişken işaretsiz olduğundan yüksek bir değer alacak ve karşılaştırma hatalı olacaktır. Bu nedenle işaretli ve işaretsiz değişkenleri bir arada kullanmaktan kaçınmalısınız.

  5. Dizi taşmaları (buffer overflow)
    C’deki dizilerin elemanlarına indis değeri vererek erişiriz. Ancak C’de dizilerde boyut kontrolü olmadığından eğer dizilere boyutundan büyük bir elemana erişmek isterseniz derleyici hata vermeyecektir. Programınızın ne yapacağı da şansa kalmış!

    int ornekDizi[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for( i = 0; i<11; i++ )
    {
      ornekDizi[i] = i+1;   
    }

    Yukarıdaki örnekte dizinin elemanlarına for döngüsü ile erişiliyor. Döngünün son turunda
    i değişkeni 10 değerini alıyor ancak dizimiz 10 elemanları olduğundan son elamanın indis değerinin
    9 olması gerekiyor. Dolayısıyla burada hatalı bir erişim var. Geçmiş olsun!

    Bu hata en yaygın güvenlik açıklarından birisi olan “buffer overflow”‘ olarak anılır.

  6. Karşılaştırma ifadelerinde “==” yerine “=” kullanmak
    C’de en sık yapılan hatalardan birisi karşılaştırma amaçlı “==” operatörü ile atama operatörünün “=” karıştırılmasıdır. Bu durumda if, while gibi ifadeler içerisindeki şart her zaman True değeri döndürdüğünden programınız hatalı çalışacaktır. Bu hatadan kaçınmak için karşılaştırma ifadesinde sabiti önce değişkeni sonra yazabilirsiniz: if (2 == x) şeklinde.
    Benzer şekilde  != ifadesi yerine =! yazıldığında da hatalı sonuçlar oluşacaktır.

    if (degisken == deger)
     
    if(degisken = 2)
    {
    ...
    }
    // ya da
     
     
    if(degisken =! 2)
    {
    ...
    }
  7. Switch ifadesinde break’leri unutmak
    switch(degisken)
    {
    case 1:
     fonk1();
    break;
     
    case 2:
     fonk2();
     
    case 3:
     fonk3();
    break;
     
    default:
     fonk4();
    break;
    }

    switch-case yapısında bir değişken birden fazla değerle karşılaştırılıp her durum için farklı işlemler yapılması sağlanılır. Her bir case grubu break ile sonlandırılıp programın çalışması switch ifadesinden sonraki bölümden devam eder. Ancak case ifadelerinden sonra break unutulursa, o case bloğundan sonraki case bloğu da işletilir ve istenmeyen bir durum oluşur. Bazı durumlarda bu istenilerek de yapılabilir ancak bu durumda bir yorumla bunun istenilerek yapıldığı belirtilmelidir.

  8. Tam sayı bölmesi hatası
    Tam sayılarla bölme işlemi yapıldığında sonuç kesirli bir sayı olabilir. Siz de bunu düşünerek sonucu float yada double cinsinden bir değişkene atayabilirsiniz ancak aşağıdaki örnekte olduğu gibi sonuç 2.4 değil 2 olacaktır.

    int sayi1 = 12;
    int sayi2 = 5;
    float sonuc = 0;
    sonuc = sayi1 / sayi1;

    Bunun sebebi iki tam sayı bölündüğünde sonucun da tam sayı olarak işlem görerek ondalık kısmın kaybolmasıdır. Bunu çözmek için bölümdeki değişkenlerin en az birisinin ondalık sayı olması gerekiyor.

    int sayi1 = 12;
    int sayi2 = 5;
    float sonuc = 0;
    sonuc = sayi1 / (float)sayi1;
  9. Karakter dizileri (string) ile çalışırken “null” karakterini unutmak
    char string[10];

    Yukarıda 10 karakterlik bir karakter dizisi tanımladık. Ancak bu diziye en fazla 9 karakterli bir string atayabiliriz. Çünkü C’de bütün karakter dizilerinin sonunda NULL karakteri (\0) yer alır. Bu unutulduğunda string’lerle ilgili birçok fonksiyon doğru çalışmayacaktır.

  10. İşaretçilere (pointer) adres yerine farklı bir değer atamak
    Son hatamız da C hakkında en çok zorlanılan konularından biri olan işaretçilerle (pointers) ilgili.

    int * ptr;
    int m = 20 ;
    ptr = m;

    Yukarıda işaretçiye bir m değişkeninin adresi yerine değeri atanmaya çalışılıyor. Sonrasında ptr ile işlem yapıldığında geçersiz bir adres içerdiğinden hatalı sonuçlar oluşacaktır. Doğrusu aşağıdaki gibi olmalıdır.

    int * ptr;
    int m = 20 ;
     
    ptr = &m;

Daha çok kişiye ulaşabilmesi için yazımı sosyal medyada paylaşmayı unutmayın lütfen!

2 thoughts on “C Programlama Dilinde En Sık Yapılan 10 Hata

  1. kolay gelsin

    bende bahsettiğiniz benzer bir hata almaktayım yardımcı olursanız sevinirim.üç farklı dizim var;

    int nozula[4] = {0,1,2,3};
    int nozulb[4] = {4,5,6,7};
    int nozulc[4] = {8,9,10,11};

    bu dizilerdeki sayılar ile for döngüsü içerisindeki int i aynı olunca karşılaştırma yapmasını istiyorum, şöyle;

    for(i = 0; i ara)){digitalWrite(LEDG, HIGH);}
    if ((i == nozulb[i]) && (Array[i] > ara)){digitalWrite(LEDB, HIGH);}
    if ((i == nozulc[i]) && (Array[i] > ara)){digitalWrite(LEDR, HIGH);}
    }

    şöyle bir hata yapıyor tek başına nozula çalışıyor fakat nozulb satırı ve nozulc satırı çalışmıyor.iyi çalışmalar.

  2. ben hatanın diğer dizilerde sıfırdan başlaması gerektiğinden kaynaklandığını düşünüyorum.Çünkü ikinci dizi olan nozulb’nin başına sıfır koyunca sorun düzeldi yani hata dizinin başladığı elemandan başlatmak şu anki problem bu olmalı…

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak.