1

I'm having some issues with C.

I was tasked with this assignment:

Create a dynamically allocated matrix (max 5x5), let the user fill in the values, then send it to a function along with an unallocated array (1D) which will be used to store all values of the matrix that are lower than the average of each row. The 1D array should be defined in the main function and allocated inside the function that finds the desired elements.

This was going fine, I made my matrix, I sent it to the aforementioned function, but I could not change the values of the newly allocated 1D array.


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

int lower_than_average(int **matrix, int **p, int m, int n) {
    int i, j, sum;
    float average;
    int count = 0, counter = 0;
    for (i = 0; i < m; i++) {
        sum = 0;

        for (j = 0; j < n; j++) sum += matrix[i][j];
        average = (float)sum / n;

        for (j = 0; j < n; j++){
            if (matrix[i][j] < average) count++;
        }
    }

    *p = (int*)malloc(count * sizeof(int));

    for (i = 0; i < m; i++) {
        sum = 0;
        for (j = 0; j < n; j++) sum += matrix[i][j];
        average = (float)sum / n;
        for (j = 0; j < n; j++) {
            if (matrix[i][j] < average) *p[counter++] = matrix[i][j];
        }
    }

    printf("\n\n");

    return(count);
}

void print_matrix(int **matrix, int m, int n) {
    int i, j;
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n\n");
    }
}

int main(void) {
    int m, n, **matrix, *elements_a = NULL;
    int i, j, elements_a_size;

    do {
        printf("Enter the number of rows and columns [max 5x5]: ");
        scanf("%d %d", &m, &n);
    } while (n > 5 || n < 0 || m > 5 || m < 0);

    matrix = (int**)malloc(m * sizeof(int*)); // Alokacija redaka

    /*

        X | <empty>
        X | <empty>
        X | <empty>
        X | <empty>

    */

    for (i = 0; i < m; i++) matrix[i] = (int*)calloc(n, sizeof(int)); // Alokacija stupaca

    /*

        X | Y Y Y Y Y Y
        X | Y Y Y Y Y Y
        X | Y Y Y Y Y Y
        X | Y Y Y Y Y Y

    */

    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            printf("Enter [%d][%d] element: ", i, j);
            scanf("%d", &matrix[i][j]);
        }
    }

    printf("\n\n");

    print_matrix(matrix, m, n);

    elements_a_size = lower_than_average(matrix, &elements_a, m, n);

    printf("\nElements of rows smaller than the row average value: ");
    for (i = 0; i < elements_a_size; i++) printf("%d ", elements_a[i]);

    for (i = 0; i < m; i++) free(matrix[i]);
    free(matrix);

    return 0;
}

For the input: 3 3 then 1 2 3 4 5 6 7 8 9 It outputs literally nothing.

**p and *p[0] 

instead of

*p[counter++]

it outputs this: 7 -2467754 -2467754

What am I doing wrong? I thought the allocation was correct and that I could access *(p + n) but it doesn't do anything...

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • 1
    `*p[counter++]` Precedence bug here. `[]` has higher precedence than `*`. You end up with int** arithmetic which was not the intention. – Lundin Aug 23 '18 at 13:21
  • Why use a double pointer (`**p`) for a 1D matrix? A regular pointer to `int` will suffice. – Susmit Agrawal Aug 23 '18 at 13:21
  • Try `(*p)[counter++]` – KamilCuk Aug 23 '18 at 13:21
  • You forgot to `free(p)` or `free(elements_a)`. – KamilCuk Aug 23 '18 at 13:22
  • Also see [Correctly allocating multi-dimensional arrays](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) for how to do this proper. – Lundin Aug 23 '18 at 13:22
  • Oh wow, that worked. Thanks for the help! –  Aug 23 '18 at 13:23
  • @SusmitAgrawal Because he wants to return the allocated address to the caller. – Lundin Aug 23 '18 at 13:23
  • And I was told to use a double pointer to change the value of pointers from inside a function call. –  Aug 23 '18 at 13:24
  • 1
    @MatijaNovosel Yeah the double pointer for `p` is fine if you need to return the address to the caller. However, an array of pointers is not a 2D array, which is explained in the link I posted. – Lundin Aug 23 '18 at 13:25
  • @MatijaNovosel Anyway, if `(*p)[counter++]` solved the problem I think we can close this question as "simple typo". Bugs like these are fairly common. – Lundin Aug 23 '18 at 13:25
  • @Lundin Alright thanks a bunch for helping :) –  Aug 23 '18 at 13:26
  • There's no such thing as unallocated array. *The 1D array should be defined in the main function and allocated inside the function that finds the desired elements* is pure nonsense. You define a *pointer* in the main function, not an array. Many people erroneously think pointers and arrays are the same thing. It would be really sad if the authors of your course are among those people. – n. m. could be an AI Aug 23 '18 at 14:53
  • What happens if the user specifies a matrix size of 0x0? – Tim Randall Aug 23 '18 at 15:22

2 Answers2

4

You have to change the line

 *p[counter++] = matrix[i][j];

by

 (*p)[counter++] = matrix[i][j];

because [] take priority over *

See : Operator priorities in c/c++

Yanis.F
  • 612
  • 6
  • 18
-1

The easiest way may be to create a one dimensional array that is big enough to store all the elements in an array, and then populate the 1D array as you go through each row of the 2D array. Once you have gone through the 2D array you copy the values that you need to an array that is just long enough and return.

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

int lower_than_average(int **matrix, int **p, int m, int n) {
    int i, j, sum;
    float average;
    int count = 0, counter = 0;

    int *buff;
    buff = (int *)malloc(m * n * sizeof(int));
    if (NULL == buff)
    {
        return (-1);  //return negative value to show an error occurred
    }

    for (i = 0; i < m; i++) {
        sum = 0;

        for (j = 0; j < n; j++) sum += matrix[i][j];
        average = (float)sum / n;

        for (j = 0; j < n; j++){
            if (matrix[i][j] < average) 
            {
                buff[count] = matrix[i][j];
                count++;
            }
        }
    }

    *p = (int*)malloc(count * sizeof(int));
    if(NULL == *p)
    {
        free(buff);
        return (-1);  //return negative value to show an error occurred
    }
    memcpy(*p, buff, count*sizeof(int));
    free(buff);

    printf("\n\n");

    return(count);
}

void print_matrix(int **matrix, int m, int n) {
    int i, j;
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n\n");
    }
}

int main(void) {
    int m, n, **matrix, *elements_a = NULL;
    int i, j, elements_a_size;

    do {
        printf("Enter the number of rows and columns [max 5x5]: ");
        scanf("%d %d", &m, &n);
    } while (n > 5 || n < 0 || m > 5 || m < 0);

    matrix = (int**)malloc(m * sizeof(int*)); // Alokacija redaka

    /*

        X | <empty>
        X | <empty>
        X | <empty>
        X | <empty>

    */

    for (i = 0; i < m; i++) matrix[i] = (int*)calloc(n, sizeof(int)); // Alokacija stupaca

    /*

        X | Y Y Y Y Y Y
        X | Y Y Y Y Y Y
        X | Y Y Y Y Y Y
        X | Y Y Y Y Y Y

    */

    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            printf("Enter [%d][%d] element: ", i, j);
            scanf("%d", &matrix[i][j]);
        }
    }

    printf("\n\n");

    print_matrix(matrix, m, n);

    elements_a_size = lower_than_average(matrix, &elements_a, m, n);

    printf("\nElements of rows smaller than the row average value: ");
    for (i = 0; i < elements_a_size; i++) printf("%d ", elements_a[i]);

    printf("\n");  //a new line so the prompt isn't on the same line as the output

    for (i = 0; i < m; i++) free(matrix[i]);
    free(matrix);
    free(elements_a);  //also free the memory dynamically allocated in the function!

    return 0;
}

And the results:

Enter the number of rows and columns [max 5x5]: 3
3
Enter [0][0] element: 1
Enter [0][1] element: 2
Enter [0][2] element: 3
Enter [1][0] element: 4
Enter [1][1] element: 5
Enter [1][2] element: 80
Enter [2][0] element: 12
Enter [2][1] element: 2
Enter [2][2] element: 1


1 2 3 

4 5 80 

12 2 1 




Elements of rows smaller than the row average value: 1 4 5 2 1
Spoonless
  • 561
  • 5
  • 14