Минимум два числа с плавающей запятой

Я изучаю 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 ответа
3

Универсальность

Версия указателя менее универсальна.

Если два значения взяты из выражений, подобных в min_value(x + 13, 2 * y), вы не можете использовать версию указателя, поскольку ни x + 13 ни 2 * y существуют как точки памяти, к которым можно указывать, только как временные значения.

Сюрпризы

Версия указателя может дать удивительные результаты в долгосрочной перспективе.

Если сейчас first ниже чем second, функция вернет указатель на first. Если вы позже измените содержание first переменная, значение результата также изменяется.

Если first а также second локальные переменные, объявленные внутри функции foo(), и вы вернули pointer_min_value() результат (указатель), то после выхода foo(), переменные больше не существуют, и ваш результат указывает на мусорную память.

  • 2

    Обратите внимание, что использование const ссылки избегают этих сюрпризов и дают вам ценить семантика, при этом технически все еще используя указатели под капотом. Это например то, что std::min() делает.

    — Г. Сон



  • 1

    поэтому используя простое значение / double была бы более «правильная» / лучшая версия в этом случае?

    — Матиас Бургер



  • 4

    @MatthiasBurger Да. Как правило, это зависит от предполагаемого использования функции, но я не могу представить убедительного варианта в пользу версии с указателями.

    — Ральф Клеберхофф

  • 3

    @ G.Sliepen, это C, а не C ++. Хотя, const указатели по-прежнему актуальны.

    — Руслан

Некоторые украшения

думаю 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

    Современные соглашения о вызовах проходят doubles в регистрах (если параметров с плавающей запятой мало), что делает вопрос об их размере не слишком актуальным.

    — Руслан

Рекомендуется всегда передавать примитивные переменные по значениям. Указатели передачи следует зарезервировать для объектов, занимающих больше места, таких как массивы или структуры. Это также делает функции и их вызовы более удобочитаемыми. Если вы придираетесь к мелочам, вы также можете привести аргумент, что что-то вроде int обычно использует 4 байта памяти, в то время как указатель обычно использует 8, поэтому функция требует немного больше памяти.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *