C++ (2)

ChoRong0824·2023년 3월 27일
0

C

목록 보기
9/17
post-thumbnail

5~6 : 함수와 활용

Function

c++에서 함수를 사용하려면 선행되어야 하는것들

  1. 함수 정의 제공
  2. 함수 원형 제공
  3. 함수 호출

함수란,

  1. 리턴값이 있는 타입
typeName functionName(parameterList){
	statement(s);
    return value;
}
  1. 리턴값이 없는 타입
void functionname(parameterList){
	statement(s);
	return; // 생략될 수 있음. (종종 생략되곤함)
}

으로 나뉩니다.

여기서 리턴값이란, 자신을 호출한 함수에게 되돌려 주는것

#include <iostream>

using namespace std;

const float PIE = 3.14;
// 함수의 원형 미리 정의
void cheers(int n);
float circle(int x);

int main(){

    int a;
    cout << "하나의 수를 입력하십시오." << endl;
    cin >> a;
    cheers(a);

    int b;
    cout << "원의 반지름 길이를 입력하세요." << endl;
    cin >> b;
    float c = circle(b);
    cout << "원의 넓이는" << c << "입니다." << endl;
}
// 함수를 정의한 부분
// cheers 라는 부분은, void로 선언. return 없음.(생략)
void cheers(int n){ 
    for (int i = 0; i < n; i++)
    {
        cout << "cheers" << endl;
    }
}

float circle(int x){
    return x * x * PIE;
}

파라미터, 매개변수

사용자의 필요에따라 갯수를 지정할 수 있음.

  • parameter,argument

파라미터 1개

// 1
#include <iostream>

using namespace std;

void helloCPP(int);

int main(){

    int times;
    cout << "정수를 입력하십시오.\n";
    cin >> times;
    helloCPP(times);

    return 0;
}
// 함수정의
void helloCPP(int n){
    for(int i=0;i<n;i++)
    cout << "HELLO, C++\n";
}

매개변수 2개

// 2
#include <iostream>

using namespace std;
// 파라미터
void helloCPP(int,int);

int main(){

    int times1, times2;
    cout << "정수를 입력하십시오.\n";
    cin >> times1;
    cout << "한번 더 정수 입력"<< endl;
    cin >> times2;
    // 함수 값 전달
    helloCPP(times1,times2);

    return 0;
}
// 함수정의, 전달인자 argument
void helloCPP(int n,int m){
    for(int i=0;i<n;i++)
    cout << "HELLO, ";
    for(int i=0;i<m;i++)
    cout << " C++";
}

함수와 배열

  • c++에서 배열 이름을 그 배열의 첫번째 원소의 주소로 인식
//수정 전 

#include <iostream>

using namespace std;

const int SIZE = 8;
//위에 이렇게 해줘야 아래 사용가능.
int sumArr(int[],int);

//배열의 요소 모두 출력
int main(){
    // arr은 배열이 아니라 포인터임. 
    int arr[SIZE]={1,2,4,6,7,8,772,992};
    // arr == &arr[0]
    int sum = sumArr(arr,SIZE);
    
    cout << "함수의 총합은 "<< sum << endl;
    return 0;
}
// c++에서 배열 이름을 그 배열의 첫번째 원소의 주소로 인식함.
// 즉 sumArr은 주소를 전달받게 되는것임.
int sumArr(int arr[],int n){
    int total=0;

    for (int i = 0; i < n; i++){
        total+=arr[i];
    }

    return total;
}
  • 배열의 이름이 배열의 첫번째 원소의 주소를 가리킴.
// 수정 후

#include <iostream>

using namespace std;

const int SIZE = 8;
//위에 이렇게 해줘야 아래 사용가능.
int sumArr(int*,int);

//배열의 요소 모두 출력
int main(){
    // arr은 배열이 아니라 포인터임. 
    int arr[SIZE]={1,2,4,6,7,8,772,992};
    // arr == &arr[0]
    int sum = sumArr(arr,SIZE);
    
    cout << "함수의 총합은 "<< sum << endl;
    return 0;
}
// c++에서 배열 이름을 그 배열의 첫번째 원소의 주소로 인식함.
// 즉 sumArr은 주소를 전달받게 되는것임.
int sumArr(int* arr,int n){
    int total=0;

    for (int i = 0; i < n; i++){
        total+=arr[i];
    }

    return total;
}
  • 파라미터에 배열의 시작주소, 배열의 사이즈 || 배열의 끝
#include <iostream>

using namespace std;

const int SIZE = 8;
//위에 이렇게 해줘야 아래 사용가능.
int sumArr(int*,int*);

//배열의 요소 모두 출력
int main(){
    // arr은 배열이 아니라 포인터임. 
    int arr[SIZE]={1,2,4,6,7,8,772,992};
    // arr == &arr[0]
    int sum = sumArr(arr,arr+SIZE);
    cout << "함수의" << SIZE << "까지의 합은 "<< sum << "입니다\n";

    sum=sumArr(arr,arr+3);
    cout<< "함수의 " <<"세 번째 인덱스 까지의 합은 " << sum << endl;
    return 0;
}

// 파라미터에 배열의 시작 주소, 배열의 사이즈 || 배열의 끝
int sumArr(int* begin,int* end){
    int total=0;
    int* pt;

    for (pt = begin; pt != end;pt++){
        total+= *pt;
    }

    return total;
}

함수와 구조체

#include <iostream>

using namespace std;
struct Time{
    int h;
    int min;
};
// 함수의 원형제공 
const int minPerHr = 60;

Time sum(Time*, Time*);

void showTime(Time t1);

int main(){

    // 함수는 원본이 아닌 복사본을 대상으로 작업합니다.
    // 구조체를 값으로 전달할 때는 단점이 있음. -> 메모리 용량이 커져서 낭비 심함. -> 그래서 포인터 사용하게 됨.
    
    Time day1 = {5,45};
    Time day2 = {4,55};

    Time total = sum(&day1, &day2);

    cout << "이틀간 소요 시간 : ";
    showTime(total);

    return 0;
}

// 구조체 + 구조체 = 구조체 구현
Time sum(Time* t1, Time* t2){
    Time total;

    // 구조체가 아니라 구조체에 대한 포인터가 매개변수임으로, " . " 사용해서는 절대 안됨.
    // 구조체의 주소에 대하여서 그 멤버에 접근하고 싶을 때에는 무조건 간접 멤버연산자인 " -> " 을 사용해줘야합니다.
    // 즉, " . " : 구조체의 값에서 멤버접근
    // " -> " : 구조체의 주소에서 멤버 접근
    total.min = (t1->min + t2->min)% minPerHr;
    total.h = t1 -> h + t2 -> h + 
            (t1->min + t2->min)/minPerHr;

    return total;
}
// 구조체의 값을 매개변수로 받음.
void showTime(Time t1){
    cout << t1.h << "시간 ," << t1.min << "분 입니다." << endl;
}

재귀함수

  • 재귀 호출 : c++에서 함수는 자기 자신을 호출할 수 있습니다.
  • 재귀함수는 보통 if문과 자주쓰임

예시,

#include <iostream>
using namespace std;
int main(){
    void recurs(argumentList){
        //code #1
        if (condition)
            recurs(argumentList);
        //code #2
    }
    return 0;
}
#include <iostream>

using namespace std;
void countDown(int n);

int main(){

    countDown(5);
    
    return 0;
}
void countDown(int n){
    cout << "Counting..." << n << endl;
    if ( n > 0 )
        countDown(n-1);
    cout << n << "번째 재귀함수" << endl;    
    
}

함수를 지시하는 포인터

  • 어떠한 함수에 함수의 주소를 매개변수로 넘겨주는 경우에 유용하게 사용할 수 있습니다.

매개변수로 넘겨주는 경우를 취하기 위해서 필요한 조건

  1. 함수의 주소를 얻는다.
    -> (함수가 선언되어있을 때, 뒤에붙은 괄호를 빼고 함수의 이름만 사용하면, 그 함수의 주소를 얻을 수 있습니다)
  2. 함수를 지시하는 포인터를 선언한다.
  3. 함수를 지시하는 포인터를 사용하여 그 함수를 호출한다.
#include <iostream>

using namespace std;

int func(int);

int main(){

    int (*pf)(int);
    // 이 포인터에게 함수의 주소를 저장
    pf = func; // 이제 이 pf는 함수를 지시하게됨 , 이제 pf가 함수이름과 같은 역할을 수행하게됨.

    cout << (*pf)(3) <<endl;

    return 0;
}

int func(int n){
    return n+1;
}

Utilization of Functions

인라인 함수

  • 프로그램의 실행속도를 높이기 위해서 C++에서 새로 보완된 것임.
  • 일반적으로 함수의 호출은 함수의 주소로 점프하는 과정.
    인라인 함수는 컴파일된 함수 코드가 프로그램의 다른 코드에 삽입.
    컴파일러의 인라인 함수 호출 = 점프가 아닌 / 그에 대응하는 함수 코드로 대체
#include <iostream>

using namespace std;

// 함수의 원형 앞에 inline 함수를 붙여서 사용함
inline float square(float x){ return x*x; };

int main(){

    //인라인 함수
    int a=5;
    cout << "한 변의 길이가 "<< a<<"인 정사각형의 넓이는?" << endl;
    float b = square(a);
    cout << b << endl;
    return 0;
}

디폴트 함수

#include <iostream>

using namespace std;

const int SIZE = 8;
int sumArr(int*,int n=1);

// 디폴트 매개변수
int main(){
    int arr[SIZE]={1,2,4,6,7,8,772,992};
    int sum = sumArr(arr);
    
    cout << "함수의 총합은 "<< sum << endl;
    return 0;
}

int sumArr(int* arr,int n){
    int total=0;

    for (int i = 0; i < n; i++){
        total+=arr[i];
    }

    return total;
}
  • default 매개변수 사용, (가장 오른쪽에 위치하게 해주는 것이 좋음)
    첫번째 배열만 argument로 지정 해주고 따로 배열의 크기를 argument로 보내주지 않았을 때,
    c++는 내부적으로 함수의 원형에서 정의되어 있는 int n=1이라는 값이 sumArr의 int n에 1이 전달되어 동작함.

참조변수 (중요)

  • 참조(reference) 란?
    미리 정의된 변수의 실제 이름 대신 사용할 수 있는 대용 이름
    필요한 이유 : 함수의 매개변수에 사용함.
  • 참고전달,
    int a;
    int &b = a;
    // int a에 대한 참조변수를 사용하고자 한다면, 참조연산자 &를 사용 + 참조 변수로 사용할 변수명 쓰면 됨.
#include <iostream>

using namespace std;
void swap(int,int);

int main(){

    int wallet1 = 100;
    int wallet2 = 200;

    cout << "최초 상태 " << endl;
    cout << "wallet1 = " << wallet1 <<", wallet2= "<< wallet2 <<endl;

    cout << "참조를 이용한 값의 교환\n";
    swapA(wallet1,wallet2);
    cout << "참조 교환 이후 상태\n";
    cout << "wallet1 = " <<wallet1 << ",wallet2" << wallet2 <<endl;

    cout << "포인터를 이용한 값의 교환\n";
    swapB(&wallet1,&wallet2);
    cout << "포인터 교환 이후 상태\n";
    cout << "wallet1 = " <<wallet1 << ",wallet2" << wallet2 <<endl;

    cout << "값를 이용한 값의 교환\n";
    swapC(wallet1,wallet2);
    cout << "값 교환 이후 상태\n";
    cout << "wallet1 = " <<wallet1 << ",wallet2" << wallet2 <<endl;

    return 0;
}
// 매개변수 3가지 경우,
// 참조로 전달하는 방식
void swapA(int& a, int& b){
    int temp;

    temp =a;
    a=b;
    b=temp;
}
// 포인터로 전달하는 방식
void swapB(int* a, int *b){
    int temp;
    
    temp = *a;
    *a = *b;
    *b = temp;
}
// 값으로 전달하는 방식
void swapC(int a, int b){
    int temp;

    temp =a;
    a=b;
    b=temp;
}

함수 오버로딩

  • 함수의 다형
    다형 : 다양한 형태를 지님
  • 함수의 오버로딩
    여러 개의 함수를 같은 이름으로 연결한다.
  • 즉, 다형과 오버로딩은 유사함.
  • 함수 오버로딩은 기본적으로 서로 다른 데이터형을 대상으로 하지만, 같은 작업을 수행하는 함수들에 사용하는 것이 바람직합니다.
#include <iostream>

using namespace std;

int sum(int, int);
float sum (float,float);

int main(){

    cout << "두 정수를 입력하세요.\n";
    int a,b;
    cin >> a >> b;
    cout << "두 정수의 합은" << sum(a,b) << "입니다." << endl;
    cout << "두 실수를 입력하세요." << endl;
    
    float c,d;
    cin >> c >> d;
    cout << "두 실수의 합은 " << sum(c,d) << "입니다" << endl;

    return 0;
}
int sum (int a, int b){
    return a+b;
}
float sum(float a, float b){
    return a+b;
}

함수의 오버로딩 사용할 수 없는 경우

  1. 함수의 리턴형만 다를 경우
  2. 함수를 사용할 때, 두 개 이상의 함수에 대응되는 경우
    (예) 같은 파라미터를 받는데, 리턴형만 다르다면, 오버로딩 불가능
// 예시 1
// 참고로 당연하게도 맨 앞은 리턴형임.
int sum(int, int);
float sum (int, int););

함수 템플릿 (중요)

template <class원하는이름>
// class 혹은 typeName 사용

  • 함수 템플릿 : 함수의 일반화에 대한 서술임.
    구체적인 데이터형을 포괄할 수 있는 일반형으로 함수를 정의함.
    즉, 범용적으로 사용할 수 있게함
// 수정 전
 #include <iostream>

using namespace std;

template <class Any>
Any sum(Any, Any);

int main(){

    int a = 3;
    int b = 4;    
    cout << sum (a,b) << endl;

    float c = 3.14;
    float d = 1.592;
    cout << sum(c,d) << endl;

    //cout << sum(a,c) << endl;
    

    return 0;
}
template <class Any>
Any sum(Any a, Any b){
    return a+b;
}
// 수정 후
// 매개변수 int float 두개 다 받게됨.
#include <iostream>

using namespace std;

template <class T>
T sum(int , T);

int main(){

    int a = 3;
    float c = 3.14;
    cout << sum(a,c) << endl;

    return 0;
}
template <class T>
T sum(int a, T b){
    return a+b;
}

템플릿 + 오버로딩

#include <iostream>

using namespace std;

template <class Any>
Any sum(Any , Any);
template <class Any>
Any sum(int , Any);

int main(){

    int a = 3;
    int b =4;
    // cout << sum(a,b) << endl; //첫 번째와 두 번째 sum 둘다 매칭되기 때문에 사용할 수 없음

    float c =3.14;
    float d= 1.1231;
    cout << sum (c,d)<< endl;
    cout << sum(a,c) << endl;
    
    return 0;
}
template <class Any>
Any sum(Any a, Any b){
    return a+b;
}
template <class Any>
Any sum(int a, Any b){
    return a+b;
}
profile
컴퓨터공학과에 재학중이며, 백엔드를 지향하고 있습니다. 많이 부족하지만 열심히 노력해서 실력을 갈고 닦겠습니다. 부족하고 틀린 부분이 있을 수도 있지만 이쁘게 봐주시면 감사하겠습니다. 틀린 부분은 댓글 남겨주시면 제가 따로 학습 및 자료를 찾아봐서 제 것으로 만들도록 하겠습니다. 귀중한 시간 방문해주셔서 감사합니다.

0개의 댓글