указатели на объяснение функций в C - PullRequest
1 голос
/ 08 июня 2011

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

Может кто-нибудь помочь мне понять это

Ответы [ 5 ]

3 голосов
/ 08 июня 2011

Возьмите следующее:

int i = 10;

Соответствующий указатель может быть определен так:

int* p = &i;

Переменная «p» очень похожа на «i» в том, что они оба числа Однако значение 'p' является адресом памяти переменной 'i', другими словами, это точный адрес памяти, где хранится значение 10. Кроме того, 'p' знает тип значения по этому адресу памяти. Он знает, что это int, поскольку он был определен как int + star.

Аналогично рассмотрим функцию:

int m(char* arg1, double arg2)
{
    /* do something */
}

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

Однако существует сходство между функцией и переменной. У них обоих есть тип. Тип функции состоит из:

  1. Тип возврата
  2. Список типов параметров , а именно:
    1. Тип параметра # 1
    2. Тип параметра # 2
    3. ...
    4. Тип параметра # N

C рассматривает все функции, которые имеют одинаковые списки возвращаемого типа и типа параметра, как " того же типа функции ". Подобно тому, как две переменные, объявленные как «int i, j», рассматриваются как один и тот же тип, так и две функции с одинаковой сигнатурой считаются одним и тем же типом.

Синтаксис для описания типа функции включает в себя минимум: тип возвращаемого значения и типы каждого параметра (в правильном порядке):

return-type (* <variable-name>)(Type-of-Param-1, Type-of-Param-2, ..., Type-of-Param-N)

Фактически, чтобы объявить указатель на функцию 'm' выше:

int (*p)(char*, double) = &m;

«int» - это тип возвращаемого значения метода «m», первая пара круглых скобок и звезда являются частью синтаксиса, «p» - это имя переменной, «char *» - тип первого параметра. и "double" является типом второго параметра. Нет ссылки на имена параметров - поскольку имена параметров не имеют отношения к типу / сигнатуре функции.

Обратите внимание, что, как и для переменной, адрес метода получается точно так же, как и для переменной, т. Е. Путем добавления к нему амперсанда.

Указатели на функции могут передаваться вокруг указателей на переменные, и, что более важно, может вызываться код функции по этому конкретному адресу памяти. Например, чтобы вызвать функцию 'm' с помощью указателя 'p', потребуется что-то вроде этого:

int result = p(NULL, 10.0);
int result = (*p) (NULL, 10.0); // alternative syntax
3 голосов
/ 08 июня 2011

Давайте посмотрим в стандартной библиотеке C:

void qsort(void *BASE, size_t NMEMB, size_t SIZE, 
    int (*COMPAR)(const void *, const void *) );

последний аргумент qsort - это указатель для сравнения функции .функция сравнить используется для сравнения двух элементов из массива (она определяет порядок).Если qsort() не будет использовать указатель на функцию , мы должны будем писать снова и снова qsort(), если у нас другое требование к порядку или новые types / struct , которые мы хотели бысортировать.

2 голосов
/ 08 июня 2011

Типичным примером является функция сортировки, которая требует, чтобы вы указали ее на функцию, которая может сравнивать два элемента.Вы передаете эту функцию указателю на функцию сравнения, чтобы она могла вызывать вашу функцию, когда ей нужно сделать сравнение.Вы не можете на самом деле передать функцию, но вы можете передать ей указатель на функцию, которая является просто переменной, которая «указывает» на то, где ваша функция находится в памяти.Функция сортировки может вызывать вашу функцию с помощью этого указателя.В общем, указатели - это просто переменные, которые хранят адрес памяти.Этот адрес памяти является тем, на что он «указывает», и по этому адресу он может быть чем угодно - функцией, целым числом, серией символьных переменных, заканчивающихся нулевым символом.Указатели на функции - это просто переменные, которые хранят адрес памяти того места, где находится функция, так что функция может быть вызвана другим фрагментом кода.

Надеюсь, это объяснение поможет.

0 голосов
/ 08 июня 2011

Указатели функций используются для динамического вызова функций.Например, вы можете взять указатель на функцию в качестве аргумента для другой функции и в некотором смысле обеспечить дополнительную функциональность таким образом.Вы также можете создать структуры , которые имеют указатели на функции и, таким образом, своего рода функции-члены, как для классов.Это может быть полезно, если у вас есть функция, которая работает с вашими структурами, но они могут немного отличаться в том, что на самом деле нужно делать с ними.Например:

// Structures for our "objects"
typedef int funcPtr();

struct foo {
  int a;
  int b;
  funcPtr* run;
}

struct bar {
  int a;
  int b;
  funcPtr* run;
  char* s;
}

// Functions that we will use as our "member functions"
int runOne() {
  return 1;
}

int runTwo() {
  return 2;
}

// Functions to create objects... kinda like new operators
struct foo* NewFoo(int aVal, int bVal) {
  struct foo* this = (stuct foo*)malloc(sizeof(struct foo));
  this->a = aVal;
  this->b = bVal;
  this->run = runOne;
  return this;
}

struct bar* NewBar(int aVal, int bVal) {
  struct bar* this = (stuct bar*)malloc(sizeof(struct bar));
  this->a = aVal;
  this->b = bVal;
  this->run = runTwo;
  return this;
}

// Create "objects"
struct foo* myFoo = NewFoo(10, 20);
struct bar* myBar = NewBar(30, 40);

// Run the run function on them (which actually runs different functions for each "object")
int result1 = myFoo->run();
int result2 = myBar->run();

result1 теперь будет 1 , а result2 будет 2 .Это может быть использовано, если у вас есть структуры, содержащие различные виды «модулей» с похожим интерфейсом, но с разным поведением, например.

0 голосов
/ 08 июня 2011

Это не так просто, как это.

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

С http://www.cplusplus.com/doc/tutorial/pointers/

// my first pointer
#include <iostream>
using namespace std;

int main ()
{
  int firstvalue, secondvalue;
  int * mypointer;

  mypointer = &firstvalue;
  *mypointer = 10;
  mypointer = &secondvalue;
  *mypointer = 20;
  cout << "firstvalue is " << firstvalue << endl;
  cout << "secondvalue is " << secondvalue << endl;
  return 0;
}

И вывод для вышеупомянутого равен

firstvalue is 10
secondvalue is 20

Теперь с http://www.newty.de/fpt/intro.html#what У нас есть функциональные указатели.

//------------------------------------------------------------------------------------
// 1.2 Introductory Example or How to Replace a Switch-Statement
// Task: Perform one of the four basic arithmetic operations specified by the
//       characters '+', '-', '*' or '/'.


// The four arithmetic operations ... one of these functions is selected
// at runtime with a swicth or a function pointer
float Plus    (float a, float b) { return a+b; }
float Minus   (float a, float b) { return a-b; }
float Multiply(float a, float b) { return a*b; }
float Divide  (float a, float b) { return a/b; }


// Solution with a switch-statement - <opCode> specifies which operation to execute
void Switch(float a, float b, char opCode)
{
   float result;

   // execute operation
   switch(opCode)
   {
      case '+' : result = Plus     (a, b); break;
      case '-' : result = Minus    (a, b); break;
      case '*' : result = Multiply (a, b); break;
      case '/' : result = Divide   (a, b); break;
   }

   cout << "Switch: 2+5=" << result << endl;         // display result
}


// Solution with a function pointer - <pt2Func> is a function pointer and points to
// a function which takes two floats and returns a float. The function pointer
// "specifies" which operation shall be executed.
void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float))
{
   float result = pt2Func(a, b);    // call using function pointer

   cout << "Switch replaced by function pointer: 2-5=";  // display result
   cout << result << endl;
}


// Execute example code
void Replace_A_Switch()
{
   cout << endl << "Executing function 'Replace_A_Switch'" << endl;

   Switch(2, 5, /* '+' specifies function 'Plus' to be executed */ '+');
   Switch_With_Function_Pointer(2, 5, /* pointer to function 'Minus' */ &Minus);
}

Как вы увидите из приведенного выше вызова, передается адрес функции Minus (), который затем передается для вызова фактической функции через указатель, и в этом случае pt2Func (...).Обратите внимание, что в случае указателей функций вы также позаботитесь о сигнатуре функции.

  • float (*pt2Func)(float, float)
  • float Minus (float a, float b) { return a-b; }

AsВы можете видеть выше, подписи одинаковы, поэтому вы можете передать любой адрес функции, и вызов будет работать.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...