Я изучаю C, и у меня только что было упражнение по написанию функции, которая проверяет нижнюю из двух чисел с плавающей запятой. Итак, я подумал, что я мог бы использовать указатель и также вернуть указатель на меньшее значение — в противном случае я просто мог бы использовать значения и вернуть меньшее значение.
double* pointer_min_value(double* first, double* second){
return *first > *second ? second : first;
}
double calc_min_value(double first, double second){
return first > second ? second : first;
}
int main() {
printf("Enter two numbers to define the minimum!n");
double first, second;
scanf("%lf%lf", &first, &second);
printf("The lower value is %lf", *pointer_min_value(&first, &second));
printf("The lower value is %lf", calc_min_value(first, second));
return 0;
}
они оба работают, но что может иметь больше смысла? следует ли мне использовать указатель только в том случае, если я хочу изменить значение (я имею в виду, я не должен изменять какие-либо параметры в функции «получить наименьшее число»), или было бы лучше в любом другом представлении (ресурсы, производительность , …).
3 ответа
Универсальность
Версия указателя менее универсальна.
Если два значения взяты из выражений, подобных в min_value(x + 13, 2 * y)
, вы не можете использовать версию указателя, поскольку ни x + 13
ни 2 * y
существуют как точки памяти, к которым можно указывать, только как временные значения.
Сюрпризы
Версия указателя может дать удивительные результаты в долгосрочной перспективе.
Если сейчас first
ниже чем second
, функция вернет указатель на first
. Если вы позже измените содержание first
переменная, значение результата также изменяется.
Если first
а также second
локальные переменные, объявленные внутри функции foo()
, и вы вернули pointer_min_value()
результат (указатель), то после выхода foo()
, переменные больше не существуют, и ваш результат указывает на мусорную память.
Некоторые украшения
думаю first < second ? first : second
немного читабельнее. Первое приходит первым.
Двойные проблемы
С плавающей точкой сложно. Что будет, если один из двойников будет NaN? Конечно, вы всегда можете сказать, что функция предполагает, что оба значения действительны, но вы тоже должны это учитывать.
Проблемы с указателем
Указатели также сложны. pointer_min_value(NULL, NULL)
вызовет УБ. Еще раз, добавление комментария «недопустимые значения NULL» — это нормально, но игнорирование этой возможности — нет.
Убедиться, что значения, передаваемые указателями, не изменятся
Можете добавить const
модификатор аргументов и возвращающее значение для этого, если вы имеете в виду это.
Соображения производительности
Передача большого аргумента по значению может быть плохой идеей; но двойники всего 8 байт — как указатели на архитектуре 86×64; указатели на 86×32 составляют 4 байта, поэтому вы можете сэкономить 8 байтов пространства стека с помощью pointer_min_value
. Но кого волнуют современные размеры оперативной памяти?
С другой стороны, указатели разыменования не бесплатны, поэтому calc_min_value
будет немного быстрее, но кого волнуют современные скорости ЦП / ОЗУ и размеры кеша?
Главное отличие
Единственное pointer_min_value
делает это calc_min_value
нет — он возвращает указатель. Почему это важно? Потому что вы можете изменить возвращаемое значение!
*pointer_min_value(&first, &second) = 0.0;
меняет меньшую единицу на 0,0. Это самая большая разница.
- 2
Ой, главное отличие, приятно .. Мне нравится!
— Матиас Бургер
- 3
Современные соглашения о вызовах проходят
double
s в регистрах (если параметров с плавающей запятой мало), что делает вопрос об их размере не слишком актуальным.— Руслан
Рекомендуется всегда передавать примитивные переменные по значениям. Указатели передачи следует зарезервировать для объектов, занимающих больше места, таких как массивы или структуры. Это также делает функции и их вызовы более удобочитаемыми. Если вы придираетесь к мелочам, вы также можете привести аргумент, что что-то вроде int
обычно использует 4 байта памяти, в то время как указатель обычно использует 8, поэтому функция требует немного больше памяти.
Обратите внимание, что использование
const
ссылки избегают этих сюрпризов и дают вам ценить семантика, при этом технически все еще используя указатели под капотом. Это например то, чтоstd::min()
делает.— Г. Сон
поэтому используя простое значение /
double
была бы более «правильная» / лучшая версия в этом случае?— Матиас Бургер
@MatthiasBurger Да. Как правило, это зависит от предполагаемого использования функции, но я не могу представить убедительного варианта в пользу версии с указателями.
— Ральф Клеберхофф
@ G.Sliepen, это C, а не C ++. Хотя,
const
указатели по-прежнему актуальны.— Руслан