802.11 Kanal değiştirme simülasyonu (Omnet++ )

Bu çalışmada Ad-Hoc modunda çalışan bir 802.11 modülünün haberleşme halinde iken kanal değiştirme senaryosunu gerçekleştireceğiz. Kanal değişimini ise Omnet++ ortamında C++ ile yazdığımız kod parçası sayesinde gerçekleştireceğiz.

Şekil 1 – Ağ Yerleşimi

Gelelim Senaryomuza: 802.11 alt yapısını kullanrak Ad-Hoc modda UDP haberleşmesi yapan iki adet cihazımız var. Bu iki cihazda mobileHost[0] 100 ms aralılarla 1000Bayt lık bir UDP paketi gönderiyor. 100 saniye süren simulasyon boyunca 10 saniye aralılarla göndericinin MAC katmanında kanalı değiştiriliyor. Kanal haberleşmenin olduğu 5. kanalda başlarken 10 saniye aralıklarla 5. ve 0. kanal arasında değiştiriliyor.

## file name: omnetpp.ini
sim-time-limit = 100s
**.mobileHost[0].numApps = 1
**.mobileHost[0].app[0].typename = "UdpBasicApp"
**.mobileHost[0].app[0].destAddresses = "mobileHost[1]"
**.mobileHost[0].app[0].destPort = 1000
**.mobileHost[0].app[0].messageLength = 1000B
**.mobileHost[0].app[0].sendInterval = 0.1s

**.mobileHost[1].numApps = 1
**.mobileHost[1].app[0].typename = "UdpSink"
**.mobileHost[1].app[0].localPort = 1000

**.mobileHost[*].wlan[0].radio.channelNumber = 5

Kanal değiştirme.

802.11 de oluğu gibi omnet oratamında kanal değiştirme 2. katmanda yönetiliyor. Mac katmanında oluşturulan “physicallayer::Ieee80211ConfigureRadioCommand” mesajnı radyo modülüne göndererek yapılır. Komutta kanal numarası alanı istenilen kanal olarak atanır ve oluşturulacak Request’e ControlInfo olarak eklenir ve gönderilir.

Şekil 2 – 2. katman Modülleri
void Ieee80211Mac::handleSelfMessage(cMessage *msg)
{
    //ASSERT(false);
    Ieee80211Radio * myradio = check_and_cast<Ieee80211Radio *>(this->radio);
    Ieee80211TransmitterBase *ieee80211Transmitter = const_cast<Ieee80211TransmitterBase *>(check_and_cast<const Ieee80211TransmitterBase *>(myradio->getTransmitter()));
    int channel = ieee80211Transmitter->channel->getChannelNumber();
    if(channel==5)
        channel=0;
    else
        channel=5;
    physicallayer::Ieee80211ConfigureRadioCommand *conf =  new Ieee80211ConfigureRadioCommand();
    conf->setChannelNumber(channel);

    auto request = new Request("configureRadioMode", RADIO_C_CONFIGURE);
    request->setControlInfo(conf);
    take(request);
    sendDown(request);
    scheduleAt(simTime() + 10.0, msg); // Tekarar değişimi tetikler.
}

Radyo katmanı ilgili komutu alır ve trensmiite ve reciever modüllerini ayrı ayrı istenilen kanala ayarlar.

Sonuçlar

Simulasyon sonucu mobilHost[0] için kanal değilşim ve mobilHost[1] için alınan PaketByte verisi tek garfik te çizdirildiğinde aşağıdaki sonuç elde edilmektedir. Şekil 3 tende görüldüğü üzere kanl değişiminden sonra tekrardan veri gönderimi başlayana kadar biraz süre geçmekte ve haberleşme gecikmeli olarak başlayabilmektedir. Burada sebep Routing Algoritması AODV’nin (ve dolayısıyla link katmanının) tekrardan link kurulumunu sağlaması için geçen süredir.

Yine şekil 1 de görüldüğü üzere 1000 paket gönderilmiş fakat 479 paket alınmıştır. Bir paket alınamadan simülasyon bittiği için 480 paket kabul edilmelidir. Sonuç olarak Yarı yarıya iletim sağlanması beklenirken 20 paket iletim hatası vardır. Başlangıç hariç 4 kez tekrardan haberleşme kanalına geçildiği düşünülürse 20/4 ten her tekrardan link kurulumu 5 paket süresi yani 500 ms sürmekte ve bu aralıkta 5 paket kaybı olmaktadır.

Sonuç
Şekil 3 – Sonuç

Ek bilgi: Simülasyon Akışı

Senaryoyu oluşturmak için self message yöntemi kullanılmıştır. Bunun için Ieee80211Mac.cc dosyasında init fonksiyonuna aşağıdaki kod bloğu eklenmiştir ve Her bir mesaj tekrardan 10 saniye sonra gelecek bir mesajı tetiklemektedir.

    if(strcmp(this->getParentModule()->getParentModule()->getFullName(),"mobileHost[0]")==0)
    {
        cMessage *msg = new cMessage("tecrubedenkatreler.com");
        scheduleAt(simTime()+10.0, msg);
    }

Açık kaynak Yazılımlar

Linux

Media yayınları için Gstreamer:
https://gstreamer.freedesktop.org/

PCB çizim için KiCAT:
http://kicad-pcb.org

GNU Octave : Matlab Alternatifi
https://www.gnu.org/software/octave/

Windows

Termite: Bir Uart dinleme uygulamsı hex olarak görüntüleme yapabiliyor
https://www.compuphase.com/software_termite.htm

Pdf birleştirmek için kullanabileceğiniz masaüstü yazılım.
https://pdfbinder.jaleco.com

Kütüphanler

LibOpenCM3 ARM Cortex-M3 için Open-Source alt seviye donanım kütüphanesi (STM32 yi de kapsar)

Kütüphane Kodlamak Eğitim Serisi (Video Anlatım ve Notlar)

Bismillahirrahmanirrahim. Bir başlangıçsa bu Besmeleyle olsun: Aziz olsun, kolay olsun, hayırlı olsun. Muhataba Selam olsun.

Öncelikle şunu belirtmek isterim ki bu yazıda ve eğitim içeriğinde vaat edilen her şey doğal olarak şuana kadar edinmiş olduğum tecrübelerim ve bilgim dahilinde olacaktır. Sürç-i lisan ederisek affola.

Bu eğitim serisi kapsamında Drawing Dendrogram isimli bir kütüphane kodlayacak, örnek kullanım kodlarıyla birlikte son kullanıcı dokümanı oluşturarak hizmete sunacağız.

Dendrogram Örneği

Kütüphanemiz veri madenciliği ( data maining ) alanında gösterim şekli olarak kullanılan dendrogram’ın c# ortamında çizilmesine yardımcı olacaktır.

 

KazanımSeri sonunda elde edeceğimiz kazanımlardan bahsedersek:

Fikrin ürüne yolculuğu

Fikrin ürüne yolculuğu

  1. Bir Projenin Fikir aşamasından son kullanıcıya sunulması arasında geçen tüm sürecin aktarılması.
  2. Açık kaynak (open source) dünyasına bir adım.
  3. Git sürüm kontrol sistemlerinin öğrenilmesi (Github – SourceTree).
  4. Nesneye dayalı programlamanın standartlarına uygun kodlama.
  5. Projelerin Analiz, Tasarım, Mimari ve Gerçekleştirim kısımlarının anlaşılması.
  6. Artırımsal (çevik) kodlamanın öğrenilmesi. ( Giriş seviyesinde görmüş olduğum en büyük problem ).
  7. Programlama temellerinin öğrenilmesi, kütüphaneleri kullanma becerisini geliştirme, algoritma geliştirme.
  8. Analiz.
  9. Tasarım (Kağıt kalem çalışmak).
  10. Seri boyunca kullanılacak olan teknoloji ve araçları tanıma olanağı.

Daha fazla söz etmeden sizi Seri ile başa bırakmak isterim: Görüş, öneri ve uyarılarınızı gerek e-mail gerekse yorum aracılığıyla iletmeniz işleyişi iyileştirecektir.

İyi seyirler.

Git projelerini commit bazlı nasıl takip edebileceğinizi bu_videodan (5:28 dk’lık) öğrenebilrisiniz.

Not: Ayrıntılar Zamanla Eklenecektir. Kodlara ve Hazır olan eğitim videolarına asağıdaki linklerden ulaşabilirisiniz.

Linkler:

Github kod deposu : https://github.com/AbdullahBay/DrawingDendrogram

Youtube Seri Linki: Oynatma Listesi: Kütüphane Kodlamak ( Dendrogram c# )

BitBucket ve SourceTree ile Ekip olarak kodlamak

Bitbucked nedir?

Genelde kod paylaşımı ve ekip çalışmalarında ortak bir havuz oluşturmak için kullanılan depolama sistemlerinden biridir. Tabi paylaşmak istediğiniz yazı, tanıtıcı dokuman, ders dokumanı gibi şeyleride paylaşmak mümkün.

Ekip çalışmalarında projeyi yönetmek için kullanacağınız araçlar sayesinde tek bir proje ekip olarak çalışmayıda mümkün kılar.

Neden Bitbucket derseniz :

  • 5 kullanıcıya kadar ücretsiz ekip kurabilme,
  • Projelerinizi gizli olarak geliştirebilme,
  • En az 5 farklı ekip kurabilme (tecrübe)- Her ekibe 5 kişi :),

özellikleri benim tercih sebebim oldu.

Bitbucket’e aşağıdaki linkten üye olunuz:

https://bitbucket.org/

Ve Alttaki linkten yönetim aracını indiriniz.

http://www.sourcetreeapp.com/

Kurulum ve kullanım için videoya göz atınız:

Kullanım ayrıntıları

Daha fazla bilgi için :

Bitbucket Dokumanları:

SourceTree Dokumanları:

Genel Git Dökümanları:

Bir Probleme nasıl yaklaşmalı – Veri yapıları – Algoritma – Ödev

Bir bilgisayar programcısının ödeve(projeye) bakması gereken açıyı anlatmya çalıştım.

İçerik :

  1. Ödev dökümanı nasıl okunlmalı,
  2. ekrana şekil bastırma (çıktıyı düzenleme)
  3. Nesneye dayalı programlama,
  4. cout aşırı yükleme (function overloading)- 35:52 dk,
  5. hep bellek bölgesi (new)
  6. eden çöpleri toplamalıyız: (delete)
  7. Örnek bir uygulama incelendi

Birkaç aksaklık (girişte biraz heycan, static 🙂 ) olsada, faydalı olması dileğiyle…..

Dökümanlar:
https://www.dropbox.com/sh/jwar422ozjtxo36/AAAH0osmak05V8rJTuWbZ3ZBa?dl=0

Not: İlk anlatılan dökümanda(ödev dokumanı): Sepet içinde çivilerin bulunmsa durumu değilde, Sepetlerin Çiviye asılamsı durumu istenmiş görselde de gösterilmiş. Yani harfler Çivi değil.

çivi

Keywordler: Veri yapıları, Ödev1, Sakarya Üniversitesi, Bir yaklaşım, Problem Çözme, Algortima geliştirme, Ödev yapmak, Bilgisayr Mühendisliği, c++

Matlab ile dicom Formatını avi’ye Çevirme

Dönüştüreceğimiz dicom dosyasının  seçimi için ‘uigetdir‘ komutu kullanılabilir yada direkt dosya yolu verilebilir.

%diyalog penceresi açarak seçilen dosya yolunu döndürür
%DICOMDIR_path=uigetdir;
%info=dicominfo('DICOMDIR_path');
info=dicominfo('D:\...\...); %dosya yolu
I=dicomread(info);  %dicom formatlı görüntü alınır

Alınan dosyanın avi formatına dönüşümü için aşağıdaki kodlar yazılır.

videoAd='video';  %yeni oluşturulacak video adı belirlenir
%strcat ile avi'nin kaydedileceği konum ile video adı birleştirilir
obj=VideoWriter(strcat('D:\...\...\',videoAd),'Uncompressed AVI');
open(obj);
writeVideo(obj,I); %Videoyu obj dosyasına yazar
close(obj);

Video formatı ‘Uncompressed AVI’ olarak seçilir. İstenirse diğer kayıt formatlarının listesine VideoWriter.getProfiles();  komutu ile ulaşılabilir.

Dicom Dosyasından Frame Alma

Dicom dosyasından istenen frameleri almak için öncelikle görüntü üç boyutlu hale dönüştürülür. Ardından üçüncü boyuttan görüntünün istenen frame’i alınabilir. Alınan resmi bilgisayara kaydetmek için de ‘imwrite’ komutu kullanılabilir.

I=I(:,:,:);  %3-D ye dönüştürme
indis=20; % alınacak indis
imshow(I(:,:,indis));
resim=I(:,:,indis);
resimAd='resim';
imwrite(resim,strcat('D:\Kullanıcılar\lenovo\Desktop\görüntü\',resimAd));

Dağıtımda Optimizasyon Vogel Algoritması ( C# )

Bu yazımda hem bir algoritmadan hemde C# taki ilk kapsamlı form uygulamamdan bahsedeceğim.

Ekran Göörüntüsü

Kodların GitHub linki: https://github.com/AbdullahBay/Uygundagilim

Çalıştırılabilir Dosya: https://www.dropbox.com/s/429xrtjky5q2odk/ayrik.exe

Ana Ekran

Ana Ekran


Örnek Problem ve Çözümü

Örnek Problem ve Çözümü

Abdullah Salih BAYRAKTAR
Alıntı yaparken link veriniz.

Cmd de Java Konsol uygulaması çalıştırmak.

Bu yazımda Cmd de Java Konsol uygulamasını nasıl çalıştırabileceğimizi anlatacağım.

1. Adım: jar dosyası oluşturma

Çalıştırılabilir jar (.exe gibi) oluşturma işini eclipse’te export yardımıyla yapabiliyoruz.(bu sadece bir seçenek ve ben bu yazımda sadece bundan bahsedeceğim.)

export

Projemizi jvm için derleyelim

1. Package Explorerda Projemize sağ tıklıyoruz
2. Export’a tıklıyoruz
3. Java/Runnable JAR File seçiyoruz
4. Yeni ekranda oluşacak jarık konumunu seçiyoruz(Export destination). Launch Configuration seçeneği altında çalışacak olan ana sınıfı seçiyoruz. Eğer kullandığımız kütüphaneler varsa “Package required libraries into generated JAR” seçeneğini seçmeyi unutmuyoruz.
5. Finish ile sonlandırıp jarımızı oluşturuyoruz.

2.Adım: Java ayarlarını yapmak (Windows için)

Bilgisayarınızda javanın kurulu olduğunu varsayıyorum. Ki zaten java yoksa eclipse çalışmayacaktır. Ayarları yapmaya başlayalım.

Path Ayarları

Path Ayarları (Windows)

  1.  Bilgisayarım’a sağ tıklıyoruz özellikleri seçiyoruz
  2. Gelişmiş sistem ayarlarına tıklıyoruz.
  3. Gelişmiş sekmesinden  Ortam değişkenlerini açıyoruz
  4. Daha sonra Sistem değişkenleri altındaki PATH değişkeninin sonuna  “;C:\Program Files\Java\jre1.5.0_02\bin” i ekliyoruz. {\jre1.5.0_02\ versiyonu belirtir,sizde farklı olabilir kontrol ediniz}
  5. Ve şimdi artık java komutu sorunsuz çalışıyor olmalı.

Adım3: .jar isimli kendi yazdığımız programımızı cmd de açalım.cmd

  1. cmd (konsol)da  .jar dosyasını oluşturduğumuz klasöre gidiyoruz. Burada kasörü açıp adres çubuğuna cmd yazmak pratik oluyor.
  2. konsola şunu yazıyoruz “java -jar programımızınadı.jar” ve enterlıyoruz.
  3. Programınız çalışıyor olmalı.
  4. Her zaman bu işlemi yapmak istemiyorsanız Pratik bir yol:  metin editörünüzü açın ve içine “java -jar programımızınadı.jar” yazın sonra bunu jar dosyanızın yanına  istediğiniz-isim.bat diye kaydedin. çalıştırdığınız da programınız konsolda açılacaktır.

Abdullah Salih BAYRAKTAR

Matlab ile Nesne Bulma ve Sayma

Matlabın içerisinde hazır bulunan coins.png resmindeki paraları sayalım.

%-- Resim bw formatına dönüştürülüp boşlukları doldurulur.Kenar çizgileri belirlenir --%

resim = imread('coins.png');
bwResim=im2bw(resim); %resim bitwise'a dönüştürülür
fillResim = imfill(bwResim,'holes'); %paraların içinde kalan siyah bölgeleri beyazlatır
figure; imshow(imread('coins.png'));
kenarlar= bwboundaries(fillResim); %paraların kenar bilgilerini alır,siyah beyaz geçiş noktalarını
text(10,10,strcat('\color{red}',num2str(length(kenarlar)),'\color{red} nesne bulundu'))
%length: çizilen daire sayısıdır
%text(x,y,'string'):x ve y koordinatlardır.string'te son&nbsp;resmin üzerine basılacak yazıdır

%-- Kenarlar resmin üzerine çizilir--%
hold on; %ekrana yeni şeyler çizdirilecekken eski ekranın silinmemsini sağlar

for k=1:length(kenarlar) %length satır-sütundan büyük olan sayıyı alır
boundary = kenarlar{k}; %noktaların x y koordinatlarını tutan 2 boyutlu matris
plot(boundary(:,2),boundary(:,1),'b','LineWidth',2);
end

kenarlı

[Bilgi Sayi]=bwlabel(fillResim);
%default 8,isteğe bağlı 4 connected ile 1 sayılarını 1,2.. şeklinde etiket atayarak %resimdeki nesne sayısını bulur.

%sayı=etiket sayısı,bilgi=etiketlenmiş matris
prop=regionprops(Bilgi,'Area','Centroid'); %matrisin iki elemanı oluşturuldu

%prop belirlenen region'ların merkez koordinatlarını ve alan bilgilerini
%tutar

%----Paraların boyutlarına göre 5 veya 10 cent olduğu&nbsp;resmi üzerine yazdırılır----%

total=0;
figure; imshow(imread('coins.png'));hold on
for n=1:size(prop,1) %prop matrisinin 1.boyutunun eleman sayısını belirtir=10
cent=prop(n).Centroid;
X=cent(1);Y=cent(2); %paranın merkez koordinatları
if prop(n).Area&gt;2000
text(X-10,Y,'5 C')
total=total+5;
else
total=total+10;
text(X-10,Y,'10 C')
end
end
hold on
title(['Toplam: ',num2str(total),'cent']) ;

cent

Kaynak:http://www.elektrikport.com/teknik-kutuphane/matlab-ile-goruntu-isleme-uygulamasi-elektrikport-akademi/8434#ad-image-0

İşaretçiler namı diğer “Pointer”

Bu yazımızda işaretçilerden bahsedeceğim.                       İşaretçi= Adres tutucu=Pointer;

       İşaretçiler bellekten aldığınız yerin adresini tutmada kullanılır. Bir işaretçiyi “ int *pIsaretciAdi; ” şeklinde kodlayarak oluştururuz. İşaretçilerin başlarına p harfini koyarız ki onun işaretçi olduğunu unutmayalım. Sizde bunu standart haline getirseniz iyi olur.

işaretçi

  1. Şekilde görüldüğü üzere ilk verilen tip pointerin değil tutulmak istenen tipi işaret eder bu tip: char, int, double… olabilir. Fakat pointerin tipi herzaman “int” dir
  2. Yıldız sayısı arttıkça pointerin derecesi artar. Peki  ya bu ne demek? Yeni başladıysanız sizin için önemli değil fakat pointerıda bir pointerda tutma ihtiyacı hissediyorsanız burada yıldısayısı arttıyor. (bir dahaki yazımda bu konuyu anlatacağım)
  3. işaretçiye vermek istediğiniz ism başına p koymak ide’lerde işaretçileri ayırt etmenizi sağlar.

İşaretçiler bellekten aldığınız yerin adresini tutmak için c/c++ dilinde vardırlar.
Stack (dinamik olmayan) hafızada oluşturduğumuz değişkenlerin adresleri değişken adında tutulduğu için zaten bellidir o yüzden tekrar bir işaretçiye genelde ihtiyaç duyulmaz. Fakat kullanmakta mümkündür.

Örnek verecek olursak

int a;  // dediğimizde stackden yer almış oluruz ve
        //bunun adresini zaten “a” değişkeni tutuyordur.
int* pA=&a;  // şeklinde a’nın adresini yinede tutabiliriz.

Fakat dikkat edilmesi gereken bazı hususlar vardır. Bir stack verisi kod bloğu bittiğinde silinir.

Yani

{
    int a=5;
    int* pA=&a;
    return pA;
}

Diyerek döndürdüğünüz pointerın (pA)  tuttuğu adrese erişmek istediğinizde kod bloğu bitmiş olan a değişkeninin yeri boşaltılmış (serbest bırakılmış) olacağından hatalı erişim sağlamış olacaksınız, sadece hatalı olsa iyi belki o hücreye başka programlar tarafından farklı değerler yazılmış olma ihtimali ile karşılaşacak, yanlış değerle işlem yapacaksınız yada başka programın kullandığı hücreyi kullanarak diğer programaın akışını bozacaksınız.

Bu durumu gidermek istersek pA pointerının tuttuğu adresi (yeri) de heapten almalıyız.

{
    int* pA= new int;
    *pA=5;
    return pA;
}

Bu ise yukarıda görüldüğü gibi “ int * pA= new int; “ şeklinde alınır.

Burada yapılacak en büyük hata tek int’lik yer alınmasına rağmen

    *(pA+1)=25;     /*veya*/   cout<<pA[2]; // ikiside hatalı

Sıfırıncı hücre dışındaki hücrelere erişimin sağlanmasıdır. Bu tamamen sizin kontrol etmeniz gereken bir durumdur.(genelde bu hata döngülerde programcının gözünden kaçar)

Şu unutulmamalı ki her pointer bir adres tutar. Ve işaretçinin adı yazıldığında tuttuğu adrese, başına “*” koyduğunuzda adresteki değere, başına “&” koyduğunuzda ise işaretçinin adresine ulaşırsınız.
Adsız

İşaretçiye ihtiyaç stack (dinamik) hafızadan alınan verilerin adreslerinin sadece bir seferliğine yani alınırken erişilir olmasından kaynaklanır.

new int[2];

Yazılması durumunda hafızadan 2 integerlik yer alınacak new fonksiyonu tarafından dizinin ilk adresi döndürülecektir fakat siz bu adresi tutmazsanız size ait olan yere tekrardan ulaşamazsınız.
İşte bu dönen adresleri tutmak için oluşturulmuş tipler pointerlardır.

int* pA= new int[2]; // 2 integer kadar yer alındı ve
                     //dönen adres pA pointerına atandı.
*pA=5;               // ilk adreste bulunan yere 5 atandı.
pA[1]=7;		 // ikinci adreste bulunan yere 7 atandı

Burada atama işleminde pointer iki şekilde kullanılmıştır.
a) “*pA” pA bir adres tutucusuydu, önüne yıldız (*) konulduğunda o adresteki veriye erişim sağlanmış olur.
a. Diğer hücrelere erişmek için ise *pA, *(pA+1), *(pA+2), *(pA+3)… şeklinde kodlanır.
b. Buradaki “pA+1” toplanan sayı yani +1 diğer değişkene geçmek demekti. Değişkenin türü int ise ,integer 4 baytdir, (pA’nın tuttuğu adres+4) anlamına gelir.
1
b) “pA[1]” Adres tutan pA pointerina indis verilince derleyici içine erişilmek istediğini anlıyor ve [ ] indisin içindeki değer ne ise o indisin ifade ettiği hücreye işlem yapmaya başlıyor.
a. Diğer hücrelere erişmek için pA[0], pA[1], pA[2], pA[3]… gibi kullanılabilir. Resimde görmek için tıklayınız.

Küçük bir program üzerinden anlatmaya devam edelim. Bu program aşağıda yazılan işleri sırası ile yapacaktır:
1. Stackden bir pointer yeri alacak
2. Sonra o pointer’a heapten aldığımız 5 int’lık yerin ilk adresini tutacak
3. Bu 5 elemanlı dizinin 5 elamanına (indisi^4) atanacak (ilk for)
4. Ve sonra Değer ler tek tek bastırılacak. (ikinci for)

Pointer-Örnek:

#include<iostream>

using namespace std;

int main ()
{
	int* pIsaretci= new int [5];

	for (int i = 0; i < 5 ; i++)
	{
		*(pIsaretci+i)=i*i*i*i;   // i^4= i*i*i*i;
	}

	for (int i = 0; i < 5; i++)
	{
		cout<<"Deger "<<i<<"= "<< pIsaretci[i]<<endl;
	}
	return 0;
}
 

2
Resim: Program ekran çıktısı
Uygulamada işaretçi ile olan iki erişim yöntemini de kullandık.
1. *(pIsaretci+i)
2. pIsaretci[i]
Tek dereceli işaretçilerde kapalı parantezli yöntem daha anlaşılır ve kullanışlı oluyor.

Tüm içerik Abdullah Salih BAYRAKTAR tarafından hazırlanmıştır.