|
| Inddata fra tastatur af ukendt længde Fra : Jacob Jensen |
Dato : 19-08-04 17:34 |
|
I alle de eksempler jeg har set bruges en buffer (char array) af en vis
længde til at holde inddata fra tastaturet, hvorefter man kan oprette et
array dynamisk af den rette længde.
På http://www.fredosaurus.com/notes-cpp/newdelete/alloc-cstring.html gør de
netop dette og de skriver også at der er et problem med disse fixed size
arrays. Så viser de en måde at udvide disse arrays på, men så vidt jeg kan
se holder det kun for arrayet der indeholder pegere til ordene og altså ikke
bufferen.
Men hvad hvis man så taster noget længere end denne buffer?
Er der en god løsning? Der skal vel foreligge en buffer inden indhentnnig af
data fra tastaturet? Og denne kan vel ikke udvides mens der indtastes?
Er mit spørgsmål forstået? Jeg havde lidt svært ved at formulere det :)
-Jacob
| |
Jakob Møbjerg Nielse~ (19-08-2004)
| Kommentar Fra : Jakob Møbjerg Nielse~ |
Dato : 19-08-04 19:25 |
| | |
Mogens Hansen (19-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 19-08-04 20:30 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
[8<8<8<]
> Er der en god løsning? Der skal vel foreligge en buffer inden indhentnnig
af
> data fra tastaturet? Og denne kan vel ikke udvides mens der indtastes?
Se Bjarne Stroustrup's artikel "Learning Standard C++ as a New Language"
( http://www.research.att.com/~bs/new_learning.pdf), og du vil se at der både
er en god løsning og en grundig gennemgang af dit spørgsmål.
Se iøvrige tråden "I tvivl om indlæring af C/C++" fra denne gruppe i 2002,
hvor bl.a. ovennævnte artikel blev diskuteret igennem for at få flere syn på
spørgsmålet.
( http://groups.google.dk/groups?hl=da&lr=&ie=UTF-8&threadm=airs4a%24cer%241%
40news.cybercity.dk&rnum=1&prev=/groups%3Fq%3D%2522I%2Btvivl%2Bom%2Bindl%25C
3%25A6ring%2Baf%2BC%252FC%252B%252B%2522%26ie%3DUTF-8%26hl%3Dda)
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 13:13 |
|
> Se Bjarne Stroustrup's artikel "Learning Standard C++ as a New Language"
> ( http://www.research.att.com/~bs/new_learning.pdf), og du vil se at der
> både
> er en god løsning og en grundig gennemgang af dit spørgsmål.
Tak. Koden på Jakob Nielsens link virker fint (efter et par småting er
rettet som min compiler brokker sig over), men jeg vil lige kigge på den
artikel alligevel.
> Se iøvrige tråden "I tvivl om indlæring af C/C++" fra denne gruppe i 2002,
> hvor bl.a. ovennævnte artikel blev diskuteret igennem for at få flere syn
> på
> spørgsmålet.
Puha. 124 indlæg. Jeg er i tvivl om, om du mener at der i den tråd står
noget om det her med indlæsning fra tastatur (mit oprindelige spørgsmål, jeg
kan ikke finde det) eller om der i den tråd står noget om artiklen du
linkede til. Jeg antager det sidste.
Jacob
| |
Mogens Hansen (20-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 20-08-04 14:20 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
> Tak. Koden på Jakob Nielsens link virker fint
Forhåbentligt.
Men der er andre egenskaber ved kode, som er væsentlige.
Er det f.eks. nemt at overbevise sig om at det er korrekt ?
Er det god kodestil ?
Svaret afhænger naturligvis bl.a. af ens baggrund, men det forekommer mig at
være for kompliceret, og det er netop derfor jeg henviste til artiklen.
Se eventuelt Anders J. Munch's kode fra den nævnte tråd
( http://groups.google.dk/groups?q=g:thl35729365d&dq=&hl=da&lr=&ie=UTF-8&selm
=LaG39.3764%24G3.610087%40news010.worldonline.dk&rnum=83).
> men jeg vil lige kigge på den
> artikel alligevel.
Godt
[8<8<8<]
> Puha. 124 indlæg.
Ja. En god del er ikke direkte relevant for dit spørgsmål.
> Jeg er i tvivl om, om du mener at der i den tråd står
> noget om det her med indlæsning fra tastatur (mit oprindelige spørgsmål,
jeg
> kan ikke finde det)
Den del som Anders J. Munch startede, indeholder direkte et eksempel på det
du spurgte om.
Det skal ses som en kommentar til noget af koden i artikelen, som også
direkte behandler det du spørger om.
> eller om der i den tråd står noget om artiklen du
> linkede til. Jeg antager det sidste.
Egentlig begge dele.
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 14:14 |
|
> Se Bjarne Stroustrup's artikel "Learning Standard C++ as a New Language"
> ( http://www.research.att.com/~bs/new_learning.pdf), og du vil se at der
> både
> er en god løsning og en grundig gennemgang af dit spørgsmål.
....så jeg kunne bare have brugt string-klassen? Jeg kender ikke rigtigt til
den, men det ser ud som om den selv resizer osv. Hvordan fungerer det her?:
string name;
cin >> name;
Hvornår og hvordan udvider name sig?
Jacob
| |
Mogens Hansen (20-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 20-08-04 14:26 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote_
[8<8<8<]
> ...så jeg kunne bare have brugt string-klassen? Jeg kender ikke rigtigt
til
> den,
Det var hvad jeg forventede - derfor henviste jeg til artiklen.
Hvis du vil lære mere af den slags pæn, simpel og moderne C++, kan jeg varmt
anbefale bogen
Accelerated C++, Practical Programming by Example
Andrew Koenig, Barbara E. Moo
ISBN 0-201-70353-X
> men det ser ud som om den selv resizer osv. Hvordan fungerer det her?:
>
> string name;
> cin >> name;
>
> Hvornår og hvordan udvider name sig?
Når der er brug for det Det er egentlig tilstrækkeligt at vide.
Og den frigiver hukommelsen af sig selv når den går ud af scope.
Hvad der rent faktisk sker varierer nok lidt mellem forskellige
implementeringer - men grundliggende gør den det som du ellers selv var nød
til at gøre.
Det er nemt, overskueligt og sikker.
Og ikke mindst udtrykker det meget direkte hvad man vil.
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 15:23 |
|
> Det var hvad jeg forventede - derfor henviste jeg til artiklen.
....men det virker ikke :) Følgende virker ikke hos mig:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string name;
cin >> name;
cout << name << endl;
}
Den indlæser tilsyneladende fint nok, men taster jeg f.eks. "Hello world"
udskriver den kun "Hello".
Jacob
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 19:53 |
|
Jeg vil lige tilføje:
hvis jeg skriver:
getline(cin, name);
istedet for:
cin >> name;
....virker det som jeg gerne ville have.
Men hvorfor læser cin tilsyneladende videre efter første whitespace indtil
newline. Er det bare sådan den gør? Hvad er pointen i det hvis den alligevel
kun "fanger" indtil første whitespace?
Jacob
| |
Mogens Hansen (20-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 20-08-04 19:56 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
[8<8<8<]
> ...virker det som jeg gerne ville have.
Godt
>
> Men hvorfor læser cin tilsyneladende videre efter første whitespace indtil
> newline. Er det bare sådan den gør?
"cin" er en strøm (stream) af tegn.
Når man læser en streng ind, så læser den indtil whitespace, selvom der
måtte være flere tegn tilbage i streamen.
Tilsvarende når man f.eks. læser et heltal, så læses der indtil man møder et
ikke-tal.
Man kan derfor f.eks. skrive
string name;
int age;
cin >> name >> age;
if(cin) {
// reading succeeded without error
}
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 20:03 |
|
Ok. lige som forvirringen begyndte at lægge sig fandt jeg ud af at følgende
faktisk ikke giver problemer. Jeg intaster f.eks. strengen
"AndersenJensenHansen". Hvorfor virker dette?:
#include <iostream>
using namespace std;
int main()
{
char navn[10];
cin >> navn;
cout << navn[14] << endl;
return 0;
}
Jacob
| |
Mogens Hansen (20-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 20-08-04 20:27 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
> Ok. lige som forvirringen begyndte at lægge sig fandt jeg ud af at
følgende
> faktisk ikke giver problemer. Jeg intaster f.eks. strengen
> "AndersenJensenHansen". Hvorfor virker dette?:
Det virker heller ikke. Du har blot ikke lagt mærke til at det ikke virker
Det er undefined behaviour.
Der er princielt præcist sådan alle buffer-overrun sikkerhedshuller er
lavet.
Det ser umiddelbart ud som om det virker, men det virker ikke.
Det nemmeste er at lade være med at bruge "char array", men holde sig til
"std::string" i stedet.
Prøv at ændre programmet lidt
<C++>
#include <iostream>
int main()
{
using namespace std;
char text1[] = "before";
char name[10];
char text2[] = "after";
cin >> name;
cout << text1 << endl
<< name << endl
<< text2 << endl;
}
</C++>
så kan man f.eks. få følgende uventede resultat
enJensen
AndersenHansenJensen
after
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 20:46 |
|
> Det er undefined behaviour.
ok
> Det nemmeste er at lade være med at bruge "char array", men holde sig til
> "std::string" i stedet.
Men hvorfor lagrer den overhovedet mere end 10 (9 + '\0') tegn når arrayet
kun er 10 stort? Det havde jeg ikke forventet. Jeg har meget at lære endnu
om c++ kan jeg fornemme :)
Jacob
| |
Mogens Hansen (20-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 20-08-04 21:01 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
[8<8<8<]
> Men hvorfor lagrer den overhovedet mere end 10 (9 + '\0') tegn når arrayet
> kun er 10 stort?
Det er fordi det ikke er muligt alene ud fra en pointer at finde ud af hvor
stort et område pegeren peger på.
> Det havde jeg ikke forventet. Jeg har meget at lære endnu
> om c++ kan jeg fornemme :)
Sikkert - det er et stort sprog.
Start med at lære de simple ting først.
Derfor: lad være med at benytte "char array" til at holde tekst - brug
"std::string" i stedet, det første gode stykke tid.
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 20:53 |
|
> Det nemmeste er at lade være med at bruge "char array", men holde sig til
> "std::string" i stedet.
Jeg er nysgerrig. Hvad gør man ellers?
Jacob
| |
Igor V. Rafienko (20-08-2004)
| Kommentar Fra : Igor V. Rafienko |
Dato : 20-08-04 22:30 |
|
[ Jacob Jensen ]
> > Det nemmeste er at lade være med at bruge "char array", men holde
> > sig til "std::string" i stedet.
>
> Jeg er nysgerrig. Hvad gør man ellers?
Dersom du med "ellers" mener "hva gjør man når man ikke kan bruke
std::string", så er svaret "man programmerer defensivt". Det er
hovedsaklig to tilnærminger: enten pålegger man brukeren å holde seg
innenfor et visst antall tegn, eller utvider man bufferet dynamisk
selv, når det er behov for det. I dette første tilfellet kan man greie
seg fint med fgets. I det siste tilfellet er det en kombinasjon av
fgets, malloc og realloc (evt. deres C++ ekvivalenter).
Og når man har gjort øvelsen over en gang, går man lykkelig tilbake
til std::string (jeg anbefaler på det sterkeste at du faktisk gjør
øvelsen over, slik at du kan sette pris på de mulighetene som
std::string tilbyr).
ivr
--
My compiler compiled yours
- Visual C++ .Net 2003 motto
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 20:06 |
|
> Når man læser en streng ind, så læser den indtil whitespace, selvom der
> måtte være flere tegn tilbage i streamen.
ok
> Tilsvarende når man f.eks. læser et heltal, så læses der indtil man møder
> et
> ikke-tal.
ok
> Man kan derfor f.eks. skrive
> string name;
> int age;
> cin >> name >> age;
> if(cin) {
> // reading succeeded without error
> }
Det kan godt være jeg er ved at være træt, men hvornår er cin hhv. sand og
falsk? (evt. ikke-nul og nul)
Jacob
| |
Mogens Hansen (20-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 20-08-04 20:18 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
[8<8<8<]
> Det kan godt være jeg er ved at være træt, men hvornår er cin hhv. sand og
> falsk? (evt. ikke-nul og nul)
Den er sand når der ikke er opstået en fejl ved læsning.
Hvis man f.eks. prøver på at læse et heltal (int) men der ikke står et
ciffer i streamen, så fejler læsningen og "cin" bliver falsk.
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 15:26 |
|
> Det er nemt, overskueligt og sikker.
> Og ikke mindst udtrykker det meget direkte hvad man vil.
Jeg er helt enig, men jeg forstår ikke. Når jeg kalder cin >> name, så
indlæser den vel indtil den er færdig? Hvordan kan name udvides mens dette
sker?
Der udføres vel ikke noget kode "imens" det sker? Det kræver vel flere tråde
og sådan. I Jakob Nielsens eksempel foretager man jo også udvidelsen efter
indlæsning hvorefter man så indlæser igen.
Jacob
| |
Mogens Hansen (20-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 20-08-04 17:44 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
[8<8<8<]
> Når jeg kalder cin >> name, så
> indlæser den vel indtil den er færdig?
Hvad forståes ved "færdig" ?
Det er i dette tilfælde ved næste whitespace.
Det kunne også f.eks. være til slutningen af linien eller slutningen af
filen (streamen).
Hvis du vil læse hele linien, skal du bruge getline:
getline(cin, name);
> Hvordan kan name udvides mens dette
> sker?
I første omgang er det tilstrækkeligt at vide at det sker.
Men udtrykket
cin >> name;
kalder i virkeligheden funktionen
istream& operator>>(istream& is, string& s);
(eller noget i den stil), og der således får en reference til et string
objektet hvor den putte de læste tegn ind i.
Når man putter enkelt tegn ind i et string objekt så udvider det sig når der
er behov.
>
> Der udføres vel ikke noget kode "imens" det sker?
Nej.
Venlig hilsen
Mogens Hansen
| |
Jacob Jensen (20-08-2004)
| Kommentar Fra : Jacob Jensen |
Dato : 20-08-04 19:41 |
|
>Hvad forståes ved "færdig" ?
>Det er i dette tilfælde ved næste whitespace.
Jeg vil anmode om at denne del af diskutionen føres videre som svar på mit
indlæg kl. 16:22. Det virker nemlig ikke som om cin stopper ved whitespace.
Og samtidig gør det faktisk. hmmm.
> Men udtrykket
> cin >> name;
> kalder i virkeligheden funktionen
> istream& operator>>(istream& is, string& s);
> (eller noget i den stil), og der således får en reference til et string
> objektet hvor den putte de læste tegn ind i.
Tak det var lige det jeg manglede :)
Jacob
| |
|
|