Tam Sürümünü Görmek İçin : yığın hatası
kaan0489
09/04/2004, 20:27
ben soyle bir calısma yaptım.Calısmanın amacı kisinin girdiği sayıyı carpanlarına ayırmak.Calısmamı deneyemediğim icin dogru olup olmadıgı bilmiyorum ama kodları soyleri.
#include <iostream>
using namespace std;
class count
{
private:
int x;
int y;
int j;
int top;
public:
count() : x(0) , y(0) , j(0) , top(0)
{}
void get_top()
{
cout << "Enter the top : " << endl;
cin >> top;
}
void get_system()
{
for(j=0;j < top/2;j++, y++)
{
if ( x*y == top )
cout << x << " * " << y << " = " << top << endl;
x = x+1;
get_system();
}
}
};
int main()
{
count c1;
c1.get_top();
c1.get_system();
return 0;
}
ve programı calıstırdıgımda yıgın hatasına neden oldu diyor neden olur acaba?
acehreli
09/04/2004, 23:26
Nedeni, get_system islevinin kendisini surekli cagiriyor olmasi. Her cagri yigita bir takim bilgiler yaziyor ve sonunda program yigiti tukeniyor.
Ayrica notlar:
1) 'Yigin' mi 'yigit' mi? Turkce terimler konusunda iyi degilim ama galiba bu durumda 'yigit' kullaniliyor. (?)
2) Bu sinifin deneme amaciyla yazildigi belli; yoksa ayni isi bir isleve yaptirmak daha dogal olurmus gibi geliyor.
3) j nesnesi yalnizca get_system icinde kullanildigi icin sinif icinde tanimlanmayabilirmis:
for (int j = /* ... */)
4) Sinifin adi olarak 'count' secmek sanssiz olmus. Cunku <algorithm> basliginda tanimlanan 'count' adinda bir de sablon var. g++ 3.2 ve 3.3.1 surumleri ben programi derlerken hata verdiler.
Bu karisikligin nedeni,
using namespace std;
satirini kullandigimiz icin, std ad alani icindeki adlarin <iostream> yoluyla gelenlerini programa ekliyor olusumuz. Bazi programcilarin neden o satirdan rahatsiz olduklarinin guzel bir ornegi olmus oldu. :)
<iostream>'in 'count' adini biz <algorithm>'i acikca eklemedigimiz halde dolayli yoldan bizim programimiza getiriyor olmasinin etik ve baska yonlerden nasil karsilanmasi gerektigini bilmiyorum :) Bir kac sene once Scott Meyers comp.lang.c++.moderated'a aynen bu soruyu sormustu. Grubun genelde nasil bir yanit verdigini hatirlamiyorum. :)
Ali
Kögüdey Meygen
10/04/2004, 00:15
gcc 2.95.3 ile derleniyor ama çalışırken arkadaşın dediği sorunla karşılaşılıyor.
gcc 3.3.2 ile derlenmiyor.
Şimdi arkadaş çalışırken hata olduğundan bahsediyor dolayısıyla asıl konumuz derlenme hatası değil
çalışma mantık hatası.(bu arada ileriki zamanlarda böyle hatalar olmaması için değişiklik yapmakta zarar yok)
Şimdi gelelim asıl konuya:
hatanin nedeni sonsuz döngü.
gdb ile bir calistirayim dedim ve gdb ciktisi
-------------------
gdb) list
24 cout << x << " * " << y << " = " << top << endl;
25 x = x+1;
26 get_system();
27 }
28 }
29 };
30
31 int main()
32 {
33 count c1;
(gdb)
34
35 c1.get_top();
36 c1.get_system();
37 return 0;
38 }
(gdb) break 35
Breakpoint 1 at 0x8048765: file x.cpp, line 35.
(gdb) break 36
Breakpoint 2 at 0x8048774: file x.cpp, line 36
(gdb) run
Starting program: /home/km/x
Breakpoint 1, main () at x.cpp:35
35 c1.get_top();
(gdb) display c1
1: c1 = {x = 0, y = 0, j = 0, top = 0}
(gdb) step
count::get_top (this=0xbffffc4c) at x.cpp:16
16 cout << "Enter the top : " << endl;
(gdb)
Enter the top :
17 cin >> top;
(gdb)
10
18 }
(gdb)
Breakpoint 2, main () at x.cpp:36
36 c1.get_system();
1: c1 = {x = 0, y = 0, j = 0, top = 10}
(gdb) continue
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x08048816 in count::get_system (this=0xbffffc4c) at x.cpp:20
20 {
(gdb) print x
$1 = 174742
(gdb) print y
$2 = 0
(gdb) print j
$3 = 0
(gdb) print top
$4 = 10
(gdb) where
#0 0x08048816 in count::get_system (this=0xbffffc4c) at x.cpp:20
#1 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#2 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#3 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#4 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#5 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#6 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#7 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#8 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#9 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#10 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#11 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#12 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#13 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#14 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#15 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
....
.....
......
#40008 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#40009 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#40010 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#40011 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#40012 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#40013 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#40014 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#40015 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
...
....
.....
#69366 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
#69367 0x080488c6 in count::get_system (this=0xbffffc4c) at x.cpp:26
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) kill
Kill the program being debugged? (y or n) y
(gdb) q
--------------
Kısaca
j'nin değeri daima sıfır kalıyor.
Çünkü:
for döngüsü içerisinde j++ kısmının çalışmasını için döngünün en son işleminin çalışması gerekiyor.
fakat en son işlem işlevin kendisi(get_system) bu çağırıldığı anda
for döngüsü çalıştırılacağı zaman j=0 oluyor.
get_system işlevi bu yüzden yüzbinlerce kez aynı şey oluyor ve en sonunda SEGMENTATION FAULT!
Cözüm yolunun doğruluğunu incelemedim sadece hatasına baktım.
x ve y'yi ilk olarak 1 den başlata bilirsin,0'ın hiç bir anlamı yok çarpanlarda.
if den sonra bir {} ile tam olarak hangi satırları çalıştırmak istediğini belirtirsen daha iyi olur.
Çöz bakalım hatanı:)
Bu arada türkçe adlar kullanmakta ne zarar var?
count yerine say
get_top yerine üst_al gibi...
acehreli
10/04/2004, 00:32
Kogudey, (bu arada ileriki zamanlarda böyle hatalar olmaması için değişiklik yapmakta zarar yok) diyorsun. Ne tur hatalari onlemek icin nasil degisiklik yapmaktan bahsediyorsun? Gercekten anlamadim :)
kaan0489
10/04/2004, 01:19
tessekurler arkadaslar bana cok yardimci oldunuz.
Kögüdey Meygen
10/04/2004, 10:44
Kogudey, (bu arada ileriki zamanlarda böyle hatalar olmaması için değişiklik yapmakta zarar yok) diyorsun. Ne tur hatalari onlemek icin nasil degisiklik yapmaktan bahsediyorsun? Gercekten anlamadim :)
Şu 'count' olayından bahsediyordum.
count yerine başka bir kelime kullanmak gibi bir değişiklikten...
Arkantos
10/04/2004, 14:29
Arkadaşın yazdığı get_system fonksiyonu ile ilgili yorumlarım:
void get_system()
{
for (int j=0; j < top/2; j++, y++)
{
cout << j << " " << y << " " << x << "\n";
x = x + 1;
// get_system();
// Bu satırı kullanınca 0 0 1
// 0 0 2
// 0 0 .
// 0 0 86171
// şeklinde 86171'e kadar sayıyor.Bu yüzden x * y
// her zaman 0 oluyor.
// Sanırım get_sytem()i kullanınca her seferinde
// döngüyü en baştan başlatıyoruz.
// Kullanmadığımızda ise 0 0 0
// 1 1 1
// 2 2 2
// . . .
// gibi bir çıktı veriyor.Sonuç olarak x * y
// hiç bir zaman top'a eşit olmuyor.
/*
if ( x*y == top )
{
cout << x << " * " << y << " = " << top << endl;
}
*/
}
}
Bir de şunu soracaktım:
Bu karisikligin nedeni,
using namespace std;
satirini kullandigimiz icin, std ad alani icindeki adlarin <iostream> yoluyla gelenlerini programa ekliyor olusumuz. Bazi programcilarin neden o satirdan rahatsiz olduklarinin guzel bir ornegi olmus oldu.
Yani bunu derken örneğin using namespace std; satırı yerine örneğin sadece cin ve cout fonksiyonlarını kullandığımız bir programımız varsa
using std::cout;
using std::cin;
şeklinde kullanmak mı daha doğru olur? Bir de using namespace std; şeklinde kullanmanın (örneğin programda hiç kullanılmayan bir fonksiyonla ilgili başlık dosyasının programa eklenip programın boyutunun artması gibi) bir zararı olabilir mi?
#include <iostream>
class Dunya
{
public:
Dunya (int no)
: _numara (no)
{
std::cout << _numara << "\n";
}
~Dunya()
{
std::cout << _numara << "\n";
}
private:
const int _numara;
};
int main()
{
Dunya dunya (1);
return 0;
}
Son olarak da yukardaki gibi bazı nesnelerin özel (private) veri üyeleri yazılırken farklı bir notasyon kullanıldığı dikkatimi çekti. int _numara; gibi ama bazı kaynaklarda da int numara_; şeklinde kullanıldığını gördüm. Bu yazım biçimlerinden hangisi daha yaygın kullanılmaktadır?
acehreli
11/04/2004, 05:37
'using namespace' satirlari ad alanlarinin getirdikleri yararlari ortadan kaldiran satirlardir. Madem 'using namespace' diyerek ad alanlari icindeki adlari birbirleriyle karistiriyoruz, neden ad alani var...
Iste bu gorusler yuzunden, hemen her programda gordugumuz 'using namespace std;' satirina kotu gozle bakilir. Koddaki 'std::' on eklerini ortadan kaldirarak kodu daha kolay okunur yaptigi icin, bazi gruplara ornek program yazanlar bu satirdan once ozur diler havada aciklamalar bile koydular. :) Sunun gibi:
#include <iostream>
/*
Asagidaki satirin kotu oldugunu biliyorum
ama bu kadar kisa bir ornek program icinde
kullanilabilir.
*/
using namespace std;
Ad alanlarinin dile eklenmis olmasinin o kadar da basarili bir karar olmadigini savunan cok sayida usta da vardir. Ornegin Scott Meyers.
Ne olursa olsun, oyle bir satirin hicbir zaman bir baslikta bulunmamasinda herkes hemfikirdir. Cunku o durumda 'using namespace' satirlari yalnizca kendi kodumuzu degil, bizim basligimizi ekleyen kullanici kodlarini da etkilerler. Boyle bir kullanim durumunda bazen kullanicilar tarafindan sopayla kovalanma tehlikesinden bahsedilir :)
Kendi programimda 'using namespace std;' kullanarak yalnizca kendimi etkiledigim icin bunu kendi hatam olarak gorebilirim. Bunun yaninda Arkantos'un gosterdigi
using std::cout;
gibi using bildirimleri kullanilabilir. Pek bilinmemekle birlikte her iki kullanim da aslinda bir kapsam icinde kisitlanabilir:
void foo()
{
using namespace std;
/* std icindeki adlar yalnizca burada gorulebilirler */
}
Ucuncu yontem de her adi acik acik yazmak: std::cout. Bu konuda da kesin bir karar oldugu soylenemez; kimi seviyor, kimi sevmiyor.
Evet, ozel ogelerin adlari oge olduklari belli olsun diye ozel bir sekilde yazilir. Bazi programcilar bunun karsisinda olsalar da ben adlarin sonuna '_' karakteri koyarim. Oyle olmadigi zaman, sinifin tanimlandigi koda baktigim zaman, 'numara' adindaki nesnenin nerede tanimlandigini goremiyorum. Gozumu islevin yukarilarina kaydiriyorum, ariyorum, bulamiyorum. Acaba global olarak mi tanimlanmis diye kutugun bas tarafina gidiyorum. Yani oturup aramam gerekebiliyor.
Halbuki o ozel kodlamayi gordugum an, o nesnenin su anda icinde bulundugum sinifin bir ogesi oldugunu ve onun baslik kutugunde tanimlanmis oldugunu anliyorum. Onun icin oge adlarinin sonuna '_' koyuyorum.
Bence adin sonuna '_' koymak en yaygin yontem. Bunun disinda adin basina da '_' koyanlar yaygin. Ancak, basinda '_' olan bazi adlar uygulamaya ayrildigi icin, ve tam olarak hangilerinin boyle oldugunun kurallari karisik oldugu icin, ben hicbir zaman herhangi bir adin basina '_' koymuyorum.
Bildigim yontemlerden baska birisi de adlarin onune oge (member) adi oldugunu belirtmek icin 'm_' koymak. Ben bunu sevmiyorum :)
Ali
Arkantos
11/04/2004, 11:51
Ne olursa olsun, oyle bir satirin hicbir zaman bir baslikta bulunmamasinda herkes hemfikirdir.
Ben aslında başlık dosyası derken using namespace std satırının başlık dosyasına eklenmesini değil de örneğin:
#include <iostream>
using namespace std;
/*
Diyelim ki bu programda sadece cout fonksiyonunu
kullanıyoruz.Ama hiç bu ad alanında tanımlanmış
diğer fonksiyonları (cin gibi) programda kullanmıyoruz.
Yani bu şekilde eklemeninin üçüncüdeki kullanmadığımız
bir başlık dosyasını programa eklemek gibi bir zararı
olabilir mi diye düşünmüştüm.Kodun boyutunun artması vs..
*/
burada da
#include <iostream>
using std::cout;
/*
Burada yine sadece cout kullanıyoruz.
*/
#include <iostream>
#include <string>
/*
Bu programda aslında string hiç kullanılmıyor. Ama
yanlışlıkla ekliyorum ve kod boyutu artıyor.
*/
#include <iostream>
/*
Zaten stringe gerek yoktu ve eklemedim gibi :)
*/
Bir de bu foo nedir :) acaba özel bir fonksiyon mu diye düşünürken sizin kullanımınızdan fonksiyonun kısaltması olduğunu anlıyorum.Açıklamalardan anladığım kadarıyla using namespace std; kullanmak ya da using std::cout; şeklinde ya da direkt olarak std::cout << ... şeklinde direkt program içinde kullanmanın programın boyutunu arttırması gibi bir etkisi yoktur diye bir sonuca vardım.
acehreli
11/04/2004, 18:26
Kod buyuklugu konusunu unutmusum.
1) 'using namespace' satirlari veya using bildirimleri kod buyuklugunu etkilemezler. Kullanildiklari kapsama yeni adlar getirirler. Dikkat edersen islev, degisken, vs. degil de 'ad' diyorum. Cunku using, gercekten adlarla ilgilidir.
2) Gereksiz eklenen basliklar kod buyuklugunu etkilemezler. Dene gor! :) Basliklardaki sablonlar da ancak eger o sablonlar kullaniliyorlarsa derlenirler.
3) 'foo' ve 'bar'in hicbir ozel anlami yoktur. Hicbir ozelligi olmayan seyleri adlandirmak icin kullanilir. Eger bir islev gosterilecekse ve o islevin adinin hic onemi yoksa islevin adi 'foo' yapilir. Boyle ikinci bir islev otomatik olarak 'bar' olur :)
Bunun nereden geldigi kesin olarak bilinmiyor. Bir fikir su: Bir savas (Ikinci Dunya Savasi mi acaba?) sirasinda tamir edilemeyecek derecede hasar gormus olan arac ve gereclere kisaca ve kabaca FUBAR deniyormus. FUBAR: 'f*cked-up beyond all repair' (tamir edilemeyecek derecede hasar gormus). O da 'foobar' diye okundugu icin oradan geldigi saniliyor.
Buna benzer bir de 42 sayisi vardir. Herhangi bir onemi olmayan bir degeri gostermek icin kullanilir:
C c(42);
cout << c << '\n';
gibi... O sayi da Douglas Adams'in bir kitabinda (galiba Hitchhiker's Guide to the Galaxy) en onemli ve en buyuk sorunun cevabi olarak verilir. Bir bilgisayar yapilir; o bilgisayar cok uzun sure "en onemli sorunun" cevabini bulmak icin uzun bir sure calisir (galiba nesiller surer; emin degilim). Ondan sonra da cevabi bildirir: 42. :)
Ali
Arkantos
11/04/2004, 18:35
Bu kadar ayrıntılı ve güzel bilgiler için teşekkürler :)
Forum Yazılımı : vBulletin v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.