Array notation for pointers

Viewed 57

I made a function that returns a pointer to a newly created matrix. Now I want this function to return an error code of type status_t instead of the pointer. To do this, another pointer level has to be added and the matrix has to be returned by reference. However, I can't understand why a segmentation error appears. Here is part of my working code (a) and my failed attempt (b):

(a)

int **create_matrix(size_t dimension) {
    int **p;
    size_t e;
    size_t h;

    if (dimension == 0)
        return NULL;

    for (h = 0; h < dimension; ++h) {
        if ((p[h] = malloc(dimension * sizeof(int))) == NULL) { 
            for (e = h; e >= 0; --e) {  
                free(p[e]);
                p[e] = NULL;
            } <-------- missing closing brace
            return NULL;
        }
    }
    return p;
}

(b)

status_t create_matrix(size_t dimension, int ***p) {
    size_t e;
    size_t h;

    if (p == NULL)
        return ERROR_NULL_POINTER;

    for (h = 0; h < dimension; ++h) {
        if (((*p)[h] = malloc(dimension * sizeof(int))) == NULL) { 
            for (e = h; e >= 0; --e) {  
                free((*p)[e]);
                (*p)[e] = NULL;
            } <-------- missing closing brace
            return ERROR_NO_MEMORY;
        }
    }
}

thanks!

1 Answers

(a) isn't exactly "working":

For one thing, it has more { than }, so it doesn't even compile. You probably forgot to terminate your outer for loop.

int ** p;
...
    if ((p[h]=...))

This dereferences p before it was initialized. Using the value of an uninitialized variable is undefined behavior. You need to assign something to p before you use it (probably by dynamically allocating another array).

To determine whether version (b) has the same issue, we'd have to see the calling code, but at a guess it's also UB.

There's another problem in the inner loop:

        for (e = h; e >= 0; --e)

e is a size_t, which is an unsigned integer type, so the condition e >= 0 is always true.

What compiler (and compiler options) are you using? With gcc -Wall -Wextra -pedantic I get warnings for both of these.

A fixed version would look like this:

int **create_matrix(size_t dimension) {
    int **p = calloc(dimension, sizeof *p);
    if (!p) {
        return NULL;
    }

    for (size_t i = 0; i < dimension; i++) {
        if (!(p[i] = calloc(dimension, sizeof *p[i]))) {
            while (i--) {
                free(p[i]);
            }
            free(p);
            return NULL;
        }
    }

    return p;
}

Version (b) can then be defined as

status_t create_matrix_2(size_t dimension, int ***p) {
    if (!p) {
        return ERROR_NULL_POINTER;
    }
    if (!(*p = create_matrix(dimension))) {
        return ERROR_NO_MEMORY;
    }
    return SUCCESS_OR_SOMETHING;
}

I'm not sure what you want to return for success; your version (b) is missing a return statement there.

Related