/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Strings i C++
Fra : Trygleren [9000]


Dato : 08-10-02 12:35

Hej gruppe,
jeg døjer med overgangen fra Java til C++. Jeg sidder tit og laver små
ubrugelige programmer, for at blive fortrolig med et sprog. Men det er som
om at C++ ikke kan li' mig. Hvordan HULEN sammenligner man Strings i C++? Og
er der funktion som javas subString, hvor jeg kan hive f.eks. "aske" ud af
en string "Vasketøj" via denneString = enString.subString(1,4);??

Det program jeg har siddet og leget vil nok se ca. sådan her ud i Java:

public class Test
{
public static void main(String[] args)
{
String indPass, pass = "Kaj";
Boolean accepted = false;

while(!accepted)
{
System.out.println("Indtast password: ");
String indPass = Keyboard.readString();

if(indPass.equalsIgnoreCase("kaj"))
{
System.out.println("Password ok.)";
accepted = true;
}
}//end while

}//end main
}//end class



--
"Sic gorgiamus allos subjectatos nunc"
Lars 'Trygleren' Winther






 
 
Bertel Lund Hansen (08-10-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 08-10-02 12:46

Trygleren [9000] skrev:

>om at C++ ikke kan li' mig. Hvordan HULEN sammenligner man Strings i C++?
>Og er der funktion som javas subString, hvor jeg kan hive f.eks. "aske" ud af
>en string "Vasketøj" via denneString = enString.subString(1,4);?

#include <iostream>
using namespace std;

string s1 = "Pass";
string s2 = "word ok.";

int main(){
cout << s1+s2 << endl;
if (s1==s2) cout << "Hurra!" << endl;
cout << (s1==s2) << endl;
cout << (s1+s2).substr(1,3) << endl;

return 0;
}

--
Bertel
http://bertel.lundhansen.dk/   FIDUSO: http://fiduso.dk/

Trygleren [9000] (08-10-2002)
Kommentar
Fra : Trygleren [9000]


Dato : 08-10-02 12:58

Dit eksempel gav mig femten fejl:
testAfString.cpp(8) : error C2784: 'class
std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> __cdecl std:erator +(_D,const
class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &)' : could not deduce
template argument
for '' from 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
osv...

Den bølle her returnerede lige 884 fejl og 1.9 milliarder warnings - hvorfor
nu det?

//------------------------
#include <iostream>
using namespace std;

string s1 = "Pass";
string s2;


int main(){

cout << "Indtast password: ";
cin >> s2;

if (s1==s2)
{
cout << "Hurra!" << endl;
}

return 0;
}

//------------------

--
"Sic gorgiamus allos subjectatos nunc"
Lars 'Trygleren' Winther



"Bertel Lund Hansen" <nospam@lundhansen.dk> skrev i en meddelelse
news:b5h5qu82tp1o93hco79ntg8mjfjda8jnc6@news.telia.dk...
> Trygleren [9000] skrev:
>
> >om at C++ ikke kan li' mig. Hvordan HULEN sammenligner man Strings i C++?
> >Og er der funktion som javas subString, hvor jeg kan hive f.eks. "aske"
ud af
> >en string "Vasketøj" via denneString = enString.subString(1,4);?
>
> #include <iostream>
> using namespace std;
>
> string s1 = "Pass";
> string s2 = "word ok.";
>
> int main(){
> cout << s1+s2 << endl;
> if (s1==s2) cout << "Hurra!" << endl;
> cout << (s1==s2) << endl;
> cout << (s1+s2).substr(1,3) << endl;
>
> return 0;
> }
>
> --
> Bertel
> http://bertel.lundhansen.dk/ FIDUSO: http://fiduso.dk/



Martin Moller Peders~ (08-10-2002)
Kommentar
Fra : Martin Moller Peders~


Dato : 08-10-02 13:13

In <3da2c830$0$51535$edfadb0f@dspool01.news.tele.dk> "Trygleren [9000]" <TryglerenSLETDETHER@tdcadsl.dk> writes:

>Dit eksempel gav mig femten fejl:
>testAfString.cpp(8) : error C2784: 'class
>std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> __cdecl std:erator +(_D,const
>class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &)' : could not deduce
>template argument
> for '' from 'class std::basic_string<char,struct
>std::char_traits<char>,class std::allocator<char> >'
>osv...

>Den bølle her returnerede lige 884 fejl og 1.9 milliarder warnings - hvorfor
>nu det?

Den compiler er nok defekt. Hvilken compiler bruger du ?
Jeg har ingen problemer med at compile Bertels program.

mvh

Martin
ps. Skriv venligst _under_ det du svarer paa.


>//------------------------
>#include <iostream>
>using namespace std;

>string s1 = "Pass";
>string s2;


>int main(){

> cout << "Indtast password: ";
> cin >> s2;

> if (s1==s2)
> {
> cout << "Hurra!" << endl;
> }

> return 0;
>}

>//------------------

>--
>"Sic gorgiamus allos subjectatos nunc"
>Lars 'Trygleren' Winther



>"Bertel Lund Hansen" <nospam@lundhansen.dk> skrev i en meddelelse
>news:b5h5qu82tp1o93hco79ntg8mjfjda8jnc6@news.telia.dk...
>> Trygleren [9000] skrev:
>>
>> >om at C++ ikke kan li' mig. Hvordan HULEN sammenligner man Strings i C++?
>> >Og er der funktion som javas subString, hvor jeg kan hive f.eks. "aske"
>ud af
>> >en string "Vasketøj" via denneString = enString.subString(1,4);?
>>
>> #include <iostream>
>> using namespace std;
>>
>> string s1 = "Pass";
>> string s2 = "word ok.";
>>
>> int main(){
>> cout << s1+s2 << endl;
>> if (s1==s2) cout << "Hurra!" << endl;
>> cout << (s1==s2) << endl;
>> cout << (s1+s2).substr(1,3) << endl;
>>
>> return 0;
>> }
>>
>> --
>> Bertel
>> http://bertel.lundhansen.dk/ FIDUSO: http://fiduso.dk/



Trygleren [9000] (08-10-2002)
Kommentar
Fra : Trygleren [9000]


Dato : 08-10-02 13:20

> Den compiler er nok defekt. Hvilken compiler bruger du ?
> Jeg har ingen problemer med at compile Bertels program.

Jeg bruger Visual C++.

> ps. Skriv venligst _under_ det du svarer paa.

Lad lige være med at få ondt i røven over en enkelt smutter.


--
"Sic gorgiamus allos subjectatos nunc"
Lars 'Trygleren' Winther



Martin Moller Peders~ (08-10-2002)
Kommentar
Fra : Martin Moller Peders~


Dato : 08-10-02 13:35

In <3da2cd8c$0$51514$edfadb0f@dspool01.news.tele.dk> "Trygleren [9000]" <TryglerenSLETDETHER@tdcadsl.dk> writes:

>> Den compiler er nok defekt. Hvilken compiler bruger du ?
>> Jeg har ingen problemer med at compile Bertels program.

>Jeg bruger Visual C++.

Hvilken version og er den mon rigtigt installeret ?

>> ps. Skriv venligst _under_ det du svarer paa.

>Lad lige være med at få ondt i røven over en enkelt smutter.

Fint, nu har du laert det.

/Martin



Trygleren [9000] (08-10-2002)
Kommentar
Fra : Trygleren [9000]


Dato : 08-10-02 13:57

> >Jeg bruger Visual C++.
>
> Hvilken version og er den mon rigtigt installeret ?

6.0 og den har virket fint ind til videre.

--
"Sic gorgiamus allos subjectatos nunc"
Lars 'Trygleren' Winther






Jesper Sørensen (08-10-2002)
Kommentar
Fra : Jesper Sørensen


Dato : 08-10-02 14:49

> > >Jeg bruger Visual C++.
> >
> > Hvilken version og er den mon rigtigt installeret ?
>
> 6.0 og den har virket fint ind til videre.

Ja jeg må beklageligvis også sige at jeg ligeledes får 15 fejlmeddelelser.
Det drejer sig om understøttelsen af string. Jeg er netop nu ved at
undersøge hvad der er galt.

Jeg bruger VC++ 6.0 med SP5, fejlene er vedhæftet.

mvh
JS

E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(8) : error
C2784: 'class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> __cdecl
std:erator +(_D,const class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &)'
: could not deduce template arg
ument for '' from 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(8) : error
C2676: binary '+' : 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >' does not define this
operator or a conversion to a type accept
able to the predefined operator
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(9) : error
C2784: 'bool __cdecl std:erator ==(const class std::allocator<_Ty>
&,const class std::allocator<_U> &)' : could not deduce template argument
for 'const class std::alloca
tor<_Ty> &' from 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(9) : error
C2784: 'bool __cdecl std:erator ==(const class
std::istreambuf_iterator<_E,_Tr> &,const class
std::istreambuf_iterator<_E,_Tr> &)' : could not deduce template argument f
or 'const class std::istreambuf_iterator<_E,_Tr> &' from 'class
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(9) : error
C2784: 'bool __cdecl std:erator ==(const class
std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &,const class
std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &)' : could not deduce t
emplate argument for 'const class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D>
&' from 'class std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(9) : error
C2784: 'bool __cdecl std:erator ==(const struct std::pair<_T1,_T2>
&,const struct std::pair<_T1,_T2> &)' : could not deduce template argument
for 'const struct std::pair
<_T1,_T2> &' from 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(9) : error
C2676: binary '==' : 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >' does not define this
operator or a conversion to a type accep
table to the predefined operator
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(10) :
error C2784: 'bool __cdecl std:erator ==(const class std::allocator<_Ty>
&,const class std::allocator<_U> &)' : could not deduce template argument
for 'const class std::alloc
ator<_Ty> &' from 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(10) :
error C2784: 'bool __cdecl std:erator ==(const class
std::istreambuf_iterator<_E,_Tr> &,const class
std::istreambuf_iterator<_E,_Tr> &)' : could not deduce template argument
for 'const class std::istreambuf_iterator<_E,_Tr> &' from 'class
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(10) :
error C2784: 'bool __cdecl std:erator ==(const class
std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &,const class
std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &)' : could not deduce
template argument for 'const class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D>
&' from 'class std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(10) :
error C2784: 'bool __cdecl std:erator ==(const struct std::pair<_T1,_T2>
&,const struct std::pair<_T1,_T2> &)' : could not deduce template argument
for 'const struct std::pai
r<_T1,_T2> &' from 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(10) :
error C2676: binary '==' : 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >' does not define this
operator or a conversion to a type acce
ptable to the predefined operator
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(11) :
error C2784: 'class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> __cdecl
std:erator +(_D,const class std::reverse_iterator<_RI,_Ty,_Rt,_Pt,_D> &)'
: could not deduce template ar
gument for '' from 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >'
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(11) :
error C2676: binary '+' : 'class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> >' does not define this
operator or a conversion to a type accep
table to the predefined operator
E:\Program Files\Microsoft Visual Studio\MyProjects\jaja\jaja.cpp(11) :
error C2228: left of '.substr' must have class/struct/union type
Error executing cl.exe.

jaja.exe - 15 error(s), 0 warning(s)



Per Abrahamsen (08-10-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 08-10-02 14:08

Bertel Lund Hansen <nospam@lundhansen.dk> writes:

> #include <iostream>
> using namespace std;

Prøv med

#include <iostream>
#include <string>
using namespace std;

Visual C++ 6.0 hiver ikke automatisk "string" ind i namespace når man
inkluderer iostream, derfor kan Trygleren ikke oversætte. Med
ovenævnte tilføjelse virker det fint.

Trygleren [9000] (08-10-2002)
Kommentar
Fra : Trygleren [9000]


Dato : 08-10-02 14:18

> Visual C++ 6.0 hiver ikke automatisk "string" ind i namespace når man
> inkluderer iostream, derfor kan Trygleren ikke oversætte. Med
> ovenævnte tilføjelse virker det fint.

Takker og bukker.

--
"Sic gorgiamus allos subjectatos nunc"
Lars 'Trygleren' Winther







Bertel Lund Hansen (08-10-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 08-10-02 14:26

Per Abrahamsen skrev:

>Visual C++ 6.0 hiver ikke automatisk "string" ind i namespace når man
>inkluderer iostream

Er det en fejl at min compiler gør det?

--
Bertel
http://bertel.lundhansen.dk/   FIDUSO: http://fiduso.dk/

Mogens Hansen (08-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 08-10-02 20:06


"Bertel Lund Hansen" <nospam@lundhansen.dk> wrote in message
news:47n5qug3jan2btccam4v50nr1par2c35sb@news.telia.dk...

> Er det en fejl at min compiler gør det?

Nej.
Det er tilladt at en C++ header includerer andre C++ headere - §17.4.4.1
Men det er ikke påkrævet at en given header includerer en anden.

Det er således tilladt at en compiler oversætter dit oprindelige program,
ligesom det er tilladt at den ikke oversætter det.
Hvis man includerer både <iostream> og <string> _skal_ alle C++ compilere
oversætte det - ellers er de fejlbehæftede.

Det er en fordel at man husker at includere alle de nødvendige headere
explicit, så man derved øger portabiliteten.
Men det er ikke det store problem i praksis, at man skal tilføje et par
headerfiler hist og her, når man skifter compiler.

Venlig hilsen

Mogens Hansen



Byrial Jensen (08-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 08-10-02 22:54

Mogens Hansen <mogens_h@dk-online.dk> skrev:
>
> Det er tilladt at en C++ header includerer andre C++ headere - §17.4.4.1

Er det derfor at nedenstående program kan ikke oversættes med gcc?
Det kan oversættes og køre uden problemer hvis jeg enten ændrer
alle forekomster af "string" til "string2" eller fjerner "using
namespace std;".

Skal man generelt undgå at bruge ethvert navn som erklæres i en C++
header selvom man ikke inkluderer pågældende header, hvis man har
"using namespace std"?


#include <iostream>
#include <cstring>
// ingen #include af <string>

using namespace std;

class string // Min egen super-primitive class string
{
private:
char *s;
const string operator=(const string&);
string();

public:
string(const char *str)
{
s = new char[strlen(str) + 1];
strcpy (s, str);
};
~string() { delete [] s; };
operator const char *() { return s; };
};

int main()
{
string s("Hej verden\n");
std::cout << s;
return 0;
}

Mogens Hansen (09-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 09-10-02 05:23


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnaq6ke2.2ms.bjensen@ask.ask...

[8<8<8<]
> Skal man generelt undgå at bruge ethvert navn som erklæres i en C++
> header selvom man ikke inkluderer pågældende header, hvis man har
> "using namespace std"?

Det er svært at garantere at man ike bruger et navn som er erklæret i en C++
header - nu og i fremtiden.
Namespace er lavet for at man kan håndtere det.
"using namespace std" er en voldsom handling, som nogenlunde sætter
virkningen af namespace ud af kraft.
Derfor bør man _aldrig_ skrive det i en header, og i øvrigt omgås det med
forsigtigthed, hvis der er tegn på problemer. I stedet kan man sige mere
præcist hvad man har brug for (det er f.eks. hvad "Accelerated C++"
konsekvent gør).

[8<8<8<]
> using namespace std;

Istedet kan du skrive

using std::cout;
using std::strcpy;
using std::strlen;

[8<8<8<]
> const string operator=(const string&);

Et par småting:
Den assignment operator er atypisk. Almindeligvis returneres en ikke-const
reference til sig selv
string& operator=(const string&);
Den vil ikke virke, idet default copy-constructoren ikke virker efter
hensigten. Det bliver så reddet af at assignment operatoren ikke er
tilgængelig.

Du mangler at tage stilling til copy-constructoren.

[8<8<8<]
> string(const char *str)
> {
> s = new char[strlen(str) + 1];
> strcpy (s, str);
> };

Jeg ville foretrække at initialisere s i initializer-listen, i stedet for
tildeling:
string(const char* str) :
s(strcpy(new char[strlen(str)+1], str)
{}

ikke fordi det spiller den nogen særlig rolle her, men generelt er det at
foretrække.


Venlig hilsen

Mogens Hansen



Byrial Jensen (12-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 12-10-02 04:49

Mogens Hansen <mogens_h@dk-online.dk> skrev:
> "Byrial Jensen" <bjensen@nospam.dk> wrote in message
>
>> const string operator=(const string&);
>
> Et par småting:

Tak for kommentarerne.

> Den assignment operator er atypisk. Almindeligvis returneres en ikke-const
> reference til sig selv
> string& operator=(const string&);
> Den vil ikke virke, idet default copy-constructoren ikke virker efter
> hensigten. Det bliver så reddet af at assignment operatoren ikke er
> tilgængelig.
>
> Du mangler at tage stilling til copy-constructoren.

Jeg prøvede på at erklære private tildelingsoperator og
copy-constructor for at forhindre tildelinger og kopieringer, men
begge dele mislykkedes da jeg ikke havde fokus på dette, og
metoderne endnu er uvante.

>> string(const char *str)
>> {
>> s = new char[strlen(str) + 1];
>> strcpy (s, str);
>> };
>
> Jeg ville foretrække at initialisere s i initializer-listen, i stedet for
> tildeling:
> string(const char* str) :
> s(strcpy(new char[strlen(str)+1], str)
> {}
>
> ikke fordi det spiller den nogen særlig rolle her, men generelt er det at
> foretrække.

Jeg havde ikke lige tænkt på at kalde new-operatorer inden i
argumentlisten til strcpy() da jeg generelt når jeg programmerer
prøver på at undgå at gøre mere en ting på samme linje for ikke at
gøre udtrykkene unødigt komplicerede (det er også indviklet nok til
at du mangler en afsluttende højre-parentes).

Hvad ville du mene om en blandingsform af de 2 måder som denne?

string(const char* str)
: s (new char[strlen(str) + 1)
{ strcpy (s, str); };

Mogens Hansen (12-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 12-10-02 08:25


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnaqf6r7.1lk.bjensen@ask.ask...

> Jeg havde ikke lige tænkt på at kalde new-operatorer inden i
> argumentlisten til strcpy() da jeg generelt når jeg programmerer
> prøver på at undgå at gøre mere en ting på samme linje for ikke at
> gøre udtrykkene unødigt komplicerede

Det kan jeg godt følge generelt.
I det konkrete tilfælde, syntes jeg det var i orden, men det nærmer sig
grænsen.
Det er vigtigere at skrive klart end at skrive smart.

> (det er også indviklet nok til
> at du mangler en afsluttende højre-parentes).

Ja.
Jeg havde ikke compileret det

>
> Hvad ville du mene om en blandingsform af de 2 måder som denne?
>
> string(const char* str)
> : s (new char[strlen(str) + 1)
> { strcpy (s, str); };

Jeg laver somme tider en lille hjælpefunktion, når initialiseringen er lidt
kompliceret.
Det virker godt, selv hvis initialiseringen bliver temmelig kompliceret.
F.eks.

<ikke testet kode>

inline char* stringdup(const char* str)
{
char* s = new char[strlen(str) + 1];
strcpy(s, str);
return s;
}

string(const char* str) :
s(stringdup(str))
{
}

</ikke testet kode>

Venlig hilsen

Mogens Hansen



Byrial Jensen (12-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 12-10-02 15:13

Mogens Hansen <mogens_h@dk-online.dk> skrev:
>
> Jeg laver somme tider en lille hjælpefunktion, når initialiseringen er lidt
> kompliceret.
> Det virker godt, selv hvis initialiseringen bliver temmelig kompliceret.

Det var en god ide som jeg vil tænke på når jeg laver "rigtige"
programmer. Tak for det.

Bertel Lund Hansen (12-10-2002)
Kommentar
Fra : Bertel Lund Hansen


Dato : 12-10-02 09:24

Byrial Jensen skrev:

.... og jeg har en bibemærkning.

>gøre udtrykkene unødigt komplicerede (det er også indviklet nok til
>at du mangler en afsluttende højre-parentes).

> string(const char* str)
> : s (new char[strlen(str) + 1)
> { strcpy (s, str); };

Pudsigt nok mangler du selv en kantet parentes. Jeg skriver altid
to sammenhørende tegn samtidig, altså f.eks. (), og så fylder jeg
dem ud bagefter. Jeg har ikke haft primære parentesfejl siden jeg
begyndte med det.

Sekundære parentesfejl dukker op når man retter i noget kode.

--
Bertel
http://bertel.lundhansen.dk/   FIDUSO: http://fiduso.dk/

Per Abrahamsen (08-10-2002)
Kommentar
Fra : Per Abrahamsen


Dato : 08-10-02 16:55

Bertel Lund Hansen <nospam@lundhansen.dk> writes:

> Per Abrahamsen skrev:
>
>>Visual C++ 6.0 hiver ikke automatisk "string" ind i namespace når man
>>inkluderer iostream
>
> Er det en fejl at min compiler gør det?

Jeg ved ikke hvad der er tilladt eller garanteret, det må en af
gruppens sprogadvokater afgøre.

Men jeg mener afgjort det er pænere at lade være, på den måde undgår
man at skrive uportabel kode ved et uheld (det er sku' underligt at
skulle rose Visual C++ over GCC på det punkt!)

Jeg ved nu ikke helt hvordan det teknisk kan lade sig gøre, definerer
<iostream> ikke interfaces der bruger strings? Hvordan kan man gøre
det uden at hente <string> ind?

Jeg kunne kigge i headere, men det ville være snyd.

Mogens Hansen (08-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 08-10-02 15:28

"Trygleren [9000]" <TryglerenSLETDETHER@tdcadsl.dk> wrote in message
news:<3da2c35c$0$23913$edfadb0f@dspool01.news.tele.dk>...

> Hvordan HULEN sammenligner man Strings
> i C++?

Jeg antager at du snakker om klassen "std::string" (Hvis ikke så overvej
lige hvorfor)

<code>
void foo(const std::string& s1, const std::string& s2)
{
if(s1 == s2) {
// same value
}
}
</code>

> Og er der funktion som javas subString, hvor jeg kan hive
> f.eks. "aske" ud af en string "Vasketøj" via denneString =
> enString.subString(1,4);??

<code>
#include <string>

int main()
{
using std::string;

string s("vasketøj");
string sub = s.substr(1, 4);
}
</code>

>
> Det program jeg har siddet og leget vil nok se ca. sådan her ud i
> Java:

Man har ikke en funktion á la "equalsIgnoreCase" til rådiged.

Hvis man alene vil løse problemet med "equalsIgnoreCase" kan man lave en
lille hjælpefunktion:

<code>
#include <iostream>
#include <string>
#include <locale>
#include <algorithm>
#include <functional>

using namespace std;

inline bool equal_ic(const std::string& s1, const std::string& s2)
{
if(s1.length() != s2.length()) return false;

std::string::const_iterator s1i = s1.begin();
const std::string::const_iterator s1_end = s1.end();
std::string::const_iterator s2i = s2.begin();
while(s1_end != s1i) {
if(toupper(*s1i) != toupper(*s2i)) return false;
++s1i;
++s2i;
}
return true;
}

int main()
{
const string pass = "Kaj";
bool accepted = false;

while(!accepted) {
cout << "Enter password:" << endl;
string password;
cin >> password;
if(equal_ic(pass, password)) {
cout << "Password OK" << endl;
accepted = true;
}
}
}
</code>


Hvis man vil løse problemet lidt mere generelt, så kan man forholdsvis
simpelt lave en variant af "std::string", som ikke er case-sensitiv.
I virkeligheden er "std::string" en typedef af "std::basic_string<class
charT, class traits = char_traits<charT>, class Allocator = allocator<charT>
>".
"char_traits" siger noget om egenskaberne for den pågældende tegn-type. Det
gælder bl.a. hvordan man sammenligner tegn.
Ved at lave en specialisering af "std::char_traits<char>" kan man sige
hvordan tegn sammenlignes. Det kan man så bruge til at lave en ny
string-lignende klasse med.

<code>
#include <iostream>
#include <string>
#include <locale>

using namespace std;

struct ci_char_traits : public char_traits<char>
{
static bool eq( char c1, char c2 )
{ return toupper(c1) == toupper(c2); }

static bool ne( char c1, char c2 )
{ return toupper(c1) != toupper(c2); }

static bool lt( char c1, char c2 )
{ return toupper(c1) < toupper(c2); }

static int compare(const char* s1, const char* s2, size_t n )
{
while(n--) {
char s1u = toupper(*s1++);
char s2u = toupper(*s2++);
if(s1u != s2u) {
return static_cast<int>(s1u) - static_cast<int>(s2u);
}
}
return 0;
}

static const char* find( const char* s, int n, char a )
{
while( n-- > 0 && toupper(*s) != toupper(a) ) {
++s;
}
return s;
}
};

typedef basic_string<char, ci_char_traits> ci_string;

inline basic_ostream<char, char_traits<char> >&
operator<<(basic_ostream<char, char_traits<char> >& os, const ci_string&
str)
{
os << str.c_str();
return os;
}

inline basic_istream<char, char_traits<char> >&
operator>>(basic_istream<char, char_traits<char> >& is, ci_string& str)
{
string tmp;
is >> tmp;
str.assign(tmp.begin(), tmp.end());
return is;
}

int main()
{
const ci_string pass = "Kaj";
bool accepted = false;

while(!accepted) {
cout << "Enter password:" << endl;
ci_string password;
cin >> password;
if(pass == password) {
cout << "Password OK" << endl;
accepted = true;
}
}
}
</code>


Se eventuelt http://www.gotw.ca/gotw/029.htm eller bogen
Exceptional C++
Herb Sutter
ISBN 0-201-61562-2
Item 1 og Item 2

Venlig hilsen

Mogens Hansen



Byrial Jensen (08-10-2002)
Kommentar
Fra : Byrial Jensen


Dato : 08-10-02 19:49

Mogens Hansen <mogens_h@dk-online.dk> skrev:

> int main()
> {
> const string pass = "Kaj";
> bool accepted = false;
>
> while(!accepted) {
> cout << "Enter password:" << endl;
> string password;
> cin >> password;
> if(equal_ic(pass, password)) {
> cout << "Password OK" << endl;
> accepted = true;
> }
> }
> }

Jeg spekulerer på hvorfor du erklærer "string password" inden i
løkken. Betyder det ikke at der unødigt skal oprettes og nedlægges
en string med kald af constructor og destructor til følge ved
hvert løkke-gennemløb?

Eller det sker måske ikke i praksis med nutidens oversættere?

Mogens Hansen (08-10-2002)
Kommentar
Fra : Mogens Hansen


Dato : 08-10-02 20:29


"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnaq67cs.1f5.bjensen@ask.ask...

> Jeg spekulerer på hvorfor du erklærer "string password" inden i
> løkken. Betyder det ikke at der unødigt skal oprettes og nedlægges
> en string med kald af constructor og destructor til følge ved
> hvert løkke-gennemløb?

Generelt foretrækker jeg at erklære variable med så begrænset scope som
muligt.
Og helst så de bliver initialiseret med en fornuftig værdi - men det er ikke
muligt i dette tilfælde.
Det syntes jeg begrænser muligheden for side-effekter og utilsigtet misbrug
i koden.

Det er rigtigt at det er et overhead - hvis passwordet ikke tastes rigtigt
første gang.

Indholdet af strengen skal under alle omstændigheder bygges op i hvert
gennemløb, men implementeringen kunne sikkert genbruge den underliggende
buffer.
Det væsentligste overhead vil formodentlig komme fra heap-allokering.

Nogle std::string implementeringer (f.eks. den i Visual C++.NET) har en fast
buffer, så der slet ikke allokeres dynamisk når man bruger små strenge.
I det (almindelige) tilfælde er det ikke dyrt at kalde constructor (3
assembler instruktioner) og destructor (3 assembler instruktioner).

Hvis profiling viser at det er en flaskehals, så ville jeg afgjort forsøge
at flytte den uden for løkken - men ikke før det er blevet påvist ved
profiling.

> Eller det sker måske ikke i praksis med nutidens oversættere?

Jo, der _skal_ kaldes en constructor og destructor for hvert gennemløb.

Venlig hilsen

Mogens Hansen



Trygleren [9000] (13-10-2002)
Kommentar
Fra : Trygleren [9000]


Dato : 13-10-02 01:02

Hmm... rigtig mange indlæg - godt spørgsmål jeg fik stillet der =)

--
"Sic gorgiamus allos subjectatos nunc"
Lars 'Trygleren' Winther



Søg
Reklame
Statistik
Spørgsmål : 177500
Tips : 31968
Nyheder : 719565
Indlæg : 6408509
Brugere : 218887

Månedens bedste
Årets bedste
Sidste års bedste