-1

In the example below in the function "Highest Number" it takes a pointer to an integer and sorts through the array until it finds the highest number ranging from the sentinel value INT_MIN, to the biggest number in the array. However, using the "sizeof" function on pointers passed as function parameters does not seem to work. How can I properly find the highest number in the array given the array is passed to the function "Highest Number" through a parameter.

#include <stdio.h>
#include <stdlib.h>
int HighestNumber(int* array)
{
    int highest = INT_MIN;
    for(size_t x = 0; x < sizeof(array) / sizeof(array[0]); x++)
        if(array[x] > highest)
            highest = array[x];
    return highest;
}
int main()
{
    int *array = (int*)malloc(4*sizeof(int));
    array[0] = 66;
    array[1] = 552;
    array[2] = -17;
    array[3] = 1000;
    printf("%d", HighestNumber(array));
    return 0;
}
Rezno
  • 1
  • 3
  • 5
    The `sizeof` trick doesn't work on pointers! If applied to pointers you get the (truncated) ratio between the size of a pointer, which is always the same, no matter how large your array is, and the size of a single element in that array. – Aconcagua Feb 16 '23 at 13:11
  • possible other dups: https://stackoverflow.com/questions/5493281/c-sizeof-a-passed-array https://stackoverflow.com/questions/25680014/find-the-size-of-integer-array-received-as-an-argument-to-a-function-in-c – mch Feb 16 '23 at 13:56

4 Answers4

2

The function parameter array has the pointer type int *.

int HighestNumber(int* array);

So the expression sizeof(array) / sizeof(array[0]) is equivalent to expression sizeof( int * ) / sizeof( int ) and yields usually either value 2 or 1 dependent of the sizes of pointers and integers.

You need explicitly to pass the number of elements in the array As for example

int HighestNumber(int* array, size_t n );

Pay attention to that the user can pass 0 for the parameter n. In this case using your approach to the function definition the function can return an invalid value.

The function should be declared and defined the following way. As the function does not change the processed array then the first parameter should have the qualifier const.

size_t HighestNumber( const int *array, size_t n )
{
    size_t highest = 0;

    for ( size_t i = 1; i < n; i++ )
    {
        if ( array[highest] < array[i] )
        {
            highest = i;
        }
    }

    return highest;
}

And the function is called like

printf("%d\n",  array[HighestNumber(array, 4 )] );

or

size_t highest = HighestNumber(array, 4 );

printf( "The largest number is %d at the position %zu\n",
        array[highest], highest);

As you can see the advantage of such function definition is that you can also determine the position where the highest element is stored in the array.

Pay attention to that you need to free the dynamically allocated memory.

free( array );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    `size_t highestNumber(...)` – indeed nice addition, though I'd consider returning a pointer yet superior (with `NULL` possibly indicating no maximum for `n == 0`), so I'd mention, too. – Aconcagua Feb 16 '23 at 13:40
1

The moment you pass array to the function HighestNumber(), you lose the size information of the array. This is called an array-to-pointer decay.

To the function HighestNumber() it only sees a pointer, without knowing anything about the array.

Consider pass the array size as the second parameter to the function, such as

int HighestNumber(int* array, size_t num) {
    // ..
}
aafulei
  • 2,085
  • 12
  • 27
1

The sizeof trick doesn't work on pointers!

If applied to pointers you get the (truncated) ratio between the size of a pointer, which is always the same, no matter how large your array is, and the size of a single element in that array, so in your case with int* most likely either 2 (64-bit system, typically 8-byte pointers, 4-byte int) or 1 (32-bit system, typically 4-byte pointers, 4-byte int), though other systems can yield yet other values, but still not the required one (apart from accidentally matching array size...).

To use sizes on array you need to pass it explicitly by another parameter:

int highestNumber(size_t length, int* array)
{
    int highest = INT_MIN;
    while(length--)
    {
        if(*array > highest)
        {
           highest = *array;
        }
        ++array;
    }
    return highest;
}

while you can then apply the sizeof trick on the array being passed to:

int array[4];
// assign values to

// array has not yet decayed to pointer, thus you can do:
int highest = highestNumber(sizeof(array)/sizeof(*array), array);

However in your example you use a dynamically allocated array – these only can be assigned to pointers, thus there's no way around tracking the size explicitly:

size_t length = 4;
int* array = malloc(length * sizeof(*array));
// assign values
int highest = highestNumber(length, array);

Final note: You might as well use the length/size as second parameter, of course; having it as first would allow for:

int highestNumber(size_t length, int array[length]);

which is fully equivalent, as for the outermost dimension an explicitly specified array size is ignored and the parameter still remains a pointer (note that this does not apply for further dimensions), but this declaration expresses more explicitly what the function actually expects as arguments.

Edit (stealing from Vlad from Moscow's answer):

As you do not (intend to) modify the array within the function it is a good choice to accept a pointer to const – this allows to use both non-const and const arrays while the original function signature excludes the latter without need:

int highestNumber(size_t length, int const* array)
int highestNumber(size_t length, int const array[length]);
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • Definition of `int highestNumber()` does not return anything. – chux - Reinstate Monica Feb 16 '23 at 16:31
  • 2
    Somewhat humorous for [Aconcagua](https://en.wikipedia.org/wiki/Aconcagua) to discuss _highest_. – chux - Reinstate Monica Feb 16 '23 at 16:33
  • 1
    @chux-ReinstateMonica Indeed *'stored'* is a miswording – fixed, thanks for the hint. The other one – well, west vs. east const-ers ;) Anywhere else `const` refers to what's left from it, and there's solely this exceptional case – east-consting is more consistent in this respect and, by the way, seems more common in C++ code, though still not a majority... – Aconcagua Feb 23 '23 at 16:37
0

An array decays to a pointer in function parameters. sizeof on a pointer then returns the size of the pointer, and not the pointed to data.

Possible solution:

Pass the size of the array as the second argument.

int HighestNumber(int* array, size_t size) {
    //...
}
Harith
  • 4,663
  • 1
  • 5
  • 20
  • 1
    Sentinel is actually problematic as it reduces the range of legally usable values in the array (if still used the algorithm aborts prematurely), thus in given case less recommendable unless otherwise assured it won't be used. *If* using a sentinel `INT_MIN` is a nice choice as it would indicate *no minimum found* (array of size 0) without needing any change and additionally it makes (in two's complement) positive and negative range equally sized ;) – Aconcagua Feb 16 '23 at 13:37