[C++] Door char* iteraten en dan char[i] combineren

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • topaj
  • Registratie: April 2008
  • Laatst online: 18:21
Hallo tweakers :)

Misschien een doodsimpele vraag, maar dit is het enige stukje code wat ik nooit helemaal begrepen heb.

Ik heb een char[] met een stukje tekst.
Bijv:
C++:
1
2
char map[] = {"Hallo"
"medetweakers"};


Nu convert ik deze naar een pointer, en ga ik erdoor loopen:
C++:
1
2
3
4
5
char *mapPointer;
mapPointer = map;

for (int i = 0; i < 160; i++)
{


De bedoeling is dat ik van deze voorgeprogrammeerde char array elke letter om ga zetten in een png path, en die wil gaan tekenen in mijn algoritme.

Dus bijv. de eerste keer geeft:
Images/Sprites/H.png
2e keer:
Images/Sprites/a.png
enz.

C++:
1
2
3
4
5
6
7
// In de loop
char path[40]; 
strcpy(path,"Images/Sprites/");
strcat(path, (char*)mapPointer[i-1]); // <- Hier crasht hij als ik debug in MSVC
strcat(path, ".png");

CCSprite* item = CCSprite::spriteWithFile(path, // Rest is niet relevant voor de vraag


Ik heb me lam gezocht, maar kon de combinatie van iteraten + combineren van chars niet voorelkaar krijgen.

Danku zeer :)

[ Voor 4% gewijzigd door topaj op 17-08-2011 12:06 ]

Groeten


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
http://www.cplusplus.com/reference/clibrary/cstring/strcat/

Strcat heeft een adres nodig, geen waarde. Dus in het geval van een normale variabele of string: &variabele[0] of in het geval van een pointer gewoon 'pointer'.

Dus het adres dat in de pointer zit, niet de waarde op dat adres die jij dus passed. Zoiets:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char *mapPointer = &map[0]; // adres van nulde item, hetzelfde als '= map' voor arrays

for(int a = 0;a < strlen(map);a++) {

    // In de loop 
    char path[40];  
    strcpy(path,"Images/Sprites/"); 
    strcat(path, mapPointer);
    strcat(path, ".png");

    // 1 byte opschuiven
    mapPointer++;

    CCSprite* item = CCSprite::spriteWithFile(path, // Rest is niet relevant
}


Oh, en hij crasht omdat je probeert de lezen op byte nummertje (ansi-waarde-van-char). Dus in het geval van H gaf je strcat het adres 56 mee, en daar mag je waarschijnlijk niet komen.

[ Voor 21% gewijzigd door Orwell op 17-08-2011 12:44 ]


Acties:
  • 0 Henk 'm!

  • topaj
  • Registratie: April 2008
  • Laatst online: 18:21
Thanks man,
Het begint een beetje te dagen.
Ik snap de gedachte erachter, maar toch loop ik nog tegen een probleem op.

Met het ophogen van de byte crasht de zooi, en in de try / catch zie ik het volgende verschijnen:
Error:
Get data from C:\<blabla>\Images\Sprites[b]HalloMedetweakers[/b].png failed!

Hij loopt er dus niet mooi letter voor letter doorheen, maar pakt de hele string, en bij het pakket van volgende byte crasht hij.

Groeten


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

C:
1
(char*)mapPointer[i-1]
Wat doe je hier nu eigenlijk? Je hebt een array van chars. Door mapPointer[i-1] te schrijven krijg je dus één char terug. Vervolgens doe je een expliciete cast van een char naar een char pointer, en dat dat fout gaat is nogal wiedes natuurlijk. :P

Orwell: zoals je kan lezen in de documentatie die je zelf aanhaalt verwacht strcat wel (logischerwijs) een zero-terminated string als argument, geen char. Je kan dan ook beter gebruik maken van een sprintf:
C:
1
sprintf(path, "Images/Sprites/%c.png", mapPointer[i-1]);

topaj: waarom laat je die for-loop tellen van 1 tot 160 in plaats van 0 tot strlen(string)? Beginnen bij 1 terwijl je een zero based index hebt is sowieso niet handig, en magic numbers zijn nooit goed. ;)

Verder: je zegt dat je C++ gebruikt in je topictitel. Waarom gebruik je dan C-strings in plaats van de C++-variant daarop?

[ Voor 15% gewijzigd door NMe op 17-08-2011 12:54 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
Ups, foutje, ja, hij blijft doorgaan t/m '\0'. Het heet ook niet voor niks STRINGconcat. :$

En idd, gewoon in plaats van al het stukjesgerommel in één keer die enkele byte schrijven.

Zelfcorrectie voor het geval je 0 t/m strlen gebruikt:

C++:
1
sprintf(path, "Images/Sprites/%c.png",*ptr); // Deze wil weer waarde en niet adres hebben (adres levert geen extra tempo op met chars in de stack)

[ Voor 21% gewijzigd door Orwell op 17-08-2011 12:55 ]


Acties:
  • 0 Henk 'm!

  • topaj
  • Registratie: April 2008
  • Laatst online: 18:21
Mensen, ontzettend bedankt, het werkt fantastisch.
Ik ga me zometeen verdiepen in pointers e.d.

Ik programmeer voornamelijk Obj-C op een Mac, en assembly op Windows.
Dit verklaart mijn rare syntax van map[i] e.d.
C++ is een beetje nieuw voor me:)

[ Voor 4% gewijzigd door topaj op 17-08-2011 13:35 ]

Groeten


Acties:
  • 0 Henk 'm!

Verwijderd

Waarom gebruik je niet gewoon een std::string?

C++:
1
2
3
4
5
6
7
std::string str = "Hello, world!";

for (size_t i = 0; i < str.length(); i++) {
    std::string path = std::string("Images/Sprites/") + std::string(str[i]) + std::string(".png");

    // Doe dingen met path...
}

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Volgens mij kan die std::string(str[i]) zelfs gewoon str[i] zijn. 'k zou het dus zou schrijven:

C++:
1
2
3
4
5
6
7
8
9
static const std::string dir = "Images/Sprites/";
static const std::string ext = ".png";
std::string str = "Hello, world!"; 

for (size_t i = 0; i < str.length(); i++) { 
    std::string path = dir + str[i] + ext; 

    // Doe dingen met path... 
}

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

Verwijderd

Volgens mij ook, maar ik wist het niet meer zeker, dus ik deed het op de veilige manier :P.

Acties:
  • 0 Henk 'm!

  • xos
  • Registratie: Januari 2002
  • Laatst online: 12-09 12:41

xos

Of als je compiler de nieuwe for range base loop al ondersteund:

C++:
1
2
3
4
5
6
7
8
9
static const std::string dir = "Images/Sprites/";
static const std::string ext = ".png";
std::string str = "Hello, world!"; 

for (char c : str) { 
    std::string path = dir + c + ext; 

    // Doe dingen met path... 
}

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
NMe schreef op woensdag 17 augustus 2011 @ 12:50:
[...]

Wat doe je hier nu eigenlijk? Je hebt een array van chars. Door mapPointer[i-1] te schrijven krijg je dus één char terug. Vervolgens doe je een expliciete cast van een char naar een char pointer, en dat dat fout gaat is nogal wiedes natuurlijk. :P
Het is trouwens niet de cast die de crash veroorzaakt het is het gebruik van de uiteindelijke pointer. Die pointer wijst namelijk hoogst waarschijnlijk naar een stuk geheugen waar niet je stack of heap data staat.

[ Voor 34% gewijzigd door NC83 op 17-08-2011 23:22 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

NC83 schreef op woensdag 17 augustus 2011 @ 23:21:
[...]

Het is trouwens niet de cast die de crash veroorzaakt het is het gebruik van de uiteindelijke pointer. Die pointer wijst namelijk hoogst waarschijnlijk naar een stuk geheugen waar niet je stack of heap data staat.
Uiteraard. :P Ik ken in elk geval weinig operating systems waarin je adressen kan aanspreken die je aan kan wijzen met enkel een char. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • topaj
  • Registratie: April 2008
  • Laatst online: 18:21
Tsja. zou ook kunnen :)
Alleen het is crossplatform, dus de library waar ik gebruik van maak gebruikt chars.
Ik weet eigenlijk niet hoe dit zou gaan compilen op een Mac / Android NDK.

Edit: Volgens mij snap ik de fout. In plaats van een waarde te geven aan de stack (dat gedeelte snap ik van mijn assembly ervaring :)), geef ik een waarde aan het pointer adres.
Danku zeer NC83 en NMe :)

[ Voor 35% gewijzigd door topaj op 18-08-2011 13:26 ]

Groeten


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Andersom. :P Strcat verwachtte een pointer naar de eerste character van een null-terminated string. Jij pakte echter de waarde van het byte op het adres op een paar bytes verwijderd van de byte waar mapPointer naar verwijst. Die waarde gaf je vervolgens door alsof het een adres was, en dat adres is lager dan het door jouw aanspreekbare geheugengebruik, dus krijg je daar last mee. :P

Zijdelings gerelateerd: arrays "zijn" pointers, en C-strings zijn niet meer dan speciale arrays van chars. Om die reden is mapPointer[i - 1] gelijk aan *(mapPointer + ((i - 1) * sizeof(char))), zo uit het hoofd met mijn stoffige C-kennis. Die sizeof is natuurlijk anders als het een array van integers of iets anders zou zijn. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • topaj
  • Registratie: April 2008
  • Laatst online: 18:21
Je hebt gelijk, bedankt voor de uitleg.

Dat array gedeelte wist ik al, maar dank voor het verduidelijken :)

Groeten


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

NMe schreef op donderdag 18 augustus 2011 @ 13:54:
Om die reden is mapPointer[i - 1] gelijk aan *(mapPointer + ((i - 1) * sizeof(char)))
Toevallig wel, maar puur door het feit dat sizeof(char) == 1. Als het om een array van ints zou gaan (met een bijbehorende sizeof(int) uiteraard), dan zou je voorbeeld niet meer kloppen.

Het rekenen met pointers is namelijk exact equivalent aan het indexeren van een array.
a[b] <=> *(a + b) <=> *(b + a) <=> b[a]

disclaimer: dit verhaal gaat uiteraard alleen op als het ene type een array of pointer is en het andere type een integer

[ Voor 10% gewijzigd door .oisyn op 18-08-2011 22: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.

Pagina: 1