Как вызвать функцию как аргумент?

248
20 февраля 2017, 17:48

Смысл такой, что нужно расписать программу для сортировки массива по функциям без использования глобальных переменных. Я решил пойти путём вызова функций как параметров для функций(ведь это же можно сделать с помощью указателей???) Листинг моего "чудо"-кода:

#include <cmath>
#include <iostream>
using namespace std;
void print(double a[10])
{
    //double a[10];
    for (int i = 0; i < 10; i++)
    {
        cout << a[i] << " ";
    }
}
double find_min_element(double a[10])
{
    double var;
    //  double a[10];
    int n = 10;
    var = 9223372036854775807;
    int index = 0;
    for (int i = 0; i < n - 1; i++)
    {
        if (a[i] < var)
        {
            var = a[i];
            index = i;
        }
    }
    return index;
}
double sort_array(double a[10])
{
    //double a[10];
    int m;
    int n = 10;
    for (int i = 0; i < n; i++)
    {
        m = i;
        for (int j = i + 1; j < n; j++)
        {
            if (a[j] < a[i])
            {
                m = j;
                swap(a[i], a[m]);
            }
        }
        cout << a[i] << " ";
    }
    return a[n];
}
double filling()
{
    int i;
    double a[10];
    int n = 10;
    cout << "fill the row, 10 elements" << endl;
    for (i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    return a[i];
}
int main(int argc, char** argv)
{
    //using pointer_to_function = double(*)();
    //int (*pointerToFunction)(double ) = NULL;
    //pointerToFunction = &filling;
    pointer_to_function ptf = filling;
    filling();
    find_min_element(
        ptf);       /*В find_min_element надо отправить заполненный массив. 
                    Такой у нас имеется после вызова filling.
                    Так как глобальные переменные использовать нельзя,
                    то получается, что в main'е зацепить массив в переменную я не могу*/
    print(ptf);
    return 0;
}

На выходе компилятор выдаёт следующие ошибки

g++ -Wall -c "Functions.cxx" (в каталоге: /home/alex/Yandex.Disk/Программирование/1D_arrays_from_functions)

Functions.cxx: In function ‘int main(int, char**)’: Functions.cxx:94:8: error: expected nested-name-specifier before ‘pointer_to_function’ using pointer_to_function = double(*)();

^ Functions.cxx:97:2: error: ‘pointer_to_function’ was not declared in this scope pointer_to_function ptf = filling;

^ Functions.cxx:99:19: error: ‘ptf’ was not declared in this scope
find_min_element(ptf);
^ Сборка завершилась с ошибкой.

Среда - Geany, g++. ^ - разделитель между ошибками.

Answer 1

Вы уж извините, но у вас код... Давайте по нему пройдемся.

void print(double a[10])
{
    //double a[10];
    for (int i = 0; i < 10; i++)
    {
        cout << a[i] << " ";
    }
}

Пожалуй, одна из реально работающих функций :)

double find_min_element(double a[10])
{
    double var;
    int n = 10;
    var = 9223372036854775807;

Что за странная константа? Тем более что double такую точность не поддерживает, и все равно ее обрежет. А если вы хотели максимальное значение double, так это numeric_limits<double>::max().

    int index = 0;
    for (int i = 0; i < n - 1; i++)

Почему вы не рассматриваете последний элемент массива? И вообще - зачем вводить переменную, если это у вас - жестко прошитая константа?

double sort_array(double a[10])
{

Честно говоря, на беглый взгляд вроде и ничего... но зачем эта переменная m? int m;

И что вы возвращаете? Несуществующий элемент массива? Зачем? return a[n]; }

double filling()
{
    int i;
    double a[10];
    int n = 10;
    cout << "fill the row, 10 elements" << endl;
    for (i = 0; i < n; i++)
    {
        cin >> a[i];
    }

Допустим. Заполнили. Заполнили локальный массив, который при выходе из функции исчезнет...

    return a[i];

И опять вернули несуществующий элемент.

int main(int argc, char** argv)
{
    //using pointer_to_function = double(*)();

Это правильное объявление типа для указателя на filling, только раскомментировать :)

    //int (*pointerToFunction)(double ) = NULL;

А это какая-то ерунда; если вы хотели так сделать указатель на filling, то писать надо double (*ptf)() = filling;

    pointer_to_function ptf = filling;
    filling();
    find_min_element(ptf);

Ваша функция требует передачи ей массива, а вы передаете ей указатель на функцию. И что ей с ним делать?

    print(ptf);

Аналогично.

Собственно, все, что от вас хотел преподаватель, я выложил вот тут (земенив только чтение массива заполнением случайными числами): http://ideone.com/w70pVj Вам нужно было передавать массив и его размер. Все. Так никаких глобальных переменных нет. Работать с указателями на функции можно (а иногда и нужно :)), но не в вашем случае...

Answer 2

Используйте std::vector вместо массива. Или же вместе с массивом передавайте его размер. В Вашем случае 10. Можно обойтись и без глобальных переменных и без указателей на функции. Функция sort_array возвращает 1 значения типа double a[10], которое выходит за пределы массива.filling - аналогично.

Answer 3

В вашей программе имеется несколько ошибок.

Функцию print правильно будет объявить, указав второй параметр - размер массива, так как в самой функции не возможно определить размер переданного ей массива в качестве аргумента, так как он неявно преобразуется в указатель на свой первый элемент. То есть в данном объявлении параметра функции

void print(double a[10]);
                  ^^^^

число 10 не играет никакой роли, так как та же самая функция может быть объявлена с любым значением размера массива, который просто игнорируется в виду преобразования параметра массива в указатель на элемент массива. То есть данные объявления функций эквивалентны и объявляют одну и ту же функцию

void print(double a[100]);
void print(double a[10]);
void print(double a[]);
void print(double *a);

Поэтому правильно будет определить функцию следующим образом

void print( const double a[], size_t n )
{
    for ( size_t i = 0; i < n; i++ )
    {
        std::cout << a[i] << " ";
    }
}

Можно объявить функцию с одним параметром. Но в этом случае тип параметра должен быть ссылкой на массив. Например

void print( const double ( &a )[10] )
{
    for ( size_t i = 0; i < 10; i++ )
    {
        std::cout << a[i] << " ";
    }
}

Или, если компилятор поддерживает цикл for на основе диапазона, то можно записать

void print( const double ( &a )[10] )
{
    for ( double x : a  )
    {
        std::cout << x << " ";
    }
}

Для функции find_min_element имеется точно такая же проблема с объявлением функции. Кроме того используется некая магическая константа, не понятно, откуда взявшаяся, использование которой может дать результат не тот, который вы ожидаете, так как при преобразовании к типу double может иметь место ее неточное представление.

К тому же почему-то последний элемент массива игнорируется

for (int i = 0; i < n - 1; i++)
                ^^^^^^^^^

Имеется стандартный алгоритм std::min_element, объявленный в заголовке , который выполняет задачу по поиску минимального элемента массива. Кроме того вы объявили тип возвращаемого значения функции как double в то время, как возвращаете индекс на минимальный элемент. Логичнее было бы, если бы возвращаемый тип значения функции был целочисленным. А иначе это вводит в заблуждение читающих ваш код, так как можно подумать, что возвращается не индекс минимального значения, а само минимальное значение.

size_t find_min_element( const double a[], size_t n )
{
    size_t min_i = 0;
    for ( size_t i = 1; i < n; i++ )
    {
        if ( a[i] < a[min_i] )
        {
            min_i = i;
        }
    }
    return min_i;
}

Или если объявить первый параметр функции как ссылку на массив, то

size_t find_min_element( const double ( &a )[10] )
{
    size_t min_i = 0;
    for ( size_t i = 1; i < 10; i++ )
    {
        if ( a[i] < a[min_i] )
        {
            min_i = i;
        }
    }
    return min_i;
}

В функции сортировки существует та же самая, описанная выше проблема с объявлением функции. Измените ее объявление, как это показано для других функций. Кроме того функция имеет неопределенное поведение, так как она возвращает из функции не существующий элемент массива. То есть идет обращение к памяти за пределами массива.

return a[n];
       ^^^^^

Нет никакого смысла что-о возвращать из функции. Поэтому лучше объявить тип возвращаемого значения как Void . Например,

void sort_array( double a[], size_t n );

или

void sort_array( double ( &a )[10] );

В функции filling заполняется локальный массив, который прекратит свое существование после выхода из функции, и снова возвращается из функции несуществующий элемент локального массива. ТО есть функция имеет неопределенное поведение.

Измените ее объявление как

void filling( double a[], size_t n );

или как

void filling( double ( &a )[10] );

double filling()
{
    int i;
    double a[10];
    int n = 10;
    cout << "fill the row, 10 elements" << endl;
    for (i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    return a[i];
}

Судя по первому показанному сообщению об ошибке

Functions.cxx: In function ‘int main(int, char**)’: Functions.cxx:94:8: error: expected nested-name-specifier before ‘pointer_to_function’ using pointer_to_function = double(*)();

ваш компилятор не поддерживает объявление алиаса с использованием ключевого слова using.

Поэтому попробуйте заменить его на typedef объявление

typedef  double( *pointer_to_function )();
READ ALSO
как правильно передать массив в функцию?

как правильно передать массив в функцию?

Почему в функцию передается TCHAR(&name)[100], а не TCHAR *name?

281
Как запустить сервис на Android при помощи Qt?

Как запустить сервис на Android при помощи Qt?

Пытаюсь написать сервис который будет кликать по экрануДелаю это так:

387
Наполнения списка возможных Command Arguments

Наполнения списка возможных Command Arguments

Есть ли возможность для *vcxproj указать перечень возможных аргументов для запуска приложения?

211
Не отображается IDC в resorce.h файле

Не отображается IDC в resorce.h файле

Пишу программу на winApi, но когда перетаскиваю например из Toolbox Button eё IDC не отображается в resorceh файле

248