Error Pointer to pointer in c++!

Asked

Viewed 391 times

3

I created a Matrix class, to manipulate a matrix. In the class statement I have the following members (publicos):

class Matrix{
public:
    unsigned char **mat; //ponteiro para ponteiro de uchar
    int nRows; //numero de linhas
    int nCols; //numero de colunas da matriz
    Matrix(int nRows, int nCols); //construtor
    void putColumn(int *Col, int j); //metodo para adicionar colunas à matriz
}

In the constructor I start nRows and nCols and allocate memory to mat.

Matrix::Matrix(int rows, int cols)
//Construtor da classe que recebe número de linhas e número de colunas.
{
    nRows = rows;
    nCols = cols;
    mat = (unsigned char**)malloc(nRows*nCols*sizeof(unsigned char));
}

The matrix indices are arranged along memory sequentially, as if we had an array, and to access them would be something like:

unsigned char * p; 
p = mat[i] + j*nRows;//onde i = linha e j =coluna

Then I have a method to add columns to the matrix:

void Matrix::putColumn(int *Col, int j)
{
    unsigned char *p;
    p = *mat + j*nRows;//j é a coluna que pretendo adicionar
    //ou seja, coluna 1, 2, 3, 4 até completar a matriz
    memcpy(p,Col,nCols);
}

In the main function after creating a Matrix object, add a column to the matrix:

unsigned char *col;
col = (unsigned char*) malloc(nlinhas*sizeof(unsigned char));

for ( int i = 1; i <= nlinhas; i++){
    col[i] = i;
}
matrix.putColumn(col,0);

The problem here is that when executing this function (main) in the putColumn method of the Matrix I get the following error: Access Violation writing Location 0xcdcdcd. I’d appreciate it if someone could help me, thank you!

  • You are programming middle in C and middle in C++. You should choose a style and keep it. As you are using C++ you should not use malloc, memcpy, raw pointers and things like that. Even in C it shouldn’t do cast in the malloc. http://stackoverflow.com/q/605845/221800. I have trouble finding generic errors in full-pointer codes just by looking at them. It would be interesting to give better information or better, post something that we can execute and see what is happening: http://answall.com/help/mcve

  • Off you are mixing types. Your "Matrix" is created from unsigned char but when you insert columns you use int. On a 32bit architecture unsigned char will have 1 byte and the int 4 bytes...

  • @Luiz Vieira Even when inserting uchar columns it still gives error, so I deduced that the problem did not come from there.

  • 1

    Well, I don’t know what the main problem is, but inserting columns of integers into something allocated like char will give error as well. :)

  • 1

    Another thing that is "weird": you allocate the new column by multiplying by nlinhas (which, moreover, should not be nRows?), but the memcpy uses (correctly) nCols. Looks like you should allocate the new column from nCols.

  • @bigown I know I’m mixing languages, but it’s intentional. I think the malloc cast is mandatory for c++. When debugging the error appears in memcpy. I do not see what else I can edit, because that is what is essential, and I think that there is no lack of information in the code posted. I’m grinding my head a little bit with this, but I can’t solve the problem. Thanks for your help :)

  • @Luiz Vieira nRows is a member of my class, this part of the code corresponds to the main function and does not belong to the Matrix class. I used them just to know that they were the number of lines :) Imagine that after that and before Matrix.putColumn(col,0); I called the class constructor passing as arguments nLinhas and nColunas. : ) Thank you

  • 1

    But, Marco, if nlinhas has a different value than nCols, will give even error. Because out you allocate *col from nlinhas*sizeof(int) and inside you copy with memcpy(p,Col,nCols)!

  • @Luiz Vieira PS: I already changed the input of the columns to play and the error remains... When debugging the code gives error in memcpy. Then you’d have to have something like: memcpy(p,Col,nRows)?

Show 4 more comments

1 answer

5


In addition to the potential problems already mentioned in comments, you are using a pointer to pointer (**mat) to manipulate the data, only it was not properly initialized. So when you reference *mat the referenced memory area is not valid.

You don’t need to use a pointer to pointer, just have a simple pointer to unsigned char (and it is important to use the same type of data to avoid problems). Example C code, working:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char *mat; // Pointeiro simples, e não ponteiro para ponteiro
int nRows;
int nCols;

void putColumn(unsigned char *Col, int j)
{
    unsigned char *p;
    p = mat + j * nRows; // Aritmética de ponteiro, simples
    memcpy(p, Col, nCols);
}

int main(int argc, char* argv[])
{
    // Reproduzindo o seu construtor
    nRows = 10;
    nCols = 10;
    mat = (unsigned char*) malloc(nRows * nCols * sizeof(unsigned char)); // Alocação de ponteiro simples

    // Reproduzindo o seu main
    unsigned char *col;
    int nlinhas = 10; // Apesar da variável chamar "nlinhas", esse valor DEVERIA ser o mesmo definido em nCols!
    col = (unsigned char*) malloc(nlinhas * sizeof(unsigned char));

    for(int lin = 0; lin < 10; lin++)
    {
        for ( int i = 0; i < nlinhas; i++){
            col[i] = 65 + lin; // Para gravar os caracteres ASCII maiúsculos [A, B, C, ...]
        }
        putColumn(col, lin);
    }

    return 0;
}

The result of this example is the following (the variable was inspected via watch Visual Studio 2012, using mat,100 to limit the memory area display to 100 bytes):

inserir a descrição da imagem aqui

As I mentioned in comments, although you use a variable called nlinhas to set the size of the new column, it should be the same as the class property (nCols). For if it is smaller (change to int nlinhas = 5; in the example code), you will leave invalid data in memory:

inserir a descrição da imagem aqui

Note: And invalid data is only all the same (ýýýýý«) because I executed the compilation in DEBUG. In RELEASE the compiler does not automatic pre-initialization of memory areas and there will be what whether he was already on previous programme runs.

As in putColumn you force the copy with nCols, use a value greater than 10 (in this example) will not give problems.

If your intention with the code is to allow the creation of columns with partial data (as in the example, with nlinhas with a value of less than 5), it is good practice also to reset the total memory of each column using memset. This prevents a column from improperly retaining data from a previous update.

Note also that in its original code (main) you updated the new column from the index 1 (and C/C++ arrays and pointers are indexed from the 0):

for ( int i = 1; i <= nlinhas; i++){

In addition to not updating the first position of each column, when you were updating the last column the <= there would exceed the limit of the memory area reserved for your program, also causing problems of improper access.

  • 1

    Thank you very much for the help, excellent explanation :D thank you very much! Solved

Browser other questions tagged

You are not signed in. Login or sign up in order to post.