[C언어 스터디 - 10] 반환값을 이용하는 함수 (function using return)

2020. 6. 30. 11:0003. Resources/C, C++

728x90
반응형

C언어 함수 정리

참고 문헌 (Ch 61): https://dojang.io/mod/page/view.php?id=527

함수에서 반환값 사용하기

함수에서 반환값을 사용하기 위해서는 함수를 정의할 때 반환값의 자료형을 지정해주고, 함수 안에서 return 키워드로 값을 반환하면 된다.

반환값자료형 함수이름()
{
    return 반환값;
}

중요한 점: 반환값과 반환값의 자료형이 일치해야한다.

/*
↓ 반환값 자료형 */
int one()    // 반환값이 int형인 one 함수 정의
{
    return 1;    // 1을 반환 => 1은 int 형
} //       ↑ 반환값
#include <stdio.h>

int one()    // 반환값이 int형인 one 함수 정의
{
    return 1;    // 1을 반환
}

int main()
{
    int num1;

    num1 = one();    // int형을 반환했으므로 int형 변수에 저장

    printf("%d\n", num1);    // 1

    return 0;
}

int 가 아닌 다른 자료형 반환 예시

#include <stdio.h>
#include <stdbool.h>    // bool, true, false가 정의된 헤더 파일

float realNumber()    // 반환값이 float형인 realNumber 함수 정의
{
    return 1.234567f;    // 1.234567: float형을 반환
}

bool truth()    // 반환값이 bool형인 truth 함수 정의
{
    return true;    // true: bool형을 반환
}

int main()
{
    float num1;
    bool b1;

    num1 = realNumber();    // float형을 반환했으므로 float형 변수에 저장
    b1 = truth();           // bool형을 반환했으므로 bool형 변수에 저장

    printf("%f\n", num1);   // 1.234567
    printf("%d\n", b1);     // 1

    return 0;
}

물론 return 값의 자료형을 강제로 변환해주면 이용할 수 있긴 하다.

#include <stdio.h>

int one()    // 반환값이 int형인 one 함수 정의
{
    float a = 1.1f;

    return (int)a;    // a를 int로 변환하여 반환
}

int main()
{
    int num1;

    num1 = one();    // int형을 반환했으므로 int형 변수에 저장

    printf("%d\n", num1);    // 1

    return 0;
}

또한 함수 반환값의 자료형을 함수를 이용할 때 강제로 바꿔줄 수도 있다.

#include <stdio.h>

float onePointOne()    // 반환값이 float형인 onePointOne 함수 정의
{
    return 1.1f;    // 실수 1.1을 반환
}

int main()
{
    int num1;

    num1 = (int)onePointOne();    // onePointOne의 반환값을 int로 변환하여 저장

    printf("%d\n", num1);    // 1

    return 0;
}

포인터 반환하기

일반적인 자료형을 반환하는 것과 비슷하지만, *를 추가적으로 붙여준다.

반환값자료형 *함수이름()
{
    return 반환값;
}

예시 (잘못된 코드)

#include <stdio.h>

int *ten()    // int 포인터를 반환하는 ten 함수 정의
{
    int num1 = 10;   // num1은 함수 ten이 끝나면 사라짐

    return &num1;    // 함수에서 지역 변수의 주소를 반환하는 것은 잘못된 방법
} //        ↑ warning C4172: 지역 변수 또는 임시 변수의 주소를 반환하고 있습니다.

int main()
{
    int *numPtr;

    numPtr = ten();    // 함수를 호출하고 반환값을 numPtr에 저장

    printf("%d\n", *numPtr);    // 10: 값이 나오긴 하지만 이미 사라진 변수를 출력하고 있음

    return 0;
}

지역변수의 주소를 반환하는 경우, 함수에서 이용된 다음 값이 사라지기 때문에 좋은 방법이 아님. 메모리를 할당한 다음, 해당 주소를 반환해야 한다.
예시 (제대로 된 코드)

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

int *ten()    // int 포인터를 반환하는 ten 함수 정의
{
    int *numPtr = malloc(sizeof(int));    // int 크기만큼 동적 메모리 할당

    *numPtr = 10;    // 역참조로 10 저장

    return numPtr;   // 포인터 반환. malloc으로 메모리를 할당하면 함수가 끝나도 사라지지 않음
}

int main()
{
    int* numPtr;

    numPtr = ten();    // 함수를 호출하고 반환값을 numPtr에 저장

    printf("%d\n", *numPtr);    // 10: 메모리를 해제하기 전까지 안전함

    free(numPtr);    // 다른 함수에서 할당한 메모리라도 반드시 해제해야 함

    return 0;
}

대신 이용한 다음에는 꼭 할당된 동적 메모리를 해제해주어야한다. 그렇지 않은 경우 메모리 누수가 발생한다.
또 다른 예시 (문자열 반환)

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일
#include <string.h>    // strcpy 함수가 선언된 헤더 파일

char *helloLiteral()       // char 포인터를 반환하는 helloLiteral 함수 정의
{
    char *s1 = "Hello, world!";

    return s1;    // 문자열 Hello, world!는 메모리에 저장되어 있으므로 사라지지 않음
                  // 문자열 포인터 리턴
}

char *helloDynamicMemory()    // char 포인터를 반환하는 helloDynamicMemory 함수 정의
{
    char *s1 = malloc(sizeof(char) * 20);    // char 20개 크기만큼 동적 메모리 할당

    strcpy(s1, "Hello, world!");    // Hello, world!를 s1에 복사

    return s1;   // 문자열 포인터 리턴
}

int main()
{
    char *s1;
    char *s2;

    s1 = helloLiteral();
    s2 = helloDynamicMemory();

    printf("%s\n", s1);    // Hello, world!
    printf("%s\n", s2);    // Hello, world!

    free(s2);    // 동적 메모리 해제

    return 0;
}

void 포인터 반환하기

자료형에 상관없이 값을 꺼내오고 싶을 때 이용하는 방법

#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일
#include <string.h>    // strcpy 함수가 선언된 헤더 파일

void *allocMemory()    // void 포인터를 반환하는 allocMemory 함수 정의
{
    void *ptr = malloc(100);    // 100바이트만큼 동적 메모리 할당

    return ptr;    // void 포인터 반환
}
/* 코드 줄이는 방법
void *allocMemory()
{
    return malloc(100);    // malloc 함수를 호출하면서 바로 반환
}
*/

int main()
{
    char *s1 = allocMemory();       // void 포인터를 char 포인터에 넣어서 문자열처럼 사용
    strcpy(s1, "Hello, world!");    // s1에 Hello, world! 복사
    printf("%s\n", s1);             // Hello, world!
    free(s1);                       // 동적 메모리 해제

    int *numPtr1 = allocMemory();   // void 포인터를 int 포인터에 넣어서 정수 배열처럼 사용
    numPtr1[0] = 10;                // 첫 번째 요소에 10 저장
    numPtr1[1] = 20;                // 두 번째 요소에 20 저장
    printf("%d %d\n", numPtr1[0], numPtr1[1]); // 10 20
    free(numPtr1);                  // 동적 메모리 해제

    return 0;
}

구조체와 구조체 포인터 반환하기

함수의 반환값으로 구조체를 이용하는 방법!

struct 구조체이름 함수이름()
{
    return 구조체변수;
}

예시

#include <stdio.h>
#include <string.h>    // strcpy 함수가 선언된 헤더 파일

struct Person {
    char name[20];
    int age;
    char address[100];
};

struct Person getPerson()    // Person 구조체를 반환하는 getPerson 함수 정의
{
    struct Person p;

    strcpy(p.name, "홍길동");
    p.age = 30;
    strcpy(p.address, "서울시 용산구 한남동");

    return p;    // 구조체 변수 반환
}

int main()
{
    struct Person p1;

    p1 = getPerson();    // 반환된 구조체 변수의 내용이 p1로 모두 복사됨

    // getPerson에서 저장한 값이 출력됨
    printf("이름: %s\n", p1.name);       // 홍길동
    printf("나이: %d\n", p1.age);        // 30
    printf("주소: %s\n", p1.address);    // 서울시 용산구 한남동

    return 0;
}

구조체 변수를 반환하여 다른 변수에 저장하면, 반횐된 구조체의 내용을 모두 복사하게 되는데, 이는 구조체 크기가 커지면 메모리를 많이 잡아먹게 된다.
따라서 구조체 복사가 일어나지 않도록 malloc 함수로 동적 메모리를 할당한 뒤 구조체 포인터를 반환하는 것이 좋음

struct 구조체이름 *함수이름()
{
    return 구조체포인터;
}

예시

#include <stdio.h>
#include <string.h>    // strcpy 함수가 선언된 헤더 파일
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

struct Person {
    char name[20];
    int age;
    char address[100];
};

struct Person *allocPerson()    // Person 구조체 포인터를 반환하는 allocPerson 함수 정의
{
    struct Person *p = malloc(sizeof(struct Person));    // 구조체 포인터에 동적 메모리 할당;

    strcpy(p->name, "홍길동");
    p->age = 30;
    strcpy(p->address, "서울시 용산구 한남동");

    return p;    // 구조체 포인터 반환
}

int main()
{
    struct Person *p1;

    p1 = allocPerson();    // 포인터를 반환하여 p1에 메모리 주소 저장

    // allocPerson에서 저장한 값들이 출력됨
    printf("이름: %s\n", p1->name);       // 홍길동
    printf("나이: %d\n", p1->age);        // 30
    printf("주소: %s\n", p1->address);    // 서울시 용산구 한남동

    free(p1);    // 동적 메모리 해제

    return 0;
}

만약 구조체 별칭을 사용하는 경우라면

typedef struct _Person {
    char name[20];
    int age;
    char address[100];
} Person, *PPerson;    // 구조체 별칭 Person, 구조체 포인터 별칭 PPerson

PPerson allocPerson()    // Person 구조체 포인터의 별칭을 반환값 자료형으로 지정
{
    PPerson p = malloc(sizeof(Person));    // 구조체 포인터에 동적 메모리 할당

    strcpy(p->name, "홍길동");
    p->age = 30;
    strcpy(p->address, "서울시 용산구 한남동");

    return p;    // 구조체 포인터 반환
}
반응형