HARİTA MÜHENDİSLERİ İÇİN C DİLİ UYGULAMALARI

Transkript

HARİTA MÜHENDİSLERİ İÇİN C DİLİ UYGULAMALARI
HARİTA MÜHENDİSLERİ İÇİN C DİLİ UYGULAMALARI
C BİLGİSAYAR
BİLGİSAYAR PROGRAMLAMA DERSLERİ İÇİN UYGULAMALAR
HAZIRLAYAN
Prof.Dr. İ. Öztuğ BİLDİRİCİ
İÇİNDEKİLER
1. PROGRAMLAMA ORTAMI ...................................................................................................3
1.1
Proje Klasörü .................................................................................................................3
1.2
Visual Studio .NET EXPRESS 2010.............................................................................5
2. BASİT PROGRAMLAR .........................................................................................................10
2.1
İlk Program ..................................................................................................................10
2.2
printf ile hesaplama......................................................................................................10
2.3
Tam Sayılarla Hesaplama ............................................................................................11
2.4
Reel Sayılarla Hesaplama ............................................................................................11
2.5
Formatlı Sayı Gösterimi...............................................................................................12
2.6
İki nokta arasındaki kenar hesabı.................................................................................13
2.7
İki Nokta Arasında Açıklık Açısı Hesabı.....................................................................14
2.8
for Çevrimi ile Toplama...............................................................................................15
2.9
Faktöriyel .....................................................................................................................16
2.10
İç İçe for Çevrimi: Çarpım Tablosu Programı .............................................................17
2.11
Alan Hesabı..................................................................................................................17
2.12
e Sayısının Hesabı........................................................................................................19
3. KARAKTER, DİZİ ve POINTER KULLANILAN ÖRNEKLER ..........................................19
3.1
Dizi Kullanarak Alan Hesabı .......................................................................................19
3.2
Pointer Kullanımı.........................................................................................................20
3.3
Karakter Dizileri Örneği ..............................................................................................20
4. FONKSİYON KULLANILAN PROGRAMLAR...................................................................22
4.1
Fonksiyonlara Değer Aktarma .....................................................................................22
4.2
Açıklık Açısının Fonksiyon Olarak Programlanması ..................................................23
4.3
Açıklık Açısı ve Kenarı Birlikte Döndüren Fonksiyon................................................25
4.4
Fonksiyonlar Arası Dizi Aktarma ................................................................................26
4.5
Fonksiyon Olarak Alan Hesabı ....................................................................................27
İ.Ö.BİLDİRİCİ, 02.04.12
1
5. DOSYA KULLANIMI ............................................................................................................28
5.1
Dosyadan Okuma.........................................................................................................29
5.2
Dosyaya Yazma ...........................................................................................................30
5.3
İki Boyutlu Dizilerle Çalışma: Matris Çarpımı............................................................31
6. İLERİ TEKNİKLER................................................................................................................33
6.1
Struct, Union ve Typedef .............................................................................................33
6.2
Struct ve Dosya Kullanımı...........................................................................................35
6.3
Komut Satırından Parametre Almak ............................................................................36
6.4
Sisteme Komut Göndermek .........................................................................................37
6.5
Header File Kullanmak ................................................................................................38
7. C++ ÖRNEKLERİ...................................................................................................................39
7.1
Ekrandan Veri Giriş Çıkışı...........................................................................................39
7.2
Dosya İşlemleri ............................................................................................................40
7.3
Nesneye Yönelik Programlama ...................................................................................41
İ.Ö.BİLDİRİCİ, 02.04.12
2
1. PROGRAMLAMA ORTAMI
Metinde verilen uygulamalar herhangi bir yazılım geliştirme ortamına bağlı değildir. Laboratuar
uygulamalarında yazılım geliştirme ortamı olarak Microsoft Visual Studio 6.0 ya da Microsoft
Visual Studio.Net kullanılmaktadır. Bu bölümde her iki ortamda da “console application”
(komut satırından çalışan program) oluşturma konusunda kısaca bilgi verilecektir. Günümüzde
kullanılan tüm yazılım geliştirme ortamları proje mantığına göre çalışırlar. Proje mantığında
proje dosyasında projeyi oluşturan kod dosyalarının adresleri ve proje ile ilgili genel
ayarlamalar saklanır. Kod dosyaları yanında başka dosyalarda oluştuğundan proje bir klasörde
saklanır.
1.1
Proje Klasörü
Projeniz için ilk olarak Windows Explorer (Windows Gezgini) ile bir klasör oluşturun.
Windows Explorer iki şekilde açılabilir:
1. Masaüstünde My Computer ikonuna sağ tuş ile tıklayın . Burada “Explore” (Araştır) seçin.
2. Windows tuşu ve “e” tuşuna birlikte basın. Windows tuşu klavyede sol tarafta Ctrl ve Alt
tuşları arasındaki tuştur.
Windows
tuşu
Ctrl
Alt
Aşağıdaki şekilde Windows Explorer penceresi görülmektedir. Pencerenin sol tarafında
bilgisayarınızdaki kayıt ortamları (disket, sabit diskler, CD, masaüstü vb). Sağ tarafta ise sol
tarafta seçilen elemanın içeriği görülmektedir.
Çalışma klasörü olarak d:\harita\xxxxxxxxx\prjy (x’ler yerine numaranızı yazınız, y yerine
proje no yazınız) kullanılacaktır. Klasör açmak için sol pencerede D diskini seçin sağ
pencerede boş alanda farenin sağ tuşuna basın “New Folder” (Yeni Klasör) seçin.
Kullandığınız bilgisayarda D diski yok ise aynı işlemi C diskinde yapınız. Bu anda “New
Folder” olarak adlandırılmış bir klasör oluşacaktır. Bu yazı seçilmiş durumda iken (karartılmış
durumda) klavyeden klasör ismini girip enter tuşuna basın. Klasör ismi değişmiş olacaktır. Fare
ile çift tıklayarak bu klasörü açabilirsiniz. Klasör ismi olarak “harita” girerken mutlaka
küçük harflerle yazınız!
İ.Ö.BİLDİRİCİ, 02.04.12
3
Disket
Sabit diskler
CD
Bu alanda farenin sağ
tuşu ile tıklayın!
Klasörler açılmış ise yeniden açmaya çalışmayınız! Örneğin harita klasörü varsa açın, içinde
numaranız olup olmadığına bakın yoksa açın. İşlemi doğru yapmış iseniz Windows Explorer
penceresi aşağıdaki gibi görünecektir. Pencereyi minimize edip programlama ortamını
çalıştırın.
İ.Ö.BİLDİRİCİ, 02.04.12
4
Pencereyi minimize
etmek için bu
ikona tıklayın!
Sağ pencerede daha sonra kendi klasörünüz altında oluşturacağınız proje klasörünüzü
diskete kopyalamak için sol pencerede proje klasörü üzerinde farenin sağ tuşuna tıklayın.
Açılan menüden “Send to Floppy” seçin. Klasörü seçip, sürükleyip disket sürücü (Floppy A:)
ikonu üzerine bırakarak da aynı işlemi yapabilirsiniz. Disketten proje klasörü kopyalamak için
ise D diskinde açtığınız klasör (numaranız) görünürken disket sürücü (Floppy A:) ikonuna
tıklayın sağ tarafta disketin içeriği görünecektir. Buradan proje klasörünü seçin, sürükleyip D
diskinde açtığınız klasöre (numaranız) sürükleyin.
1.2
Visual Studio .NET EXPRESS 2010
Laboratuarda VisualStudio.NET yüklü ise bu bölümdeki açıklamaları takip ediniz.
VisualStudio6.0 kullanılıyorsa bu bölümü atlayabilirsiniz.
Start (Başlat) > Programs (Programlar) > Microsoft Visual C++ 2010 Express seçerek programı
çalıştırın. Yeni projeye başlamak için File > New > Project ile aşağıdaki pencerenin
görüntülenmesini sağlayın.
İ.Ö.BİLDİRİCİ, 02.04.12
5
Installed templates kısmından Win32 seçin, sağ taraftaki pencereden Win32 Console
Application seçin. Location kutusunun yanındaki butona (Browse...) basarak açmış olduğunuz
klasörü gösterin (D:\HARITA\), name olarak “proje1” girin. Create directory for solution
kutusunu işaretlemeyin! OK butonuna basın.
Next butonuna bastıktan sonra gelen pencerede Empty Project seçin.
İ.Ö.BİLDİRİCİ, 02.04.12
6
Projeniz açılınca, görünüm aşağıdaki gibi olmalıdır.
Sol tarafta bulunan Solution Explorer penceresinde Surce Files ikonuna farenin sağ tuşu ile
tıklayın, açılan penceren add new item seçin.
İ.Ö.BİLDİRİCİ, 02.04.12
7
C++ File seçin ve dosya adı olarak proje1 (ya da başka bir isim) verin. Kod dosyası eklendikten
sonra dosya adının üzerine farenin sağ tuşu ile tıklayın. Açılan menüden rename seçerek
dosyanın uzantısını c yapın.
İ.Ö.BİLDİRİCİ, 02.04.12
8
Benzer şekilde projenize başlık dosyası da (Header File) ekleyebilirsiniz.
Yazdığınız kodu derlemek ve bağlamak için (compile & link) build menüsünden build ...
(kısayol F7), kodu çalıştırmak için ise Debug menüsünden Start Without Debugging ... (kısayol
Ctrl F5) seçilir.
Projenizi kaydetmek için File > Save all seçin. Projenizi sık sık kaydetmeniz sizin
yararınızadır!
İ.Ö.BİLDİRİCİ, 02.04.12
9
Dikkat: Bir projede yalnızca bir main fonksiyonu olabilir. Bir programı bitirip yeni bir
programa geçmek için yeni bir proje oluşturmak gerekir.
Önceden kaydettiğiniz projenizi açmak için proje klasöründe oluşan vcxproj ya da sln uzantılı
dosyayı (örneğin proje1.sln) açınız. Kod dosyasını (örneğin proje1.c) tıklayarak açmayınız!!!
Projenizi yedeklerken geçici olarak proje klasörü altında oluşturulan ve diskte fazla yer
kaplayan Debug klasörünü silebilirsiniz.
2. BASİT PROGRAMLAR
2.1
İlk Program
Ekrana “Merhaba” mesajı yazdıran bir program kodu aşağıdaki gibidir:
/*prg01*/
#include <stdio.h>
main()
{
printf("\nMerhaba");
}
yukarıdaki kodu inceleyelim:
•
•
•
•
•
•
include tanımlamaları hemen her C programının başında yer alır. Burada programda
kullanılan fonksiyonların hangi kütüphaneden alınacağı bildirilir.
{ ve } ile bir programlama bloğu tanımlanır. Programlama blokları içi içe kullanılabilir.
printf ekranda veri görüntülemek için kullanılan temel C fonksiyonlarından biridir.
Her ifade ; ile sonlandırılır.
C dilinde bir program fonksiyonlardan (alt program parçacıklarından) oluşur. Bir programda
en az bir fonksiyon olmak zorundadır. Programın çalışmaya başlayacağı fonksiyon “main”
olarak adlandırılır. Bu ad değiştirilemez. Bu bağlamda bir program tek bir fonksiyondan
oluşuyorsa o fonksiyonun adı “main” olmak zorundadır.
/* ve */ işaretleri arasında kalan bölüm derleyici tarafından dikkate alınmaz. Bu bölüme
program hakkında notlar yazılabilir.
2.2
printf ile hesaplama
printf fonksiyonu altında hesaplama da yapmak mümkündür:
/*prg02*/
#include <stdio.h>
/* printf fonksiyonu ile hesaplama */
main()
{
printf("\n12*2=%i",12*2);
printf("\n12/2=%i",12/2);
}
Buradaki %i ifadesi ile ilgili yerde integer tipli bir değişken görüntüleneceği belirtilmektedir. \n
ile ekranda imlecin bir alt satıra geçmesi sağlanır. \t tab anlamında olup imleci sekiz boşluk sağa
öteler, \a ise alarm anlamında olup kısa bir ses çalınmasını sağlar.
Programın çalışması sonucunda aşağıdaki gibi bir ekran görüntüsü elde edilir:
12*2=24
İ.Ö.BİLDİRİCİ, 02.04.12
10
12/2=6
2.3
Tam Sayılarla Hesaplama
Verilen iki sayının toplamını, çıkarmasını, çarpmasını yapan bir program için aşağıdaki kod
kullanılabilir:
/*prg03*/
#include <stdio.h>
int main()
{
int x,y;
printf("\n\tHesaplayici\n");
printf("\nx=");
scanf("%i",&x);
printf("\ny=");
scanf("%i",&y);
printf("\n\nx+y=%i\tx-y=%i",x+y,x-y);
printf("\n\nx*y=%i\tx/y=%i",x*y,x/y);
return 0;
}
Yukarıdaki kodu kısaca inceleyelim. İlk olarak integer (tam sayı) tipinde x ve y değişkenleri
tanımlanmıştır. Önceki kodlardan farklı olarak printf içerisinde \t kullanılmıştır. Bunun anlamı
ekranda kürsörün sekiz karakter sağa ötelenmesidir. Bunu klavyeden tab tuşuna basılmış gibi
düşünebiliriz. scanf fonksiyonunda ise ilk olarak tırnak içerisinde ekrandan okunacak değerin
formatı belirtilir. Burada %i bir tamsayı değerin okunacağı anlamına gelir. & işareti ise ileride
ayrıntıları verilecek olarak pointer anlamındadır. Burada sadece &x kodunun x değişkenine
bellekte ayrılan adresi gösterdiğinin bilinmesi yeterlidir.
main fonksiyonunun önünde yer alan “int” bildirimi main fonksiyonunun geriye tamsayı
döndürdüğünü belirtmektedir. Geriye döndürülen değer son satırda return fonksiyonu ile
belirtilir. Bu değer bu program için 0 olarak belirlenmiştir. Fonksiyonun geriye bir değer
döndürmediği “int” yerine “void” ile belirtilebilir. Ancak main fonksiyonu için void bildirimi
LINUX gcc derleyicisi tarafından kabul edilmez.
2.4
Reel Sayılarla Hesaplama
Tamsayılarla hesap yapan program (prg03) bölme işleminde tam bölünme olmaması durumunda
bölme sonucunun ondalıklı kısımlarını vermez. Ondalıklı kısımları elde etmek için reel sayılarla
işlem yapılmalıdır. Bu amaçla C iki değişken tipi içermektedir. Reel sayılar için kullanılan
değişken tiplerinden float 4 byte, double 8 byte uzunluğundadır. prg03 kodunu bir kez de float
tipi kullanarak yazabiliriz.
/*prg04*/
#include <stdio.h>
int main()
{
float x,y;
printf("\n\tHesaplayici\n");
printf("\nx=");
scanf("%f",&x);
printf("\ny=");
scanf("%f",&y);
printf("\n\nx+y=%f\nx-y=%f",x+y,x-y);
printf("\n\nx*y=%f\nx/y=%f",x*y,x/y);
return 0;
}
İ.Ö.BİLDİRİCİ, 02.04.12
11
scanf ve printf fonksiyonlarında bu kez %i yerine %f geldiğini görüyoruz. %f float değişkenler
için kullanılan format tanımlamasıdır. Bu kodu çalıştırdığımızda sayıların ondalık kısımlarının
da görüntülendiğini görürüz. Aynı kodu double tipi kullanarak yazmak gerekirse, float yerine
double %f yerine ise %lf kullanılması gerekir. Reel sayı kullanılması gereken programlarda
yeterli hesap inceliğini riske atmamak için genel olarak float değil double değişken tipi tercih
edilir.
2.5
Formatlı Sayı Gösterimi
Verilen üç sayının toplamını ve ortalamasını bulan bir program yazarak, sonuçların iki
basamaklı olarak gösterilmesi sağlayalım.
/*prg05*/
#include <stdio.h>
int main()
{
double top=0.0,sayi;
printf("\n\tHesaplayici\n");
printf("\n1.sayi=");
scanf("%lf",&sayi);
top=top+sayi;
printf("\n2.sayi=");
scanf("%lf",&sayi);
top=top+sayi;
printf("\n3.sayi=");
scanf("%lf",&sayi);
top=top+sayi;
printf("\ntoplam=%.2lf",top);
top=top/3;
printf("\nortalama=%.2lf",top);
return 0;
}
Değişken tanımlamalarında, double top=0.0 ifadesi top adlı değişkenin başlangıç değerinin sıfır
olarak atandığını ifade etmektedir. C dilinde değişkenlere başlangıç değeri vermek çoğu zaman
gerekli ve yararlıdır. Çünkü başlangıç değeri belirtilmemiş değişkenlerin programın başlama
anındaki değerleri kullanılan derleyiciye göre sıfır olmayabilir. C bu açıdan diğer pek çok
programlama dilinden ayrılır.
top=top+sayi şeklinde bir ifade matematiksel açıdan geçersiz olarak düşünülebilir.
Matematiksel olarak bu eşitliğin sağlanabilmesi için sayi değişkeninin sıfıra eşit olması gerekir.
Ancak buradaki = işareti eşitlik anlamında değil değer ataması anlamında kullanılmıştır. Bu
ifade bilgisayar programlama açısından “top değişkeninin halihazırdaki değerine sayi
değişkeninin değeri ekle ve elde edilen değeri tekrar top değişkenine ata” şeklinde
anlaşılmalıdır. Bu mantıktan hareketle neden top değişkenine başlangıç değeri atandığı daha
kolay anlaşılabilir.
printf fonksiyonlarında kullanılan %.2f format bildirimleri, ilgili değişkenin değerinin ondalık
kısmının iki basamak olarak gösterilmesini sağlar.
Printf fonksiyonunda kullanılan format bildirimleri şunlardır:
d
o
x
u
c
s
f
desimal
oktal
heksadesimal
unsigned (işaretsiz)
karakter
string (karakter katarı)
float (kayar nokta)
İ.Ö.BİLDİRİCİ, 02.04.12
12
Bu harfler, bir yüzde işaretinden sonra kullanırlar. Bu iki harf arasına şunlar ilave edilebilir:
(n)
.
(m)
l
sahasının içinde sola dayanmış
minimum saha uzunluğunu belirler
n ile m yi birbirinden ayırır
float tipi için noktadan sonraki hane sayısı
'long' tipi olduğunu belirtmek için
Değişik formatlı gösterimler için aşağıdaki programı çalıştırıp inceleyin.
/*prg06*/
#include <stdio.h>
int main()
{
int a;
long int b;
short int c;
unsigned int d;
char e;
float f;
double g;
a
b
c
d
e
f
g
=
=
=
=
=
=
=
/* basit tamsayı tipi
/* uzun tamsayı tipi
/* kısa tamsayı tipi
/* işaretsiz (+ - siz) tamsayı
/* karakter tipi
/* reel sayı (tek incelikli)
/* çift incelikli reel sayıkta
*/
*/
*/
*/
*/
*/
*/
1023;
2222;
123;
1234;
'X';
3.14159;
3.1415926535898;
printf("a = %d\n",a);
printf("a = %o\n",a);
printf("a = %x\n",a);
printf("b = %ld\n",b);
printf("c = %d\n",c);
printf("d = %u\n",d);
printf("e = %c\n",e);
printf("f = %f\n",f);
printf("g = %f\n",g);
printf("\n");
printf("a = %d\n",a);
printf("a = %7d\n",a);
printf("a = %-7d\n",a);
printf("\n");
printf("f = %f\n",f);
printf("f = %12f\n",f);
printf("f = %12.3f\n",f);
printf("f = %12.5f\n",f);
printf("f = %-12.5f\n",f);
return 0;
/*
/*
/*
/*
/*
/*
/*
/*
/*
desimal
*/
oktal
*/
heksadesimal
*/
uzun desimal
*/
kısa desimal
*/
işaretsiz
*/
karakter
*/
reel sayı
*/
çift incelikli reel sayı
*/
/* basit 'int' çıktı
*/
/* 7 uzunlukta bir saha kullan*/
/* sola dayalı 7 lik saha
*/
/*
/*
/*
/*
/*
tek incelikli reel sayı */
12 lik bir saha kullan*/
noktadan sonra 3 hane */
noktadan sonra 5 hane */
sola dayalı 12 hane */
}
2.6
İki nokta arasındaki kenar hesabı
Verilen iki noktanın koordinatlarından iki nokta arasındaki kenar,
s=
(x2 − x1 )2 + ( y 2 − y1 )2
ifadesinden hesaplanır. Burada karekök almak için sqrt fonksiyonu, math.h kütüphanesindedir.
/*prg07*/
#include<stdio.h>
#include<math.h>
int main()
İ.Ö.BİLDİRİCİ, 02.04.12
13
{
double x1,y1,x2,y2,s;
printf("\nx1=");
scanf("%lf",&x1);
printf("\ny1=");
scanf("%lf",&y1);
printf("\nx2=");
scanf("%lf",&x2);
printf("\ny2=");
scanf("%lf",&y2);
s=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
printf("\nKenar=%.2f",s);
return 0;
}
2.7
İki Nokta Arasında Açıklık Açısı Hesabı
İki nokta arasında açıklık açısı (semt) hesabı,
 y − y1 

t12 = arctan 2
−
x
x
 2
1 
bağıntısından hesaplanır. Buradan elde edilen açılara bölge düzeltmelerinin getirilmesi gerekir.
Bölge düzeltmeleri ise pay ve paydanın negatif ya da pozitif olmasına göre yapılır.
+
−
−
⇒ +200 g ⇒ +400 g ⇒ +200 g
−
+
−
C de trigonometrik fonksiyonlar yalnızca radyan birimi ile çalışır. π sayısını veren bir
kütüphane fonksiyonu yoktur. Bu nedenle yeterli incelikte π sayısı trigonometrik ters
fonksiyonlar yardımıyla elde edilebilir.
π = 2 arcsin(1)
/*prg08*/
#include<stdio.h>
#include<math.h>
int main()
{
double x1,y1,x2,y2,t,pi;
printf("\nx1=");
scanf("%lf",&x1);
printf("\ny1=");
scanf("%lf",&y1);
printf("\nx2=");
scanf("%lf",&x2);
printf("\ny2=");
scanf("%lf",&y2);
pi=2*asin(1.0);
x1=x2-x1;
y1=y2-y1;
t=atan(y1/x1);
t=t*200/pi;
if(x1<0)
{
t=t+200;
}
if(t<0)
{
t=t+400;
İ.Ö.BİLDİRİCİ, 02.04.12
14
}
printf("\nAciklik Acisi=%.5f",t);
return 0;
}
Yukarıdaki kodu incelersek bölme işleminde, sıfıra bölüm olasılığına karşı bir önlem
alınmadığını görürüz. Başka bir deyişle arctan fonksiyonu kullanılmadan önce açıklık açısının
0, 100, 200 ve 300 gibi bir değeri olup olmadığı araştırılmalıdır. Bu düşünceye göre program
kodu aşağıdaki gibi değiştirilebilir.
/*prg09*/
#include<stdio.h>
#include<math.h>
int main()
{
double x1,y1,x2,y2,t,pi;
printf("\nx1=");
scanf("%lf",&x1);
printf("\ny1=");
scanf("%lf",&y1);
printf("\nx2=");
scanf("%lf",&x2);
printf("\ny2=");
scanf("%lf",&y2);
pi=2.0*asin(1.0);
if(abs(x2-x1)<=1.e-7)
{
if(y2>y1)
{
t=100.0;
}
else
{
t=300.0;
}
}
else
{
x1=x2-x1;
y1=y2-y1;
t=atan(y1/x1);
t=t*200/pi;
if(x1<0)
{
t=t+200;
}
if(t<0)
{
t=t+400;
}
}
printf("\nAciklik Acisi=%.5lf\n",t);
return 0;
}
2.8
for Çevrimi ile Toplama
for çevrimi kullanılarak kullanıcı tarafından verilen sayıda sayının toplamını ve ortalamasını
hesaplayan bir program kodu aşağıda verilmiştir.
/*prg10*/
#include<stdio.h>
int main()
{
İ.Ö.BİLDİRİCİ, 02.04.12
15
int i,j;
double top=0.0,sayi;
printf("\n kac sayi toplanacak?");
scanf("%i",&j);
for (i=1;i<=j;i=i+1)
{
printf("%i.sayi=",i);
scanf("%lf",&sayi);
top=top+sayi;
}
printf("\ntoplam=%.2lf\tortalama=%.2lf",top,top/(i-1));
return 0;
}
2.9
Faktöriyel
Verilen sayının faktöriyelini hesaplayan program:
/*prg11*/
#include<stdio.h>
int main()
{
int x,i;
double fa=1.0;
printf("\nx=");
scanf("%i",&x);
for (i=x;i>=1;i=i-1)
{
fa=fa*i;
}
printf("\nx!=%.0lf",fa);
return 0;
}
Matematiksel olarak faktöriyel değeri tam sayı olmasına karşın yukarıdaki program kodunda fa
değişkeni double olarak tanımlanmıştır. Bunun nedeni, hızla büyüyen faktöriyel değerini int tipi
ile hesaplamadan doğan güçlüktür.
fa değişkeni int ve long int olarak da tanımlanarak denenebilir. Bu durumda printf içindeki
format ifadesi “%.0lf” yerine int için “%i” long int için “%ld” şeklinde değiştirilmelidir.
Ancak yukarıdaki kod belli bir büyüklükten sonra (yaklaşık 168!) double tipi ile de hesaplama
yapamayacağından program kırılır. Buna karşı bir önlem olarak program aşağıdaki gibi
geliştirilebilir. Aşağıdaki kod, negatif bir sayı verilmedikçe, hesaplamaya da devam etmektedir.
/*prg12*/
#include<stdio.h>
int main()
{
int x=1,i;
double fa=1.0;
printf("\a\tFaktoriyel Programi, cikis icin negatif sayi girin");
while(x>=0)
{
fa=1.0;
printf("\nx =");
scanf("%i",&x);
if(x>=0&&x<=168)
{
for (i=x;i>=1;i=i-1)
{
fa=fa*i;
}
printf("x!=%.0lf",fa);
}
else
İ.Ö.BİLDİRİCİ, 02.04.12
16
{
printf("Hesaplanamiyor");
}
}
printf("\n\tbitti---");
return 0;
}
2.10 İç İçe for Çevrimi: Çarpım Tablosu Programı
Aşağıdaki kısa kod 1 den 10 a kadar sayılar için çarpım tablosunu ekranda gösterir:
/*prg13*/
#include<stdio.h>
int main()
{
int x,y;
for (x=1;x<=10;x=x+1)
{
printf("\n");
for (y=1;y<=10;y=y+1)
{
printf("%4i",x*y);
}
}
return 0;
}
Program çalışması sonucu aşağıdaki ekran görüntüsü elde edilir.
1
2
3
4
5
6
7
8
9
10
2
4
6
8
10
12
14
16
18
20
3
6
9
12
15
18
21
24
27
30
4
8
12
16
20
24
28
32
36
40
5
10
15
20
25
30
35
40
45
50
6
12
18
24
30
36
42
48
54
60
7
14
21
28
35
42
49
56
63
70
8
16
24
32
40
48
56
64
72
80
9 10
18 20
27 30
36 40
45 50
54 60
63 70
72 80
81 90
90 100
printf fonksiyonu içinde kullanılan “%4i" ifadesi ekranda dört karakterlik yere x*y çarpımının
sonucunu sağa dayalı olarak yazdırmaktadır. Sola dayalı yazdırmak için “%-4i” kullanılmalıdır.
2.11 Alan Hesabı
Köşe koordinatları bilinen bir şeklin alanı,
F=
1
∑ (x n y n+1 − xn+1 y n )
2
bağıntısı ile hesaplanır. Buna göre nokta koordinatlarını sıra ile alan, kullanıcı esc tuşuna
basınca alanı hesaplayan bir program kodu aşağıdaki gibidir.
/*prg14*/
/*Bu program LINUX altinda calismaz!*/
#include<stdio.h>
#include<conio.h>
#include<math.h>
int main()
İ.Ö.BİLDİRİCİ, 02.04.12
17
{
double x1,y1,xn,yn,xm,ym,f=0.0;
int i=0,j=0;
do
{
j=j+1;
printf("\nx%i=",j);
scanf("%lf",&xm);
printf("\ny%i=",j);
scanf("%lf",&ym);
if(j==1)
{
x1=xm;
y1=ym;
}
else
{
f=f+(xn*ym-xm*yn);
}
yn=ym;
xn=xm;
printf("\ndevam icin bir tusa basin, cikis esc");
i=_getch();
}
while(i!=27);
f=f+(xm*y1-x1*ym);
f=fabs(f)/2.0;
printf("\nf=%.2lf",f);
return 0;
}
Kullanıcıdan nokta sayısı sorularak alan hesaplanmak istenirse kod aşağıdaki gibi
değiştirilebilir:
/*prg15*/
#include<stdio.h>
#include<math.h>
int main()
{
double x1,y1,xn,yn,xm,ym,f=0.0;
int j,n;
printf("\nNokta Sayisi=");
scanf("%i",&n);
for(j=1;j<=n;j++)
{
printf("\nx%i=",j);
scanf("%lf",&xm);
printf("\ny%i=",j);
scanf("%lf",&ym);
if(j==1)
{
x1=xm;
y1=ym;
}
else
{
f=f+(xn*ym-xm*yn);
}
yn=ym;
xn=xm;
}
f=f+(xm*y1-x1*ym);
f=fabs(f)/2.0;
printf("\nf=%.2lf",f);
return 0;
}
Test amacıyla aşağıdaki veriler kullanılabilir:
NN
Y
İ.Ö.BİLDİRİCİ, 02.04.12
X
18
1
145.00
2
348.00
3
710.00
4
896.00
5
484.00
F=284636.00
549.00
752.00
827.00
398.00
192.00
2.12 e Sayısının Hesabı
Doğal logaritmanın tabanı olan e sayısı seri yardımıyla hesaplanabilir.
e = 1+
1 1 1
+ + + ...
1! 2! 3!
double tipinin verebildiği maksimum inceliği elde etmek için, serinin terim değeri 10-14den
küçük oluncaya kadar hesaplama yapılacaktır.
Program doğru çalışırsa 18 terim hesaplanacaktır (derleyici ve işlemciye göre değişebilir).
/*prg16*/
#include<stdio.h>
int main()
{
int i=0,j;
double e=1.0,payda,fark=1.e-15;
do
{
i=i+1;
payda=1.0;
for(j=i;j>=1;j--)
{
payda=payda*j;
}
e=e+1.0/payda;
}
while (1.0/payda>=fark);
printf("\n%i terim ile hesaplanan e=%.14lf",i,e);
return 0;
}
3. KARAKTER, DİZİ ve POINTER KULLANILAN ÖRNEKLER
3.1
Dizi Kullanarak Alan Hesabı
Dizi kullanılarak aşağıdaki gibi bir program yazılabilir:
/*prg17*/
#include<stdio.h>
#include<conio.h>
#include<math.h>
#define max 100
int main()
{
double x[max],y[max],f=0.0;
int j,n;
char cevap='e';
do
{
f=0.0;
İ.Ö.BİLDİRİCİ, 02.04.12
19
printf("\nNokta Sayisi(max%i)=",max-2);
scanf("%i",&n);
if(n>2&&n<max-1)
{
for(j=0;j<=n-1;j++)
{
printf("\nx%i=",j);
scanf("%lf",&x[j]);
printf("\ny%i=",j);
scanf("%lf",&y[j]);
}
x[n]=x[0];
y[n]=y[0];
for(j=0;j<=n-1;j++)
{
f=f+(x[j]*y[j+1]-x[j+1]*y[j]);
}
f=fabs(f)/2.0;
printf("\nf=%.2lf",f);
}
printf("\nDevam mI?e/h");
cevap=getch();
}
while(cevap=='e');
printf("\n----b i t t i---");
return 0;
}
#define ile sabitler tanımlanır. Yukarıdaki kodda dizi boyutu max adlı sabit ile tanımlanmıştır.
Bu şekilde tanımlamanın avantajı sadece #define satırında değişiklik yapılarak dizi boyutunun
değiştirilebilmesidir. C dilinde dizi indisleri sıfırdan başlar. Bu nedenle x ve y dizilerinin
indisleri 0-99 arasındadır.
3.2
Pointer Kullanımı
Pointer, bir değişkene bellekte ayrılan yerin adresini içeren bir değişken tipidir.
/*prg18*/
#include<stdio.h>
#include<conio.h>
int main()
{
int i;
int *ptr;
char cvp;
do
{
printf("\nBir sayi girin");
scanf("%i",&i);
ptr=&i;
printf("Girdiginiz sayi=%i, adresi=%u",i,ptr);
printf("Devam mI? e/h");
cvp=getch();
}
while(cvp=='e'||cvp=='E');
return 0;
}
3.3
Karakter Dizileri Örneği
char değişken tipi tek bir karakteri tanımlar. Bir kelime ya da cümleyi saklayabilmek için char
tipinde bir dizi kullanmak gerekir. Dizi kullanılmasından dolayı, dizi boyutunun yani
saklayacağımız karakter bilginin uzunluğunu belirlemek zorunludur. Karakter dizilerinde girilen
karakterin bitişi \0 ile belirlenir. Bu karakter ASCII kodu sıfır olan karakter olup, rakam olarak
İ.Ö.BİLDİRİCİ, 02.04.12
20
0 ile ilgisi yoktur. Karakterin bitişi bu şekilde belirtilmek zorunda olduğundan tanımlanan
uzunluğun tamamı kullanılamaz, bir eksiğine kadar kullanılabilir. Örnek:
0
S
1
e
2
l
3
a
4
m
5
\0
Uzunluğu 6 olan bu dizide son karakter \0 olmak zorunda olduğundan beş karakterlik kısmı
kullanılabilir. Yukarıdaki değişkenin uzunluğu 10 olsaydı,
0
S
1
e
2
l
3
a
4
m
5
\0
6
7
8
9
Dört karakterlik kısım kullanılmazdı. Kullanılamayan kısımlar (6,7,8,9) aslında boş değildir.
Buralarda compiler tarafından atanmış rasgele değerler ya da önceden kalma değerler olabilir.
Karakter işlemleri için çok sayıda kütüphane fonksiyonu olduğundan, çoğu kez karakterin
sonlandırılmasıyla uğraşılmasına gerek kalmaz. Sadece tanımlanan uzunluğun bir karakterinin
\0 için kullanılacağının bilinmesi yeterlidir.
Aşağıdaki kod kullanıcıya adı ve soyadını sorarak, bir karakter dizisine atamaktadır. Ardından
ilk boşluk aranarak (space) onun yerine \0 atanıp, karakterin soyadı kısmı kesilmektedir.
/*prg19*/
#include<stdio.h>
#include<string.h>
#include<conio.h>
int main()
{
int i;
char cvp, adsoyad[80];
do
{
printf("\nAdinizi soyadinizi girin:");
gets(adsoyad);
printf("\nAdiniz soyadiniz:%s",adsoyad);
printf("\nUzunlugu=%i",strlen(adsoyad));
for (i=0;i<=79;i++)
{
if(adsoyad[i]==' ')
{
adsoyad[i]='\0';
break;
}
}
printf("\nAdiniz:%s",adsoyad);
printf("\nDevam mI? e/h");
cvp=getch();
}
while(cvp=='e'||cvp=='E');
return 0;
}
Yukarıda kullanılan gets ve strlen fonksiyonları, string.h kütüphanesine ait fonksiyonlardır. gets,
scanf fonksiyonu gibi çalışır, ekrandan karakter okunmasını sağlar. Strlen ise karakterin geçerli
uzunluğunu verir. Yukarıdaki kodda adsoyad dizisinin tanımlı uzunluğu 80 dir. Ancak bu 80
karakterin bir kısmı kullanılır. strlen programın çalışması sırasında kullanıcı tarafından girilen
kısmının uzunluğunu verir. Örneğin kullanıcı “Ali Kuş” şeklinde bir giriş yapmış ise, strlen
geriye 7 değerini döndürür. Bunun anlamı ilk 7 karakterlik kısım dolu, sekizinci karakterde \0
mevcut demektir, geri kalan karakterler kullanılmamaktadır.
İ.Ö.BİLDİRİCİ, 02.04.12
21
4. FONKSİYON KULLANILAN PROGRAMLAR
4.1
Fonksiyonlara Değer Aktarma
Fonksiyonlar arası değer aktarma iki şekilde olabilir. Çağıran fonksiyon çağırılan fonksiyona
ilgili değişkenlerin değerini aktarabilir ya da adresini aktarabilir. Değer aktarma durumunda
çağırılan fonksiyonda yapılan değişiklik çağıran fonksiyonda etkili olmaz. Değişikliklerin etkili
olması için adres aktarması yapmak gereklidir. Bu amaçla pointer kullanılması gereklidir.
İki değişkenin değerini değiş tokuş etmek amacıyla aşağıdaki kodu yazalım.
/*prg20*/
#include <stdio.h>
void degistokus(int, int );
/*fonksiyon prototipi*/
int main()
{
int x,y;
printf("\nx=");
scanf("%i",&x);
printf("\ny=");
scanf("%i",&y);
degistokus(x,y);
/*değer aktarma*/
printf("\nx=%i\ty=%i",x,y);
return 0;
}
void degistokus(int a, int b)
{
int c;
c=a;
a=b;
b=c;
}
Yukarıdaki kodu çalıştırın. Ana fonksiyonda x ve y değişkenlerine atanan değerlerin degistokus
fonksiyonunda değiş tokuş edilmesine rağmen ana fonksiyonda etkili olmadığı görülecektir.
Bunun nedeni ana fonksiyondaki değişkenlerin bir kopyalarının alt fonksiyona aktarılmasıdır.
Alt fonksiyondaki değişikliğin etkili olması için yukarıdaki kod aşağıdaki şekilde
düzenlenmelidir.
/*prg21*/
#include <stdio.h>
void degistokus(int *, int *);
/*fonksiyon prototipi*/
int main()
{
int x,y;
printf("\nx=");
scanf("%i",&x);
printf("\ny=");
scanf("%i",&y);
degistokus(&x,&y);
/*adres aktarma*/
printf("\nx=%i\ty=%i",x,y);
return 0;
}
void degistokus(int *a, int *b)
{
int c;
İ.Ö.BİLDİRİCİ, 02.04.12
22
c=*a;
*a=*b;
*b=c;
}
Yukarıdaki kodlarda & operatörü kullanılmıştır. Adres operatörü olarak tanımlanan & operatörü
bir değişkenin adresini verir. Bunun tersi * operatörüdür. * operatörü verilen adresteki değeri
döndürür (içerik alma operatörü).
4.2
Açıklık Açısının Fonksiyon Olarak Programlanması
Açıklık açısını hesaplayan kod bir fonksiyon olarak yazılırsa, değişik programlarda kolaylıkla
yeniden kullanılabilir.
/*prg22*/
#include<stdio.h>
#include<conio.h>
#include<math.h>
double aciklik_acisi(double x1,double y1,double x2,double y2)
{
double pi,t;
/* pi sayısı ...*/
pi=2.0*asin(1.0);
/* açıklık açısı */
if(abs(x2-x1)<=1.e-7) /*payda sıfır ise*/
{
if(y2>y1)
{
t=100.0;
}
else
{
t=300.0;
}
}
else
{
x1=x2-x1;
y1=y2-y1;
t=atan(y1/x1)*200.0/pi;
if(x1<0)t=t+200;
if(t<0) t=t+400;
}
return(t);
}
int main()
{
double x1,y1,x2,y2,t;
char
cvp;
do
{
printf("\nx1=");
scanf("%lf",&x1);
printf("y1=");
scanf("%lf",&y1);
printf("x2=");
scanf("%lf",&x2);
printf("y2=");
scanf("%lf",&y2);
t=aciklik_acisi(x1,y1,x2,y2);
printf("\nAciklik Acisi=%.5lf",t);
printf("\nDevam mi?e/h");
cvp=_getch();
}
while(cvp!='h');
İ.Ö.BİLDİRİCİ, 02.04.12
23
printf("\n---->bitti");
return 0;
}
Fonksiyon prototipi kullanılarak yazım:
/*prg23*/
#include<stdio.h>
#include<conio.h>
#include<math.h>
double aciklik_acisi(double,double,double,double);
int main()
{
double x1,y1,x2,y2,t;
char
cvp;
do
{
printf("\nx1=");
scanf("%lf",&x1);
printf("y1=");
scanf("%lf",&y1);
printf("x2=");
scanf("%lf",&x2);
printf("y2=");
scanf("%lf",&y2);
t=aciklik_acisi(x1,y1,x2,y2);
printf("\nAciklik Acisi=%.5lf",t);
printf("\nDevam mi?e/h");
cvp=_getch();
}
while(cvp!='h');
printf("\n---->bitti");
return 0;
}
double aciklik_acisi(double x1,double y1,double x2,double y2)
{
double pi,t;
/* pi sayısı ...*/
pi=2.0*asin(1.0);
/* açıklık açısı */
if(abs(x2-x1)<=1.e-7) /*payda sıfır ise*/
{
if(y2>y1)
{
t=100.0;
}
else
{
t=300.0;
}
}
else
{
x1=x2-x1;
y1=y2-y1;
t=atan(y1/x1)*200.0/pi;
if(x1<0)t=t+200;
if(t<0) t=t+400;
}
return(t);
}
İ.Ö.BİLDİRİCİ, 02.04.12
24
4.3
Açıklık Açısı ve Kenarı Birlikte Döndüren Fonksiyon
Bir fonksiyonun iki değer döndürebilmesi için pointer kullanmak gerekir. Fonksiyon geriye
direkt olarak bir değer döndürmemekte, çağıran fonksiyondan (main) gönderilen iki değişkenin
adresini alarak hesaplanan değerleri bu adresler yoluyla çağıran fonksiyona aktarmaktadır. Öte
yandan, fonksiyon kodu main fonksiyonundan sonra yer aldığı için, main fonksiyonundan önce
fonksiyonun prototipi verilmiştir.
/*prg24*/
#include<stdio.h>
#include<conio.h>
#include<math.h>
void aci_kenar(double,double,double,double,double *,double *);
int main()
{
double x1,y1,x2,y2,t,s;
char
cvp;
do
{
printf("\nx1=");
scanf("%lf",&x1);
printf("y1=");
scanf("%lf",&y1);
printf("x2=");
scanf("%lf",&x2);
printf("y2=");
scanf("%lf",&y2);
aci_kenar(x1,y1,x2,y2,&t,&s);
printf("\nAciklik Acisi=%.5lf\tkenar=%.2lf",t,s);
printf("\nDevam mi?e/h");
cvp=_getch();
}
while(cvp!='h');
printf("\n---->bitti");
return 0;
}
void aci_kenar(double x1,double y1,double x2,double y2,double *t,double *s)
{
double pi;
/* kenar hesabı*/
*s=sqrt(pow((x2-x1),2)+pow((y2-y1),2));
/* pi sayısı ...*/
pi=2.0*asin(1.0);
/* açıklık açısı */
if(abs(x2-x1)<=1.e-7) /*payda==0 mi?*/
{
if(y2>y1)
{
*t=100.0;
}
else
{
*t=300.0;
}
}
else
{
x1=x2-x1;
y1=y2-y1;
*t=atan(y1/x1)*200.0/pi;
if(x1<0)
{
*t=*t+200;
}
if(*t<0)
İ.Ö.BİLDİRİCİ, 02.04.12
25
{
*t=*t+400;
}
}
}
4.4
Fonksiyonlar Arası Dizi Aktarma
Fonksiyonlara değişkenlerin aktarılmasını daha önce inceledik. Fonksiyonlar arası dizi
değişkenlerinin aktarılması biraz farklıdır. Dizi değişkenleri için tanımlanan değişken ismi
parantezsiz kullanılırsa o dizinin ilk elemanının pointerını tanımlar. x biri dizi olmak üzere
aşağıdaki iki ifade birbiri ile eşdeğerdir.
x
&x[0]
Aşağıdaki örnekte 5 elemanına atama yapılan bir dizinin bir fonksiyona aktarılarak ekranda
görüntülenmesi sağlanmaktadır. Burada dizinin aktarılma şekline ve fonksiyon prototipinin nasıl
tanımlandığına dikkat edin.
/*prg25*/
#include <stdio.h>
#define max 100
void diziyaz(double *,int); /*fonksiyon prototipi*/
int main()
{
double x[max];
int i,j;
i=5;
for(j=0;j<i;j++)
{
x[j]=2*j+1;
}
diziyaz(x,i);
return 0;
}
void diziyaz (double *x,int i)
{
int j;
for(j=0;j<i;j++)
{
printf("\nx(%i)=%.0lf",j,x[j]);
}
}
Aşağıdaki örnek ise karakter dizileri fonksiyonlara aktarılmaktadır. Buradaki fonksiyonlardan
yaz1 de fonksiyona aktarılan karakter dizisinin içeriği, dizi kullanılarak ekrana yazılmakta, yaz2
de ise aynı işlem pointer kullanılarak gerçekleştirilmektedir. Bu örnekte pointer ve dizi
kavramlarının birbirleriyle ilişkisi daha açık olarak görülmektedir.
/*prg26*/
#include <stdio.h>
void yaz1(char *text)
{
int x=0;
while(text[x]!='\0')
{
putchar(text[x]);
x++;
}
}
void yaz2(char *text)
{
İ.Ö.BİLDİRİCİ, 02.04.12
26
while(*text)
{
putchar(*text++);
}
}
int main ()
{
char text[80];
printf("\nBir cumle yazin: ");
gets(text);
yaz1(text);
yaz2(text);
return 0;
}
4.5
Fonksiyon Olarak Alan Hesabı
Daha önce de incelenen alan hesabı probleminin fonksiyon olarak kullanımı için aşağıdaki kodu
inceleyin. Burada koordinatlar ana programda iki diziye yazılmakta, hesaplama alanhesap adlı
fonksiyon içinde yapılmaktadır.
/*prg27*/
#include <stdio.h>
#include<math.h>
#define max 1000
double alanhesap(double *,double *, int); /*fonksiyon prototipi*/
int main()
{
double x[max],y[max],a;
int n=max,j;
while(n>2)
{
printf("\nNokta Sayisi / Cikis -->0 (max%i)=",max-1);
scanf("%i",&n);
n--;
if(n>=2&&n<=max-1)
{
for(j=0;j<=n;j++)
{
printf("\nx%i=",j+1);
scanf("%lf",&x[j]);
printf("\ny%i=",j+1);
scanf("%lf",&y[j]);
}
a=alanhesap(x,y,n);
printf("\nalan=%.2lf",a);
}
}
return 0;
}
double alanhesap (double *x,double *y, int n)
{
int j;
double f=0.0;
x[n+1]=x[0];
y[n+1]=y[0];
for(j=0;j<=n;j++)
{
f=f+(x[j]*y[j+1]-x[j+1]*y[j]);
}
f=fabs(f)/2.0;
return(f);
}
İ.Ö.BİLDİRİCİ, 02.04.12
27
5. DOSYA KULLANIMI
Programların verileri ve ürettikleri sonuçlar dosyalarda saklanır. Şimdiye kadar ki basit
örneklerde, programın giriş verileri ve sonuçları için ekran kullanılmıştı. Bu şekilde elde edilen
sonuçlar ekranda göründükten sonra kaybolurlar. Oysa elde edilen sonuçların kaybedilmesi
istenen bir şey değildir. Bu bölümde verileri dosyalardan okuyan ve ürettikleri sonuçları
dosyalara yazan programlar incelenecektir.
Dosyalar sequential ve random olmak üzere temel olarak ikiye ayrılırlar. Sequential dosyalar
ASCII File, Text File olarak da isimlendirilirler. Bu bölümde bu tip dosyalar üzerinde örnekler
verilecektir.
Bir dosya ile çalışmanın ilk adımı onu açmaktır. Bu şekilde işletim sistemi tarafından diskte
kullanılabilir bir alan hazırlanır. Dosya açma amacıyla fopen fonksiyonu kullanılır. Dosya açılıp
işlendikten sonra fclose fonksiyonu ile kapatılır.
Sadece bir dosyayı açıp tekrar kapatan aşağıdaki kodu inceleyin.
/*prg28*/
#include <stdio.h>
int main()
{
FILE *dosya_ptr;
dosya_ptr=fopen("abc.txt","w");
if(dosya_ptr != NULL)
{
fclose(dosya_ptr);
}
return 0;
}
Yukarıda ilk olarak dosya tipinde dosya_ptr adlı bir pointer tanımlanmaktadır. Eğer dosya açma
işlemi başarılı olmuş ise if bloğu içinde dosya tekrar kapatılmaktadır. Eğer çalışılan klasörde
abc.txt adlı bir dosya var ise, bu dosya yok olacaktır. Bunun nedeni fopen fonksiyonundaki
ikinci parametredir (“w”). İkinci parametre değerleri ve anlamları aşağıdaki gibidir:
•
•
•
r (read) dosya okunmak üzere açılır. Eğer dosya mevcut değilse açma işlemi başarısız olur.
w (write) dosya yazılmak üzere açılır. Dosya mevcut ise üzerine yazılır, değilse yeniden
oluşturulur.
a (append) dosya yazılmak üzere açılır ve dosyanın sonuna gidilir. Eğer dosya yok ise
yeniden oluşturulur.
Dosya tipi (FILE) daha önce kullanılan tiplerden farklıdır. Bu önceden tanımlanmış bir tip olup
stdio.h kütüphanesi içinde yer almaktadır. Büyük harflerle yazılması gerekir. Eğer dosya
açılamazsa dosya_ptr ye NULL ataması yapılır. NULL da stdio.h içinde tanımlıdır.
Yukarıdaki program biraz daha geliştirilerek aşağıdaki hale getirilebilir.
/*prg29*/
#include <stdio.h>
int main()
{
FILE *dosya_ptr;
char dosya_adi[80];
printf("\nAcilacak dosya adini girin: ");
gets(dosya_adi);
dosya_ptr=fopen(dosya_adi,"r");
if(dosya_ptr != NULL)
İ.Ö.BİLDİRİCİ, 02.04.12
28
{
printf("\n%s adli dosya acildi!\n",dosya_adi);
fclose(dosya_ptr);
}
else
{
printf("\n%s adli dosya acilaMadi!\n",dosya_adi);
}
return 0
}
5.1
Dosyadan Okuma
Dosyalardan veri okuma için çeşitli kütüphane fonksiyonları vardır. Dosyadan her seferinde bir
karakter okumak için fgetc fonksiyonu kullanılır. Aşağıdaki kodu denemeden önce çalışma
klasörünüzde notepad ile bir dosya oluşturun. Bu dosya içine bir kaç satır yazı yazın,
kaydederek kapatın. Programı çalıştırırken hazırladığınız dosyanın adını verin.
/*prg30*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char dosya_adi[80];
int ch;
printf("\nDosya adi: ");
gets(dosya_adi);
if((stream=fopen(dosya_adi,"r"))==NULL)
{
printf("\nDosya acilamadi!");
return 0;
}
ch=fgetc(stream);
while(!feof(stream))
{
putchar(ch);
ch=fgetc(stream);
}
fclose(stream);
return 0;
}
Yukarıdaki örnekte dosyadan her defasında bir karakter okunmaktadır. Tek tek karakter okumak
genel olarak programlama mantığına uygun değildir. fgets fonksiyonu ile satir satir okuma
mümkündür. Buna göre değiştirilmiş kod aşağıdaki gibidir:
/*prg31*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char dosya_adi[80], satir[80];
printf("\nDosya adi: ");
gets(dosya_adi);
if((stream=fopen(dosya_adi,"r"))==NULL)
{
printf("\nDosya acilamadi!");
return 0;
}
while(!feof(stream))
{
fgets(satir, 100, stream);
printf("%s",satir);
İ.Ö.BİLDİRİCİ, 02.04.12
29
}
fclose(stream);
return 0;
}
fscanf, scanf fonksiyonuna benzer olarak dosyadan formatlı değer okuma işlemini
gerçekleştirir. Aşağıdaki kodu uygulamadan önce çalışma klasörünüzde notepad ile bir dosya
oluşturun. Dosyaya toplam uzunluğu 12 karakteri aşmayan reel sayılar yazın. Ondalık ayıracı
olarak nokta kullanın, virgül kullanmayın! Hazırladığınız dosyayı programı çalıştırırken
kullanın.
/*prg32*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stream;
char dosya_adi[80];
int i=-1;
double liste[80];
printf("\nDosya adi: ");
gets(dosya_adi);
if((stream=fopen(dosya_adi,"r"))==NULL)
{
printf("\nDosya acilamadi!");
return 0;
}
while(!feof(stream))
{
i++;
fscanf(stream,"%12lf",&liste[i]);
printf("\nliste(%i)=%lf",i,liste[i]);
}
fclose(stream);
return 0;
}
5.2
Dosyaya Yazma
Dosyaya yazma işlemi fscanf fonksiyonun eşi olarak düşünülebilecek fprintf fonksiyonu ile
gerçekleştirilir. fprintf ve fscanf fonksiyonları tamamen printf ve scanf fonksiyonları gibi
davranırlar. Aralarındaki tek fark giriş çıkış ortamının ekran ya da dosya olmasıdır.
Aşağıdaki örnekte prg13 kodunda ekranda oluşturulan çarpım tablosu bu kez bir dosyada
oluşturulmaktadır.
/*prg33*/
#include <stdio.h>
int main()
{
FILE *stream;
char dosya_adi[80];
int x,y;
printf("\nDosya adi: ");
gets(dosya_adi);
if((stream=fopen(dosya_adi,"w"))==NULL)
{
printf("\nDosya acilamadi!");
}
else
{
for (x=1;x<=10;x=x+1)
{
for (y=1;y<=10;y=y+1)
İ.Ö.BİLDİRİCİ, 02.04.12
30
{
fprintf(stream,"%4i",x*y);
}
fprintf(stream,"\n");
}
fclose(stream);
}
return 0;
}
Dosyaya yazdığımız bilgileri tekrar okuma amaçlı olarak aşağıdaki kodu uygulayın. Burada
çarpım tablosu içeriği iki boyutlu bir diziye alınarak, kontrol amaçlı olarak ekranda
görüntülenmektedir.
/*prg34*/
#include <stdio.h>
int main()
{
FILE *stream;
char dosya_adi[80];
int x,y;
int n[10][10];
printf("\nDosya adi: ");
gets(dosya_adi);
if((stream=fopen(dosya_adi,"r"))==NULL)
{
printf("\nDosya acilamadi!");
}
else
{
for (x=0;x<=9;x++)
{
for (y=0;y<=9;y++)
{
fscanf(stream,"%4i",&n[x][y]);
}
}
fclose(stream);
for (x=0;x<=9;x++)
{
for (y=0;y<=9;y++)
{
printf("%4i",n[x][y]);
}
printf("\n");
}
}
return 0;
}
Yukarıda iki boyutlu dizinin kullanımına dikkat edin. Önce dosya açılarak dizi doldurulmakta,
daha sonra dizinin elemanları ekranda görüntülenmektedir. Bu şekilde diske kaydettiğimiz
verileri herhangi bir kayıp olmadan tekrar okuyup, değişkenlere aktarmış olduk.
5.3
İki Boyutlu Dizilerle Çalışma: Matris Çarpımı
Matris işlemleri için iki boyutlu dizilerle çalışmak gereklidir. Bu bölümdeki örnekte iki matrisi
bir dosyadan okuyan ve matris çarpımını başka bir dosyaya yazan bir program kodu verilecektir.
/*prg35*/
#include<stdio.h>
#define matboy 100
void matrisoku(FILE *stream, int *sa, int *su, double n[matboy][matboy])
{
int i,j;
fscanf(stream,"%12i%12i",sa,su);
İ.Ö.BİLDİRİCİ, 02.04.12
31
for(i=1;i<=*sa;i++)
{
for(j=1;j<=*su;j++)
{
fscanf(stream,"%12lf",&n[i][j]);
}
}
}
void matrisyaz(FILE *stream, int *sa, int *su, double n[matboy][matboy])
{
fprintf(stream,"\n%12i%12i\n",*sa,*su);
int i,j;
for(i=1;i<=*sa;i++)
{
for(j=1;j<=*su;j++)
{
fprintf(stream,"%12lf",n[i][j]);
}
fprintf(stream,"\n");
}
}
void matrisyazekr(int *sa, int *su, double n[matboy][matboy])
{
int i,j;
for(i=1;i<=*sa;i++)
{
for(j=1;j<=*su;j++)
{
printf("%12lf",n[i][j]);
}
printf("\n");
}
}
int main()
{
FILE *dosya1;
char dosya_adi[80];
int asa,asu,bsa,bsu,csa,csu,i,j,k;
double a[matboy][matboy],b[matboy][matboy],c[matboy][matboy];
printf("\nDosya adi: ");
gets(dosya_adi);
if((dosya1=fopen(dosya_adi,"r"))==NULL)
{
printf("\nDosya acilamadi!");
}
else
{
matrisoku(dosya1,&asa,&asu,a);
matrisoku(dosya1,&bsa,&bsu,b);
if(asu==bsa)
{
csa=asa;csu=bsu;
for(i=1;i<=csa;i++)
{
for(j=1;j<=csu;j++)
{
c[i][j]=0;
for(k=1;k<=asu;k++)
{
c[i][j]=c[i][j]+a[i][k]*b[k][j];
}
}
}
}
İ.Ö.BİLDİRİCİ, 02.04.12
32
matrisyazekr(&csa,&csu,c);
fclose(dosya1);
if((dosya1=fopen(dosya_adi,"a"))!=NULL)
{
matrisyaz(dosya1,&csa,&csu,c);
fclose(dosya1);
}
}
return 0;
}
Matrislerin dosyadan okunması, matris çarpım sonucunun ekranda gösterilmesi ve dosyaya
yazdırılması matrisoku, matrisyaz, matrisyazekr adlı fonksiyonlar yardımıyla yapılmaktadır. Bu
programda kullanılmak üzere Notepad/Not Defteri (ya da benzeri bir editör) ile rakamlar 12
karakterlik alanlara gelmek üzere aşağıdaki gibi bir dosya hazırlayın.
3
4
1.0000
-5.0000
1.1000
4
5.0000
-2.2000
-5.0000
3.2000
5.0000
-2.2500
1.5000
4.0000
-0.2250
1.5000
5.0000
2.5000
2.0000
2.2000
2.0000
4.5000
5.0000
3.0000
1.0000
2.2500
8.0000
5
2.5000
-6.0000
1.1000
6.0000
-5.0000
0.0000
6.0000
7.0000
Burada ilk iki tamsayı rakam (3 ve 4) takip eden matrisin satır ve sütun sayısını ifade
etmektedir. Birinci matristen sonra gelen iki tamsayı (4 ve 5) yine takip eden matrisin
boyutlarını ifade etmektedir.
Bu matrisler çarpıldığında (ilk matris ikinci ile çarpıldığında) aşağıdaki sonuç elde edilecektir:
3
5
-14.980000
30.200000
28.925000
37.500000
2.000000
-29.425000
34.100000
27.100000
-18.830000
27.200000
26.050000
-8.562500
24.700000
83.000000
-20.575000
prg35 kodunda dosya (FILE) değişkeninin ve iki boyutlu dizilerin fonksiyonlara nasıl
aktarıldığına dikkat edin.
6. İLERİ TEKNİKLER
6.1
Struct, Union ve Typedef
Bir struct, kullanıcı tarafından tanımlanmış bir veri tipidir. Standart veri tiplerinden çok daha
karmaşık olanları, bu yolla tanımlayabilirsiniz. Bir struct, daha önce tanımlanmış olan veri
tiplerinin bir araya gelmiş halidir - ki bu veri tiplerine, daha önce tanımlanan struct’lar da
dahildir (iç içe struct tanımlamaları). Struct’lar, verilerin program kodunun daha anlaşılır olması
için gruplanması olarak düşünülebilir. Struct yapısını daha iyi anlamak için aşağıdaki kodu
inceleyin.
/*prg36*/
#include<stdio.h>
int main()
{
struct {
char bas_harf;
İ.Ö.BİLDİRİCİ, 02.04.12
/* Soyadın bas harfi
*/
33
int yas;
int not;
} oglan,kiz;
/* çocuğun yaşı
*/
/* okulda not ortalaması (100 üzerinden) */
oglan.bas_harf = 'R';
oglan.yas = 15;
oglan.not = 75;
kiz.yas = oglan.yas - 1;
kiz.not = 82;
kiz.bas_harf = 'H';
/* o, oglandan bir yas küçük */
printf("%d yasindaki %c'nin aldigi not, %d dir.\n",
kiz.yas, kiz.bas_harf, kiz.not);
printf("%d yasindaki %c'nin aldigi not, %d dir.\n",
oglan.yas, oglan.bas_harf, oglan.not);
return 0;
}
Üç değişkenden oluşan bir struct tipi olarak oglan ve kiz adli değişkenler tanımlanmaktadır. Bu
değişkenlerin bileşenlerine “.” yazım tarzı ile ulaşılmaktadır (örneğin oglan.yas).
Prg36 kodu tanımlanan struct tipine bir ad verilerek aşağıdaki gibi düzenlenebilir.
/*prg37*/
#include<stdio.h>
struct ogrenci{
char bas_harf;
int yas;
int not;
};
/* Soyadın bas harfi
*/
/* çocuğun yaşı
*/
/* okulda not ortalaması (100 üzerinden) */
int main()
{
struct ogrenci oglan,kiz; /*ogrenci tipli degiskenlerin tanımlanması*/
oglan.bas_harf = 'R';
oglan.yas = 15;
oglan.not = 75;
kiz.yas = oglan.yas - 1;
kiz.not = 82;
kiz.bas_harf = 'H';
/* o, oglandan bir yas küçük */
printf("%d yasindaki %c'nin aldigi not, %d dir.\n",
kiz.yas, kiz.bas_harf, kiz.not);
printf("%d yasindaki %c'nin aldigi not, %d dir.\n",
oglan.yas, oglan.bas_harf, oglan.not);
return 0;
}
Burada ogrenci adlı tip global olarak tanımlanmıştır. Main fonksiyonu içinde ise, kiz ve oglan
adlı değişkenler ogrenci tipinde tanımlanmıştır. Global olan ogrenci tipi bir header file içinde de
olabilir. Bu şekilde önceden hazırlanmış tipler değişik programlarda kullanılabilirler. Bu tip
kullanımı kolaylaştırma amacıyla ogrenci tipini standart değişken tipi gibi tanımlamak için
typedef yapısı kullanılır. Typedef var olan değişken tiplerinin (standart değişkenler ya da
struct’lar) başka bir adla (daha basit bir adla) tanımlanmalarını sağlar. Typedef kullanarak
kodun değiştirilmiş hali aşağıdaki gibidir.
/*prg38*/
#include<stdio.h>
struct ogrenci
{
char bas_harf;
İ.Ö.BİLDİRİCİ, 02.04.12
/* Soyadın bas harfi
*/
34
int yas;
int not;
/* çocuğun yaşı
*/
/* okulda not ortalaması (100 üzerinden) */
};
typedef struct ogrenci ogr;
int main()
{
ogr oglan,kiz;
/*ogrenci tipindeki değişkenlerin tanımlanması*/
oglan.bas_harf = 'R';
oglan.yas = 15;
oglan.not = 75;
kiz.yas = oglan.yas - 1;
kiz.not = 82;
kiz.bas_harf = 'H';
/* o, oglandan bir yas küçük */
printf("%d yasindaki %c'nin aldigi not, %d dir.\n",
kiz.yas, kiz.bas_harf, kiz.not);
printf("%d yasindaki %c'nin aldigi not, %d dir.\n",
oglan.yas, oglan.bas_harf, oglan.not);
return 0;
}
Union yapısı tamamen struct yapısına benzer. Aralarındaki fark struct yapısında tüm bileşenler
kullanılabilir. Union’da ise yalnızca bileşenlerden biri kullanılabilir. Bir bileşene atama
yapıldıktan sonra bir başka bileşene atama yapılırsa önceki silinir.
6.2
Struct ve Dosya Kullanımı
Struct ile tanımlanan tipte bir değişken ve dosya kullanımı aşağıdaki kodla incelenebilir. Burada
nokta tipi oluşturulmakta, kullanıcıdan alınan bilgiler bir binary dosyaya yazılmaktadır. Daha
sonra dosya içeriği ekranda gösterilmektedir.
/*prg39*/
#include<stdio.h>
struct nokta
{
char nno[10];
double x;
double y;
};
void noktaal(FILE *stream, int n, struct nokta *p)
/*verilen n ci sıradaki noktayı okur ve p değişkenine aktarır*/
{
fseek(stream,(n-1)*26,SEEK_SET);
fread( p->nno, sizeof(p->nno), 1, stream);
fread( &p->x, sizeof(p->x) , 1, stream);
fread( &p->y, sizeof(p->y) , 1, stream);
}
int main()
{
FILE *stream;
struct nokta nok;
int i;
if( (stream = fopen( "test.dat", "w+" )) != NULL )
{
fseek( stream, 0, SEEK_END);
/*Dosya sonuna git
*/
while(1==1)
/*noktaların ekrandan alınması*/
{
printf("\nNokta adi [Devam >> * ]=");
scanf("%s",nok.nno);
if(nok.nno[0]=='*') break;
İ.Ö.BİLDİRİCİ, 02.04.12
35
printf("\nx=");
scanf("%lf",&nok.x);
printf("\ny=");
scanf("%lf",&nok.y);
fwrite(nok.nno, sizeof(nok.nno),1, stream);
fwrite(&nok.x, sizeof(nok.x) , 1, stream);
fwrite(&nok.y, sizeof(nok.y) , 1, stream);
}
rewind(stream);
/*dosyayı başa sar*/
printf("\nGirdiginiz Noktalar");
i=0;
while(i>=-1 )
{
printf("\nKacinci kayit?[Cikis >> -2/Tum kayitlar >> -1]:");
scanf("%i",&i);
if(i>=0)
{
noktaal(stream,i,&nok);
printf("\n%3i %10s %10.2lf %10.2lf",i,nok.nno,nok.x,nok.y);
}
else if(i==-1)
{
i=0;
do
/*dosya içeriği*/
{
i++;
noktaal(stream,i,&nok);
printf("\n%3i %10s %10.2lf %10.2lf",i,nok.nno,nok.x,nok.y);
}
while(!feof(stream));
}
}
printf("\nBitti\n");
fclose(stream);
}
return 0;
}
bu örnekte kullanılan test.dat adlı dosya içeriği Notepad gibi bir editör ile görülemez. fwrite ve
fread fonksiyonları dosyalara formatsız yazma ve okuma işlemlerinde kullanılırlar. fseek
fonksiyonu ise dosyada işaretçinin (cursor) belli bir başlangıçtan itibaren belli sayıda byte kadar
ilerlemesini sağlar.
Nokta tipli olarak tanımlanan nok adlı değişkenin dosyadan okunarak doldurulması noktaal adlı
fonksiyonda gerçekleştirilmektedir. Bu fonksiyona struct olarak tanımlı değişkenin parametre
olarak nasıl aktarıldığına dikkat edin. Değişkenin değeri çağıran fonksiyona aktarılmak zorunda
olduğundan burada pointer kullanılarak aktarma yapılması gerekmektedir. Burada,
p->x
biçimindeki yazım,
(*p).x
şeklindeki yazım ile eşdeğerdir. Burada . operatörünün * operatörüne göre önceliği olması
nedeniyle parantez kullanılması gereklidir. -> işaretleri ile yazım daha anlaşılması kolay olduğu
için tercih edilir.
6.3
Komut Satırından Parametre Almak
Çoğu konsol uygulamada (Console Application) programa bazı parametreler komut satırından
sonra yazılarak aktarılır. Örneğin,
Print deneme.txt
İ.Ö.BİLDİRİCİ, 02.04.12
36
Burada print programına yazıcıya göndereceği dosya ismi aktarılmaktadır. Programlara bu
şekilde veri aktarma kullanım kolaylığı yanında programların başka programlarla
kullanılmasına da olanak sağlar.
/*prg40*/
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
int i;
if(argc<2)
{
printf("\nKomut satirinda parametre yok!");
return 0;
}
for(i=1;i<argc;i++)
{
printf("\nParametre %i=%s",i,argv[i]);
}
return 0;
}
Burada main fonksiyonu işletim sisteminden iki parametre almaktadır. argc parametrelerin
sayısını, argv[] ise parametreleri içermektedir. Bu değişken isimleri farklı olabilir, ancak bu
isimler genellikle değiştirilmeden kullanılır. argc değişkeninin değeri 1 ise, komut satırında hiç
bir parametre yok demektir. Bu durumda işletim sistemi birinci değer olarak programın kendi
ismini göndermiş demektir. argv tanımlaması gereği (char *argv[]) bir karakter değişkenini
gösteren bir pointerin pointeridir. Başka bir deyişle argv pointerlar içeren bir dizinin pointeridir.
Bu dizideki pointerlar, parametreleri göstermektedirler.
Bu kodu exe dosyasını oluşturduktan sonra, editörden değil bir komut istemi penceresinden
(command prompt) çalıştırın. Program isminden sonra boşluklarla ayrılmış olarak parametreler
girin.
6.4
Sisteme Komut Göndermek
Programlardan komut satırından kullanılan DOS komutlarını, ya da başka programları işletim
sistemine komut göndererek çalıştırmak mümkündür. Bu amaçla system fonksiyonu kullanılır.
Aşağıdaki kod ile oluşturduğunuz programı yine komut istemi penceresinde çalıştırın. Program
tamamen dir komutu gibi çalışır.
/*prg41*/
#include<stdio.h>
#include<process.h>
#include<string.h>
int main(int argc, char *argv[])
{
char line[80];
strcpy(line,"dir ");
if(argc>1)
{
strcat(line,argv[1]);
}
system(line);
return 0;
}
İ.Ö.BİLDİRİCİ, 02.04.12
37
6.5
Header File Kullanmak
Şimdiye kadar yazdığımız bütün kodlarda en az bir tane header file kullandık. Kullandığımız
dosyalar c derleyicisi ile gelen standart kütüphanelerdi. Kullanıcılar tarafından da header file lar
hazırlanabilir. Bu şekilde test edilmiş fonksiyonlar bir header file da toplanır ve çeşitli
programlarda kullanılabilir.
Uygulama amacıyla matris işlemleri yaptığımız prg35 kodunu ele alalım. Buradaki
fonksiyonları ayrı bir dosyaya kopyalayın. Bu dosyanın içeriği aşağıdaki gibi olmalıdır.
#define matboy 100
void matrisoku(FILE *stream, int *sa, int *su, double n[matboy][matboy])
{
int i,j;
fscanf(stream,"%12i%12i",sa,su);
for(i=1;i<=*sa;i++)
{
for(j=1;j<=*su;j++)
{
fscanf(stream,"%12lf",&n[i][j]);
}
}
}
void matrisyaz(FILE *stream, int *sa, int *su, double n[matboy][matboy])
{
fprintf(stream,"\n%12i%12i\n",*sa,*su);
int i,j;
for(i=1;i<=*sa;i++)
{
for(j=1;j<=*su;j++)
{
fprintf(stream,"%12lf",n[i][j]);
}
fprintf(stream,"\n");
}
}
void matrisyazekr(int *sa, int *su, double n[matboy][matboy])
{
int i,j;
for(i=1;i<=*sa;i++)
{
for(j=1;j<=*su;j++)
{
printf("%12lf",n[i][j]);
}
printf("\n");
}
}
Dosyayı örneğin jeomat.h olarak adlandırıp, proje klasörü altına kaydedin. Program kodu
aşağıdaki gibi olmalıdır. (VS 6.0 ya da VS.NET kullanıyorsanız önce File>New menüsünden
yeni “C++ Header File” oluşturun yukarıdaki kodu bu dosya içine yazın). Proje klasörü altında
yer alan header dosyasının deklere edilmesi şekil olarak standart header dosyalarının deklere
edilmesinden farklıdır.
/*prg42*/
#include<stdio.h>
#include"jeomat.h"
int main()
{
FILE *dosya1;
char dosya_adi[80];
İ.Ö.BİLDİRİCİ, 02.04.12
38
int asa,asu,bsa,bsu,csa,csu,i,j,k;
double a[matboy][matboy],b[matboy][matboy],c[matboy][matboy];
printf("\nDosya adi: ");
gets(dosya_adi);
if((dosya1=fopen(dosya_adi,"r"))==NULL)
{
printf("\nDosya acilamadi!");
}
else
{
matrisoku(dosya1,&asa,&asu,a);
matrisoku(dosya1,&bsa,&bsu,b);
if(asu==bsa)
{
csa=asa;csu=bsu;
for(i=1;i<=csa;i++)
{
for(j=1;j<=csu;j++)
{
c[i][j]=0;
for(k=1;k<=asu;k++)
{
c[i][j]=c[i][j]+a[i][k]*b[k][j];
}
}
}
}
matrisyazekr(&csa,&csu,c);
fclose(dosya1);
if((dosya1=fopen(dosya_adi,"a"))!=NULL)
{
matrisyaz(dosya1,&csa,&csu,c);
fclose(dosya1);
}
}
return 0;
}
7. C++ ÖRNEKLERİ
Bu bölümde basit C++ örnekleri verilecektir.
7.1
Ekrandan Veri Giriş Çıkışı
C dilindeki printf ve scanf fonksiyonlarına benzer olarak C++ dilinde cin ve cout fonksiyonları
kullanılır. Cin ve cout fonksiyonları karakter dizileri okumak için önemli yararlar sağlar.
/*prg43*/
#include <iostream.h>
int main ()
{
char ad[20];
char soyad[20];
cout << "\nAdiniz:";
cin >> ad;
cout << "\nSoyadiniz:";
cin >> soyad;
cout << "\nSayin \t" << ad << " " << soyad;
cout << "\nHosgeldiniz\n";
return 0;
İ.Ö.BİLDİRİCİ, 02.04.12
39
}
C++ ile I/O işlemrinde özellikle reel sayılara ilişkin biçimlendirme C’nin printf ve scanf
fonksiyonlarından biraz farklıdır. C++’da çıktıyı ekrana yazmak için cout komutuyla birlikte
insertion << operatörünün kullanılması zorunludur. cin komutunda ise >> operatörü kullanılır.
Aşağıdaki örnekte ekrandan cin komutu ile alınan üç reel sayı, başka bir değişkende
toplandıktan sonra ortalaması alınmaktadır. Toplam sonucu noktadan sonra iki, ortalama ise üç
basamak olarak yazdırılmak isteniyor. Standart I/O kütüphanesinin (iostream.h) yanı sıra
sonuçların biçimlendirilmesi için iomanip.h kütüphanesi de programa dahil edilmelidir. Burada
setiosflags ile sayının biçimlendirilmesinde kullanılacak bayrak ayarlanıyor. Desimal sayıların
gösterimi için açılan bu bayrak fixed dır. Basamak sayısının ayarlanması ise setprecision
komutu ile sağlanır. Fonksiyonun alacağı değer basamak sayısını gösterir.
/*prg44*/
#include <iostream.h>
#include <iomanip.h>
int main()
{
double top=0.0,sayi=0.0;
cout << "\n\tHesaplayici\n";
cout << "\n1.sayi=";
cin >> sayi;
top=top+sayi;
cout << "\n2.sayi=";
cin >> sayi;
top=top+sayi;
cout <<"\n3.sayi=";
cin >> sayi;
top=top+sayi;
cout << setiosflags(ios::fixed)
<< setprecision(2)
<< "\ntoplam= " << top;
// Desimal sayilarin gosterimi
// Noktadan sonra iki basamak
top=top/3;
cout << setprecision(3)
<< "\nOrtalama= " << top << endl;
return 0;
}
7.2
Dosya İşlemleri
Dosya işlemlerine örnek olarak prg33 kodu C++ fonksiyonları ile yeniden düzenlenecektir.
prg33 kodundan farklı olarak dosyada oluşturulan çarpım tablosu, dosyadan tekrar okunarak
ekranda görüntülenmektedir. C++’da dosya dosyaları okuma ve yazma (I/O) işlemleri
fstream.h kütüphanesi kullanılarak yapılır. Okuma ve yazma akımları (nesneleri) sırasıyla
ifstream ve ofstream sınıf örnekleriyle yaratılır. Adı kullanıcı tarafından isteğe bağlı olarak
belirtilen bu nesneler, ekran giriş/çıkış komutları olarak kullanılan cin ve cout nesnelerine
karşılık gelir. Bu nedenle çıkış akımı için << operatörü, giriş akımı içinse >> operatörü
kullanılmalıdır. I/O komutlarının tümü birer nesne olduğu için nesneye ait üye değişken ve
fonksiyonlara . ile erişilebilir.
/*prg45*/
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>
İ.Ö.BİLDİRİCİ, 02.04.12
40
int main()
{
ofstream stream1;
ifstream stream2;
char dosya_adi[80];
char satir[80];
int x,y;
cout << "\nDosya adi: ";
cin >> dosya_adi;
stream1.open(dosya_adi,ios::out);
if(stream1.fail())
{
cout << "\nDosya acilamadi!";
}
else
{
for (x=1;x<=10;x=x+1)
{
for (y=1;y<=10;y=y+1)
{
stream1 << setw(4) << x*y;
}
stream1 << "\n";
}
}
stream1.close();
/* Acilan dosyanin tekrar okunmasi*/
stream2.open(dosya_adi,ios::in);
if(!stream2.fail())
{
stream2.getline(satir,80,'\n');
cout << satir << endl;
while (!stream2.eof())
{
stream2.getline(satir,80,'\n');
cout << satir << endl;
}
}
stream2.close();
return 0;
}
7.3
Nesneye Yönelik Programlama
C++ ile ilgili ikinci örneğimiz ise nesneye yönelik programlama (object oriented programming).
Nesneye yönelik programlama C++’nın C’ye göre en üstün yanını oluşturmaktadır. Şimdiye
değin temel değişken tipleriyle (char, float, double vb) program yazmaya çalıştık. C’de
kullanıcıya özgü değişken tipleri daha önceden de bildiğiniz gibi struct komutuyla
tanımlanıyordu. C++’da bu yöntemin karşılığı, nesne yani class oluşturmaktır. Kısaca
tanımlamak gerekirse nesne, içerisinde veri ve fonksiyon fonksiyon bulunduran bir yapı
bloğudur. Standart değişkenlerin tanımlanmasında nasıl değişken türü ve değişken adı şeklinde
bir kodlama yapıyorsak, aynı durum nesne oluşturmak için de geçerlidir. Örneğin aşağıda
olduğu gibi temel ödev hesaplarının yapılmasına yönelik içinde üye değişken ve üye fonksiyon
bulunduran sınıf örneği hazırlanmış olsun. Bu sınıf örneğinden yararlanarak,
TemelOdev12 odev2(X1, Y1, X2, Y2);
komutuyla bir odev2 nesnesi yaratabiliriz. Bundan sonra yapılması gereken, nesne içerisinde
saklanacak verileri nesneye göndermek ve üye fonksiyonlar aracılığıyla işlenen sonuçları
gerektiğinde geri almak.
İ.Ö.BİLDİRİCİ, 02.04.12
41
Nesneyi (ya da sınıf örneğini) oluşturan değişken ve fonksiyonlar iki gruba ayrılır: private ve
public. Private değişken ya da fonksiyonun sadece sınıf içerisinde tanımlıdır. Public değişken ve
fonksiyonlara ise sınıf içerisinden erişilebileceği gibi sınıf dışından da erişilebilir.
/*prg46*/
#include <iostream.h>
#include <iomanip.h>
#include <math.h>
const double pi=3.14159265358979;
class TemelOdev12
{
private:
double x1, y1, x2, y2;
double dx, dy;
public:
double kenar();
double semt();
TemelOdev12(double xa, double ya, double xb, double yb);
};
double TemelOdev12::kenar()
{
return sqrt(dx*dx+dy*dy);
}
double TemelOdev12::semt()
{
double aci=0.0;
aci=atan2(dy,dx);
if(aci<0)
aci+=2*pi;
return aci;
}
TemelOdev12::TemelOdev12(double xa, double ya, double xb, double yb)
{
x1=xa;
y1=ya;
x2=xb;
y2=yb;
dx=x2-x1;
dy=y2-y1;
}
int main()
{
double X1, Y1, X2, Y2;
cout << "\nKoordinatlari giriniz\n";
cout << "x1=
cin >> X1;
cout << "y1=
cin >> Y1;
cout << "x2=
cin >> X2;
cout << "y2=
cin >> Y2;
İ.Ö.BİLDİRİCİ, 02.04.12
";
";
";
";
42
TemelOdev12 odev2(X1, Y1, X2, Y2);
cout << "\n\nKoordinatlar\n";
cout << "
nn
x
y
\n";
cout << "======= ============ ===========\n\n";
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout << "
1
cout << "
2
" << setw(12) << setprecision(3) << X1
<< setw(12) << setprecision(3) << Y1 << endl;
" << setw(12) << setprecision(3) << X2
<< setw(12) << setprecision(3) << Y2 << endl;
cout << "Kenar = " << odev2.kenar() << " m" << endl;
cout << "Semt = " << setprecision(4) << odev2.semt()*200/pi << " g"
<< endl;
return 0;
}
İ.Ö.BİLDİRİCİ, 02.04.12
43