Skip to content

Latest commit

 

History

History
270 lines (221 loc) · 7.48 KB

211030.md

File metadata and controls

270 lines (221 loc) · 7.48 KB

Day 29

Review C

가변 인자 함수 만들기

함수에서 가변 인자를 정의할 때는 고정 매개변수가 한 개 이상 있어야 하며 고정 매개변수 뒤에 ...을 붙여 매개변수의 개수가 정해지지 않았다는 표시를 해줌, ... 뒤에 다른 매개변수를 지정할 수 없다.

반환값자료형 함수이름(자료형 고정매개변수, ...)
{
}
/*--------------------------------------------*/
#include <stdarg.h> // va_list, va_start, va_arg, va_end가 정의된 헤더 파일

void printNum(int args, ...) // 가변 인자의 개수를 받음
{
    va_list ap; // 가변 인자 목록 포인터

    va_start(ap, args); // 가변 인자 목록 포인터 설정
    for (int i = 0; i < args; i++) // 가변 인자 목록 포인터 설정
    {
        int num = va_arg(ap, int); // int 크기만큼 가변 인자 목록 포인터에서 값을 가져옴, ap를 int 크기만큼 순방향으로 이동
        printf("%d", num);
    }
    va_end(ap); // 가변 인자 목록 포인터를 NULL로 초기화
}

printNum(2, 10, 20); // 인자 개수 2개

va_start(ap, args)를 하면 ap가 가변 인자의 시작 부분을 가리키게 된다.

자료형이 다른 가변 인자 함수 만들기

swich와 가변 인자를 함께 사용하면 됨

void printVal(char *types, ...) // 가변 인자의 자료형을 받는다.
{
    va_list ap;
    int i = 0;

    va_start(ap, types); // types 문자열에서 문자 개수를 구해서 가변 인자 포인터 설정
    while (types[i] != '\0') // 가변 인자 자료형이 없을 때까지 반복
    {
        switch (types[i])
        {
            case 'i': // int형일 때
                printf("%d", va_arg(ap, int)); // int 크기만큼 가져오고, ap를 int 크기만큼 순방향 이동
                break;
            case 'd': // double형일 때
                printf("%f", va_arg(ap, double)); // double 크기만큼 가져오고, ap를 double 크기만큼 순방향 이동
                break;
            case 'c': // char형일 때
                printf("%c", va_arg(ap, char)); // char크기만큼 가져오고, ap를 char 크기만큼 순방향 이동
                break;
            case 's': // char *형 문자열일 때
                printf("%s", va_arg(ap, char *)); // char * 크기만큼 가져오고, ap를 char * 크기만큼 순방향 이동
                break;
            default:
                break;
        }
        i++;
    }
    va_end(ap); // 가변 인자 포인터를 NULL로 초기화
}

printVal("dci", 1.23456, 'a', 10); // double, char, int

va_start는 문자열을 넣으면 문자의 개수를 구해서 포인터를 설정해줌

재귀호출 사용

함수 안에서 함수 자신을 호출하는 방식을 재귀호출이라 한다.
종료 조건을 만들지 않으면 계속 호출하다가 스택 오버플로우가 발생한다.

void hi(int count)
{
    if (count == 0) // 종료 조건
        return;
    printf("Hi");
    hello(--count); // count를 감소시켜서 hi에 다시 전달
}

hi(5);

함수 포인터 만들기

반환값자료형 (*함수포인터이름)();
/*--------------------------------*/

void hi()
{
    printf("Hi");
}

void (*fp)(); // 반환값과 매개변수가 없는 함수 포인터 fp 선언

fp = hi; // hi 함수의 메모리 주소를 함수 포인터 fp에 저장
fp(); // Hi 출력, 함수 포인터로 hi 함수 호출

반환값과 매개변수가 있는 경우

반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);
int add(int a, int b)
{
    return a + b;
}

int (*fp)(int, int); // 반환값이 int형이고 int형 매개변수 두 개가 있는 함수 포인터 선언

fp = add;
printf("%d", fp(10, 20)); // 30 출력

함수 포인터 배열 사용

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

int sub(int a, int b)
{
    return a - b;
}

int mul(int a, int b)
{
    return a * b;
}

int div(int a, int b)
{
    return a / b;
}

int main()
{
    int funcNumber;    // 함수 번호
    int num1, num2;
    int (*fp[4])(int, int);    // int형 반환값, int형 매개변수 두 개가 있는 함수 포인터 배열 선언

    fp[0] = add;    // 첫 번째 요소에 덧셈 함수의 메모리 주소 저장
    fp[1] = sub;    // 두 번째 요소에 뺄셈 함수의 메모리 주소 저장
    fp[2] = mul;    // 세 번째 요소에 곱셈 함수의 메모리 주소 저장
    fp[3] = div;    // 네 번째 요소에 나눗셈 함수의 메모리 주소 저장

    printf("함수 번호와 계산할 값을 입력하세요: ");
    scanf("%d %d %d", &funcNumber, &num1, &num2);    // 함수 번호와 계산할 값을 입력받음

    printf("%d\n", fp[funcNumber](num1, num2));    // 함수 포인터 배열을 인덱스로 접근하여 함수 호출

    return 0;
}

선언과 동시에 초기화도 가능하다

int (*fp[4])(int, int) = {add, sub, mul, div};

함수 포인터를 구조체 멤버로 사용

struct 구조체이름 {
    반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);
};
/*----------------------------------------------------------------*/

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

struct Cals {
    int (*fp)(int, int); // 함수 포인터를 구조체 멤버로 지정
}

struct Cals c;

c.fp = add;

printf("%d", c.fp(10, 20)); // 30 출력

함수 포인터를 함수의 매개변수로 사용

반환값자료형 함수이름(함수포인터반환값자료형 (*함수포인터이름)(함수포인터매개변수자료형1, 함수포인터매개변수자료형2))
{
}
/*-----------------------------------------------------------------------------------------------------------*/

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

void executer(int (*fp)(int, int))
{
    printf("%d", fp(10, 20));
}

exectuer(add);

함수 포인터를 함수의 반환값으로 사용

함수포인터반환값자료형 (*함수이름(매개변수자료형 매개변수))(함수포인터매개변수자료형1, 함수포인터매개변수자료형2)
{
}
/*------------------------------------------------------------------------------------------------------*/

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

int (*getAdd())(int, int) // 함수 포인터를 반환값으로 지정
{
    return add; // add 함수의 메모리 주소를 반환
}

printf("%d", getAdd()(10, 20));

매개변수가 있는 함수에서 함수 포인터를 반환할 경우

int (*getAdd(int x, int y))(int, int)
{
    printf("%d %d", x, y);
    return add;
}

printf("%d", getAdd(8, 9)(10, 20)); // 8과 9는 getAdd에 전달되고, 10과 20은 getAdd에서 반환된 add에 전달한다.

함수 포인터 별칭 정의

typedef 반환값자료형 (*함수포인터별칭)(매개변수자료형1, 매개변수자료형2);
/*-------------------------------------------------------------------*/

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

typedef int (*FP)(int, int); // FP를 함수 포인터 별칭으로 정의

FP getAdd() // 함수 포인터 별칭을 반환값으로 지정
{
    return add;
}

struct Calc {
    FP fp; // 함수 포인터 별칭을 구조체 멤버 자료형으로 사용
};

void exectuer(FP fp) // 함수 포인터 별칭을 매개변수 자료형으로 사용
{
    printf("%d", fp(20, 30));
}

printf("%d", getAdd()(10, 20));

FP fp1;
fp1 = add;
printf("%d", fp1(10, 20));

FP fp[10];
fp[0] = add;
printf("%d", fp[0](10, 20));

struct Calc c;
c.fp = add;
printf("%d", c.fp(20, 30));

executer(add);