"Pray, v. To ask that the laws of the universe be annulled in behalf of a single petitioner, confessedly unworthy." --Ambrose Bierce, The Devil's Dictionary
Het zou wel fijn zijn als je dan aan gaf waaruit jij de conclusie trekt dat het niet werktHertog schreef op 13 maart 2004 @ 22:59:
Ik snap niet waarom dit niet werkt.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Hmm, dat detail ben ik inderdaad vergeten te vermelden.oisyn schreef op 14 maart 2004 @ 00:16:
[...]
Het zou wel fijn zijn als je dan aan gaf waaruit jij de conclusie trekt dat het niet werktCrasht je programma? Geeft ie een verkeerd resultaat terug? Zo ja, welk resultaat dan? Etc. Zie ook P&W FAQ - De "quickstart"
Het programma crashed met VC++. Er komt een standaard windows 'wilt u een foutrapport versturen?' melding, maar ik denk niet dat microsoft mijn probleem gaat oplossen
Inmiddels heb ik het ook al op een solaris en een linux pc geprobeerd, met respectievelijk een segmentation fault en een bus error als gevolg. Ik heb al geprobeerd de resultaatstring van te voren te alloceren (alhoewel dat niet nodig zou moeten zijn) maar dat hielp ook niet.
Het lijkt er op alsof strtok de tab 'mist' en vervolgens na het einde van de string verder probeert te lezen. Dat is tenminste de enige verklaring die ik kan vinden (Alhoewel je toch zou verwachten dat zo'n functie controleert of de string niet is afgelopen.)
"Pray, v. To ask that the laws of the universe be annulled in behalf of a single petitioner, confessedly unworthy." --Ambrose Bierce, The Devil's Dictionary
Er worden dus null characters geschreven naar die eerste parameter. En kijk eens wat je meegeeft: je geeft een string mee waarin niet geschreven mag worden. En ik denk dat als je je code compileert, dat je dan toch ook wel een flinke warning voor je neus krijgt...The function strtok() writes null characters into the buffer pointed to by s1.
putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
De enige error dan wel warning die hij zou moeten krijgen is dat main een int moet retourneren, en dat void main () dus ongeldig is
De oplossing is dus om je string in een beschrijfbaar stuk geheugen te zetten. Je kunt bijvoorbeeld gewoon een char array op de stack aanmaken dmv
1
2
3
4
| int main () { char str[] = "hallo daar!"; } |
[ Voor 28% gewijzigd door .oisyn op 14-03-2004 00:48 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Volgens de pagina die ik gelezen had was het tweede argument (de string waarop gesplitst moet worden dus) een string waar niet in geschreven mag worden, const char*. Het eerste argument is gewoon char*. Daar mag toch gewoon in geschreven worden?Infinitive schreef op 14 maart 2004 @ 00:42:
http://www.mkssoftware.com/docs/man3/strtok.3.asp
[...]
Er worden dus null characters geschreven naar die eerste parameter. En kijk eens wat je meegeeft: je geeft een string mee waarin niet geschreven mag worden. En ik denk dat als je je code compileert, dat je dan toch ook wel een flinke warning voor je neus krijgt...
Windows doet daar niet zo moeilijk over - maar dit was dan ook alleen testcode..oisyn schreef op 14 maart 2004 @ 00:46:
De enige error dan wel warning die hij zou moeten krijgen is dat main een int
moet retourneren, en dat void main () dus ongeldig is
Die code zou dan dit moeten worden:De oplossing is dus om je string in een beschrijfbaar stuk geheugen te zetten. Je kunt bijvoorbeeld gewoon een char array op de stack aanmaken
1
2
3
4
5
6
7
8
9
10
11
| #include <iostream> #include <string.h> using namespace std; void main() { char regel[] = "a\tb"; char* a = strtok(regel, "\t"); cout << a << endl; } |
Dat lost inderdaad het probleem op. Ik dacht overigens ergens gelezen te hebben dat het enige verschil tussen char * en char[] was dat een char * een \0 op het einde heeft. Weer wat geleerd. Waarom strtok als eerste argument 'char *' verwacht, snap ik dan weer niet. Zowiezo, waarom mag je bij een char * niet in het geheugen waar die pointer naar wijst schrijven? Zo'n beetje alle c-functies gebruiken 'char *' als type voor een string.
Overigens is mijn probleem hiermee nog niet helemaal opgelost. Ik had hier het probleem enigszins geabstraheerd, maar de echte code die ik nodig heb zit in een functie - die een char * als argument mee krijgt. Moet ik dan in die functie die string gaan kopieren? Daar gaat de efficientie...
"Pray, v. To ask that the laws of the universe be annulled in behalf of a single petitioner, confessedly unworthy." --Ambrose Bierce, The Devil's Dictionary
Daar zit nu net de gemeenheid: als eerste parameter geef je wel iets mee dat het type char* heeft, maar op de regel erboven doe je:Volgens de pagina die ik gelezen had was het tweede argument (de string waarop gesplitst moet worden dus) een string waar niet in geschreven mag worden, const char*. Het eerste argument is gewoon char*. Daar mag toch gewoon in geschreven worden?
1
| char *regel = "a\tb"; |
Ik zou me geen zorgen maken over het maken van zo'n kopietje en performance. Als dat namelijk echt een probleem zou vormen, dan kom je dat wel tegen als je je code gaat profilen. En dan kan je op dat moment wel actie ondernemen.
[ Voor 26% gewijzigd door Infinitive op 14-03-2004 01:24 ]
putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
Pointers en arrays in C/C++ zijn in feite hetzelfde: je hebt een referentie naar het eerste element in de lijst, en je hebt toegang tot de rest van de elementen aan de hand van de eerste. Het enige verschil tussen een T* en een T[] is dat je in het eerste geval echt een variabele hebt waar letterlijk een verwijzing staat naar een geheugenadres (waar het eerste element van de array zich bevindt). Bij T[] heb je niet echt zo'n variabele, je hebt de array zelf en de compiler weet waar deze zich bevindt. Een T[] kan automatisch naar een T* gecast worden door simpelweg het adres, dat al bekend is bij de compiler, in een variabele te stoppen.
Const wil echter zeggen dat het object waar de pointer naartoe wijst niet aan kunt passen; je kunt het alleen maar uitlezen. Een const char * wijst dus naar een string die je niet mag veranderen, en string literals, dus lappen tekst tussen quotes, zijn eigenlijk ook const char *'s. Echter zoals ik al zei, door een 'feature' is het mogelijk een string literal toe te kennen aan een non-const char *, en dan gaat het dus fout zodra je die probeert aan te passen (je krijgt dan geen compile error bij het aanpassen, een char * is immers geen const char *, dus je mag iets wijzigen)
Dus waar jij voor moet zorgen is dat je een string literal nooit toekent aan een char *, dan kan het in feite niet fout gaan. Maar als je een string literal ergens aan toe wilt kennen en als je het later aan wilt kunnen passen, dan moet je die string dus kopieren naar een stukje geheugen zodat het aangepast kan worden. Dat stukje geheugen kun je dynamisch alloceren dmv new, maar je kunt ook gewoon een lokale non-const array definieren. Gelukkig kun je string literals ook gebruiken om arrays mee te initialiseren, en dat is dus wat er gebeurt in mijn voorbeeldcode.
Als jouw strtok code in een functie staat die een char * als parameter heeft dan is er niets aan de hand, de code die de functie aanroept moet ervoor zorgen dat die array van chars ook daadwerkelijk schrijfbaar is (als dat niet had gehoeven dan had je de parameter ook beter kunnen definieren als const char *, maar dat is nu natuurlijk niet het geval)
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Leuk, maar je legt niet uit waarom die string literal niet mag worden veranderd. Dat is namelijk omdat je zo....oisyn schreef op 14 maart 2004 @ 01:25:
Ik denk dat je nog maar even bij moet gaan lezen over pointers, arrays en wat const inhoudt
Blablablablablablablabla. Bla.
1
| char *bla = "Hello, world"; |
1
2
| char *bla = _strdup("Hello, world!"); // er vanuit gaande dat je MSVC gebruikt... |
.oisyn: Échte programmeurs haten PHP met een passie. Ben jij soms geen echte programmeur?
Bedankt voor de heldere uitleg hierover..oisyn schreef op 14 maart 2004 @ 01:25:
Ik denk dat je nog maar even bij moet gaan lezen over pointers, arrays en wat const inhoudt
Dat eerste had ik al begrepen, dat tweede wist ik nog niet...Const wil echter zeggen dat het object waar de pointer naartoe wijst niet aan kunt passen; je kunt het alleen maar uitlezen. Een const char * wijst dus naar een string die je niet mag veranderen, en string literals, dus lappen tekst tussen quotes, zijn eigenlijk ook const char *'s.
Nu snap ik tenminste ook waarom dit zo is. Ik ga eerst maar eens kijken of ik het zonder new ook voor elkaar gaat krijgen, deze code moet namelijk een paar 1000 keer worden uitgevoerd en volgens mij gaat het dan wel tellen als ik iedere keer new wil doenDus waar jij voor moet zorgen is dat je een string literal nooit toekent aan een char *, dan kan het in feite niet fout gaan. Maar als je een string literal ergens aan toe wilt kennen en als je het later aan wilt kunnen passen, dan moet je die string dus kopieren naar een stukje geheugen zodat het aangepast kan worden. Dat stukje geheugen kun je dynamisch alloceren dmv new, maar je kunt ook gewoon een lokale non-const array definieren. Gelukkig kun je string literals ook gebruiken om arrays mee te initialiseren, en dat is dus wat er gebeurt in mijn voorbeeldcode.
"Pray, v. To ask that the laws of the universe be annulled in behalf of a single petitioner, confessedly unworthy." --Ambrose Bierce, The Devil's Dictionary
implementatie-detail, je mag een const char * gewoon niet veranderen, of dit in het echt nu wel kan of niet doet er niet toe (en zo te zien begreep de TS mijn uitleg helemaalKorben schreef op 14 maart 2004 @ 04:46:
[...]
Leuk, maar je legt niet uit waarom die string literal niet mag worden veranderd.
Ten eerste is strdup geen ANSI, ten tweede zei ik al dat als je dat wilt doen dat je het dan op een stukje geheugen neer moet zetten waar je het wel mag veranderen. Dus of een dynamisch gealloceerde array (dat is in feit wat jij doet met een non-standard functie), of gewoon lokaal op de stack (wat een stuk efficienter is, hoewel je dat dan weer niet kan returnen vanuit een functie)[code=c]
Als je dit had gedaan:
C:... was het wel goed gegaan.
1 2 char *bla = _strdup("Hello, world!"); // er vanuit gaande dat je MSVC gebruikt...
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
BUGS
Never use these functions. If you do, note that:
These functions modify their first argument.
The identity of the delimiting character is lost.
These functions cannot be used on constant strings.
The strtok() function uses a static buffer while
parsing, so it's not thread safe. Use strtok_r() if
this matters to you.
Als je de kennis hebt : Schrijf zelf een versie van split(), en laat strtok() voor wat het is.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
duh ?