Nieuws:

Welkom, Gast. Alsjeblieft inloggen of registreren.
Heb je de activerings-mail niet ontvangen?

Auteur Topic: [Opgelost][ C++ ] Segmentatiefault bij returnen struct van functie  (gelezen 1225 keer)

Offline Joshua822

  • Lid
Hallo allemaal!

Ik heb een probleem: het volgende programma waar ik op het moment aan werk geeft een segmentatiefout maar ik zou helemaal niet weten waaraan dit ligt.

Dit is de code:

#include <iostream>
#include <string>
#include <assert.h>

using namespace std;

const unsigned int MAXIMUM_CARDS ( 100 );

struct single_card
{
    string question;
    string answer;
};

class vocabulary_cards
{
    private:
        single_card stack_of_cards [ MAXIMUM_CARDS ];
        unsigned int total_elements_used;
        unsigned int index_current_card;
       
    public:
        vocabulary_cards ( const single_card list [ ] );
        struct single_card & get_card ( );
        void right ( );
        void wrong ( );
        bool done ( );
};

vocabulary_cards::vocabulary_cards ( const single_card list [ ] )
{
    assert ( sizeof ( list ) / 8  <= 0 || sizeof ( list ) / 8  > MAXIMUM_CARDS );
   
    unsigned int number_of_elements;
    unsigned int index;

    number_of_elements = sizeof ( list ) / 8;
 
    for ( index = 0; index < number_of_elements; ++index )
        stack_of_cards [ index ] = list [ index ];
       
    total_elements_used = number_of_elements;
}

struct single_card & vocabulary_cards::get_card ( )
{
    return ( stack_of_cards [ index_current_card ] );
}

void vocabulary_cards::right ( )
{
    unsigned int index;
   
    for ( index = index_current_card; index < total_elements_used - 1; ++index )
       stack_of_cards [ index ] = stack_of_cards [ index + 1 ];
       
    --total_elements_used;
}

void vocabulary_cards::wrong ( )
{
    unsigned int index;
    single_card element_to_backup;
   
    element_to_backup.question = stack_of_cards [ index_current_card ].question;
    element_to_backup.answer = stack_of_cards [ index_current_card ].answer;
   
    for ( index = index_current_card; index < total_elements_used - 1; ++index )
        stack_of_cards [ index ] = stack_of_cards [ index + 1 ];
       
    stack_of_cards [ total_elements_used - 1 ].question = element_to_backup.question;
    stack_of_cards [ total_elements_used - 1 ].answer = element_to_backup.answer;
}

bool vocabulary_cards::done ( )
{
    if ( total_elements_used == 0 )
        return true;
    else
        return false;
}

int main ( )
{
    single_card questions_answers [ 5 ] = {
                                           { "A car", "Une voiture" },
                                           { "A cat", "Un chat" },
                                           { "An airplane", "Une avion" },
                                           { "A dog", "Un chien" },
                                           { "A glass of water", "Un verre d'eau" }
                                          };
                             
    vocabulary_cards test ( questions_answers );
   
    single_card current_card;
   
    cout << "Welcome to the vocabulary learning program! \n\n"
         << "Answer with the French translation of the given word: \n";

    current_card = test.get_card ( );
   
    cout << current_card.question << '\n';

    getline ( cin, current_card.answer );

    cin.get ( );
   
    return ( 0 );
}
Dit is de uitvoer in een terminalvenster:
Welcome to the vocabulary learning program!

Answer with the French translation of the given word:
Segmentatiefout
Deze lijn in int main ( ) is hoofdverdachte:
    current_card = test.get_card ( );Maar waarom deze lijn voor een segmentatiefout zorgt zou ik niet weten :(

Met Google kan ik ook niets vinden.

Weet iemand waaraan dit ligt en hoe ik het kan verhelpen? Alvast bedankt :)


« Laatst bewerkt op: 2010/10/23, 16:47:07 door Joshua822 »

Re: [ C++ ] Segmentatiefault bij returnen struct van functie
« Reactie #1 Gepost op: 2010/10/22, 22:42:45 »
Ik ben zo goed als 99% zeker er van dat het te maken heeft met die array. Als je die doorgeeft naar een functie, vervalt die tot een pointer en verliest die de gegevens over de lengte. sizeof(list) == sizeof(void*), dus.

Oplossing: http://libsylph.sourceforge.net/docs/class_sylph_1_1_array.html
I use a Unix-based system, that means I'll get laid as often as I have to reboot.
LibSylph
SeySayux.net

Offline Joshua822

  • Lid
Re: [ C++ ] Segmentatiefault bij returnen struct van functie
« Reactie #2 Gepost op: 2010/10/22, 23:26:53 »
Bedankt voor het antwoord.

Ik heb geprobeerd de assert-statements te verwijderen uit de constructor, maar 't heeft niet veel geholpen. Dit is niet echt verrassend omdat we geen pointer, maar een referentie, aan de functie geven, en een referentie niet meer is als een andere naam voor een variabele. En zelfs al mocht het het geval zijn dat de grootte van de pointer ( 4 bytes? ) wordt berekend, dan nog zou het programma in principe geen segmentatiefout, maar een gefaalde assertie moeten vermelden.

Het moet sowieso na deze lijn gebeuren:
    cout << "Welcome to the vocabulary learning program! \n\n"
         << "Answer with the French translation of the given word: \n";
want deze lijn kan ik nog op het scherm zien voor de segmentatiefout.

Daarom denk ik dat het iets te maken heeft met het returnen van de struct naar de caller. Maar mijn kennis is te klein om te weten hoe dat problemen zou kunnen veroorzaken.

Offline Joshua822

  • Lid
Re: [ C++ ] Segmentatiefault bij returnen struct van functie
« Reactie #3 Gepost op: 2010/10/22, 23:40:05 »
Nee, je hebt toch gelijk. Het schoentje wringt inderdaad in de constructor, bij het berekenen van het aantal elementen.

Maar wat ik nu niet snap: hoe komt dit als een referentie slechts een andere naam is voor een waarde? En hoe kan ik zorgen dat het berekenen van het aantal elementen wel werkt zonder extra verwarrende libraries te gebruiken?

Offline siegi

  • Lid
Re: [ C++ ] Segmentatiefault bij returnen struct van functie
« Reactie #4 Gepost op: 2010/10/22, 23:50:44 »
Het compileren van je code gaat perfect. Echter bij het uitvoeren krijg ik volgende foutmelding.
a.out: test.cpp:32: vocabulary_cards::vocabulary_cards(const single_card*): Assertion `sizeof ( list ) / 8 <= 0 || sizeof ( list ) / 8 > MAXIMUM_CARDS' failed.
Afgebroken

Offline Joshua822

  • Lid
Re: [ C++ ] Segmentatiefault bij returnen struct van functie
« Reactie #5 Gepost op: 2010/10/23, 00:09:31 »
@Siegi: dit komt door het assert-statement in de constructor van de class.

Dit assert-statement test of de expressie sizeof ( list ) / 8  <= 0 || sizeof ( list ) / 8  > MAXIMUM_CARDS ) waar is. Dit mag nooit zo zijn ( anders hebben we een groot probleem ). Als het dus waar is wordt het programma met jouw foutmelding afgesloten ( wat ook bij mij zou moeten gebeuren trouwens, maar goed ).

Waardoor dit komt kun je in de bovenstaande posts lezen.

Nu is de grote vraag dus: hoe kun je hierom heen werken?

Re: [ C++ ] Segmentatiefault bij returnen struct van functie
« Reactie #6 Gepost op: 2010/10/23, 13:00:30 »
In plaats van een C-array moet je een "slimme array" doorgeven.

Zoals deze: http://libsylph.sourceforge.net/docs/class_sylph_1_1_array.html

#include <iostream>
#include <string>
#include <assert.h>

#include <Sylph.h>

using namespace std;

struct Card {
    String question;
    String answer;
};

class VocabularyCards {
public:
    VocabularyCards(Array<Card>);
    Card& nextCard();
    void right();
    void wrong();
    bool done() const;
private:
    Array<Card> cardStack;
    idx_t index;
};

VocabularyCards::VocabularyCards( const Array<Card> list ) : cardStack(list), index(0) {}

Card& VocabularyCards::nextCard() {
    return cardStack[index];
}

void VocabularyCards::right() {
    cardStack = cardStack[range(1,-1)];
}

void VocabularyCards::wrong() {
    Card current = cardStack[index];
    Sylph::arraycopy(cardStack,1,cardStack,0,cardStack.length - 2);
    cardStack[-1] = current;
}

bool VocabularyCards::done() const {
    return cardStack.length == 0;
}

int SylphMain(Array<String>) {
    Array<Card> cards = {
                                           { "A car", "Une voiture" },
                                           { "A cat", "Un chat" },
                                           { "An airplane", "Une avion" },
                                           { "A dog", "Un chien" },
                                           { "A glass of water", "Un verre d'eau" }
                                     };
                             
    VocabularyCards test(cards);
   
    Card card;
   
    cout << "Welcome to the vocabulary learning program! \n\n"
         << "Answer with the French translation of the given word: \n";

    card = test.nextCard();
   
    cout << card.question << '\n';

    string answer;

    cin >> answer;

    cin.get();
   
    return 0;
}
I use a Unix-based system, that means I'll get laid as often as I have to reboot.
LibSylph
SeySayux.net

Offline Joshua822

  • Lid
Re: [ C++ ] Segmentatiefault bij returnen struct van functie
« Reactie #7 Gepost op: 2010/10/23, 16:46:44 »
Dit probleem is opgelost. ik heb de code zo herschreven:
#include <iostream>
#include <string>
#include <assert.h>

using namespace std;

const unsigned int MAXIMUM_CARDS ( 100 );

struct single_card
{
    string question;
    string answer;
};

class vocabulary_cards
{
    private:
        single_card stack_of_cards [ MAXIMUM_CARDS ];
        unsigned int total_elements_used;
       
    public:
        vocabulary_cards ( const single_card list [ ],
                           unsigned int list_size );
        single_card & get_card ( );
        void right ( );
        void wrong ( );
        bool done ( );
        void dump_data ( );
};

vocabulary_cards::vocabulary_cards ( const single_card list [ ],
                                     unsigned int list_size )
{
assert ( list_size > 0 || list_size < MAXIMUM_CARDS );

    unsigned int index;
 
    for ( index = 0; index < list_size; ++index )
        stack_of_cards [ index ] = list [ index ];
       
    total_elements_used = list_size;
   
}

single_card & vocabulary_cards::get_card ( )
{
    return ( stack_of_cards [ 0 ] );
}

void vocabulary_cards::right ( )
{
unsigned int index;

    for ( index = 0; index < total_elements_used - 1; ++index )
       stack_of_cards [ index ] = stack_of_cards [ index + 1 ];
       
    --total_elements_used;
}

void vocabulary_cards::wrong ( )
{
    unsigned int index;
    single_card element_to_backup;
   
    element_to_backup = stack_of_cards [ 0 ];
   
    for ( index = 0; index < total_elements_used - 1; ++index )
        stack_of_cards [ index ] = stack_of_cards [ index + 1 ];
       
    stack_of_cards [ total_elements_used - 1 ].question = element_to_backup.question;
    stack_of_cards [ total_elements_used - 1 ].answer = element_to_backup.answer;
}

bool vocabulary_cards::done ( )
{
if ( total_elements_used == 0 )
    return true;
else
    return false;
}

void vocabulary_cards::dump_data ( )
{
unsigned int index;

cout << "Data dump of an instance of class \"vocabulary_cards\" \n"
     << "\tType\t\tName\t\t\t\tValue \n";
   
for ( index = 0; index < total_elements_used; ++index )
    cout << "\tC++ string\tstack_of_cards [ " << index << " ].question\t"
         << stack_of_cards [ index ].question << '\n'
         << "\tC++ string\tstack_of_cards [ " << index << " ].answer\t"
         << stack_of_cards [ index ].answer << '\n';
cout << '\n';
}

int main ( )
{
single_card questions_answers [ 5 ] = {
                                   { "A car", "Une voiture" },
                                       { "A cat", "Un chat" },
                                       { "An airplane", "Une avion" },
                                       { "A dog", "Un chien" },
                                       { "A glass of water", "Un verre d'eau" }
                                      };
                         
vocabulary_cards test ( questions_answers, 5 );

single_card current_card;
string user_input;

    cout << "Welcome to the vocabulary learning program! \n\n"
         << "Answer with the French word of the given word: \n";
     
    while ( true )
    {
        current_card = test.get_card ( );
   
        cout << current_card.question << '\n';
    A
        getline ( cin, user_input );

        if ( ! test.done ( ) )
        {
            if ( current_card.answer.compare ( user_input ) != 0 )
                test.wrong ( );
            else
                test.right ( );
}
else
    break;
}

    cin.get ( );
   
    return ( 0 );
}
Nu werkt het wel. Het knelpunt is dus gewoon dat je niet de grootte van een referentie kunt krijgen met de sizeof functie.