PDA

Tam Sürümünü Görmek İçin : C++ da tek dizi için farklı tip elemanlar barındırmak


teendesign
12/06/2007, 00:21
Merhaba arkadaşlar,

C++ da bir dizi tanımlamak istiyorum ve bu dizinin ne sadece int,ne sadece char elemanlar içermesini istemiyorum,bu dizinin elemanlarını çalışma esnasında tanımlayarak girmek istiyorum.

Mesela,

Hangi tipte değer gireceksiniz diye soracak,
ben integer veya char tipinde diyeceğim
bana ona göre yeri tahsis edecek.Yani aynı anda bir dizide bir çok tipte elemna sahip olacağım.


Öyle bir şey umarım açık olmuştur,

şimdiden teşekkürler


acehreli
12/06/2007, 01:20
Birden fazla yolu var:

1) Boost'un 'Any' toplulugu tam bu isi yapar:

http://boost.org/doc/html/any.html

2) Sen her ne kadar "farkli tUr" diyorsan da, aslinda ayni dizide bariniyor olmalarina bakarak bunlarin ortak bir yani oldugunu dusunebiliriz. Ornegin bunlarin hepsi 'Deger'dir. Bu 'Deger'lerle de belirli bir is yapacaksindir. Ornegin yapacagin is bunlari ekranda gostermek olsun.

O zaman Deger diye bir arayuz sinifi (ust sinif) tanimlarsin, buna Goster diye sanal bir islev verirsin. Turettigin siniflar da bu islemi kendilerine gore tanimlarlar:


class Deger
{
public:

virtual ~Deger() {}
virtual void Goster(ostream & cikis) = 0;
};

class intDeger : public Deger
{
int deger_;

public:

virtual void Goster(ostream & cikis)
{
cikis << deger_;
}

/* ... */
};

class charDeger : public Deger
{
char deger_;

public:

virtual void Goster(ostream & cikis)
{
cikis << deger_;
}

/* ... */
};

/* ... */


Temel turler gibi, baska bir suru tUr icin ayni islemi yapiyorsan ("cikis << deger_" gibi), hepsini bir sablon sinif olarak tanimlayabilirsin:


template <class T>
class BasitDeger : public Deger
{
T deger_;

public:

virtual void Goster(ostream * cikis)
{
cikis << deger_;
}

/* ... */
};


Simdi artik dizini tek bir tUrden dizi olarak tanimlayabilirsin:

2a) En iyisi budur:


// Once bu tUrU gosteren bir akilli gosterge tanimlarsin
typedef boost::shared_ptr<Deger> DegerPtr;

// Ondan sonra o gostergeyi barindiran bir topluluk:
vector<DegerPtr> degerler;
degerler.push_back(DegerPtr(new BasitDeger<int>(42));
degerler.push_back(DegerPtr(new BasitDeger<char>('a'));

// Ilk ogesiyle bir is yap:
degerler[0]->Goster(cout);


2b) boost::shared_ptr yerine yalin gostergeler kullanir ve kaynak kaybi riskine acilirsin:


vector<Deger*> degerler;
degerler.push_back(new BasitDeger<int>(42));
degerler.push_back(new BasitDeger<char>('a'));


2c) C dizisi kullanirsin:


Deger * degerler[yeterinceBuyukBirSayi];
degerler[i] = new TemelDeger<int>(42);
++i;
degerler[i] = new TemelDeger<char>('a');

// Sonra bunlari delete ile geri vermeyi unutmamak gerek!


3) Bunu onermem; cunku zaten C'de de yapilabilir: Elindeki degerlerin tUrlerini bir yerde saklaman da gerektigi icin, bir Deger yapisi tanimlarsin:



enum DegerTuru { DegerTuru_int, DegerTuru_char, /* ... */ };

struct Deger
{
DegerTuru tur;
void * deger;
};

Deger degerler[yeterinceBuyukBirSayi];

// int ekle
{
Deger deger;
deger.tur = DegerTuru_int;
deger.deger = new int(42);
degerler[i] = deger;
++i;
}

// char ekle
{
Deger deger;
deger.tur = DegerTuru_char;
deger.deger = new char('a');
degerler[i] = deger;
++i;
}

// Sonra bunlari delete ile geri vermeyi unutmamak gerek!

// Sonra kullanirken:
void foo(Deger * deger)
{
switch (deger->tur)
{
case DegerTuru_int:
{
// Gercek turune donusturmek gerek:
int * intDeger = static_cast<int*>(deger->deger);
cout << *intDeger;
break;
}

/* ... */
};
}


4) Bunu hic onermem. boost::Any herhalde buna benzer seyler yapiyordur zaten. Bir dizi kullanir ve nesneleri onun icinde sen kurarsin:


KarisikDizi dizi;

size_t degerUzunlugu = sizeof(int);
if (dizi.sonYer + degerUzunlugu > dizi.kapasite)
{
// yer kalmamis; yeni bir yer ayirmali,
// eski nesneleri oraya kopyalamaliyiz
}

// Basit new degil, "placement new":
new(dizi.degerler) int(42);
dizi.sonYer += degerUzunlugu;

// KarisikDizi'nin soyle tanimlanmasi gerek:
struct KarisikDizi
{
int kapasite;
int sonYer;

// Cok onemli bir yer: HerTurleAlignOlabilenBirTur'u
// oyle tanimlamaliyiz ki, kullanacagimiz hicbir turun
// bellekte "alignment" sorunu olmasin.
HerTurleAlignOlabilenBirTur * degerler;
};

// Yani HerTurleAlignOlabilenBirTur'u soyle tanimlayabiliriz:
union HerTurleAlignOlabilenBirTur
{
char c;
int i;
double d;
/* ... */
char * cp;
int * ip;
double * dp;
/* ... */;
};


Ali

teendesign
12/06/2007, 23:05
Uzunca cevabın için çok teşekkürler "acehreli", bahsettiklerini harmanlayarak istediğimi yaptım. Şuan da dizinin kapasitesi arttırmak ile ilgili problem yaşıyorum,yazdığım kodlar şu şekilde;


#include <iostream>
#include <string>


using std::cout;
using std::cin;
using std::endl;
using std::string;


struct veri {
int type;
union {
int intDeger;
double dblDeger;
char strDeger[21];
};
};


struct veri *listem;

int capacity=4;
int numItems=0;

void Add(int x);
void Add(double x);
void Add(const char* x);

void Add(int x)
{
listem[numItems].type = 1;
listem[numItems].intDeger = x;
numItems++;
Menu();
}

void Add(double x){
listem[numItems].type = 2;
listem[numItems].dblDeger = x;
numItems++;
Menu();
}

void Add(const char* x){
listem[numItems].type = 3;
sprintf(listem[numItems].strDeger, x);
numItems++;
Menu();
}


int main ()

{
listem = (veri*)malloc(sizeof(struct veri)*4);
//burada listem in kapasitesini 4 yapmak istedim

Menu(); //burada menu fonksiyonunu çağırıyorum

return 0;

}

void BoyutArttir()
{


capacity += (int)capacity/2;

listem = (struct veri *)realloc(listem, sizeof(struct veri)*capacity);
cout << sizeof(listem) << endl;
Menu();
}

//Bu fonksiyonda ise kapasitesini arttırmak istedim



Ama kapasite arttırmada başarılı olamadım yada aslında baştan kapasite belirlerken mi hata yaptım acaba?

acehreli
12/06/2007, 23:19
BoyutArttir'in nerede cagrildigini goremiyorum. Butun Add'ler icinden cagrilabilir. Veya Add'leri cagiran yerde numItems ile. capacity karsilastirilabilir.

Oyle yaparsan, main icindeki malloc'a da gerek kalmamis olur. Bastan listem=NULL, capacity=0 ve numItems=0 olunca BoyutArttir kendigilinden cagrilir ve yer ayirir. Bastaki ozel durumun onune gecmek icin de (capacity/2) kadar degil, ((capacity/2) + 1) kadar arttirabilirsin. (Yoksa capacity hep 0 kalir.)

Programinda baska sorunlar da var: ornegin global nesneler kullandigin icin bu programda iki tane liste kullanilamaz; 4 ve baska sihirli sabitler kullanilmis; vs.

Ali

teendesign
12/06/2007, 23:35
BoyutArttir'in nerede cagrildigini goremiyorum. Butun Add'ler icinden cagrilabilir. Veya Add'leri cagiran yerde numItems ile. capacity karsilastirilabilir.

Oyle yaparsan, main icindeki malloc'a da gerek kalmamis olur. Bastan listem=NULL, capacity=0 ve numItems=0 olunca BoyutArttir kendigilinden cagrilir ve yer ayirir. Bastaki ozel durumun onune gecmek icin de (capacity/2) kadar degil, ((capacity/2) + 1) kadar arttirabilirsin. (Yoksa capacity hep 0 kalir.)

Programinda baska sorunlar da var: ornegin global nesneler kullandigin icin bu programda iki tane liste kullanilamaz; 4 ve baska sihirli sabitler kullanilmis; vs.

Ali

Kodun bazı kısımlarını yayınladığım için BoyutArttir i nerede çağırdığım görülmemiş,kodun tamamı :

// dizi.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}

#include <iostream>
#include <string>


using std::cout;
using std::cin;
using std::endl;
using std::string;


struct veri {
int type;
union {
int intDeger;
double dblDeger;
char strDeger[21];
};
};


struct veri *listem;


int Menu();
void CreateArray();
int NewItem(int &z);
void ChooseItemType();
void ItemShow();
void ItemCount();
int ItemCount2();
void ArrayCapacity();
int ArrayCapacity2();
void FullnessRate();
void List();
int Cikis();
void BoyutArttir();

int capacity=4;
int numItems=0;

void Add(int x);
void Add(double x);
void Add(const char* x);

void Add(int x)
{
listem[numItems].type = 1;
listem[numItems].intDeger = x;
numItems++;
Menu();
}

void Add(double x){
listem[numItems].type = 2;
listem[numItems].dblDeger = x;
numItems++;
Menu();
}

void Add(const char* x){
listem[numItems].type = 3;
sprintf(listem[numItems].strDeger, x);
numItems++;
Menu();
}

int main ()

{
listem = (veri*)malloc(sizeof(struct veri)*4);
CreateArray();
Menu();

return 0;

}

void BoyutArttir()
{

//cout << sizeof(listem);
capacity += (int)((capacity/2) + 1);
listem = (veri*)realloc(listem, sizeof(struct veri)*capacity);

cout << sizeof(listem) << endl;
Menu();
}

void CreateArray()
{

}
int NewItem(int &z)
{
switch (z)
{
case 1:
if(numItems==capacity)
{
capacity += (int)capacity/2;
listem = (struct veri *)realloc(listem, sizeof(struct veri)*capacity);
}
int x;
cout << "Değeri Giriniz\n";
cin >> x;
Add(x);
break;

case 2:
double y;
cout << "Değeri Giriniz\n";
cin >> y;
Add(y);
break;

case 3:
char z;
cout << "Değeri Giriniz\n";
cin >> z;
Add(z);
break;

default :
cout << "Gecersiz secim!..\n" << endl ;
}
return 0;
}
void ItemShow()
{
int x;
system("cls");
cout << "Enter the index to get the value\n";
cin >> x;
system("cls");
if(listem[x].type==1)
{
cout << "Value: " << listem[x].intDeger << endl;
}
if(listem[x].type==2)
{
cout << "Value: " << listem[x].dblDeger << endl;
}
if(listem[x].type==3)
{
cout << "Value: " << listem[x].strDeger << endl;
}

system("pause");
system("cls");
Menu();
}
void ItemCount()
{
int Boyut = 0;
int Kapasite;

Kapasite = capacity;

for (int i=0;i<Kapasite;i++)
{
if(listem[i].type==1)
{
if (listem[i].intDeger != NULL)
{
Boyut++;
}
}
if(listem[i].type==2)
{
if (listem[i].dblDeger != NULL)
{
Boyut++;
}
}
if(listem[i].type==3)
{
if (listem[i].strDeger != NULL)
{
Boyut++;
}
}

}
system("cls");
cout << "Count:" << Boyut << endl;
system("pause");
system("cls");
Menu();

}
int ItemCount2()
{
int Boyut = 0;
int Kapasite;

Kapasite = ArrayCapacity2();

for (int i=0;i<Kapasite;i++)
{
if(listem[i].type==1)
{
if (listem[i].intDeger != NULL)
{
Boyut++;
}
}
if(listem[i].type==2)
{
if (listem[i].dblDeger != NULL)
{
Boyut++;
}
}
if(listem[i].type==3)
{
if (listem[i].strDeger != NULL)
{
Boyut++;
}
}

}

return Boyut;

}
void ArrayCapacity()
{
int ToplamKapasite;
ToplamKapasite = sizeof(listem);

system("cls");
cout << "Capacity : " << ToplamKapasite << endl;
system("pause");
system("cls");
Menu();
}
int ArrayCapacity2()
{
int ToplamKapasite;
ToplamKapasite = sizeof(listem);

return ToplamKapasite;

Menu();
}
void FullnessRate()
{
float oran;

oran = (float)ItemCount2() / (float)ArrayCapacity2() * (float)100;
system("cls");
cout << "Fullness Rate : " << (float)oran << endl;
system("pause");
system("cls");
Menu();


}
void List()
{

int Kapasite;

Kapasite = ArrayCapacity2();
system("cls");
for (int i=0;i<Kapasite;i++)
{
if(listem[i].type==1)
{
if (listem[i].intDeger != NULL)
{
cout << i << ". ->" << listem[i].intDeger << endl;
}
}
if(listem[i].type==2)
{
if (listem[i].dblDeger != NULL)
{
cout << i << ". ->" << listem[i].dblDeger << endl;
}
}
if(listem[i].type==3)
{
if (listem[i].strDeger != NULL)
{
cout << i << ". ->" << listem[i].strDeger << endl;
}
}

}
system("pause");
system("cls");
Menu();
}
int Cikis()
{
return 0;
}

int Menu()
{
int x;
cout << "1- To add a new item\n";
cout << "2- To see the content of an index\n";
cout << "3- To see item count\n";
cout << "4- To see array capacity\n";
cout << "5- To see array fullness rate\n";
cout << "6- To see array items list\n";
cout << "7- Exit\n";
cout << "Please enter your choice\n\n";
cin >> x;

//while ((x = getchar()) != '\n' && x != EOF)

switch (x)
{
case 1:
ChooseItemType();
break;

case 2:
ItemShow();
break;
case 3:
ItemCount();
break;

case 4:
ArrayCapacity();
break;
case 5:
FullnessRate();
break;

case 6:
List();
break;
case 7:
Cikis();
break;

case 8:
BoyutArttir();
break;

default :

cout << "Gecersiz secim!..\n" << endl ;


}


return x;
}
void ChooseItemType()
{
int ArrayType;
cout << "1- Integer\n";
cout << "2- Double\n";
cout << "3- String\n";

cin >> ArrayType;

cout << "" << endl;
NewItem(ArrayType);

}


Şimdi ilk kapasitemi 4 olarak belirledim,başlangıçta onun öyle olmasını istiyorum.Add ile değer girmeden önce kapasiteyi kontrol ediyorum,
eğer dolmuşsa aşağıdaki kodlar ile boyutu büyütmek ve boyut büyüdükten sonra veriyi girdirmek isitiyorm.İşte sorun tam burada boyutu büyütemiyor :(

capacity += (int)capacity/2;
listem = (struct veri *)realloc(listem, sizeof(struct veri)*capacity);


Ayrıca o hatalarımın(global değişkenler,iki liste gibi) farkındayım ama şuanki bilgimle ancak bu kadarını yapabildim,nasıl düzeltebileceğim konusunda fikir verebilirsen de öğrenmiş olurum.Ayrıca Çok teşekkürler:)

Revne
13/06/2007, 00:02
@acehreli arkadasımızın soyledigi yontemlerden 2. yontem oldukca fazla kullanılır.

Mumkun oldugunca 2. yontemi kullanmak lazım...

Kolay Gelsin...

acehreli
13/06/2007, 00:10
Simdilik iki tane hata gordum:

1) sizeof'u bazi yerlerde dogru kullaniyorsun ama ArrayCapacity icinde *cok* yanlis olmus :). Soyle degistirmen gerekiyor:

ToplamKapasite = capacity; // sizeof(listem);

2) Menuden secilen butun islevler tekrar Menu'yu cagiriyorlar. Buna gerek olmamali degil mi. Ic ice bir cok kere Menu'yu cagiriyorsun. Su islev de ancak kendisinden cikar, Menu'den degil:


int Cikis()
{
return 0;
}


3) Ek olarak, g++ ile derledigimde soyle uyarilar aldim:

warning: NULL used in arithmetic
if (listem[i].intDeger != NULL)

Orada 0 kullaninca hata gitti.

Ali