简体   繁体   中英

C++ “Bus error: 10” and working with pointers

I'm doing a Data Structures exercise and I have been blocked since yesterday with a bus error, which I reckon is because I'm doing bad things with the memory. But I cannot figure out what exactly.

These are the requirements that I have established for the practice:

  • able to add a product (any way will do) to the list
  • able to retrieve the product in the list at the current position (next, prev, moveToStart, moveToEnd… there's cursor pointer, called "actual" here)
  • any changes I do to the retrieved product should be updated in the data structure (ie. list::retrieve(*product), product->visits++)

This is the code that I have. Apologies about the var names, I have to do it in spanish and therefore names are in spanish.

class producto { // My product
public:
    string marca;
    double precio;
    int visitas;
    int compras;

    producto () {}
    producto (string M, double P, int V = 0, int C = 0) : marca(M), precio(P), visitas(V), compras(C) {}
};

class nodo {
public:
    producto valor; // value
    nodo *siguiente; // next
    nodo *anterior; // prev

    nodo (producto P, nodo *A = NULL, nodo *S = NULL) : valor(P), anterior(A), siguiente(S) {}
};

class lista { 
private: 
    nodo *inicio;
    nodo *final;
    nodo *actual;

public: 
    lista();
    bool esta_vacia(); // is empty?
    bool es_final(); // is the end?
    int insertar(producto p); // insert given p
    void moverPrincipio(); // "move to beginning"
    void siguiente(); // "next"
    void imprimir(); // "print"
    int leer(producto *p); // read, return 0 or 1 if successful, return product by ref
};

lista::lista() {
    this->inicio = NULL;
    this->final = NULL;
    this->actual = NULL;
}

bool lista::esta_vacia() {
    return (this->inicio == NULL);
}

bool lista::es_final() {
    return (this->actual == NULL);
}

void lista::moverPrincipio() {
    this->actual = this->inicio;
}

void lista::siguiente() {
    if(!this->es_final()) {
        this->actual = this->actual->siguiente;
    }
}

void lista::imprimir() {
    int i = 1;
    producto *p;
    this->moverPrincipio();

    while(!this->es_final()) {
        if(this->leer(p) == 0) {
            cout << i << ".- ##" << p->marca << "##, Views ##" << p->visitas << "##\n";
            p->visitas++;
            i++;
            this->siguiente();
        }
    }
}

int lista::leer(producto *p) {
    if(this->actual != NULL) {
        *p = this->actual->valor;

        return 0;
    } else {
        return 1;
    }
}

int lista::insertar(producto p) {
    if(this->esta_vacia()) {
        nodo *tmp = new nodo(p);
        this->inicio = tmp;
        this->final = this->inicio;
    } else {
        nodo *tmp = new nodo(p, this->final);
        this->final->siguiente = tmp;
        this->final = tmp;
    }

    return 0;
}

I have removed unnecessary code. This is how I'm using it (and failing miserably):

lista *productos = new lista();

productos->insertar(producto("Shoes", 19.90));
productos->insertar(producto("Socks", 25.00));

// I should expect views = 0
productos->imprimir();

// But now, views = 1
productos->imprimir();

Upon execution, the only thing I get is "Bus error: 10" when doing imprimir ("print"), the first time. Insertion works without errors (but something could be wrong there too).

My idea is to hold the product inside the node, and give a reference to its location when returning it, so that any changes are reflected there too (for example, increase the view or purchase counter of a retrieved element, reflects the change when reading the list later).

I'd be extremely thankful if someone could point out the mistakes I'm doing here.

Thanks!!

UPDATE Here's a compilable example .

You pass a pointer to lista::leer and you want to write a value to it. You will be writing in unallocated memory. Probably, what you wanted was a pointer to the actual element.

First of all, you need to modify the signature:

int lista::leer(producto **p);

note the double star, since we will be writing the pointer itself.

Then, you have to assign a pointer to actual->valor to it in lista::leer :

*p = &(this->actual->valor);

Finally, you have to pass a pointer to p in lista::imprimir :

 if(this->leer(&p) == 0) {
     // ...
 }

Alternatively, you might modify lista::leer to return a pointer and check if it is nullptr / NULL .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM