Назначение указателя на функцию внутри другой функции - PullRequest
0 голосов
/ 24 октября 2018

В настоящее время я пытаюсь выдать небольшую подсказку пользователю, если указатель функции назначен.Моя проблема в том, что я не могу снова получить указатель назначенной функции в main.Код выглядит следующим образом:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>

double print_2 (void);

double print_1 (void);

void promt_user_input(double (*fn)(void));

//program to test funtion pointers inside funtions

//proof of consept

int    main(void) {
  double result;
  double (*fn)(void);

  promt_user_input(fn);
  //result = *fn;
  printf("het %lf",(fn)());
  //This will not print no matter what i do.
}

void promt_user_input(double (*fn)(void)) {
  int coice;
  printf("Enter 1 or 2\n");

  scanf(" %d",&coice);

  switch(coice) {
    case 1: *(&fn) = print_1; printf("you typed 1\n"); break;
    case 2: *(&fn) = print_2; printf("you typed 2\n"); break;
    default: printf("INVALID INPUT"); break; 
  }
  printf("hi %lf\n",(fn)());
}

double print_1 (void){
  printf("This is option 1\n");
  return 1;
}

double print_2 (void){
  printf("This is option 2\n");
  return 2;
}

Он компилируется очень хорошо, и функция назначается правильно, поскольку printf внутри функции prompt_user_input выводит правильные значения.Но вне этой функции кажется, что она не работает.Функция printf даже не запустится.

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

В функции main() вы определяете неинициализированный указатель на функцию fn и передаете его ( значение ) другой функции promt_user_input, которая инициализирует его внутренне любымprint_1 или print_2 на основе пользовательского ввода ...

Но когда поток возвращается к main(), fn внутри main() остается инициализированным.Разыменование вызывает неопределенное поведение .Чтобы правильно инициализировать fn, вам нужно передать адрес в promt_user_input и, конечно, его сигнатура должна быть обновлена ​​должным образом (входной аргумент должен иметь тип указатель на указатель чтобы функционировать или заставить его возвращать указатель на функцию, что вы предпочитаете).

#include <stdio.h>

double print_2 (void);
double print_1 (void);

void promt_user_input(double (**fn)(void));

int main(void)
{
  double result;
  double (*fn)(void);

  fn = NULL;    
  promt_user_input(&fn);

  if (fn)
  {
    printf("het %lf",(fn)());
  }

  return 0;
}

void promt_user_input(double (**fn)(void))
{
  unsigned int coice;
  int res;

  printf("Enter 1 or 2\n");

  res = scanf("%u",&coice);
  if (res != 1 || !coice || coice > 2)
  {
      printf("Invalid input!\n");
      return;
  }

  switch(coice)
  {
    case 1: *fn = print_1; printf("you typed 1\n"); break;
    case 2: *fn = print_2; printf("you typed 2\n"); break;
  }

  printf("hi %lf\n",(*fn)());
}

double print_1 (void)
{
  printf("This is option 1\n");
  return 1.0;
}

double print_2 (void)
{
  printf("This is option 2\n");
  return 2.0;
}

Несколько дополнительных замечаний:

  1. Вы должны проверить значение возврата scanfпозаботиться о неверном вводе.
  2. Из-за неверного ввода fn останется неинициализированным , поэтому вы не должны разыменовывать его в таком случае.Вам нужно либо инициализировать fn некоторым недопустимым значением, а затем проверить, имеет ли оно допустимое значение, прежде чем использовать его, или заставить promt_user_input вернуть состояние, которое будет указывать, была ли успешно инициализирована входная аргумент.
  3. double константы должны иметь плавающие точки: 1 -> int, 1.0 -> double
  4. Предпочитать использовать типы без знака, когда отрицательные значения не имеют значения (например, coice).
  5. int main(void) должен возвращать значение int в конце потока.
0 голосов
/ 24 октября 2018

Поскольку C передается по значению, вам нужно передать указатель на указатель на функцию promt_user_input:

int main(void)
{
    double (*fn)(void);

    promt_user_input(&fn);
    printf("het %lf",fn());
}

void promt_user_input(double (**fn)(void))
{
    int coice;
    printf("Enter 1 or 2\n");

    scanf(" %d", &coice);

    switch(coice){
        case 1: *fn = print_1; printf("you typed 1\n"); break;
        case 2: *fn = print_2; printf("you typed 2\n"); break;
        default: printf("INVALID INPUT"); break; 
    }
}

Вещи станут легче понять, если вы создадите typedef:

typedef double (*func)(void);
void promt_user_input(func *fn);

int main(void)
{
    func fn;

    promt_user_input(&fn);
    printf("het %lf", fn());
}

void promt_user_input(func *fn)
{
    // Same as above....

Тогда вы можете избежать указателя на указатель, если функция вернет значение:

typedef double (*func)(void);
func promt_user_input();

int main(void)
{
    func fn = promt_user_input();
    if (NULL != fn) {
        printf("het %lf", fn());
    }
}

func promt_user_input()
{
    int coice;
    printf("Enter 1 or 2\n");

    scanf(" %d", &coice);

    switch(coice){
        case 1:
            printf("you typed 1\n");
            return print_1;
        case 2: 
            printf("you typed 2\n");
            return print_2;
        default: 
            printf("INVALID INPUT");
            return NULL; 
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...