Sziasztok!
Kérdés: Meg lehet-e határozni egy string tömb méretét, ha egy függvényben átadjuk, mint paraméter?
int fv(std::string t[]) {
int count;
// hány elemből áll a tömb??????
return count;
}
int main() {
std::string tomb[] = {"egy", "ketto", "harom", "negy", "ot"};
int meret = fv(tomb);
// stb...
return 0;
}
Én egyelőre nem jöttem rá, hogyan lehetséges. A sizeof(t) minden esetben csak 4-et ad vissza. Valószínűleg, mert egy pionter tulajdonképpen. Szerintetek, meg lehet határozni a tömb méretét?
- 5607 megtekintés
Hozzászólások
törölve. Rosszul értelmeztem a kérdést :)
-----------------------------
Debian "lenny", 2.6.24-amd64
- A hozzászóláshoz be kell jelentkezni
Nem jött be. Ezeket a hibaüzeneteket kaptam:
src/x.cpp:6: error: request for member ‘size’ in ‘t’, which is of non-class type ‘std::string*’
src/x.cpp:7: error: request for member ‘length’ in ‘t’, which is of non-class type ‘std::string*’
- A hozzászóláshoz be kell jelentkezni
Tudom, mert én azt hittem a string méretét akarod megtudni ;)
-----------------------------
Debian "lenny", 2.6.24-amd64
- A hozzászóláshoz be kell jelentkezni
Nem lehet meghatározni. Ez csak egy jelölés, hogy ez egy tömbként kezelt mutató. Valójában a fenti a következővel ekvivalens:
int fv(std::string *t);
Használj vektort:
int fv(std::vektor t) {
...
t.size()
t[i]
}
- A hozzászóláshoz be kell jelentkezni
Ja. Vector esetén nem nagy kunszt.
- A hozzászóláshoz be kell jelentkezni
Ez így van, de std::string tömb nem előre ismert mérettel háát kissé furcsa elképzelés, ha a tömböt át lehet adni, akkor a hosszát is. Bár ezek után kérdéses, hogy érdemes-e C++ kódot írni, ha tele van C-s kódrészletekkel ott is, ahol van C++-nak megfelelő megoldás.
- A hozzászóláshoz be kell jelentkezni
Mondjuk kerdes, h a vector mekkora memory overhead a string[] -hez kepest. Mert ugye a string[] az valahol fix meretu, csak a hivott fuggveny nem fog rajonni a meretere, kiveve ha nem valami #define -ban van meghatarozva (ami ugye preprocesszalaskor konstans szam lesz). A vector ellenben elvben vegtelen meretu.
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Ez nyilván STL implementációs kérdés, de az biztos, hogy nem nagy.
A "GNU ISO C++" implementációban pl a vektor összesen 3 mutatóval van implementálva. Ha úgy tetszik a string[] egy mutató, ha a méretét is átadod, akkor az egy mutató, és egy int (ami kb 2 mutató).
Azaz a memory overhead 1 mutató. Szerintm elfogadható a kapott szolgáltatások fényében...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
De ott is van egy lefoglalt adatterület, ami nagyobb lehet, mint amit a vector-ban lévő elemek igényelnének, nem?
KisKresz
- A hozzászóláshoz be kell jelentkezni
Persze hogy lehet nagyobb, különben a beszúrás ideje nem lenne konstans nagyságrendű. Előre lefoglal valamekkora területet, és amíg tud, addig abba szúr bele, aztán ha már nem megy, akkor lefoglal egy nagyobbat. Ha csak akkora helyet foglalna le, amennyi az épp aktuális elemszámnak kell, akkor viszont minden egyes beszúrás lineáris lenne, vagyis n elem esetén n ideig tartana, ami gyakorlatilag használhatatlanná tenné.
- A hozzászóláshoz be kell jelentkezni
A beszúrás (insert) lineáris.
Vektornál csak a push_back konstans(*). (Gondolom erre gondoltál.)
(*) Valójában persze nem mindig konstans. Ha a konstruktorban megadod a vektor méretét, akkor akkora területet fog lefoglalni. Ha túlléped a keretet, akkor lefoglal egy 2x akkora területet, és az elejére másolja a már bent lévő elemeket.
Emiatt átlagosan minden elemet 1x másol le.
Egyébként a vector::capacity visszaadja a lefoglalt területet, a vector::reserve pedig lefoglal. Így igény szerint testreszabható.
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Igen, valóban a push_back()-re gondoltam. Az a többet használt beszúrás...
Az insert() lineáris, hiszen átlagosan az elemek felét másolnia kell minden egyes alkalommal, hogy az elemek elérése is konstans időben történhessen (operator[] és at()).
Bár azt megnézném, hogy az egyes megvalósítások ezen feltételezéseknek mennyire tesznek eleget.
- A hozzászóláshoz be kell jelentkezni
Ezek felső határát a szabvány rögzíti...
http://www.tantalon.com/pete/cppopt/appendix.htm#AppendixA
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
tömb mérete: sizeof(tomb)/sizeof(tomb[0])
De csak a main-ből, nem a függvényből.
- A hozzászóláshoz be kell jelentkezni
A függvényen belül tehát reménytelen?
- A hozzászóláshoz be kell jelentkezni
Igen. Max átadod paraméterként, ha a fv-ben van rá szükség.
- A hozzászóláshoz be kell jelentkezni
Ha parameterkent kaptad, remenytelen, ha globalis/lokalis valtozo, akkor mukodik.
_________________________________________________________________________
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
- A hozzászóláshoz be kell jelentkezni
OK!
Köszönöm szépen a hozzászólásokat.
- A hozzászóláshoz be kell jelentkezni
std::string tomb[] = {"egy", "ketto", "harom", "negy", "ot", NULL};
?
- A hozzászóláshoz be kell jelentkezni
Valami ilyesmin töröm a fejem éppen.
- A hozzászóláshoz be kell jelentkezni
Majd az x0-ban. Abban vannak ilyen inicializátorok. (null nélkül) :)
- A hozzászóláshoz be kell jelentkezni
Az csak annyit segít, hogy írhatod ezt:
std::vector<std::string> tomb = {"egy", "ketto", "harom", "negy", "ot"};
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Nem gonodltam többre én sem.
- A hozzászóláshoz be kell jelentkezni
Qt-ben találták ki ezt:
QVector<QString> vect;
vect << "egy" << "ketto" << "harom";
Ennek igazából semmi akadálya std::vector-ral sem, leszámítva, hogy nem lehet az std névtérben a túlterhelt <<.
template <typename T>
inline std::vector<T>& operator<<(std::vector<T>& v,const T& t)
{
v.push_back(t);
return v;
}
inline std::vector<string>& operator<<(std::vector<string>& v,const char* t)
{
v.push_back(string(t));
return v;
}
int main()
{
vector<string> test;
test << "egy" << "ketto";
cout << test.size() << endl;
return 0;
}
Persze a C++0x tisztább, szárazabb, biztonságosabb érzés lesz...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Érdekes ötlet - tetszik. :)
- A hozzászóláshoz be kell jelentkezni
Szerintetek ez nagy hülyeség?
#include <iostream>
bool doHaveAnyControlChar(std::string& s) {
bool has = false;
for (char c = 0; c < 32; c++) {
if (s.find(c) != std::string::npos) {
has = true;
break;
}
}
return has;
}
int getStringArrayLength(std::string array[]) {
int length = 0;
while (!doHaveAnyControlChar(array[length])) {
length++;
}
return length;
}
int main() {
std::string anArray[] = {"egy", "ketto", "harom", "negy", "ot", "hat"};
std::cout << "\n A tömb mérete: " << getStringArrayLength(anArray) << "\n";
return 0;
}
- A hozzászóláshoz be kell jelentkezni
Ez túlcímez a tömbön, nem?
KisKresz
- A hozzászóláshoz be kell jelentkezni
Igen, ez elég nagy hülyeség. Az std::string megvalósításától függ, hogy mi van benne, arról meg nem tételezhetsz fel semmit. Ennek a kódrészletnek akármi (fals negatív, fals pozitív és akár programfagyi is) lehet az eredménye.
Szerk: A post megírása után felébredtem, persze először mást láttam bele, bár a lényegen nem változtat ;-)
A legnagyobb gond az, hogy a tömb utáni memóriaterületet próbálod stringként felhasználni, pedig lehet ott bármi. A másik gond az, hogy a string tartalmában keresel 0-31-ig karaktereket, amit jó eséllyel soha nem fogsz találni.
- A hozzászóláshoz be kell jelentkezni
Nos, a program érdekessége, hogy mégiscsak működik. Tehát visszaadja a tényleges tömbméretet.
Ha feltételezem, hogy a string nem tartalmaz vezérlő karaktereket, akkor talán használható is.
Vagy talán "zamboriz" javaslata lenne a legkorrektebb:
std::string tomb[] = {"egy", "ketto", "harom", "negy", "ot", NULL};
Ezzel a megoldással elég jól lehetne detektálni a tömb végét.
- A hozzászóláshoz be kell jelentkezni
Nem, nem működik. Erre:
int main() {
//std::string anArray[] = {"egy", "ketto", "harom", "negy","","","","\t","", "ot", "hat"};
std::string anArray[] = {"egy"};
std::string megegy = "haha";
std::cout << "\n A tömb mérete: " << getStringArrayLength(anArray) << "\n";
return 0;
}
nekem éppen most 3-at ad vissza.
Szerintem is a vector lenne a természetes megoldás.
KisKresz
- A hozzászóláshoz be kell jelentkezni
Ráadásul a vector/paraméterként átadott méret konstans idő alatt oldja meg a feladatot, míg az ilyen hekkelős, platform/minden-függő félmegoldások pedig a legjobb esetben is lineárisak lesznek. Ha a vectort referenciaként, esetleg konstans referenciaként adod át, akkor még a másoló operátor miatti overhead sem lesz. Nem vesztesz semmit, viszont biztonságosabb, szabványosabb kódot kapsz eredményül. A kérdés sokkal inkább az, hogy miért ragaszkodsz ehhez, ha létezik rá jó és gyors megoldás.
- A hozzászóláshoz be kell jelentkezni
Felejtsd el ezeket a baromságokat.
Most épp túlindexelsz a tömbön, és azt a területet akarod string objektumként értelmezni. Viszont a string objektum nem a karaktereket tartalmazza, hanem pl. egy mutatót a karakterekre, illetve egy számot a mutató által mutatott karakterek számával. (Persze más megvalósítás is lehetséges, sőt)
Azaz az array tömb utáni szemetet értelmezed mutatóként, illetve számként.
Mivel a program most indult, ezért teljesen véletlenül akkora mázlid van, hogy csupa nulla van ott, amit üres stringként értlemez.
Már a túlindexelés is segfault-ot eredményezhet, a szemét string-ként értelmezése szinte biztosan.
Két dolgot tehetsz:
a) használj vektort
b) ne használj string-et se
Mindenképp az a)-t ajánlom.
Nem látok semmi okot a b)-re de az így nézne ki:
int getStringArrayLength(char** strs) {
int length = 0;
while (strs && strs[length]))
++length;
return length;
}
int main() {
char* anArray[] = {"egy", "ketto", "harom", "negy", "ot", "hat",0};
std::cout << "\n A tömb mérete: " << getStringArrayLength(anArray) << "\n";
return 0;
}
Más variáció nincs.
Ez nem jó:
std::string tomb[] = {"egy", "ketto", "harom", "negy", "ot", NULL};
Itt már említettem, hogy C++-ban nincs NULL.
Ha mégis van definiálva, akkor valószínűleg 0-nak. (De ez nem szabványos.) Ezt a 0-t kapja majd meg a string konstruktora, és mivel olyan konstruktora nincs, ami egész számot vár, ezért cast-olódik char*-ra.
Ami azért gond, mert pl MinGW alatt ez rögtön elszáll.
Ha véletlenül nem (mert abban az STL implementációban ellenörzik, hogy 0-t kap-e), akkor is legjobb esetben üres string-et kapsz. Azt meg nem lehet megkülönböztetni a ""-tól.
Használj vektort.
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Köszönöm a további hozzászólásokat is!
Személy szerint én is a vector tároló használatát részesítem előnyben, csak elméletileg szerettem volna tisztázni a tömbök lehetőségeit. Jó, hogy megalkották az STL-t! Ezzel könnyebb a programozás.
- A hozzászóláshoz be kell jelentkezni
Szia Pelz! ;)
Csak nehogy túlbonyolítsd a dolgot, ha még a Qt vizeken evezel, lehet hogy nem más mint a QStringList tökéletesen kiszolgálja az igényeidet. Már ha jól értem a dolgot :D
- A hozzászóláshoz be kell jelentkezni
Hi dii!
Kösz! Nem konkrét programozási probléma megoldása miatt indítottam a témát, csak elméletileg érdekelt a kérdés.
(Info: A legutóbbi, általad is látott, alkalmazás forráskódját felraktam a qt-apps.org -ra.)
- A hozzászóláshoz be kell jelentkezni
Esetleg a string == operatora miatt lehet meg ilyent csinalni, de ez mar nagyon eroltetett:
std::string ary[] = { "1", "2", "3", "4", "5", "\xff" };
// Blank iteration code
for(std::string *s = &ary; *s == "\xff"; s++);
es akkor a "\xff" a vegejel.
Masik verzio, ha a feladat megengedi, hogy ures string a vegejel (""), es akkor csak a stringek hosszat figyelni, hogy mikor epp 0.
De a vector nyer minden fronton.
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Szerintem std::string-et hülyeség C-és array-be rakni.
Helyesen:
void fv( const vector< string > &strs ) {
unsigned size = strs.size();
....
}
Esetleg vector helyett list.
- A hozzászóláshoz be kell jelentkezni