11 Kasım 2008 Salı

C++ Dizi İşlemlerinde Dikkat Edilmesi Gerekenler

Bu yazıda C++ kullanıcıları için çok önemli bir şeye değineceğim. Bunu da edindiğim acı tecrübeden yola çıkarak yazıyorum. C++ bildiğimi zannederdim, okulda hocamızın verdiği ödevde uzun zaman sonra C++ kullanmam gerekiyordu. 2 gün boyunca boş zamanlarımda sadece char dizisini almaya ve bunu print etme işlemine çalıştım inanın. Bu ödevin önemli bir kısmını tamamlamış bulunuyorum :). Bu ödevi yaparken karşılaştığım ve yapılması yüksek ihtimal mantık hatalarından bahsedeceğim. Bu konulara hakim olup dikat etmeniz önemli. Bu sorunlarla ben karşılaştım başkaları karşılaşmasın. Bi göz atmanızı tavsiye ederim.
Aşağıda anlatacağım işlemlerde char* array = new char[20]; dizisini kullanacağım.

1 - Öncelikle 20 karakter tutabilecek bir diziye bellekten yer ayırdık. Şimdi buna array[0] = 'a'; değerini atayalım ve print edelim. a___-----_İİİ gibi anlaşılmaz şeyler print edecektir. Bunun için yer ayırdığımız dizinin her bir elemanını dolaşarak temizlemeliyiz.
for(int i=0 ; i<20;>i++)
{
array[i] ='\0'; // \0 null demektir.
}


2 - Şimdi bu diziye ilk değer olarak array[0] = 'a'; atadık. Biliyorsunuz ki dizinin son elemanından sonra null değeri vardır bu da dizinin bittiği anlamına gelir. O yüzden bu diziyi başka işlemlerde kullanacaksanız, sonunu null yapmazsanız hata alma olasılığınız çok yüksektir. Bunu önlemek için de verdiğimiz en son değerden sonraki değeri null yapmalıyız. Yani array[1] = '\0'; değerini mutlaka vermeliyiz.

3 - array[0] = '2' ile array[0] = 2 aynı şey değildir bunu çoğu kimse bilir yine de buraya ekleyip hatırlatmanın iyi olacağını düşündüm.

4 - Uzunluk ile ilgili problem. Programda int uzunluk = strlen(array); diye uzunluğu bulduk diyelim ve uzunluk = 5 olsun, dizinin de dolu olduğunu düşünelim. Dizide array[uzunluk] = 'a'; demek veya for döngüsü içinde
for(int i=0 ; i <= uzunluk; i++) {
array[i] ='a';
}
bu şekilde kullanmak programın runtime ında hataya sebep olacaktır. Çünkü diziler indis olarak 0 dan uzunluk - 1' e kadardır.

5 - Dizinin ilk 0 elemanının dolu olduğun düşünelim. 'ahmetuzun'. array[1] = '\0' yani dizinin ikinci elemanının değerini null yapıyoruz. Diziyi print ettiğiniz zaman ekrana gelen a olacaktır. strlen(array) in sonucu da 1 olacaktır. Yani dizi dolu olsa bile, null değerini koyduğumuz yerden sonraki veriler kaybolur.

6 - Şimdi yeni bir dizi tanımlıyoruz. char* temp = new char[20]; bu dizi genelde geçici bir dizi olarak tanımlanır ve işi bittiğinde silinir. temp dizisini tanımladık ve temp dizisine temp = array diyerek yukarıda tanımlamış olduğumuz diziyi atadık. Daha sonra temp dizisini kullandık ve delete[] temp; diyerek bu diziyi bellekte boşuna yer kaplamasın diye sildik.
Eğer bu şekilde yaparsanız array dizimizde silinir. Çünkü bu diziler referansa göre çağırılırlar. Yani çağırılan dizinin bellek adresine bakılır. temp = array demekle bu iki dizinin bellek adreslerini bir yapmış oluyoruz. Bu yüzden temp silinirse array de gider. Zaten görüldüğü üzere burada temp dizisiyle array dizisi bellekte aynı yeri kapladığı için silmeye gerek de yok.

Daha bu tarz yapılabilecek hatalar varsa eklerim. Sizlerin bildiğiniz bu tarz hatalar varsa onları da eklerim :D

1 Kasım 2008 Cumartesi

Traceroute

Yazmayalı uzun zaman olmuş ben bile şaşırdım kendime, yazmayınca içimde bir eksiklik hissettim. Her neyse konumuza dönelim.
İnternete herkes hayrandır şahsen ben hep şaşırırım nasıl bu kadar büyük bir ağ oluşturmuşlar ve bu ağ hiç takılmadan çalışıyor. İçinde çalışan protokoller ve application ları söylemiyorum bile.
İnternete girdiğmizde örneğin milliyet in sitesine tıkladığımızda acaba hangi router lar üzerinden geçip milliyetin server ına ulaştığımızı biliyor muyuz? Bunu öğrenmenin yolları var.
Traceroute sitesine girip bulunduğunuz ip adresini ve gitmek istediğiniz web sitesinin adını veya ip adresini yazdığınızda size nerelerden geçtiğini söylüyor. Bu nasıl çalışıyor anlatmayacağım çok uzun, fakat sonuçta bize bir şey dönüyor bu dönen verilerin ne olduğundan bahsedeceğim.
İkinci yol websitesine girmeye gerek kalmadan komut ekranından (dos) yapılabilir. Komut satırına şunu yazmamız gerekiyor [tracert www.milliyet.com.tr] Aynı işlemi yapacaktır.
Üçüncü yol program aracılığı ile PingPlotter. Bu program yardımıyla da trace işlemleriniz daha efektif bir şekilde yapabiliyorsunuz. Efektiften kastım ne yani, kaç defa trace yapacağımızı söyleyebiliyoruz, çıkan sonuçları grafiksel bir arayüzde görebiliyoruz ve bunları bilgisayarımıza kaydedebiliyoruz falan filan.
Sonuç olarak ne çıkıyor ona bakalım.
www.milliyet.com.tr [83.66.140.10]'ye izleme yolu :
1 89 ms 2 ms 1 ms 10.0.0.1
2 78 ms 76 ms 84 ms 192.168.1.1
3 56 ms 57 ms 86 ms 88.234.40.1
4 * * * istek zaman aşımına uğradı
5 85 ms 77 ms 85 ms 212.156.107.38
6 76 ms 58 ms 72 ms 81.212.25.109
7 78 ms 95 ms 93 ms 212.174.75.142
8 66 ms 61 ms 94 ms 83.66.140.10
Birinci kolon, ana server a ulaşmak için toplam kaç router dan geçtiğini belirtiyor.
İki, üç ve dördüncü kolon, yanında ip adresi bulunan routerlara geldiğinde, bu routerdan çıkabilmek için ne kadar gecikme süresi olduğunu belirtiyor. Bu izleme siz bir defa komutu yazsanız bile 3 defa yapılıyor. Sırasıyla, bu kolonlarda bulunan süreler de yapılan üç izlemenin sırasıyla gecikme süreleri.
Dördüncü kolon, geçtiği router ın ip adresi.
Eğer siz de denerseniz bu ip adreslerin yanında bir de ip adreslerine atanmış router ların isimleri vardır onları da görebilirsiniz.
Bu nerde işimize yarar diyelim bir web siteniz var ve siz ona ulaşamıyorsunuz veya çok geç ulaşıyorsunuz. Bu şekilde web sitenize ulaşıncaya kadar trace işlemi yaparsınız. Geçtiğiniz routerlarda bir problem olabilir veya router dan geçme süresi çok uzun olabilir. Sorunu saptayıp çözüme bir adım daha yaklaşırsınız.
Şunu da belirteyim. Bazı routerlarda firewall vardır ve trace işleminde bize bilgilerini vermez.

9 Eylül 2008 Salı

LINQ to SQL

Veritabanını sorgulamak için linq to sql kullanacağız.
Herhangi bir veritabanına ait bir tabloyu sorgulamak için projenizin içerisine Add->New Item->LINQ To SQL Classes eklemeniz gerekiyor. Bu bize projemizde .dbml uzantılı bir sayfa daha oluşmasını sağlıyor. Sonra sorgulamak istediğimiz tabloları Server Explorer dan bu sayfa üzerine sürükleyip bırakmalıyız. Biraz sonraki örneklerde Northwind veritabanı ve içinde calisanlar ve siparisler veritabanı kullanılmıştır.
Şimdi öncelikle kod kısmında yeni oluşturduğumuz sayfayı kullanabilmek için bir kopyasını alalım
NorthwindDataContext db = new NorthwindDataContext();

Ex1: Calisanlar tablosundan unvanı Mr. olanları çekelim. Bunu ilk önce bildiğimiz yöntemle yapalım aradaki fark anlaşılsın diye.
string baglanti = "Server=.; Database=Northwind; Integrated Security=SSPI;";
SqlConnection con = new SqlConnection(baglanti);
DataTable calisanlar = new DataTable();
SqlDataAdapter da = new SqlDataAdapter("Select * from calisanlar where unvan='Mr.'", con);
da.Fill(calisanlar);
dataGridView1.DataSource = calisanlar;
Şimdi de eşdeğer LINQ sorgusu
var calisanlar = from n in db.Calisanlars
where n.Unvan == "Mr."
select n;
dataGridView1.DataSource = calisanlar;

Ex2: Calisanlar ve siparisler tablosunu birleştirerek calisanID, adSoyad, ulke, unvan ve nakliyeUcretleri alanlarından ilk 10 tanesini alan LINQ
var calisanlar = (from c in db.Calisanlars
from s in db.Siparislers
where c.CalisanID == s.CalisanID
select new { s.CalisanID, adSoyad = c.Ad + " " + c.Soyad, c.Ulke, c.Unvan, s.NakliyeUcreti }).Take(10);

Ex3: Veri tabanına yeni bir kayıt ekleyelim.
Calisanlar calisan = new Calisanlar();
calisan.Ad = "Ahmet";
calisan.Soyad = "Kısa";
calisan.Unvan = "Mr.";
calisan.DogumTarihi = DateTime.Now;
db.Calisanlars.InsertOnSubmit(calisan);
db.SubmitChanges(); //Veri tabanına değişikleri kaydediyor. Adapter nesnesinin Update metodu gibi.

Ex4: Soyadımı yanlış yazmışım onu UPDATE edelim.
Calisanlar calisan = db.Calisanlars.First(c => c.Ad == "Ahmet");
calisan.Soyad = "UZUN";
db.SubmitChanges();

Ex5: Birden çok kayıt olursa UPDATE etmek istediğimiz. Calisanlar tablosunda bolge alanları boş bırakılmış en azından o alanlara boş yazalım.
var calisanlar = from c in db.Calisanlars
select c;
foreach (var calisan in calisanlar)
{
calisan.Bolge = "yok";
}
db.SubmitChanges();

Ex6: Yabancıların yanında benim adım iyi durmadı onu SİLelim.
var silinecek = from c in db.Calisanlars
where c.Ad == "Ahmet" && c.Soyad == "UZUN"
select c;
db.Calisanlars.DeleteAllOnSubmit(silinecek);
db.SubmitChanges();

Her türlü örnekten bir tane yapmaya çalıştım. Fazlasını herkes kendisi yapsın.
İşte size baka baka ömrünüzün yetmeyeceği LINQ örnekleri (37Kb) Microsoft çalışanı bir abimizin bloğundan almıştım ismini hatırlayamadım :(.

5 Eylül 2008 Cuma

LINQ

LINQ (Language Integrated Query) : .net 3.0 ile gelen bir yenilik. Veri tabanında select işlemleri yapmayı sevenler için süper bir özellik. Normalde yazmamız çok zaman alacak işlemleri LINQ sayesinde çok kısa bir zamanda yapabiliyoruz. Değişik çeşitleri var LINQ, LINQ to SQL, LINQ to XML vb...
Ben şimdi genel anlamda proje içinde dizilerde yapacağımız bazı örnek sorgular yapacağım başlangıç olsun diye sizinde dikkatinizi çekecektir ne kadar kolay olduğu. Belki de buradan görüp de öğrenmeye başlayanlar olabilir diye de bir başlangıç yapayım dedim ;).
Öncelikle şunu belirteyim var değişkeni. Javascriptte bulunan var değişkeni burada da aynı mantıkla kullanılıyor içinde her türlü veri tutabilen bir nevi object nesnesi tarzında bir değişken.

int[] sayilar={3,2,5,6,1,2,8,9,0};
var bulunan = from n in sayilar
where n <= 6 orderby n
select n;
6 dan küçük sayıları bularak bunları küçükten büyüğe sıralayan kodumuz bu kadar. Tamamen anlaşılır bir şekilde ve select, from, where kalıbına çok benzer.

string[] names = { "aHmet", "uZuN", "IsTanBul", "bUrSA" ,"AHmet"};
var withLowerUpperLetters = (from n in names
orderby n
select new { Lower = n.ToLower(), Upper = n.ToUpper() }).Distinct();
string sonuc = "";
foreach (var v in withLowerUpperLetters)
{
sonuc += v.Lower + " ";
}
sonuc += "\n";
foreach (var v in withLowerUpperLetters)
{
sonuc += v.Upper + " ";
}
MessageBox.Show(sonuc);
Diziyle verilen isimleri alıp onları büyük ve küçük harflere çeviren LINQ ve devamı. Aynı olan isimleri ikinciye almaz.

son örnek olarak;
string sonuc = "";
int[] sayilar = { 0, 2, 3, 7, 8, 9, 6, 4, 1 };
var numberGroups = from n in sayilar
group n by n % 5 into g
select new { g.Key, numbers = g };
foreach (var g in numberGroups)
{
sonuc += g.Key + " kalanı verenler ";
foreach (var n in g.numbers)
{
sonuc += n+" ";
}
sonuc += "\n";
}
MessageBox.Show(sonuc);
sayilar dizisindeki elemanları 5'e bölümünden kalan sayılarına göre gruplayan LINQ.
Şimdilik bu kadar. LINQ to SQL de görüşmek üzere. Herkese kolay gelsin.

20 Ağustos 2008 Çarşamba

Popüler Programlama Dilleri

Tiobe software ın yaptığı bir araştırma. Popüler programlama dillerini araştırmışlar. Kriterleri de güzel aslında, o dille toplamda kaç satır yazıldığına bakılmamış google,yahoo gibi popüler arama motorları kullanılmış, o dilde yazılmış olan 3rd party yazılımlara ve o dili kullanan dünya çapında bulunan mühendislerin sayıları gibi kavramlar ile dilin popülerliğini artırmışlar.
Listeyi görmek için buraya tıklayın.
Ben ilk gördüğümde çok şaşırdım C ve C++ ilk 4 te fakat C# yok. Ama grafiklerine bakılınca C# yükselişte. Her ay güncelleniyormuş bu liste. İleride ne olacak göreceğiz. Yine de Javanın bu popülerliğini kaybedeceğine inanmıyorum.

19 Ağustos 2008 Salı

C#'ta Transaction işlemi

Veri tabanından bildiğimiz transaction işlemlerini C# üzerinde veriTabanı bağlantılı projelerimizde de kullanabiliyoruz.
İlk önce nedir bu transaction sen neden bahsediyon kardeşim diyen olur kısaca, veri tabanı üzerinde yaptığımız değişikliklerde bir hata oluşması durumunda veya oluşmaması durumunda :) size kalmış o anda yapılan değişikleri geri alabiliyorsunuz (rollback tran) veya yapılan değişikleri artık veri tabanında gerçek yerine kaydet diyebiliyorsunuz (commit). Çünkü yapılan işlemler ram üzerinde olur commit derseniz veri tabanında ilgili yerlerde güncelleme yapılır rollback derseniz güncelleme yapılmaz eski hali kalır.

sp_calisanSil stored procedure
create proc [dbo].[sp_calisanSil]
@calisanID int

AS

delete from siparisDetaylari where siparisID IN(select siparisID from siparisler where calisanID = @calisanID)

delete from siparisler where calisanID = @calisanID

delete from calisanMemleket where calisanID = @calisanID

delete from calisanlar where calisanID = @calisanID

[C# kodu]
SqlConnection con = new SqlConnection("Data source=.; Initial Catalog=Northwind;Integrated Security=SSPI;");
SqlCommand cmd = new SqlCommand("sp_calisanSil", con);

cmd.CommandType = CommandType.StoredProcedure;

con.Open();

SqlTransaction tr = con.BeginTransaction();

cmd.Transaction = tr;
cmd.Parameters.AddWithValue("@calisanID", int.Parse(txtCalisanID.Text));
try
{
cmd.ExecuteNonQuery();

tr.Commit();
}
catch (Exception ex) {
tr.Rollback();
MessageBox.Show(ex.Message);

}

finally {
if (con.State != ConnectionState.Closed)

con.Close();
}
Burada görüldüğü gibi bir çalışanı silmek için ilk önce siparisDetaylari, siparisler, calisanMemleket ve calisanlar tablosundaki silinmek istenen calisana ait bilgiler silinmelidir. Eğer bu sırayı yanlış yaparsak örneğin siparisDetaylari, calisanMemleket, siparisler, calisanlar diye siparisDetaylari ndaki veri silinir calisanMemleket teki veri silinmez ve sp bundan ileriye gitmez hata verir bu şekilde veri bütünlüğü bozulmuş olur. Bizim örneğimizde eğer bu şekilde hata olursa yapılan işlemler geri alınır (tr.Rollback()). Eğer hata oluşmazsa değişikler veri tabanı üzerine yazılır (tr.Commit())
Normal bağlantıdan farkı SqlTransaction nesnesi. Bu nesneyi, connection nesnesi ile transaction başlatıp eşitliyoruz, command nesnesinin transaction özelliğine transaction nesnesini veriyoruz ve gereken yerlerde commit ve rollback kullanıyoruz.

11 Ağustos 2008 Pazartesi

Connection Strings

Where do you want to connect today?
.net kullanıcıları için herhangi bir bağlantı oluştururken ihtiyacı olan bağlantı string lerini buluduran bir site. Çok başarılı. www.connectionstrings.com