Şimdi Linux makinamıza Open Gl kurulumunu anlatacağım.Bize lazım olan Mesa;
ftp://ftp.freedesktop.org/pub/mesa/ sitesinden sürüm nosu çift olanlardan bir tanesini indiriniz.Hem Mesalib hemde MesaDemos dosyalarını indiriniz
ardından kurulum için;
root olduktan sonra ;(root olmak için komut penceresinde su yazıp root şifrenizi girebilirsiniz.)
tabi bu işlemleri yapmadan önce o dizine gitmeyi unutmayın
# tar xzfv MesaLib.tar.gz
# tar xzfv MesaDemos.tar.gz
# cd Mesa-sürümno/
# ./configure
# make
# make install
mesaLib.tar.gz yerine indirdiğiniz dosyanın adını yazınız.Örneğin ; MesaDemos-7.5.2.tar.gz gibi.
Derleme İşlemi
Derlerken standratların dışında bazı bayrakları vermemiz gerekecek.Örneğin ilk.c adlı kodumuzu şöyle derliyebiliriz
gcc ilk.c -o ilk -lGL -lGLU -lglut
Bu bayraklar tabi kullandığınız headerlere göre değişecektir.Ama standart olarak bunu kullanacağız.
İlk Uygulama

Sonuç

Linuxda Görsel Programlamaya Giriş
C dili ile linux altında görsel programlama konularını inceleyeceğiz ben openGL kullanacağım ancak diğer platformlarıda size tanıtmak istiyorum;
GTK+

GTK+ Linux,BeOS ve Win32 sistemleri altında GPL olarak dağıtılabilen,programcıların serbest kullanımına sunulmuş bir kütüphanedir.
GTK+ linux altında çizim yapılabilen GIMP programının tasarım aşamasında kullanılan C kütüphanesidir.Yukarıdada bahsettiğimiz gibi bir çok sistemde kullanılabilmesi ona platform özgürlüğü getirir.
GTK+ kütüphanesi bileşen tabanlı bir yapıya sahiptir.Bu bizim ne işimize yarar dersenizde bu sayede GTK+ C dili ile yazılmış olmasına rağmen Ada95,C++,Objective C,Pascal,Perl,Phyton vs. gibi birçok programlama dilinide desteklemektedir.
GTK+ kurulumu için gerekli paketler gtk+.rpm ve gtk+-devel.rpm paketleridir.Piyasada şuanda bulunan bütün dağıtımlarda nerdeyse bu paketler bulunmaktadır.Olmayan dağıtımlarda ise şu kodlarla kurulabilir;
rpm -i gtk+.rpm
rpm -i gtk+-devel.rpm
Kütüphanenin resmi web sitesi : www.gtk.org
GNOME

Eğer ubuntu kullanıyorsanız şu an kullandığınız pencere sisteminin ismi gnomedir.Gnome bir linux arayüzüdür.Gnomede gtk+ gibi bir grafik kütüphanesidir.Gnome arayüzü işte bu gnome kütüphanesi kullanılarak oluşturulmuştur.
Türkiye Web Sitesi : http://www.gnome.org.tr
OpenGL
OpenGL (İngilizce: Open Graphics Library, Türkçe: Açık Grafik Kütüphanesi), gelişmiş donanım desteğini kullanarak hem iki hem de üç boyutlu grafikleri ekrana çizmek için kullanılan ücretsiz bir grafik uygulama geliştirme arabirimidir. Windows, Linux, MacOS ve Solaris gibi birçok işletim sisteminde yaygın olarak ve Playstation 3 başta olmak üzere bazı oyun konsollarınca desteklenir. Donanım tarafında ise SGI, ATI, Nvidia veya Intel gibi büyük üreticiler her ekran kartında OpenGL desteği sunar.
1992 yılında ilk taslağı yaratılmış olan bu standart, günümüzde 4.0 sürümüne ulaşmıştır ve 250′nin üzerinde fonksiyona sahiptir. Çoklu platform desteği içeren uygulamalar ve özellikle de deneysel ve bilimsel araçlarda açık arayla önde ve standart olarak kullanılmakta olan platform OpenGL’dir.
Soket Programlama 2
Soket programlama 1 konusunun devamıdır.Kodlarımızı yazmaya başlayalım;
ilk başta bir port numaramızı belirtmeliyiz ;
#define PORT 3333
şimdi bir soket oluşturalım
int soketmaygun ;//Bildiğiniz gibi soketler bir tamsayıdır
soketmaygun = socket(AF_INET,SOCK_STREAM,0);//Soketimizi socket() fonksiyonu ile oluşturuyoruz
if (maygun < 0)//Eğeer bir değer atanmamışsa programımızı kapatıyoruz
{
printf(“Soket oluşurken bir hata oluştu
“);
exit (1);
}
// Fonksiyonumuzdaki parametleri tanımıyoruz tanıştırayım sizi
İlk parametre protokol türünübelirler hazırda 5 protkol vardır
/*
AF_UNIX (UNIX internal protocols)
AF_INET (ARPA Internet protocols)
AF_ISO (ISO protocols)
AF_NS (Xerox Network Systems protocols)
AF_IMPLINK (IMP “host at IMP” link layer)
*/
http://www.google.com.tr/
Tabi bu kadar fonksiyon kullanıyoruz bunlar standart kütüphanelerde yok
<sys/types.h> ve <sys/socket.h> kütüphaneleri kullanacağız.
if(bind(soketmaygun,(struct sockaddr *)& my_addr,size of(struct sockaddr))== -1)
{
printf(“bind”);
exit(1);
}
//bind() fonksiyonu soketi, verilen socket ismi ile ilişkilendirip yerel adres atamasını yapar.
if (listen(soketmaygun, BACKLOG) == -1)
{
perror(“listen”);
exit(1);
}
/*listen() fonksiyonu ile oluşturduğumuz soketi dinlemeye geçeriz. Artık istemciden bağlantı olunca accept() fonksiyonunu çağıracağıznci parametre kaç tane bağlantıyı kuyrukta tutacağımızı belirler. Tamsayı bir değerdir.*/
Program gerekiği sunucunun çalıştığı bilgisayarın adresi veya sunucuya bağlanan istmcilerin adresleri gerekli olabilir. Bu durunda hazır olarak verilen sockaddr_in yapısı kullanılır.
#define PORT 2222
struct sockaddr_in server_addr; /* Server adres bilgisi */
server_addr.sin_family = AF_INET; /* Adres ailesi */
server_addr.sin_port = htons(PORT); /* PORT numarasi */
server_addr.sin_addr.s_addr = INADDR_ANY; /* IP numarasi */
//Bu kodlar kendi adres bilgilerimizi elde etmek içindir. Şu an yazdığımız programın sunucu olduğuna dikkat edin.
Şimdide sunucumuza bağlanan kişinin adresini tespit edelim ;
int accept(int s, struct sockaddr *addr, int *addrlen);
Bağlantının Kabul Edilmesi
//Bizim programla bağlantı kurulduğunda bağlantıyı kabul etmemiz için accept() fonksiyonunu çağırmamız gerekir.
int fd, client_size;
struct sockaddr_in client_addr; /* Client adres bilgisi */
client_size = sizeof(struct sockaddr_in);
fd = accept(soketmaygun, (struct sockaddr *)&client_addr, &client_size));
printf(“%s sunucumuza baglandi…\n”,inet_ntoa(client_addr.sin_addr));
/*accept()’ in ilk argumenti daha önce socket() ile oluşturduğumuz, bind() ile adresini atadığımız ve listen() ile dinlemeye geçtiğimiz soketin ismidir. İkinci parametre karşı tarafın adresinin atanacağı değişken, üçüncü parametre ise adres bilgisinin toplam uzunluğudur.*/
Veri Gönderme
Bir soketten istemciye veri göndermek için send() veya write() fonksiyonları kullanılır.Ben kodlarda send() i kullandım.
int send(int s, const void *msg, int len, unsigned int flags);
Kullanım şekli şöyledir ;
send(fd,mesaj,sizeof(mesaj), 0);
Tüm kodlar ise şöyle olacak ;
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define PORT 3333 /* PORT numarasi */
main(int argc, char *argv[])
{
int ssoketmaygun, fd;
struct sockaddr_in server_addr, client_addr;
int client_size;
char mesaj[32];
printf(“%s %d portu uzerinde calismaya basladi…\n”,argv[0],PORT);
if ((soketmaygun = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf(“Error : socket”);
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(soketmaygun, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
printf(“Error : bind”);
exit(1);
}
if (listen(soketmaygun, 1) == -1)
{
printf(“Error : listen”);
exit(1);
}
while(1)
{
client_size = sizeof(struct sockaddr_in);
if ((fd = accept(soketmaygun, (struct sockaddr *)&client_addr, &client_size)) == -1)
{
printf(“Error : accept”);
continue;
}
printf(“%s sunucumuza baglandi…\n”,inet_ntoa(client_addr.sin_addr));
strcpy(mesaj,”Sunucuma baglantiniz yapildi…\n”);
if (!fork())
{
if (send(fd,mesaj,sizeof(mesaj), 0) == -1) perror(“Error : send”);
close(fd);
exit(0);
}
close(fd);
while ( waitpid(-1,NULL,WNOHANG) > 0);
}
} //Derlendi sorunsuzca çalışıyor foruma eklerken bazı hatalr oluşabilir düzenleyiniz
Şimdiye kadar hep sunucumuzu tasarladık sırada istemci(client)i oluşturmada;
Fonksiyonlar tamamen farklı çünkü biri istemci biri sunucu
#define PORT 2222
// Portumuzu tanımlıyoruz
int main(int argc, char *argv[])
{
if (argc != 2) {
printf(“Kullanimi : %s hostname\n”,argv[0]);
exit(1);
}
//Sunucunun çalıştığı bilgisayar istemciye parametre olarak verilecek
struct hostent *h_name;
if(argc > 1)
{
h_name = gethostbyname(argv[1]);
}
else
{
printf(“Kullanimi: %s hostname\n”,argv[0]);
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = *(u_long *) h_name->h_addr;
serv_addr.sin_port = htons(PORT);
printf(“Sunucu adresi: %s\n”,inet_ntoa(serv_addr.sin_addr));
//Parametre olarak alınan host ismini çözümlüyoruz. Adres yapısında olan server_addr değişkeninin PORT numarasını ve IP adresini atıyoruz.
struct hostent *h_name;
if(argc > 1)
{
h_name = gethostbyname(argv[1]);
}
else
{
printf(“Kullanimi: %s hostname\n”,argv[0]);
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = *(u_long *) h_name->h_addr;
serv_addr.sin_port = htons(PORT);
printf(“Sunucu adresi: %s\n”,inet_ntoa(serv_addr.sin_addr));
//Artık hizmetkarımıza, yani sunucumuza bağlanıp selam verme vakti geldi.
if( (soketmaygun = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror(“Hata: soket acilamadi!\n”);
if(connect(soketmaygun, (struct sockaddr *) &serv_addr, sizeof(serv_addr))< 0)
printf(“Hata: sunucuya baglanilamadi!\n”);
while(1)
{
printf(“\n==========================================\n”);
printf(“Mesajinizi girin veya \\”quit\\” yazarak cikin: “);
gets(buf);
printf(“\n”);
if(strcmp(buf,”quit”)==0) break;
if( (send(soketmaygun, buf, sizeof(buf), 0)) <= 0)
printf(“Client: Send error\n”);
strcpy(buf, “”);
if( (recv(sockfd, buf, sizeof(buf), 0)) <= 0)
printf(“Hata: paket alirken bir hata olustu!\n”);
if(buf[0] != 4)
{
printf(“Sunucu’dan gelen mesaj: %s”, buf);
}
else
{
break;
}
}
shutdown(sockfd, 2);
close(sockfd);
/*Aynen sunucu programda olduğu gibi soket açtık. Soket türümüz yine SOCK_STREAM. Sonra connect()fonksiyonunu kullanarak açtığımız soket üzerinden bir bağlantı yaptık. connect() fonksiyonu sys/types.h başlık dosyasında aşağıdaki gibi tanımlanmıştır:
int connect(int s, const void *addr, int addrlen);
lk parametre soket tanımlayıcısı, ikinci parametre bağlantı kurulacak sunucunun adres bilgilerini içeren server_addr yapısı, son parametre ise adres yapısının boyutudur.
*/
/* sunucumuzla aramızda stream bir soket bağlantısı kurmuş olduk. İstemci tarafında connect() yapıldığı zaman, sunucu tarafında accept() yapılır. Yani yapılan bağlantı kabul edilir. Daha önce yazdığımız sunucu programdaki accept() işlemi, telnet programının connect() isteğini karşılıyordu. Şimdi bizim istemimiz bu isteği gönderecek. Dikkat ederseniz ilkel bir telnet programı yazıyoruz.*/
Sunucuya Bilgi Gönderme
. Ekrandan bir mesaj alıp bunu send() fonksiyonu ile sunucuya gönderiyoruz. Bu fonksiyon, dosyalara yazmak için kullandığımız write() fonksiyonu gibidir. send() ile sokete veri gönderiyoruz. Soket sunucu ile bağlantılı olduğundan veri, sunucuya ulaşır. Sunucu ise her send() isteğine recv() ile karşılık verir. send() yada recv() işlemleri her iki tarafta da yapılabilir. Sunucudan gelen her send() isteğine karşı da istemci de bir recv() vardır. Örneğin ftp programında karşılık send() ve recv() işlemleri vardır. Siz önce istemci tarafından ’get dosya’ komutunu göndererek dosya isteğinizi belirtiyorsunuz. Sunucu bu komutu okuyup yorumluyor ve size dosyayı ftp protokolune uygun paketler halinde gönderiyor. Artık siz okumaya başlıyorsunuz. Paketleri alıp birleştirip yerel diske yazıyorsunuz. Bu aşamadan sonra istediğinizi yaptırabilirsiniz.
Socket(Soket) Programlama
C dili çok geniş bir uygulama alanına sahiptir.Networkta bu uygulamalar arasında önemli bir yer tutar.Bu makalemde de network işlemlerinin temel yapısı olan soket programlama konusu hakkında bilgiler vermeye çalışacağım.ilk başta networkun elemanlarını nelerden oluştuğunu nasıl çalıştığını incelemeye başlıyalım ;
İlk başta temel oluşumdan bahsedeyim.Bir client birde server vardır.client bir isteğini servere yollar serverde bu isteğe bir cevap verir.Arada bazı protokoller vardır.TCP/ıp gibi.Biz tarayıcımızı açıp www.xxx.com a bastığımızda direk olarak bu protokolü kabul etmiş olacağız.
Bu terimler kafanızı biraz karıştırmış olabilir tek tek terimlerin açıklamalarını yapalım ;
İstemci (Client) :Hizmet istiyen soket programlara denir.Sorguyu gönderende diyebiliriz.İstediğimiz zaman sunucuya bağlatır istediğimizi yaptırır ve kapatırız.
Sunucu (Server) :Hizmet vern soket programdır.Client(istemci)den gelen sorgulara yanıt verir.Client gibi istediğimiz zaman açıp kapatamayız.Çünkü istemcinin ne zaman sorgu göndereceği belli değildir. Linuxta bulunan bazı sunucular ;
in.telnetd,wu.ftpd,nfsd,httpd ….
Port : Bir bilgisayarda birden çok soket bulunabilir.Soketleri birbirinden ayırmak ve istemci-sunucu ikilisini buluşturabilmek için her soketin bir numarası vardır.Öğretmenin öğenciyle ilişki kurarken kullandığı okul numarası gibi.Örneğin ftp nin port numarası 21 dir.Linuxta 1-1024 arasındaki portlar standarttır ve sadece root olanlar kullanabilirler.Eğer normal kullanıcılar kullanmaya kalkarsalar yetkisizlik hatası üretir.
IP : Bilgisayarlar bir sunucu başka bir bilgisayar veya başka birşeyle iletişim kurarken Ip numarasını kullanarak haberleşir.TC no muza benzetebiliriz.Sınıf numarası ile karıştırmayalım aynı okulda olmayanların sınıf numaraları farklı olabilir ancak aynı tc ye sahip olamazlar.Port ile Ip kavramını karıştırmamak lazım.Bir istemci programı önce IP sını kullanarak sunucunun bulunduğu bilgisayara bağlanır sonra Port numarasını kullanarak hizmet istediği sunucu program ile temasa geçer.
Bu kavramlar soket programlama ve networkun temel konularıdır.
Aşşagıdaki resimde öğrendiklerimizi özetliyecektir

Soket Türleri
Bir çok soket türü bulunmaktadır ancak bizim ilgileneceğimiz iki üt soket türü vardır.”Stream Soketler” ve “Datagram Soketler”.Bunlar programlarda SOCK_STREAM ve SOCK_DGRAM isimleri ile kullanılırlar.
Stream soketlere bağlantı yönelimli (connection oriented) soketler,Datagram soketlere ise bağlantısız(connectionless) soketler denir.
İkisi arasındaki farklı güzel iki örnekle açıklayayım.Mail atmak ve online olarak konuşmak
Mail attığınızda karşı tarafın müsait olmasına yada açık olmasına gerek yoktur.Yolarsınız istediği zaman bakar.Bu bağlantısız Datagram soketlere örnektir.Ancak online olarak her iki tarafında açık olması gereken görüşmeler içinde Stream soketlere örnek verebiliriz.Kullanılan tüm internet programları soket programlama mantığı ile yazılmıştır.Başka örnek olarakta ICQ ile IRC yi örnek verebiliriz.ICQ da mesajı yazıp gönderiyorruz.Tek taraflı bir bağlantı oluyor.Ancak IRC de ise sürekli olarak iki tarafta aktif rol alıyor.
Strea soketler TCP/IP protokolünün TCP özelliğini kullanırlar.Ancak Datagram soketler ie UDP protokolünü kullanırlar.
Bu iki soket ve protokoller araındaki farkları incelersek ;
- Stream soketler verileri sıralı gönderir, datagram soketleri sıralı göndermeyebilir.
- Stream soketler güvenlidir, Datagram soketler güvensizdir.Bunun sebebi TCP deki acknowledgement denetimidir.Yeni bir paket yollandığında karşı tarafa ulaşmadan hedefini bitirmiş olmaz karşı taraftan cevap gelene kadar yollamaya devam eder ancak UDP de böle bişe yoktur.
-Stream soketler, işlem bitene kadar kesintisiz bir bağlantı kurar. Datagram soketler ise bağlantı kurmaz. Sadece veri göndereceği zaman bağlantı kurar ve işi bitince bağlantıyı kapatır.
UDP ;

TCP ;

Bu kadar dezavantaja rağmen neden datagram soket ve UDP kullanılıyor diyorsanızda
el cevap ![]()
TCP de 6×32 kadar veri kullanılırken UDP 64 bit veri kullanır.UDDP yi kullanmanın kısaca en önemli nedeni az protokol yüküdür.Video paylaşımı gibi uygulamalarda TCP çok fazla veri tüketeceğinden baız hatalar oluşabilir kısaca veri tasarrufu yapmak için UDP kullanılır.O kadar güvensiz dedikte soket programlamada yazılımcı isterse UDP paketinide güvenli bir şekile dönüştürebilir.Bu konuyla alakalı son olarakta ’telnet’ programı Stream soket, ’tftp’ programı ise Datagram sokettir diyorum.
Break ve Continue Komutu
Konuları inceledim ve ufak gözden kaçan iki eksikliği gördüm.Eklemek istedim.İlk
başta Break komutundan başlayalım ;
break
Break komutunu normalde switch yapılarında görmüştük.Normal for,while,do while
döngülerinde kullanımı göstereceğim.Break’ın anlamı zaten durdurmak gibi birşeydir.
Bir şart sağlandığında döngünün sonlanmasını istediğimizde breakı kullanırız.
Mesala bir örnek kod üzerinde göstereyim ;
/*
0 ile 99 arasında tesadüfi sayılar üreten
bir programın, kaçıncı seferde 55 sayısını
bulacağını yazan program aşağıdadır.
*/
#include<stdio.h>
int main( void )
{
int i,rastgelesayi;
int deneme_sayisi = 0;
//while içinde 1 olduğundan sonsuza kadar döngü çalışır.
while( 1 )
{
//rastgele değişkenine, 0 ile 99 arasında
//her seferinde farklı bir sayı atanır.
rastgelesayi = rand() % 100;//bu komutu öncedende görmüştük 0-99 arası rastgle sayı üretecek
//Döngünün kaç defa çalıştığını deneme_sayisi
//değişkeniyle buluruz.
deneme_sayisi++;
//Eğer tesadufi sayı 55’e eşit olursa,
//döngü kırılıp, sonlandırılır.
if( tesadufi_sayi == 55) break;
}
printf(“Toplam deneme sayısı: %d\n”,deneme_sayisi);
return 0;
}
continue
Continue de devam etmek anlamındadır.Break döngüyü durdurur.Ancak continue sayesinde
döngü durmaz.O adım atlanarak devam edilir.Mesala 0-10 arasındaki çift sayıları
belirleyen bir kod yazalım ;
#include<stdio.h>
int main( void )
{
int i;
for( i = 0; i < 10; i++ ) {
//i değişkeninin 2’ye göre modu
//0 sonucunu veriyorsa, bu onun
//bir çift sayı olduğunu gösterir.
//! ifadesi sayesinde tersi olduğunda
//yani tek olması durumunda atlayacak
//Bu durumda ekrana yazdırılmaması
//için döngü bir sonraki adıma geçer.
if( !i%2 == 0 ) continue;
printf(“%2d\\n”,i);
}
return 0;
}
Gcc Derleyicisinde Başarım inceleme
Artık köşede kuytuda konular buldukça öğrendiklerimi aktarmaya çalışıyorum.Başarımızı incelemek için gcc derleyicisinde bir raporlama hizmeti vardır.gprof deniliyor bu araca.
-pg komutu ile bu istediğimizi yapabiliyoruz yanlız hem derleme hemde bağlanma aşamalrında -pg komutunu vermeliyiz.
ör :
gcc -pg program.c
gcc program.o -o program
bu komutlarla derlenip program çalıştırılır.gmon.out diye bir dosya oluşur biz programımız kullandıktan sonra.
gprof program gmon.out diyip raporumuzu inceleyebiliriz.Hangi fonksiyonların ne kadar kullanıldığı ne kadar zorladığını vs görebiliriz.
Dosya Yönetimi( I/O İŞLEMLERİ )
Dosya Açma ve Kapama
Bir dosyanın üzerinde işlem yapmak,yada görüntülemek için ilk başta o dosyayı açmak gerekir.İlk başta bir dosya göstergecisi(pointers) oluşturmak gerekir.Dosyayı açmak için fopen(),kapatmak için fclose() fonksiyonları kullanılır.Bu fonksiyonlar stdio.h kütüphanesinde tanımlandığından ek kütüphane eklememize gerek yoktur.
Genel olarak şematize edecek olursakta ;
FILE *dosyaismi;
yaz = fopen(const char dosya_adı,const char mod);
…..
dosya işlemleri
…..
fclose(dosya);
const char mod diye belirtilen dosyanın nasıl açılacağıdır.Benim bulabildiklerim şunlarİ
“r” :Salt okunur (read only). Dosyanın açılabilmesi için önceden oluştrulmuş olması gerekir. Bu modda açılmş olan bir dosyaya yazma yapılamaz.
“w” :Yalnızca yazma (write only). Dosya diskte kayıtlı olsun veya olamsın dosya yeniden oluşturulur. Bu modda açılmış olan bir dosyadan okuma yapılamaz.
“a” : Ekleme (append). Kayıtlı bir dosyanın sonuna veri eklemek için açılır. Bu modda açılmış olan bir dosyadan okuma yapılamaz.
“r+” :Okuma ve yazma. Bu modda açılmış olan bir dosyanın daha önce varolması gerekir.
“w+” :Okuma ve yazma. Bu modda açılmış olan bir dosya var olsun veya olmasın dosya yeniden oluşturulur.
“a+ ” : Okuma ve yazma. Kayıtlı bir dosyanın sonuna veri eklemek için açılır.
Ufak bir örnekle giriş yapalım istiyorsanız ;
Yanlız kodlarımızı yazarken şuna dikkat etmeliyiz,üzerinde çalışacağımız dosya ile ana programın aynı dizinde olması önemlidir.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *dg;//pointerimizi tanımladık
const int n = 5;
char ad[10];
int no,Not,i = 0;
dg = fopen(“ogrenci.txt”,”w”);//dosyamızı oluşturduk ve açtık
if (dg == NULL)//Pointer bellekte yer kaplayamazsa uyarı verecek bize
printf(“ogrenci.txt dosyası açılamadı. \n”),exit(1);
printf (“5 ogrenciye ait bilgileri girin : \n”);
while(i++<n)
{
printf(“%d. ogrencinin numarasi: “,i); scanf(“%d”,&no);
printf(“%d. ogrencinin adi : “,i); scanf(“%s”,ad);
printf(“%d. ogrencinin notu : “,i); scanf(“%d”,&Not);
printf(“\n”);
fprintf(dg,”%5d %10s %3d\\n”,no,ad,Not);
//fprintf fonksiyonumuzla istediğmiz veriyi yazdırttık
}
fclose(dg);//Ve en sonda kapattırdık.
printf(“Bilgiler kaydedildi \n”);
return 0 ;
/oluşturduğumuz dosyayı görüntülemek içinde terminale *$ edit ogrenci.txt komutunu verebiliriz*/
}
Aşşağıda dosya işlemlerinde kullanılan bazı fonksiyonlar var ;
fopen() Dosya oluşturur, açar
fclose() Dosyayı kapatır
putc() Dosyaya bir karakter yazar
getc() Dosyadan bir 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
Dosyadan okuma,değiştirme türü işlemleri içeren ufak bir örnek daha yapalım;
/*
kelvin.sck dosyasındaki 100 tane kelvin sıcaklığını derece.sck dosyasına celciusa çevirip yolluyacaz
*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
/* dosya göstericileri */
FILE *oku, *yaz;
/* Dosya adları */
char *kaynak_dosya = “kelvin.sck”;
char *hedef_dosya = “derece.sck”;
float K,D;
int i=0, n=100;
/* Dosylara erişim mümkün mü ? */
if( (oku=fopen(kaynak_dosya, “r”)) == NULL )
{
printf(“%s dosyası acilmadi.\n”, kaynak_dosya);
exit(1);
}
if( (yaz=fopen(hedef_dosya, “w”)) == NULL )
{
printf(“%s acilmadi.\n”, hedef_dosya);
exit(2);
}
for(i=0; i<n; i++)
{
fscanf(oku,”%f”,&K); /* ’kelvin.sck’dan verileri oku */
D = K – 273.0; /* dönüşüm denklemi */
fprintf(yaz,”%8.2f\n”,D); /* verileri ’derece.sck’ya yaz */
}
/* Dosyaları kapat */
fclose(oku);
fclose(yaz);
printf(“%s > %s\n”, kaynak_dosya, hedef_dosya);
puts(“cevirme islemi tamamlandi.”);
return 0;
}
Kendi kendinize değişik örnekler yapabilirsiniz.
Standart Dosyalar
C Programlama Dili’nde bilgisayarın sahip olduğu ekran, klavye ve portlar birer dosya olarak tanımlanmıştır. Bu dosyalara standart dosyalar denir. Program çalışmaya başladığında beş adet standart dosya otomatik olarak açılır. C, stdio.h başlık dosyasında tanımlanan bütün bu standart dosyalara bazı isimler vermiştir.Aşşağıdaki lisede bunları görebilirsiniz.
stdout : Standart çıkış ortamı (ekran)
stderr : Standart hata çıkış ortamı (ekran)
stdin : Standart giriş ortamı (klavye)
bunların dışında derleyiciye özel olarak tanımlanmış dosya isimleride vardır.
Basit bir kod verecek olursakta ;
#include <stdio.h>
int main()
{
fprintf(stdout,”Bu mesaj *ekrana* yazilacak …\n”);
fprintf(stdprn,”Bu mesaj *yaziciya* yazilacak …\n”);
return 0;
}
/*
stdprn Turbo C de bulunan bir dosya ismiymiş.İnternette gezerken gördüm paylaşayım dedim.
Yazıcı bağlı değilse işletim sistemi hata verecektir ![]()
*/
Tür Belirleyiciler
const ve volatile olmak üzere iki tür niteleyici vardır.
const Belirleyicisi
const belirleyicisi,ilk değer atandıktan sonra nesnenin içeriğinin değiştirilmeyeceğini belirten anahtar sözcüktür.yereliglobal,parametre değişkenlerinin hepsinde kullanılabilir.const ile tanımlanmış değişkene ileride başka bir değer atanması gereksiz ve anlamsızdır.
const double PI = 3.1415 // Geçerlidir
int main ()
{
const int i = 10 ;//Geçerli
i = 100;//Geçersiz
return 0 ; //Geçerli
(Hızımı alamadım)
}
const ile tanımlanmış bir değişkene ilk değer girilmemesi anlamsızdır.
const İle Simgesel Değişmezler(#define ..) Arasındaki Farklar
-Simgesel değişmezler nesne olmadıkları için bellekte yer kaplamazlar.
-Derleyiciler const nesneler için daha iyi debuggin özellik sağlar.
-Bir dizi const anahtar sözcüğü ile tanımlanabilir.Ancak diziye ilk değer ataması yapıldıktan sonra bir indexe değer atamak geçersiz sayılacaktır
const char alfabe [] = “abcdefgh….”;
alfabe [3] = ’Q’ ; //Geçerisdir.
volatile Belirleyicisi
Çok özel uygulamalarda kullanılan bir belirleyicidir.İşlev olarak register in tersini yapar.Nerede neden kullanıldığınu şimdi açıklamaya çalışayım;
örnek bir kod inceleyelim
int kare(int a)
{
int b;
b = a * a;
return b ;
}
Derleyiciler daha fazla performans için bazen değişkenleri bellekte sağlamak yerine yazmaçlarda saklayabilirler.Bundan dolayı ileride bellekteki b nin değeri değişebilirken yazmaçtaki b nin değeri değişmez.Bundan dolayı bazı problemler çıkabilir.Bundan dolayı b değişkenini volatile int b ; şeklinde tanımlamak uygun olacaktır.Çok özel uygulamalarda kullanıldığı için normal kod yazarken pek kullanılmaz.Bu belirleyicinin bilinçsizce kullanılması bazen performansı aşırı derecede kötü etkiler ondan dolayı şimdilik fazla uğraşmamak lazım
Belirleyiciler
Belirliyeciler,bildirimler yaparken kullanılan nesnelerin haakkında derleyiciye bilgi verebilen anahtar sözcüklerdir.C dilinde kullanılan belirleyiciler auto, register, static, extern ve typedefdir.Tek tek incelemeye ve ne işe yaradıklarına bakalım;
auto
Sadece yerel değişkenler için kullanılabilen bir belirleyicidir.Bu sözcük sayesinde nesnenin bilinirlik alanı bittikten sonra kaybolacağını,bellekte kapladığı yerin geçerliliği kalmayacağını gösterir.Yerel değişkenler sadece bulundukları blogta yaratılır sonra kaybolurlar işte auto belirleyicisi bunu belirtir.
{
auto int a;
float b;
}
auto belirleyicisi sadece yerel nesnelerde kullanılır
auto int a;//Geçersiz
function(auto int x)//Geçersiz
{
/***/
}
register
register belirleyicisi değişkenin bellekte değilde işlemci yazmaçlarında tutulmasını istiyoruz demek için kullanılan bir belirleyicidir.Değişkenin bellekte değilde işlemci yazmaçlarında saklanması programın hızını arttırır.Yazmaçlar dediğimizde İşlemci(CPU)nun tampon bellek bölgeleridir.Yanlız register işlevini kullanırken dikkatli olmak gerekir.Çünkü her makinada yazmaçlar sınırlı sayıdadır.Derleyici size yazmaçlar doldu daha oraya değişken atıyamam türünde hatalarda vermez bundan dolayı sadece küçük önemli kod parçalarından kullanmak gerekir.register belirleyicisi sadece yerel yada parametre değişkenlerinde kullanılabilir.
register int g;//Geçersiz
int func (register int y)//Geçerli
{
register int x;//Geçerli
}
static
static belirleyicisi ancak yerel ve global değişkenlerin bildiriminde kullanılır.Parametre değişkenlerinde kullanılmaz.static anahtar sözcüğünün global ve yerel değişkenlerde kullanılması farklı anlamlara gelir ;
local değişkenlerde ;
static yer belirleyicisi ile tanımlanmış yerel değişkenler ya da yerel diziler programın çalışması boyunca bellekte kalır. Başka bir deyişle, static anahtar sözcüğü yerel değişkenlerin ömrünü otomatik ömürden statik ömre yükseltir.Static yerel değişkenler ilk değer verildikten sonra kullanılır.İlk değer verme işlemi programın çalışma sırasında değil derleme zamanında derleyici tarafından yapılır.Derleyici bellekten yer ayrılmasını sağlayacak makine kodunu oluşturur.
Örnek bir kod ile pratiğe dökelim ;
#include<stdio.h>
void func1()
{
int x = 5;
printf(“x = %d\n”, x);
x++;
}
void func2()
{
static int y = 5;
printf(“y = %d\n”, y);
y++;
}
int main()
{
int k;
printf(“func1 işlevi 5 kez çağrılıyor!\n”);
for (k = 0; k < 5; ++k)
func1();
printf(“\nfunc2 işlevi 5 kez çağrılıyor!\n”);
for (k = 0; k < 5; ++k)
func2();
return 0;
}
/*
Yukarıdaki program içinde tanımlanan func1 işlevi her çağrıldığında x değişkeni yaratılır
ve işlevin çalışması sonlandığında x değişkeni bellekten boşaltılır. Her ne kadar işlevin
sonlanmasından önce x değişkeninin değeri 1 artırılsa da, bunun bir sonraki çağrıya hiçbir
etkisi olmaz. func1 işlevinin bir sonraki çağrısında x değişkeni yine 5 değeri ile başlatılır.
Oysa func2 işlevi için durum değişiktir. func2 işlevi içindeki y isimli yerel değişken blok
bilinirlik alanına ait fakat statik ömürlüdür. y değişkenine ilkdeğer verme deyimi derleyici
tarafından üretilen kodun bir parçasıdır. y değişkeni programın başında 5 değeri ile
başlatılır ve programın sonuna kadar bellekteki yerini korur. İşlev kaç kez çağrılırsa
çağırılsın, bellekteki yeri değişmeyen aynı y değişkeni kullanılır. Bu durumda işlevin ana
bloğunun sonunda y değişkeninin değeri 1 artırıldığı için bir sonraki çağrıda artık y
değişkeninin değeri 6 olur
*/
Çıktısı :
func1 işlevi 5 kez çağrılıyor!
x = 5
x = 5
x = 5
x = 5
x = 5
func2 işlevi 5 kez çağrılıyor!
y = 5
y = 6
y = 7
y = 8
y = 9
Şeklinde olur.
Dizilerde static şeklinde tanımlanabilirler.
void func()
{
static char alfabe[] = “ABCDEFGH…..”;
}
alfabe dizimizi static şeklinde tanımladığım için ilk değer hep bellekte kalacıktır.Bundan dolayı kullanıcı diziyi her çağırdığında yeniden yeniden ilk değer ataması yapılmayacak ve performans artışı sağyalacaktır.
global olarak kullandığımızdada
örneğin
static int a = 10 ;
{
a = 15;
}//programın ilerisinde a global değişkenin değeri 15 olarak kalacaktır.
statici kullandığımızda a global değişkenini dinamik olarak kullanmış oluyoruz kısaca.
Static Yerel Değişkenler ile Global Değişkenleri Karşılaştırdığımızdada şöyle bir sonuç ortaya çıkıyor ;
Ömür açısından static local değişkenlerle global değişkenler aynılar.Ancak scope(kapsama alanı) olarak farklılardır.
extern
extern belirleyicisini öğrenmeden önce kullanılabildiği modül kavramını anlatmak istiyorum.
Modül Kavramı : Br proje birbirinden bağımsız olarak derlenebilen birden fazla kaynak dosyadan oluşabilir.(Örneğin Kernel
) Projenin bağımsız olarak derlenebilen hr dosyasına modül denir.Genelde büyük projelerde kullanılarak bir hata oluştuğunda sadece o modülü derleyerek derleme süresini kısaltılabilir.
Bir değişkenin extern ile tanımlanmaı o nesnenin başka bir modeldede tanımlandığını anlatır.
ufak bir örnekle belirteyim
ilk.c
int x ;
double func1()
{
a= 100;
}
son.c
int func()
{
a = 300 ;// hata verir.
}
aşşağıdaki gibi tanımlarsak sorun ortadan kalkar.
extern int a;
int func()
{
a =300 ;
}
Dinamik Bellek Yönetimi
Dizileri kullanmayı önceki derslerimizde öğrenmiştik.Küçük programlara yazareken pek sorun olmayan ancak ileride büyük programlar yazmaya başladığımızda kafamızı kaşırttıracak bir konu olan bellek yönetimi için C dilinde bazı hazır fonksiyonlar vardır.Bir diziyi tanımladığımızda bellekten yer ayırılır ancak diziyi kullandıktan sonra o ayrılmış bellek silinmez.Yeni nesil(java,C#) gibi dillerde çöp toplayıcılar bu işi yaparak programın performansını arttırır ancak C dilinde böyle bir olanak yoktur.
Dinamik olarak belleği yönetmemiz için calloc(),malloc() ve free() fonksiyonları vardır.Dinamik bellek yönetimi sırasında en başta diziler tanımlanırken boyutu belirlenmez.colloc veya malloc fonksiyonlarıyla gereken alan tahsil edilir ardından da free fonksiyonuyla bellekten silinir.
calloc () fonksiyonun kullanımı ;
isaretci_adi = calloc( eleman_sayisi, her_elemanin_boyutu );
malloc () fonksiyonun kullanımı ;
isaretci_adi = malloc( eleman_sayisi * her_elemanin_boyutu );
Ufak bir örnekle işe koyulalım
#include<stdio.h>
#include<stdlib.h>//calloc,malloc,free fonksiyonlarını kullanmak için ekledik
int main ()
{
int *dizi; //dinamik bir dizi yaratmak için pointerleri kullanabiliriz
int eleman_sayisi;//eleman sayısı ve döngümüz için iki değişken tanımladık
int x;
printf(“Eleman sayısını giriniz : “);
scanf(“%d”,&eleman_sayisi);
dizi = calloc(eleman_sayisi,sizeof(int));
/*
Arkadaşlar calloc fonksiyonunda eleman sayımızın kağlayacağı kadar bellek tahsis ettik.Bunun içinde her eleman sayısı için int değişkenlerin kapladığı yer kadar alan tahsis ettirdik.sizeof fonksiyonun bundan dolayı kullandık
*/
for(x=0;x<eleman_sayisi;i++)
printf(“%d\n”,dizi);
free (dizi);//can alıcı darbe burada
dizi için ayırdığımız yeri temizliyoruz
/*Eğer calloc yerine malloc için yapmak isteseydikte o satır yetine dizi = malloc( eleman_sayisi * sizeof( int ) ); yazabilirdik.İki fonksyion arasındaki tek fark mallocta ilk değer ataması yapamazız.
*/
}
Bazı durumlar olur ki belleğimiz tamamen kullanılıyodur bu tür durumlar içinde şöyle ufak bir kod blogunu kullanabiliriz;
dizi = calloc( eleman_sayisi, sizeof( int ) );
// Eger hafiza dolmussa dizi pointer’i NULL’a
// esit olacak ve asagidaki hata mesaji cikacaktir.
if( dizi == NULL )
printf( “Yetersiz bellek!\n” );
Artık dinamik olarak belleğimizi yönetebileceğiz.Aslında bu konu bir C programcısı için çok öenmli bir konudur ancak ilerletmek programcının elindedir buradaki bilgiler yeterlimidi hayır ancak daha fazlası da programcı ve öğrenmek istiyeni sıkar bundan dolayı sade bir anlatım yapıyorum Herkese kolay gelsin iyi çalışmalar.