[C++] Erg vreemde error: toewijzen van waarde aan variabel

Pagina: 1
Acties:

  • AuC
  • Registratie: Januari 2003
  • Laatst online: 08-05 08:21
Ik ben momenteel een class aan het maken voor het inlezen van ID3 tags. Classe lijkt prima te werken, maar ik krijg de volgende error als ik een waarde wil toewijzen die ik gedeclareerd heb in een class:
---------------------------
id3test1.exe - Toepassingsfout
---------------------------
De instructie op 0x00401c00 verwijst naar geheugen op 0xccccccd0. De written-bewerking op het geheugen is mislukt.


Klik op OK om het programma te beëindigen.
Klik op Annuleren om fouten op te sporen in het programma
---------------------------
OK Annuleren
---------------------------
Hier de code die ik gebruik:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef __ID3_H_
#define __ID3_H_

#include <string>
#include <fstream>
#include <iostream>

using namespace std;

//============================================================
// Structures
//============================================================

// The ID3 Tag
typedef struct
{
    int  iVersion;
    char szTitle[30];
    char szArtist[30];
    char szAlbum[30];
    char szYear[4];
    char szComment[30];
} ID3Tag;

//============================================================
// Enumeration
//============================================================
enum {
    TYPE_ID3V1 = 0,
    TYPE_ID3V2
};

//============================================================
// Class
//============================================================
class ID3Reader 
{
private:
    ID3Tag  *m_sTag;
    int      m_iType;

public:
    ID3Reader();
    
    bool ReadFile( const char* szFileName );
};

#endif //__ID3_H_



C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "id3.h"


ID3Reader::ID3Reader()
{

}

bool ID3Reader::ReadFile( const char* szFileName )
{
    char buf[3];    
    string sID;  

    ifstream fp( szFileName, ios::binary | ios::in );
    if( !fp.is_open() )
    {
        cout << "Error opening " << szFileName << ".\n";
        return false;
    }

    fp.seekg( -128, ios::end );

    fp .get(  buf, 4 );
    sID = buf;

    if( (sID.substr( 0, 3 )) != "TAG" )     // Check ID3v1
    {
        if( (sID.substr( 0, 3 )) != "ID3" ) // Check ID3v2
        {
            cout << szFileName << " does not have a valid ID3 Tag.\n";
            return false;
        }
        else
        {
            cout << "ID3v2 tag found.\n";
        }
    }
    else
    {
        cout << "ID3v1 tag found.\n";
        m_iType = TYPE_ID3V1; // Hier zit de fout dus
    }

    fp.close();

    return true;
}


Dit lijkt me toch moeten werken?

[ Voor 11% gewijzigd door AuC op 10-10-2004 21:37 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Uhm en je hebt neem ik aan al gedebugged, gestept door de code, en bepaald op welke regel het fout gaat en welke waardes de variabelen dan hebben? :?

Professionele website nodig?


  • AuC
  • Registratie: Januari 2003
  • Laatst online: 08-05 08:21
De regel waar het fout gaat is regel 41 van de cpp:

C++:
1
m_iType = TYPE_ID3V1;


m_iType zegt in de debugger: CXX0030: Error: expression cannot be evalueted.

m_sTag geeft ook fout: CXX0017: Error: symbol "" not found.

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Ik zie in je readfile methode iig een char buf[3], maar je vult die even later met vier characters. Dan overschrijf je een stuk geheugen en krijg je een toepassingsfout...

[ Voor 17% gewijzigd door SWfreak op 10-10-2004 21:45 ]


  • AuC
  • Registratie: Januari 2003
  • Laatst online: 08-05 08:21
Sorry, heb het al gevonden. Had de classe fout gedeclareerd (zonder constructor) 8)7.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-05 16:18
Toch zit die bug die SWfreak aankaart er ook nog in.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • AuC
  • Registratie: Januari 2003
  • Laatst online: 08-05 08:21
farlane schreef op 10 oktober 2004 @ 21:58:
Toch zit die bug die SWfreak aankaart er ook nog in.
Klopt, die ga ik er ook gelijk uithalen. Is er trouwens een manier om dat ophalen van gegevens uit het bestand minder omslachtig te doen? Ik moet de gegevens nu eerst in een char[3] zetten om deze vervolgens in een string te veranderen.

C++:
1
2
fp .get(  buf, 3 );
   sID = buf;


Edit:
Als ik de code aanpas zoals SWFreak zegt (fp.get( buf, 3)) dan leest hij alleen TA in i.p.v TAG. :S

[ Voor 22% gewijzigd door AuC op 10-10-2004 22:05 ]


  • SWfreak
  • Registratie: Juni 2001
  • Niet online
AuC schreef op 10 oktober 2004 @ 22:00:

Edit:
Als ik de code aanpas zoals SWFreak zegt (fp.get( buf, 3)) dan leest hij alleen TA in i.p.v TAG. :S
Dat is ook niet wat je moet doen. Dit was de bedoeling:
code:
1
char buf[4];

Als je in de documentatie van istream kijkt, lees je het volgende:
get( char*array, int nCount, char delim = '\n' ); Extracts characters from the stream until either delim is found, the limit nCount is reached, or the end of file is reached. The characters are stored in the array followed by a null terminator.

Een get van 4 heeft dus een buffer van minstens 4 chars nodig...

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 21-05 16:18
AuC schreef op 10 oktober 2004 @ 22:00:
Klopt, die ga ik er ook gelijk uithalen. Is er trouwens een manier om dat ophalen van gegevens uit het bestand minder omslachtig te doen? Ik moet de gegevens nu eerst in een char[3] zetten om deze vervolgens in een string te veranderen.
std::getline misschien ?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • AuC
  • Registratie: Januari 2003
  • Laatst online: 08-05 08:21
Dan krijg ik direct de hele regel? Ik wil echt enkel drie karakters uitlezen...

Verwijderd

AuC schreef op 10 oktober 2004 @ 21:46:
Sorry, heb het al gevonden. Had de classe fout gedeclareerd (zonder constructor) 8)7.
Een constructor heb je altijd in C++. Als je er geen declareert, zoals jij nu wel deed, dan maakt je compiler een wat men noemt 'default constructor'. Wat jij hebt geschreven als constructor neemt geen argument en doet verder ook niets in de body code, dus dat kun je net zo goed weglaten. Maakt geen verschil.
Volkomen analoog zorgt de compiler ook altijd voor een default copy constructor en assignment operator (als jij ze dus niet schrijft), welke als gedrag 'memberwise copy' hebben.

Verder zie ik daar nog een pointer als member staan in je klasse die zo te zien nergens gebruikt wordt (m_sTag dus)? Ik neem aan dat deze nog gebruikt zal worden, dus het lijkt me hier bijzonder zinvol dat je je constructor laat staan en die pointer member initialiseert om te vermijden dat er een random waarde inzit die je later gaat gebruiken (met alle gevolgen van dien). Het zelfde geldt voor je m_iType member. Pointers, en trouwens ook andere basistypes als int, long, etc, worden namelijk meestal NIET geinitialiseerd (i.e. de waarde is random als je ze niet zelf initialiseert). Dat geeft bvb:
C++:
1
2
3
4
ID3Reader::ID3Reader()
: m_sTag( NULL ), m_iType( TYPE_ID3V1 )
{
}

Voor de initiele waarde van m_iType lijkt een extra TYPE_NONE enum misschien een meer logische keuze voor initializatie, maar goed.

Ik zit me trouwens af te vragen of je niet gewoon strings kan streamen van je file om het eenvoudiger te maken? Dan hoef je niet via die buffers rond. Ik zou het moeten opzoeken omdat ik niet zeker ben (zeker niet omdat je de file binary opengooit), maar ik dacht dat streamen van strings uit een file makkelijk kon gebeuren omdat er rekening wordt gehouden met witte ruimte. Dus als je file op de huidige plaats 'TAG Test' bevat, dat je toch kunt schrijven
C++:
1
2
string sID;
fp >> sID;

en dat sID dan alleen 'TAG' zal bevatten omdat het streamen stopt bij de spatie (witte ruimte). Maar zoals gezegd: dat ben ik niet zeker, dus dat zou ik eens moeten opzoeken.

  • AuC
  • Registratie: Januari 2003
  • Laatst online: 08-05 08:21
Dat zijn enkele handige weetjes. Van de constructor wist ik, echter had ik de classe zo geinitialiseerd (altijd in de war met termen):

C++:
1
ID3Reader *pID3Reader;


In plaats van

C++:
1
ID3Reader *pID3Reader = new ID3Reader();


En dat werkte dus niet.

De constructor had ik al gemaakt omdat ik inderdaad de variabelen daarin wou initializeren.

Wat je zegt over de stream is inderdaad waar (voor zover ik weet) het probleem is alleen dat in ID3-Tags de waarde's direct achter elkaar worden geplakt. Dus achter de 3 char's van TAG komen direct (zonder spatie) 30 char's van de titel van de mp3. Ik zocht al naar een manier om enkel de 3 char's van de tag in te kunnen lezen, maar heb nog niets gevonden.

[ Voor 4% gewijzigd door AuC op 11-10-2004 01:42 ]


Verwijderd

AuC schreef op 11 oktober 2004 @ 01:42:
Dat zijn enkele handige weetjes. Van de constructor wist ik, echter had ik de classe zo geinitialiseerd (altijd in de war met termen):
C++:
1
ID3Reader *pID3Reader;
Deze regel declareert een variabele. Het initialiseert geen object en zeker geen klasse. Ik denk dat je er goed aan doet toch de termen uit je hoofd te leren B) .

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

En terwijl je dat doet, bedenk dan dat het "class" of "klasse" is, maar iig niet "classe" ;)

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.


  • AuC
  • Registratie: Januari 2003
  • Laatst online: 08-05 08:21
Verwijderd schreef op 11 oktober 2004 @ 13:53:
[...]


Deze regel declareert een variabele. Het initialiseert geen object en zeker geen klasse. Ik denk dat je er goed aan doet toch de termen uit je hoofd te leren B) .
Dat leren zou inderdaad niet verkeerd zijn. Ik vergeet ze steeds opnieuw... Toch maar eens wat meer aandacht aan bestenden zodat ik de termen iig weet. :+

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

Trouwens
Verwijderd schreef op 11 oktober 2004 @ 13:53:
[...]


Deze regel declareert definieert een variabele.
;)

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

Ohww ! Maar wat is dan het verschil tussen declareren en definieren ?
Ik heb het ooit ergens geleerd aan de hand van een struct:
- de opbouw van struct X heette z'n definitie
- de regel waar de variabele van type "struct X" werd aangemaakt heette de declaratie van de variabele.

Dat tweede staat bij nader inzien niet los van het eerste: ook de structuur van de variabele wordt op deze regel gegeven.

Ideetjes ?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

Declareren: "er bestaat een..."
Definieren: "hier is een..."
Ik heb het ooit ergens geleerd aan de hand van een struct:
- de opbouw van struct X heette z'n definitie
- de regel waar de variabele van type "struct X" werd aangemaakt heette de declaratie van de variabele.
Dat klopt niet helemaal, die 2 dingen staan weldegelijk los van elkaar.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// declaraties
struct S;
extern int eenVar;
void eenFunc ();

// definities
struct S
{
    int i;
};

int eenVar;

void eenFunc ()
{
    std::cout << "hoi" << std::endl;
}


Let op het "extern" bij variabelen. Als je de extern weglaat (waardoor het een [b]defintie wordt), en je stopt het in een header die je vanuit verschillende sourcefiles include, dan krijg je al gedefinieerde symbolen meldingen, omdat elke file z'n eigen definitie krijgt en dus ruimte reserveert voor de variabele. Een declaratie geeft echter alleen maar aan dat het ding bestaat.

[ Voor 26% gewijzigd door .oisyn op 11-10-2004 16:39 ]

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

Oh ja, externe variabelen, ik had die even vergeten. IIG snap & dank voor de uitleg.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

* curry684 trekt wat quotes uit de hoge hoed... ;)
curry684 schreef op 09 mei 2003 @ 13:45:
Ter verduidelijking:
• Declareren = roepen dat het ding bestaat
• Definieren = roepen dat het ding bestaat en bepaalde methods/properties heeft
• Implementeren = zorgen dat method x code bevat.
curry684 schreef op 04 augustus 2004 @ 00:16:
[...]

Je definieert een variabele maar eenmalig, en vervolgens moet je 'm in een andere sourcefile nog eens met extern declareren om hem te kunnen gebruiken :)
En met dank aan Van Dale:
de·cla·re·ren2 (wk.ww., zich ~)
1 zich over iets uitspreken

de·fi·ni·ë·ren (ov.ww.)
1 duidelijk omschrijven

im·ple·men·te·ren (ov.ww.)
1 (een plan) tot uitvoering brengen => verwezenlijken
2 [comp.] installeren, testen en in gebruik nemen van apparatuur, informatiesysteem, programmatuur en/of procedures => invoeren
:Y)

Professionele website nodig?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

Mwoa, ik vind "implementeren" een beetje dubieus. Bij gewone functies is een implementatie meteen de definitie, en voor een class zou je kunnen zeggen dat in een classdefinitie een functiedeclaratie staat, die je later definieert (implementeert). Ik zie het woord implementatie dan ook op een heel ander niveau, namelijk het algoritme of de methodiek die je gebruikt om een bepaald doel te bereiken. Zo kan ik bijvoorbeeld best nog geen implementatie voor een functie hebben, terwijl ie wel daadwerkelijk gedefinieerd is (meestal een lege body of een assertion oid, in de zin van: "dat moet ik nog doen")

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.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Die van Van Dale is wat dat betreft zuiverder op de korrel inderdaad: verwezenlijken insinueert dat je een methode overhoudt die datgene doet wat je naar aanleiding van z'n definitie van hem mag verwachten. Stubs doen dat niet, en pure virtuals ook niet die je verplicht moet implementeren in een derived class voordat je kunt instantieren (hoezo vakjargon :P )

Professionele website nodig?


  • Hermarcel
  • Registratie: April 2003
  • Niet online
SWfreak schreef op 10 oktober 2004 @ 22:38:
Een get van 4 heeft dus een buffer van minstens 4 chars nodig...
Vier? Ik dacht vijf. Vier karakters en een "sluitnul".

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Vrijbuiter schreef op 11 oktober 2004 @ 17:37:
[...]

Vier? Ik dacht vijf. Vier karakters en een "sluitnul".
Jup, daar heb je gelijk in.
Je moet altijd ruimte vrij houden voor een "sluitnul" om het zo maar te zeggen, tenminste zo heb ik het geleerd ;)

Blog [Stackoverflow] [LinkedIn]


Verwijderd

Nog een van mij:
- Declaratie gaat over bestaande feiten
- Definitie gaat over te verwezenlijken zaken
- Implementatie gaat over invulling van definities.

Definitie en implementatie liggen in elkaars verlengde; ze zijn extremen op 1 as.
Declaratie is een scope-fix, het tegenovergestelde van friend.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
De null-terminator is niet nodig, als je
1) precies weet hoeveel karakters je hebt
2) de str... functies vermijdt (strn... mag wel, daar geef je het exacte aantal mee)

Aan de andere kant, gebruik std::string en negeer het probleem.

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

Pagina: 1