툴곰코드 노트C언어 › C언어 함수

C언어 함수

C의 함수는 반환형을 앞에 적습니다. 그리고 인자는 값이 복사되어 넘어갑니다 — 함수 안에서 바꿔도 밖은 그대로입니다.

⬇ 예제 파일 받기 (.c)
C언어 · 회원가입 없음
내려받아 gcc 파일이름.c -o 실행파일 -Wall 로 컴파일한 뒤 실행합니다.
광고 영역

무엇을 하는 것인가

int 더하기(int a, int b)에서 맨 앞의 int이 함수가 돌려주는 값의 형입니다. 돌려줄 것이 없으면 void라고 적습니다. 파이썬의 def와 달리 무엇이 들어오고 무엇이 나가는지를 미리 못 박아 둡니다.

함수는 쓰기 전에 컴파일러가 알고 있어야 합니다. main 아래에 함수를 정의했다면, 위쪽에 int 더하기(int a, int b);처럼 프로토타입을 미리 적어 둡니다. 이걸 빠뜨리면 "암시적 선언" 경고가 나고, 요즘 컴파일러에서는 오류가 됩니다.

C는 인자를 값으로 넘깁니다. 함수에 변수를 넘기면 그 값의 복사본이 넘어갑니다. 함수 안에서 아무리 바꿔도 부른 쪽의 원본은 그대로입니다. 이걸 모르면 "함수에서 바꿨는데 왜 안 바뀌지?"에서 한참 헤맵니다.

원본을 바꾸고 싶으면 주소를 넘겨야 합니다. &변수로 주소를 넘기고 함수는 포인터로 받습니다. scanf&를 붙이는 이유가 바로 이것입니다 — 입력한 값을 내 변수 자리에 넣어 달라는 뜻이니까요.

배열은 예외처럼 보입니다. 배열을 넘기면 첫 원소의 주소가 넘어가서, 함수 안에서 고치면 원본이 바뀝니다. 배열이 통째로 복사되지 않기 때문입니다.

예제 코드

아래 코드가 위 버튼으로 받는 파일과 같은 내용입니다. 통째로 복사해 실행해 보고, 값을 바꿔 가며 결과가 어떻게 달라지는지 보는 편이 읽기만 하는 것보다 훨씬 빨리 익습니다.

/* 함수 — 값이 복사되어 넘어간다는 것
   컴파일:  gcc c-function.c -o fn -Wall                 */

#include <stdio.h>

/* 프로토타입 — main 아래에 정의한 함수를 미리 알려 둡니다 */
int  더하기(int a, int b);
void 인사(const char 이름[]);
void 못바꿈(int x);
void 바꿈(int *p);
void 두배로(int 값[], int 개수);
void 나누기(int a, int b, int *몫, int *나머지);

int main(void)
{
    printf("3 + 4 = %d\n", 더하기(3, 4));
    printf("두 배: %d\n", 더하기(3, 4) * 2);
    인사("김서연");

    /* ── 값은 복사되어 넘어갑니다 ── */
    int 수 = 10;
    못바꿈(수);
    printf("못바꿈 뒤: %d\n", 수);      /* 10 — 그대로입니다 */

    바꿈(&수);                            /* 주소를 넘깁니다 */
    printf("바꿈 뒤:   %d\n", 수);      /* 99 — 바뀌었습니다 */

    /* ── 배열은 주소가 넘어가서 원본이 바뀝니다 ── */
    int 값들[3] = {1, 2, 3};
    두배로(값들, 3);
    printf("배열: %d %d %d\n", 값들[0], 값들[1], 값들[2]);   /* 2 4 6 */

    /* 값을 두 개 돌려받기 — 담을 자리의 주소를 넘깁니다 */
    int 몫 = 0, 나머지 = 0;
    나누기(17, 5, &몫, &나머지);
    printf("17 / 5 = %d ... %d\n", 몫, 나머지);

    return 0;
}

int 더하기(int a, int b)
{
    return a + b;               /* return 을 만나면 함수는 여기서 끝납니다 */
}

void 인사(const char 이름[])     /* 돌려줄 것이 없으면 void */
{
    printf("안녕하세요, %s님\n", 이름);
}

void 못바꿈(int x)
{
    x = 99;                                     /* 복사본만 바뀝니다 */
    printf("  (함수 안에서 본 값: %d)\n", x);   /* 여기서는 99 로 보입니다 */
}

void 바꿈(int *p)
{
    *p = 99;                    /* 주소가 가리키는 자리를 고칩니다 */
}

void 두배로(int 값[], int 개수)
{
    for (int i = 0; i < 개수; i++) {
        값[i] *= 2;             /* 배열은 주소가 넘어와서 원본이 바뀝니다 */
    }
}

void 나누기(int a, int b, int *몫, int *나머지)
{
    if (b == 0) {
        *몫 = 0; *나머지 = 0;
        return;
    }
    *몫 = a / b;
    *나머지 = a % b;
}

기억할 것

광고 영역

자주 묻는 것

함수 안에서 값을 바꿨는데 밖에서는 그대로입니다

값이 복사되어 넘어갔기 때문입니다. 원본을 바꾸려면 &로 주소를 넘기고 함수는 int *p로 받아 *p = ...로 고쳐야 합니다. 아니면 return으로 돌려받아 다시 넣으세요.

implicit declaration of function 경고가 납니다

함수를 쓰는 지점보다 아래에 정의했는데 프로토타입이 없다는 뜻입니다. main 위쪽에 double 평균(const int a[], int n);처럼 한 줄 적어 두세요.

값을 두 개 돌려주려면요

return은 하나만 돌려줍니다. 방법은 둘입니다 — 결과를 담을 변수의 주소를 인자로 받아 채워 주거나, 구조체로 묶어서 돌려주는 것입니다.

함수 안에서 만든 배열의 주소를 돌려줘도 되나요

안 됩니다. 함수가 끝나면 그 자리가 사라져서, 돌려받은 주소는 이미 없는 곳을 가리킵니다. 값이 살아 있어야 하면 static으로 두거나 malloc으로 잡아야 합니다.

이어서 볼 글