C 언어 프로 그래 밍 의 함수 포인터 와 함수 리 셋 을 상세 하 게 설명 합 니 다.

함수 포인터:
함수 주 소 를 저장 하 는 지침 입 니 다.함 수 를 가리 키 는 지침 입 니 다.지침 에 저 장 된 값 은 함수 주소 입 니 다.우 리 는 지침 을 통 해 함 수 를 호출 할 수 있 습 니 다.
우 리 는 먼저 간단 한 함 수 를 정의 합 니 다.

//        
void easyFunc()
{
  printf("I'm a easy Function
"); } // void easyFunc(); // easyFunc(); // void easyFunc() { printf("I'm a easy Function
"); } // void easyFunc(); // easyFunc();
위의 세 단 계 는 우리 가 함 수 를 배 울 때 반드시 해 야 하 는 것 이다.상기 세 단 계 를 통 해 우 리 는 완전한 함 수 를 정의 한 것 이다.
어떻게 함수 지침 을 정의 합 니까?앞에서 우리 가 정의 한 다른 종류의 포인터 의 형식 은 형식*포인터 이름=하나의 주소 입 니 다.예 를 들 어:

int *p = &a;//              p
즉,우리 가 어떤 종류의 지침 을 정의 하려 면 어떤 유형 을 알 아야 한다 면 함수 의 유형 은 어떻게 확정 합 니까?함수 의 유형 은 함수 의 성명 입 니 다.함수 이름 을 없 애 면 됩 니 다.예 를 들 어 위의 함수 의 유형 은:

void ()
인자 와 반환 값 이 있 는 함 수 를 다시 설명 합 니 다.

int add(int a, int b);
위의 함수 의 유형 은 여전히 함수 이름 을 없 애 면 됩 니 다.

int (int a, int b)
함수 의 유형 을 알 게 된 이상 함수 포인터 의 유형 은 바로 뒤에*를 추가 하면 됩 니 다.그렇지 않 습 니까?

int (int a, int b) * //        
위 에서 이렇게 정의 한 것 은 잘못된 것 이다.절대적 으로 잘못된 것 이다.많은 초보 자 들 이 이렇게 한다.항상 이렇게 해 야 한다 고 생각한다.사실은 함수 포인터 의 유형 에 대한 정 의 는 비교적 특수 하 다.이것 은 다음 과 같다.

int (*) (int a, int b);//        ,         

int (*) (int a, int b);//        ,         

함수 포인터 가*뒤에 포인터 이름 만 추가 하면 됩 니 다.바로 아래 와 같 습 니 다.

int (*p)(int a, int b) = NULL;//     NULL

int (*p)(int a, int b) = NULL;//     NULL

만약 우리 가 p 에 값 을 부여 하려 고 한다 면,우 리 는 반환 값 형식 을 int 로 정의 해 야 합 니 다.두 매개 변 수 는 int 의 함수 입 니 다.

int add(int a, int b)
{
  return a + b;
}
p = add;//       

int add(int a, int b)
{
  return a + b;
}
p = add;//       

위의 할당 을 통 해 우 리 는 p 를 사용 하여 함 수 를 대표 할 수 있 습 니 다.

p(5, 6);//    add(5, 6);
printf("%d
", p(5, b)); p(5, 6);// add(5, 6); printf("%d
", p(5, b));
출력 결과:11
위의 지침 함 수 를 통 해 함 수 를 사용 합 니 다.일반적으로 함수 의 주요 용법 이 아 닙 니 다.우 리 는 함수 지침 을 사용 하여 함수 의 반전 을 실현 하고 함 수 를 매개 변수 로 사용 합 니 다.
함수 포인터 값
함수 포인터 도 일반 포인터 와 마찬가지 로 메모리 주소 입 니 다.이 주 소 는 함수 의 시작 주소 일 뿐 입 니 다.아래 프로그램 은 함수 포인터 의 값(func 1.c)을 인쇄 합 니 다.

#include <stdio.h>

typedef int (*Func)(int);

int Double(int a)
{
  return (a + a);
}

int main()
{
  Func p = Double;
  printf("%p
", p); return 0; }
컴 파일,실행 프로그램:

[lqy@localhost notlong]$ gcc -O2 -o func1 func1.c
[lqy@localhost notlong]$ ./func1
0x80483d0
[lqy@localhost notlong]$ 

그리고 우 리 는 nm 도구 로 Double 의 주 소 를 살 펴 보고 마침 0x 80483 d0 인지 아 닌 지 를 보 았 다.

[lqy@localhost notlong]$ nm func1 | sort
08048294 T _init
08048310 T _start
08048340 t __do_global_dtors_aux
080483a0 t frame_dummy
080483d0 T Double
080483e0 T main
...
뜻밖에도 Double 의 시작 주 소 는 역시 0x 080483 d0 이다.
함수 반전
함수 리 셋 의 본질은 함수 바늘 을 함수 매개 변수 로 하고 함수 호출 시 함수 주소,즉 함수 이름 을 입력 하면 된다 는 것 이다.
우 리 는 언제 리 셋 함 수 를 사용 합 니까?우리 먼저 예 를 들 자.예 를 들 어 지금 샤 오 밍 이 숙제 를 못 하 는 문제 가 있어 서 샤 오 홍 에 게 전 화 를 걸 어'나 지금 숙제 를 못 하 는 문제 가 있 는데 네가 나 를 도와 해 줄 수 있 니?그리고 답 을 알려 주 시 겠 어 요?샤 오 홍 은 이 문 제 를 듣 고 바로 풀 수 있 는 문제 가 아니 라 고 생각 하여 샤 오 밍 에 게 내 가 다 하고 알려 주 겠 다 고 말 했다.이것 을 다 한 후에 샤 오 밍 에 게 함수 의 반전 이 라 고 알려 주 었 다.샤 오 밍 에 게 어떻게 알려 주 는 지,샤 오 홍 은 반드시 샤 오 밍 의 연락처 가 있어 야 한다.이 연락 처 는 바로 반전 함수 이다.다음 에 우 리 는 코드 로 실현 한다.
샤 오 밍 은 연락 처 를 샤 오 홍 에 게 남 겨 야 하고 답 도 얻어 야 하기 때문에 답 을 저장 할 수 있 는 매개 변수 가 필요 하 다.

void contactMethod(int answer)
{
  //     
  printf("   :%d
", answer); } void contactMethod(int answer) { // printf(" :%d
", answer); } , : void tellXiaoMing(int xiaoHongAnswer, void (*p)(int)) { p(xiaoHongAnswer); } // , tellXiaoMing(4, contactMethod); void tellXiaoMing(int xiaoHongAnswer, void (*p)(int)) { p(xiaoHongAnswer); } // , tellXiaoMing(4, contactMethod);
위의 반전 에서 왜 우리 가 직접 tellXiaoMing 방법 에서 contactMethod 함 수 를 호출 할 수 없 느 냐 고 물 을 것 이다.샤 오 홍 이 함수 지침 을 매개 변수 로 할 때 샤 오 밍 의 연락 처 를 저장 할 수 있 을 뿐만 아니 라 샤 오 밍 의 연락 처 를 저장 할 수 있 기 때문에 제 가 가지 고 있 는 코드 는 수정 하지 않 아 도 됩 니 다.당신 은 서로 다른 매개 변수 만 입력 하면 됩 니 다.그래서 이런 디자인 코드 는 실용성 이 높 고 유연성 이 큽 니 다.
함수 리 턴 의 전체 과정 은 바로 위 와 같다.여기 서 중요 한 특징 은 우리 가 리 턴 을 사용 할 때 보통 한 가지 방법 으로 조작 을 기 다 려 야 할 때 사용 하 는 것 이다.예 를 들 어 위의 샤 오 홍 은 답 이 나 올 때 까지 기 다 려 야 샤 오 밍 에 게 알려 주 는 것 이다.샤 오 밍 이 샤 오 홍 에 게 물 었 을 때 샤 오 홍 이 가 직접 답 을 줄 수 있 으 면 리 턴 할 필요 가 없다.그러면 집행 순 서 는 다음 과 같다.
2016420152222457.png (458×514)
리 셋 순 서 는:
2016420152256870.jpg (904×850)
위 에 있 는 샤 오 홍 이 문 제 를 푸 는 것 은 기다 리 는 작업 이다.시간 이 걸 리 고 샤 오 밍 도 계속 전 화 를 들 고 기다 릴 수 없 기 때문에 샤 오 홍 이 가 문 제 를 풀 고 다시 전 화 를 걸 어야 샤 오 밍 에 게 답 을 알려 줄 수 있다.
따라서 함수 리 셋 은 두 가지 주요 특징 이 있다.
함수 포인터 가 매개 변수 로 서로 다른 함수 에 들 어 갈 수 있 기 때문에 서로 다른 함 수 를 되 돌 릴 수 있 습 니 다.
함수 리 셋 은 일반적으로 기다 리 거나 시간 이 걸 리 거나 일정 시간 또는 이벤트 가 발생 한 후에 리 셋 을 실행 해 야 하 는 상황 에서 사 용 됩 니 다.
우 리 는 함수 리 셋 을 사용 하여 동적 정렬 을 실현 합 니 다.우 리 는 현재 학생 의 구조 체 에 이름,나이,성적 을 포함 하고 있 습 니 다.우 리 는 학생 을 정렬 하 는 방법 이 있 습 니 다.그러나 구체 적 으로 이름 에 따라 배열 합 니까?아니면 나이 줄?아니면 성적 순위?이것 은 확실 하지 않 거나 잠시 후에 새로운 수요 가 있 을 수 있 기 때문에 동적 정렬 을 통 해 작성 한 후에 우 리 는 서로 다른 함수 만 입력 하면 된다.
학생 구조 체 정의:

//       student,  name,age   score
struct student {
  char name[255];
  int age;
  float score;
};
//typedef struct student   Student
typedef struct student Student;
비교 결 과 를 정의 하 는 매 거 진:

//        
enum CompareResult {
  Student_Lager = 1, //1     
  Student_Same = 0,// 0     
  Student_Smaller = -1// -1     
};
//typedef enum CompareResult   StudentCompareResult
typedef enum CompareResult StudentCompareResult;
성적,연령,성적 비교 함수 정의:

/*
           
*/
StudentCompareResult compareByScore(Student st1, Student st2)
{
  if (st1.score > st2.score) {//                ,   1
    return Student_Lager;
  }
  else if (st1.score == st2.score) {//                ,   0
    return Student_Same;
  }
  else { //                ,   -1
    return Student_Smaller;
  }
}
 
/*
           
*/
StudentCompareResult compareByAge(Student st1, Student st2)
{
  if (st1.age > st2.age) {//                ,   1
    return Student_Lager;
  }
  else if (st1.age == st2.age) {//                ,   0
   return Student_Same;
  }
  else {//                ,   -1
    return Student_Smaller;
  } 
}
 
/*
            
*/
StudentCompareResult compareByName(Student st1, Student st2)
{
  if (strcmp(st1.name, st2.name) > 0) {//                              ,   1
    return Student_Lager;
  }
  else if (strcmp(st1.name, st2.name) == 0) {//                              ,   0
    return Student_Same;
  }
  else {//                              ,   -1
    return Student_Smaller;
  }  
}
정의 정렬 함수:

/*
                 
  stu1[]:    
  count :    
  p :    ,            
*/
void sortStudent(Student stu[], int count, StudentCompareResult (*p)(Student st1, Student st2))
{
  for (int i = 0; i < count - 1; i++) {
    for (int j = 0; j < count - i - 1; j++) {
      if (p(stu[j], stu[j + 1]) > 0) {
        Student tempStu = stu[j];
     stu[j] = stu[j + 1];
       stu[j + 1] = tempStu;
      }
    }
  }
}
구조 체 배열 정의:

//         
Student st1 = {"lingxi", 24, 60.0};
Student st2 = {"blogs", 25, 70.0};
Student st3 = {"hello", 15, 100};
Student st4 = {"world", 45, 40.0};
//         ,        
Student sts[4] = {st1, st2, st3, st4};
출력 정렬 전 배열,정렬 및 정렬 후의 배열:

//             
printf("   
"); for (int i = 0; i < 4; i++) { printf("name = %s
", sts[i].name);// } // sortStudent(sts, 4, compareByName); // printf("
"); for (int i = 0; i < 4; i++) { printf("name = %s
", sts[i].name); }

좋은 웹페이지 즐겨찾기