Toon posts:

[c++] resultaat is bagger

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb de volgende code die wel hele rare uitvoer geeft:

1111111111;222233333;33333;444444444444444444441111111111;222233333;33333;;èR;;

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int pr_test()
{
    char record1[10];
    char record2[4];
    char record3[5];
    char record4[20];

    char result[100];

    strcpy(record1, "1111111111");
    strcpy(record2, "2222");
    strcpy(record3, "33333");
    strcpy(record4, "44444444444444444444");

    sprintf(result, %s;%s;%s;%s", record1, record2, record3, record4);

    printf("%s\n", result);

    reactie();

    return 0;
}


iemand een idee wat hier grandioos mis gaat?

[ Voor 8% gewijzigd door Verwijderd op 07-04-2003 11:38 ]


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 23-08 10:39

Janoz

Moderator Devschuur®

!litemod

Waarom zet je 7 keer een %s neer om vervolgens maar 4 strings op te geven? Dan is het inderdaad niet vreemd dat er allemaal vreemde ongedefinieerde dingen achter komen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

En bovendien heb je geen ruimte gereserveerd voor de trailing \0's

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.


Verwijderd

Topicstarter
oh dat is even een foutje van mij, ik had eerst een voorbeeld met 7 records hierboven geplaatst, echter leek het me op een gegeven moment wel duidelijk, heb het ook getest met gewoon 4 * %s, dan gaat hij nog fout

Verwijderd

Topicstarter
hoe bedoel je trailing \0?
result[strlen(result)] = '\0'; ??

  • Wirf
  • Registratie: April 2000
  • Laatst online: 18-08 17:51
Een string in C/C++ moet afgesloten worden met een \0. Als je die nul er niet in hebt zitten, gaat C/C++ gewoon door totdat ie wel een nul vind.

Dus je moet al je array's met 1 groter maken.

Heeft sinds kort zijn wachtwoord weer terug gevonden!


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

strings in C eindigen altijd op \0. Dat is om het einde van de string aan te geven, want de lengte wordt verder nergens bijgehouden.

record1 is een char[10], er is dus ruimte voor 10 chars. Maar je kopieert er vervolgens 11 naartoe (10 1'en, en nog een \0). Die string heeft dus geen einde, en dat gaat vroeg of laat gegarandeerd fout

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.


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

Nee, als je een string hebt van 10 karakters bestaat hij in geheugen altijd uit 11 karakters.
We noemen dat altijd een 0-terminated string.

Wanneer je dus strcpy uit gaat voeren zoekt deze functie op de eerstvolgende 0-karakter wat het einde van de string is.

Verwijderd

Topicstarter
toch blijft het bagger, het wordt wel beter, maar ik krijg nog een tweede regel die ik niet wil hebben

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int pr_test()
{
    char record1[10];
    char record2[4];
    char record3[5];
    char record4[20];

    char result[100];

    result[0] = '\0';
    strcpy(record1, "1111111111\0");
    strcpy(record2, "2222\0");
    strcpy(record3, "33333\0");
    strcpy(record4, "44444444444444444444\0");

    sprintf(result, "%s;%s;%s;%s", record1, record2, record3, record4);

    result[strlen(result)] = '\0';

    printf("%s\n", result);


resultaat is:
1111111111;222233333;33333;444444444444444444441111111111;222233333;33333;

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, die \0 staat er al achter (een string literal heeft altijd een trailing 0, en een strcpy kopieert die 0 ook mee). De fout is dat je er geen ruimte voor reserveert

char record[11] dus!

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.


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

Let op:
Die '\0' behoef je niet toe te voegen!!! Dit doet de compiler wel voor jou.

Doe het maar als volgt dan werkt het perfect:

int pr_test()
{
char record1[11];
char record2[5];
char record3[6];
char record4[21];

char result[100];

strcpy(record1, "1111111111");
strcpy(record2, "2222");
strcpy(record3, "33333");
strcpy(record4, "44444444444444444444");

sprintf(result, "%s;%s;%s;%s", record1, record2, record3, record4);

printf("%s\n", result);

Verwijderd

Topicstarter
dus je bedoelt
C:
1
2
strcpy(record1, "1111111111");
record1[strlen(record1)] = '\0'

??

  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

Nope!!

Vergeet die \0 nou ff. Die zit al in de string die je opgeeft!!
De string die je opgeeft ziet er in geheugen als volgt uit:

[0]='1'
[1]='1'
..
[9]='1'
[10]='\0'

Daarom moet je ook een char-array nemen van 11!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

char record1[11]

in plaats van char record1[10] wat je nu hebt

[ Voor 35% gewijzigd door .oisyn op 07-04-2003 12:04 ]

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.


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

.. Niks gezegd :)

[ Voor 82% gewijzigd door BoAC op 07-04-2003 12:16 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

BoAC schreef op 07 April 2003 @ 12:06:
NEE We tellen in C altijd van 0 tot size - 1!!!
tegen wie heb je het nou :?

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.


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

.oisyn schreef op 07 April 2003 @ 12:07:
[...]


tegen wie heb je het nou :?
Sorry tegen you. Was vergeten te 'qouten' ;)

  • nhimf
  • Registratie: September 2000
  • Laatst online: 19-08 10:00

nhimf

Lekker belangrijk allemaal

BoAC schreef op 07 April 2003 @ 12:10:
[...]


Sorry tegen you. Was vergeten te 'qouten' ;)
Groottes van arrays gaan van 1-n
in dit geval dus 11 en element 11 vraag je op door [10] en element 1 is [0]

Ik stink niet, ik ruik gewoon anders


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

BoAC schreef op 07 April 2003 @ 12:10:
[...]


Sorry tegen you. Was vergeten te 'qouten' ;)
Ja dat dacht ik al, maar dat vind ik nogal raar, want aan mijn opmerking is niets fout, en bovendien zeg ik ongeveer hetzelfde als jij :) (ik had het overigens weer tegen de topicstarter)

[ Voor 30% gewijzigd door .oisyn op 07-04-2003 12:13 ]

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.


Verwijderd

Hoi,

Een algemene opmerking gezien antwoord al gegeven is... gebruik strncpy als die ondersteund wordt in je ontwikkelomgeving.

C++:
1
2
3
4
5
6
char *strncpy(char *s1, const char *s2, size_t n);

..
char buf[10];
strncpy( buf, "blabla", sizeof(buf) );
..


Die schrijft nl. niet buiten het array als je een foutje maakt (nadeel hij laat de laatse '/0' weg als het array niet groot genoeg is, staat tegen over dat dat soort fouten makkelijker te vinden zijn dan kapotte stack frames). Van vrijwel alle str/mem functies zijn 'n' varianten. I.h.a. loont het zich om die te gebruiken. Vooral snprintf is een goede om altijd te gebruiken, sprintf is errug link.

[ Voor 10% gewijzigd door Verwijderd op 07-04-2003 12:17 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

izniegoed: dat helpt dus voor geen meter, juist om de opmerking die je maakt over het feit dat de '\0' er niet achter wordt gezet. Je verplaatst het probleem nu eigenlijk. Het kopieeren gaat nu goed, maar zodra je de gekopieerde buffer wilt gebruiken zit je weer met de gebakken peren (omdat er dus geen '\0' achter staat).

De beste oplossing is gewoon om heel simpel std::string te gebruiken, geen gezeur met buffer overruns en memory management :Y)

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.


  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 21-06 17:10
goede gewoonte:
C++:
1
char record1[10+1]

Op deze manier houd je het voor jezelf overzichtelijk, en heb je altijd ruimte voor het \0 karakter

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

Verwijderd schreef op 07 April 2003 @ 12:15:
Hoi,

Een algemene opmerking gezien antwoord al gegeven is... gebruik strncpy als die ondersteund wordt in je ontwikkelomgeving.

C++:
1
2
3
4
5
6
char *strncpy(char *s1, const char *s2, size_t n);

..
char buf[10];
strncpy( buf, "blabla", sizeof(buf) );
..


Die schrijft nl. niet buiten het array als je een foutje maakt (nadeel hij laat de laatse '/0' weg als het array niet groot genoeg is, staat tegen over dat dat soort fouten makkelijker te vinden zijn dan kapotte stack frames). Van vrijwel alle str/mem functies zijn 'n' varianten. I.h.a. loont het zich om die te gebruiken. Vooral snprintf is een goede om altijd te gebruiken, sprintf is errug link.
Maar als ik dit als volgt ga gebruiken dan krijg ik wel een raar resultaat:

C++:
1
2
3
4
5
char buf[11];
char result[100];

strncpy( buf, "blablablablabla", sizeof(buf) ); 
sprintf( result, "%s", buf );


Resultaat : blablablablý..Q.

Dit komt natuurlijk weer door die 0-terminated string.
Dus moet dit nog voor sprintf:

C++:
1
buf[10]=0;

  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 21-06 17:10
probeer dan ook
C++:
1
strncpy(buf, "blablablablabla", sizeof(buf)-1);

dan hou je zelf weer ruimte vrij voor de \0 :P

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
Verwijderd schreef op 07 April 2003 @ 12:15:
Een algemene opmerking gezien antwoord al gegeven is... gebruik strncpy als die ondersteund wordt in je ontwikkelomgeving.
Mwah, gebruik dan strlcpy, dan weet je tenminste zeker dat je buffer correct afgesloten is. Met strncpy kun je nog steeds een unterminated buffer en de nodige bijbehorende segfaults krijgen. Nadeel is wel dat strlcpy niet standaard is; als portability een issue is kun je 'm dus beter niet gebruiken.

Het is trouwens vaak beter om ofwel een dynamische string (C++: std::string!) te gebruiken, of van te voren te controleren op de lengte van de string. Meestal wil je namelijk geen beperking op de invoer hebben, of een speciale actie ondernemen wanneer de string afgekapt dreigt te wroden (de gebruiker om alternatieve invoer vragen, bijvoorbeeld).

  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 22-08 21:48

BoAC

Memento mori

riezebosch schreef op 07 april 2003 @ 12:30:
probeer dan ook
C++:
1
strncpy(buf, "blablablablabla", sizeof(buf)-1);

dan hou je zelf weer ruimte vrij voor de \0 :P
Hmm

Hou je er wel rekening mee dat variablen in C altijd ongedefinieerd zijn.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

maar goed:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>

int ptr_test ()
{
    std::string record1, record2, record3, record4;

    record1 = "1111111111";
    record2 = "2222";
    record3 = "33333";
    record4 = "44444444444444444444";

    std::string result = record1 + ';' + record2 + ';' + record3 + ';' + record4;
    std::cout << result << std::endl;

    return 0;
}

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.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
riezebosch schreef op 07 April 2003 @ 12:30:
probeer dan ook
C++:
1
strncpy(buf, "blablablablabla", sizeof(buf)-1);

dan hou je zelf weer ruimte vrij voor de \0 :P
Ja, maar die \0 komt er dan nog niet bij! Je code wordt dan:
C++:
1
2
strncpy(buf, "tekst", sizeof(buf) - 1);
buf[sizeof(buf) - 1] = 0;

Dan is "strlcpy(buf, "tekst", sizeof(buf));" een stuk eenvoudiger en duidelijker!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
.oisyn schreef op 07 April 2003 @ 12:33:
C++:
1
2
std::string result = record1 + ';' + record2 + ';' + record3 + ';' + record4;
std::cout << result << std::endl;
Is er een speciale reden dat je ze eerst concateneert voordat je ze wegschrijft? In het algemene geval (als die records een willekeurige lengte kunnen hebben) lijkt me die concatenatie erg kostbaar, omdat elke keer een nieuwe stringbuffer aangemaakt moet worden.

Verwijderd

.oisyn schreef op 07 April 2003 @ 12:18:
izniegoed: dat helpt dus voor geen meter, juist om de opmerking die je maakt over het feit dat de '\0' er niet achter wordt gezet. Je verplaatst het probleem nu eigenlijk. Het kopieeren gaat nu goed, maar zodra je de gekopieerde buffer wilt gebruiken zit je weer met de gebakken peren (omdat er dus geen '\0' achter staat).

De beste oplossing is gewoon om heel simpel std::string te gebruiken, geen gezeur met buffer overruns en memory management :Y)
Gezien het antwoord al 10 keer gegeven was leek het mij overbodig het nog een keer te herhalen, zoals ik al zei ;)

Punt is als je met buffertjes gaat/moet werken is het goed om wat best practice dingen te doen. Dus de n varianten van die functies gebruiken. std::string is inderdaad in 9 van de 10 gevallen makkelijker, dat zal ik niet ontkennen.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op 07 April 2003 @ 12:35:
[...]

Is er een speciale reden dat je ze eerst concateneert voordat je ze wegschrijft? In het algemene geval (als die records een willekeurige lengte kunnen hebben) lijkt me die concatenatie erg kostbaar, omdat elke keer een nieuwe stringbuffer aangemaakt moet worden.
Nee, nou ja eigenlijk wel, ik wilde het simpel houden voor de TS

een ostringstream had idd een betere keuze geweest (of een concatenatie dmv de += operator of string::append), hoewel daar intern natuurlijk ook gewoon elke keer een nieuwe buffer moet worden gealloceerd als het er niet meer in past

[ Voor 49% gewijzigd door .oisyn op 07-04-2003 12:40 ]

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.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
.oisyn schreef op 07 April 2003 @ 12:37:
Nee, nou ja eigenlijk wel, ik wilde het simpel houden voor de TS

een ostringstream had idd een betere keuze geweest (of een concatenatie dmv de += operator of string::append), hoewel daar intern natuurlijk ook gewoon elke keer een nieuwe buffer moet worden gealloceerd als het er niet meer in past
Ik zat eigenlijk te denken aan direct schrijven naar cout ("std::cout << veld1 << ';' << veld2 << ';' << veld 3 << std::endl"); een ostringstream leek me nogal overkill voor deze toepassing. :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Oh, bedoel je dat. Dat deed ik om het resultaat toe te kennen aan result, wat de topicstarter dus ook deed (eerst een sprintf (), en daarna een printf ()). Je kan in principe ook gewoon gelijk de hele string outputten omdat toch alles al van tevoren bekend is, en dus heel std::string achterwege laten ;)

[ Voor 9% gewijzigd door .oisyn op 07-04-2003 12:51 ]

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.

Pagina: 1