[10] 반환값을 이용하는 함수 (function using return)

C언어 함수 정리

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

함수에서 반환값 사용하기

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

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

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

1
2
3
4
5
6
/*
↓ 반환값 자료형 */
int one() // 반환값이 int형인 one 함수 정의
{
return 1; // 1을 반환 => 1은 int 형
} // ↑ 반환값
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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 가 아닌 다른 자료형 반환 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#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 값의 자료형을 강제로 변환해주면 이용할 수 있긴 하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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;
}

포인터 반환하기

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

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

예시 (잘못된 코드)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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 포인터 반환하기

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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;
}

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

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

1
2
3
4
struct 구조체이름 함수이름()
{
return 구조체변수;
}

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#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 함수로 동적 메모리를 할당한 뒤 구조체 포인터를 반환하는 것이 좋음

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

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#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;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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; // 구조체 포인터 반환
}