Эта программа должна возвращать наибольшее число в массиве «массив». Но он возвращает только наибольшее число между первым и вторым числами. Почему?
#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;
}
Отвечает ли это на ваш вопрос? Как узнать размер массива (по указателю, указывающему на первый элемент массива)?
Возможные другие дубликаты: stackoverflow.com/questions/5493281/c-sizeof-a-passed-array stackoverflow.com/questions/25680014/…
В тот момент, когда вы передаете array функции HighestNumber(), вы теряете информацию о размере массива. Это называется распадом массива к указателю.
На функцию HighestNumber() она видит только указатель, ничего не зная о массиве.
Рассмотрите возможность передачи размера массива в качестве второго параметра функции, например
int HighestNumber(int* array, size_t num) {
// ..
}
Массив распадается на указатель в параметрах функции. sizeof на указателе возвращает размер указателя, а не указанный на данные.
Возможное решение:
Передайте размер массива в качестве второго аргумента.
int HighestNumber(int* array, size_t size) {
//...
}
Sentinel на самом деле проблематичен, поскольку он уменьшает диапазон допустимых значений в массиве (если он все еще используется, алгоритм прерывается преждевременно), поэтому в данном случае менее рекомендуется, если иное не гарантирует, что он не будет использоваться. Если использование дозорного INT_MIN является хорошим выбором, так как он укажет, что минимум не найден (массив размера 0) без необходимости каких-либо изменений, и, кроме того, он делает (в дополнении до двух) положительный и отрицательный диапазон одинакового размера;)
Параметр функции array имеет тип указателя int *.
int HighestNumber(int* array);
Таким образом, выражение sizeof(array) / sizeof(array[0]) эквивалентно выражению sizeof( int * ) / sizeof( int ) и обычно дает значение 2 или 1 в зависимости от размеров указателей и целых чисел.
Вам нужно явно передать количество элементов в массиве. Например,
int HighestNumber(int* array, size_t n );
Обратите внимание, что пользователь может передать 0 для параметра n. В этом случае при вашем подходе к определению функции функция может вернуть недопустимое значение.
Функция должна быть объявлена и определена следующим образом. Поскольку функция не изменяет обрабатываемый массив, то первый параметр должен иметь квалификатор 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;
}
И функция называется как
printf("%d\n", array[HighestNumber(array, 4 )] );
Или
size_t highest = HighestNumber(array, 4 );
printf( "The largest number is %d at the position %zu\n",
array[highest], highest);
Как вы можете видеть, преимущество такого определения функции заключается в том, что вы также можете определить позицию, в которой самый высокий элемент хранится в массиве.
Обратите внимание, что вам нужно освободить динамически выделенную память.
free( array );
size_t highestNumber(...)
— действительно хорошее дополнение, хотя я бы подумал о возврате указателя, но более высокого уровня (при этом NULL
, возможно, указывает на отсутствие максимума для n == 0
), поэтому я бы тоже упомянул.
Трюк sizeof не работает с указателями!
Применительно к указателям вы получаете (усеченное) соотношение между размером указателя, который всегда одинаков, независимо от того, насколько велик ваш массив, и размером одного элемента в этом массиве, поэтому в вашем случае с int* большинство скорее всего либо 2 (64-битная система, обычно 8-байтовые указатели, 4-байтовые int), либо 1 (32-битная система, обычно 4-байтовые указатели, 4-байтовые int), хотя другие системы могут давать и другие значения, но все еще не требуется (кроме случайного совпадения размера массива...).
Чтобы использовать размеры в массиве, вам нужно явно передать его другим параметром:
int highestNumber(size_t length, int* array)
{
int highest = INT_MIN;
while(length--)
{
if (*array > highest)
{
highest = *array;
}
++array;
}
return highest;
}
В то время как вы можете применить трюк sizeof к передаваемому массиву:
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);
Однако в вашем примере вы используете динамически выделенный массив - они могут храниться только в указателях, поэтому нет возможности явно отслеживать размер:
size_t length = 4;
int* array = malloc(length * sizeof(*array));
// assign values
int highest = highestNumber(length, array);
Последнее замечание: конечно, вы можете использовать длину/размер в качестве второго параметра; наличие его в качестве первого позволит:
int highestNumber(size_t length, int array[length]);
Что полностью эквивалентно, так как для самого внешнего измерения явно указанный размер массива игнорируется, и параметр по-прежнему остается указателем (обратите внимание, что это не применяется для дальнейших измерений), но это объявление более явно выражает то, что функция фактически ожидает в качестве аргументов.
Редактировать (украл у Влада из Москвы ответ):
Поскольку вы не (намереваетесь) изменять массив внутри функции, то хорошим выбором является принятие указателя на const — это позволяет использовать как неконстантные, так и константные массивы, в то время как исходная сигнатура функции исключает последний без необходимости:
int highestNumber(size_t length, int const* array)
int highestNumber(size_t length, int const array[length]);
Определение int highestNumber() ничего не возвращает.
Несколько забавно для Аконкагуа обсуждать на высшем уровне. 😉
Трюк sizeof не работает с указателями! Применительно к указателям вы получаете (усеченное) соотношение между размером указателя, который всегда одинаков, независимо от того, насколько велик ваш массив, и размером одного элемента в этом массиве.