This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Double pointer usage "freeze"

Hello!

Iam currently working on a project with the XC2785X-104F Controller, uVision 4 and Keil C166 Compiler.
Within my code i have to work with matrices and several matrix calculations. Therefor iam working with double pointers, structs and 2 dimensional arrays.

######################### Code snippet ###################

#################################### matrix struct (incl col,row)

typedef struct { int row; int col; } MATHEAD;

typedef struct { MATHEAD head; double *matrix; } MATBODY;

typedef double **MATRIX;

#define Mathead(a) ((MATHEAD *)((MATHEAD *)(a) - 1))
#define MatRow(a) (Mathead(a)->row)
#define MatCol(a) (Mathead(a)->col)

############################################# struct to work with

typedef struct { MATRIX A, B, C; double var;

}structure;

############################################ func to "create" matrices

MATRIX mat_creat( row, col, type )
int row, col, type;
{ MATRIX A;

if ((A =_mat_creat( row, col )) != NULL) { return (mat_fill(A, type)); } else return (NULL);

return (A);
}

MATRIX _mat_creat( row, col )
int row, col;
{ MATBODY *mat; int i;

if ((mat = (MATBODY *)malloc( sizeof(MATHEAD) + sizeof(double *) * row)) == NULL) return NULL;//(mat_error( MAT_MALLOC ));

for (i=0; i<row; i++) { if ((*((double **)(&mat->matrix) + i) = (double *)malloc(sizeof(double) * col)) == NULL) return NULL;//(mat_error( MAT_MALLOC )); }

mat->head.row = row; mat->head.col = col;

return (&(mat->matrix)); //(& )
}

########################### main.c

structure test1;

// value for var
test1.var = 1.234;

// send data via uart to terminal
send_uart(test1.var); // works fine

// create a 2x1 matrix with unknown data
test1.A = mat_creat(2,1,UNDEFINED);

// fill matrix with values
test1.A[0][0] = 0x00; // <--------- causes uC-freeze at this point

// send data via uart to terminal
send_uart(test1.A[0][0]); // is not delivered
send_uart("TEST\n"); // is not delivered

########################## END Code snippet ##############################

If i comment that line out (// test1.A[0][0] = 0x00;) everything works fine.
If not, there is no error nor a warning from the compiler. Just a freeze on the uC.

In my eyes the error lies in the usage of the double pointer, but i can't find the mistake. Also tried the same code in eclipse with gnu c compiler and everything worked fine...

Does anybody know where the problem is?
Did anyone make similar experiences??

I hope someone can help me!

thank you!

Bye,
Josh

Parents
  • I'm not agreeing on this one. I normally don't want the base implementation to just have raw void* pointers that always have to be assigned to a pointer of a different type even for performing base-class functionality. I normally prefer the base class to have pointers GenericNode *prev,*next so the implementation can do all generic operations directly without an assign or type cast.

    So in the end, a type cast will then be needed first when upgrading from the base class element type into the specific type, assuming that the abstract data type is uniform, only containing objects of one single type.

    It's important to note that abstract container objects can sometimes be implemented with the assumption that all inserted objects contains any links needed. While it is also possible to create abstract container objects that instead allocate own memory to store links. The second alternative allows you to create a list of int and can work quite well with void* pointers but instead needs own memory allocations for each inserted object. The advantage is of course that a single object can be inserted into many lists. But the costs of such an implementation can be quite high. The list doesn't know the number of elements that may be added, so it can't just statically allocate these helper structures.

    Most of the time, I prefer abstract containers that assumes that inserted objects shares a common property, so they may look like:

    typedef struct {
        struct GenericNodeInfo links;
        MySpecificData xxx;
    } MySpecificNode;
    

    I normally fix type safety by something like:

    threadlist_add(Thread* t) {
        list_add(threads,(GenericNode*)t);
    }
    

    and the base class can directly work on the element:

    void list_add(GenericList* list,GenericNode *node) {
        if (!node || !list) {
            // naughty!
            return FALSE;
        }
        if (node->prev || node->next) {
            if (!list_unlink(node)) {
                // node seems to already be in a list - but not in our list...
                return FALSE;
            }
        }
        node->prev = list->tail;
        node->next = NULL;
        list->tail = node;
        if (!list->head) list->head = node;
        return TRUE;
    }
    

    Sometimes, I may extend the above by having the GenericNode object store a value in it representing type, and the container class store the same type. So an insert can complain if a list of "thread" gets an object that isn't of type "thread". Most of the time, this can be done by consuming a single byte (or smaller) since there seldom is a large number of types involved.

    But there is no own value in writing code without pointer type casts. The important thing is to reduce the risks of a normally educated developer from goofing up. Someone who really do want to do stupid things will always manage anyway.

Reply
  • I'm not agreeing on this one. I normally don't want the base implementation to just have raw void* pointers that always have to be assigned to a pointer of a different type even for performing base-class functionality. I normally prefer the base class to have pointers GenericNode *prev,*next so the implementation can do all generic operations directly without an assign or type cast.

    So in the end, a type cast will then be needed first when upgrading from the base class element type into the specific type, assuming that the abstract data type is uniform, only containing objects of one single type.

    It's important to note that abstract container objects can sometimes be implemented with the assumption that all inserted objects contains any links needed. While it is also possible to create abstract container objects that instead allocate own memory to store links. The second alternative allows you to create a list of int and can work quite well with void* pointers but instead needs own memory allocations for each inserted object. The advantage is of course that a single object can be inserted into many lists. But the costs of such an implementation can be quite high. The list doesn't know the number of elements that may be added, so it can't just statically allocate these helper structures.

    Most of the time, I prefer abstract containers that assumes that inserted objects shares a common property, so they may look like:

    typedef struct {
        struct GenericNodeInfo links;
        MySpecificData xxx;
    } MySpecificNode;
    

    I normally fix type safety by something like:

    threadlist_add(Thread* t) {
        list_add(threads,(GenericNode*)t);
    }
    

    and the base class can directly work on the element:

    void list_add(GenericList* list,GenericNode *node) {
        if (!node || !list) {
            // naughty!
            return FALSE;
        }
        if (node->prev || node->next) {
            if (!list_unlink(node)) {
                // node seems to already be in a list - but not in our list...
                return FALSE;
            }
        }
        node->prev = list->tail;
        node->next = NULL;
        list->tail = node;
        if (!list->head) list->head = node;
        return TRUE;
    }
    

    Sometimes, I may extend the above by having the GenericNode object store a value in it representing type, and the container class store the same type. So an insert can complain if a list of "thread" gets an object that isn't of type "thread". Most of the time, this can be done by consuming a single byte (or smaller) since there seldom is a large number of types involved.

    But there is no own value in writing code without pointer type casts. The important thing is to reduce the risks of a normally educated developer from goofing up. Someone who really do want to do stupid things will always manage anyway.

Children
No data