0

The pointers to max and min values are initialised exactly the same, yet there is some error which causes the min value to be set to some huge number (a value of memory adress or maximum possible value maybe?). My question is - how is that possible and what can I do to fix it? I will be grateful for your help.

#include <stdio.h>

int row_stats(int(*ptr)[5], int width, int height, int row_id, int** max, int** min, float** avg)
{
    *max = &ptr[row_id][0];
    for(int i=0;i<width;i++)
    {
        if(ptr[row_id][i]>**max)
        {
            *max = &ptr[row_id][i];
        }
    }

    *min = &ptr[row_id][0];
    for(int i=0;i<width;i++)
    {
        if(ptr[row_id][i]<**min){
            *min = &ptr[row_id][i];
        }
    }
    // At this point, the value of **min is correct and equal to 16
    *avg = &ptr[row_id][0]; // I know the types are conflicting here but if I delete it, the max and avg values stop showing.
    int sum = 0;
    for(int i=0;i<width;i++)
    {
        sum = sum+ptr[row_id][i];
    }
    **avg = sum/width;

}
int main() {
    int* max_ptr;
    int* min_ptr;
    float* avg_ptr;
    int a[5][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};

    row_stats(a,5,5,3,&max_ptr,&min_ptr,&avg_ptr);
    printf("MAX: %d\n", *max_ptr); //here the value pointed by max_ptr is correct (20)
    printf("MIN: %d\n", *min_ptr); //here the value pointed by min_ptr is 1099956224
    printf("AVG: %f\n", *avg_ptr);
    return 0;
}
  • 1
    Time to learn how to use a [*debugger*](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) and how to use it to step through the code statement by statement while monitoring variables and their values. – Some programmer dude Sep 11 '22 at 11:13
  • I debugged it and that's how i know the values at each step, but I don't understand why suddenly it changed after leaving the row_stats() function – kazimierz___tetmajer Sep 11 '22 at 11:14
  • 2
    `**avg = sum/width;` so you overwrite an `int` value with the byte representation of a `float` and are confused about the results? In that case you should rethink the whole approache of having `*avg = &ptr[row_id][0];` in the first place (and the ensueing *undefined behavior* that mess causes) – UnholySheep Sep 11 '22 at 11:15
  • "Draw" the array and all pointers on paper. Draw pointers as arrows, and erase/redraw them as you modify pointers in your code. Do all pointers end up pointing somewhere valid? – Some programmer dude Sep 11 '22 at 11:15
  • 1
    With the array that you pass into the function `*min` and `*avg` will always refer to the same array element. Which is obviously a problem, since you overwrite the value at the end of the function – UnholySheep Sep 11 '22 at 11:18
  • And if the compiler is complaining about mismatching types, perhaps you should do something about it? In this case the compiler really knows better than you. Why do you even need something like `*avg = &ptr[row_id][0]`? What problem is that supposed to solve? Who told you to use such a thing? Perhaps you're misunderstanding hoe emulating pass by reference in C works? – Some programmer dude Sep 11 '22 at 11:19
  • I'd say you don't need or want any double pointers here. In `main`, why are you using pointers for `min_ptr`, `max_ptr`, and `avg_ptr`? I would use `int min, max;` and `float avg;`. Then have `row_stats` accept `int *` and `float *`. – Steve Summit Sep 11 '22 at 12:16
  • 1
    Not your problem, but: As a general rule, unless you have special requirements, please get in the habit of always using `double` for floating-point values, not `float`. – Steve Summit Sep 11 '22 at 12:20

2 Answers2

2

You seem to be struggling with pointers. For example, if you want to return the average as a float parameter in a function, then you reserve the float variable and pass its address like this

void calc_avg(float *avg_ptr)
{
    int sum = 49;
    int width = 5;
    *avg_ptr = ((float)sum) / width; 
}

int main()
{
    float avg;
    calc_avg(&avg);
    printf("AVG: %f\n", avg);
    return 0;
}

Also, the following equation will be calculated in integer arithmetic, and as a result, will loose the fraction part:

 **avg = sum/width;

You need to change it to:

 *avg_ptr = ((float)sum) / width;

You can do similar fixes for min and max.

Sami Iqneibi
  • 175
  • 5
1

In the function the int pointers can be set to point to array elements but there isn't a valid float for the float pointer.
The average could be returned.

#include <stdio.h>

float row_stats(int(*ptr)[5], int width, int height, int row_id, int** max, int** min)
{
    *max = &ptr[row_id][0];
    for(int i=0;i<width;i++)
    {
        if(ptr[row_id][i]>**max)
        {
            *max = &ptr[row_id][i];
        }
    }

    *min = &ptr[row_id][0];
    for(int i=0;i<width;i++)
    {
        if(ptr[row_id][i]<**min){
            *min = &ptr[row_id][i];
        }
    }
    // At this point, the value of **min is correct and equal to 16
    // *avg = &ptr[row_id][0]; // I know the types are conflicting here but if I delete it, the max and avg values stop showing.
    int sum = 0;
    for(int i=0;i<width;i++)
    {
        sum = sum+ptr[row_id][i];
    }
    // **avg = sum/width;
    return (float)sum/width;
}
int main() {
    int* max_ptr;
    int* min_ptr;
    float avg;
    int a[5][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};

    avg = row_stats(a,5,5,3,&max_ptr,&min_ptr);
    printf("MAX: %d\n", *max_ptr); //here the value pointed by max_ptr is correct (20)
    printf("MIN: %d\n", *min_ptr); //here the value pointed by min_ptr is 1099956224
    printf("AVG: %f\n", avg);
    return 0;
}

Pass the address of memory defined in main:

#include <stdio.h>

void row_stats(int(*ptr)[5], int width, int height, int row_id, int** max, int** min, float *avg_ptr)
{
    *max = &ptr[row_id][0];
    for(int i=0;i<width;i++)
    {
        if(ptr[row_id][i]>**max)
        {
            *max = &ptr[row_id][i];
        }
    }

    *min = &ptr[row_id][0];
    for(int i=0;i<width;i++)
    {
        if(ptr[row_id][i]<**min){
            *min = &ptr[row_id][i];
        }
    }
    // At this point, the value of **min is correct and equal to 16
    // *avg = &ptr[row_id][0]; // I know the types are conflicting here but if I delete it, the max and avg values stop showing.
    int sum = 0;
    for(int i=0;i<width;i++)
    {
        sum = sum+ptr[row_id][i];
    }
    // **avg = sum/width;
    *avg_ptr = (float)sum/width;
}
int main() {
    int* max_ptr;
    int* min_ptr;
    float avg = 0.0;
    int a[5][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};

    row_stats(a,5,5,3,&max_ptr,&min_ptr, &avg);
    printf("MAX: %d\n", *max_ptr); //here the value pointed by max_ptr is correct (20)
    printf("MIN: %d\n", *min_ptr); //here the value pointed by min_ptr is 1099956224
    printf("AVG: %f\n", avg);
    return 0;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16
  • Thank you for your answer, now it makes sense to me, but is there a way for the average to be changed without returning it from row_stats()? I am supposed to return something else in this function so I have to figure out how to change the average via pointers. Do you have any tips? – kazimierz___tetmajer Sep 11 '22 at 12:02