오늘 배울 것은 함수 Function이다.
함수는 10번 강조해도 지나침이 없는 것이니, 제대로 공부해야 한다.
※함수 Function : 특정 기능의 코드가 작성된 영역
- 함수 정의 문법
리턴타입 함수이름(파라미터)
{
특정 기능의 코드들;
}
리턴타입 : int, double, char, void ........
함수가 없다면 코딩하는 규모가 커지면 커질수록, 똑같은 기능을 구현하기 위해
같은 코드를 또 입력하게 된다. 이는 곧 코드가 길어지는 결과를 초래한다.
그럼 코드가 길어지면 어떻게 될까?
우선 가독성이 떨어진다.
가독성이 떨어지면 디버깅할 때나
협업할 때 문제가 발생한다.
가독성을 높이고 효율을 높이기 위해서
함수를 사용해야 한다.
지금까지 우리는 void main이라는 함수를 이용해 왔다.
또 다른 함수를 만들 때는 main 안에 쓰는 것이 아닌 그 밖에 써야 한다.
그리고 main 함수의 위에 쓰나 아래에 쓰나 상관이 없다.
이런 방식으로 사용이 가능하다.
이때 실행을 시켜보면, 아무것도 나오지 않는다.
그 이유는 컴퓨터 언어의 특징 때문이다.
바로
main함수의 중괄호가 열리면 프로그램이 시작되고,
중괄호가 닫히면 프로그램이 끝나기 때문이다.
그러나, main함수에는 아무것도 없으므로 아무것도 나오지 않는 것이다. (다른 함수를 호출하지 않았다.)
그럼 함수를 사용하는 방법은 어떻게 될까?
엄청 간단하다.
이렇게 main 함수 안에 사용할 함수를 호출해주면 된다.
이때 동작방식을 보면
1번 줄부터 차례대로 진행하게 된다.
그러다가 3번 줄에서 함수를 만나게 되지만
이 함수는 main이 아니라 화면에 출력되진 않는다.
그 후 main 함수를 8번 줄에서 만나고
10번 줄에서 login 함수가 호출이 돼서
3번 줄로 올라가 함수가 실행되고
다시 11번 줄로 return 한다.
그렇다면 이렇게 login 함수가 아래에 있다면 어떻게 될까?
에러가 난다.
에러가 나는 이유 역시
컴퓨터 언어의 특징 때문이다.
첫날부터 말해왔지만,
컴퓨터 언어는 위에부터 차례대로 실행되는 특징이 있다.
즉, main부터 실행되고, login 함수는 main 함수 아래 있기 때문에
이런 상황이 나타나는 것이다.
그런데, 앞에서 main 함수 앞 뒤에 써도 된다고 했다.
맞다.
그러나 하나 더 작업을 해줘야 한다.
바로 함수의 프로토타입이다.(c언어만의 특성이다.)
마치 백화점 갔을 때, 어떤 어떤 매장이 있는지 알려주는 지도가 있듯
아래에 이런 함수가 있다는 것을 위에 미리 말해주는 것이다.
그럼 굳이 왜 이런 방식을 사용하냐?라고 의문을 가지고 물어볼 수 있다.
그 이유는 main 함수 위에 다른 함수들을 다 작성하면
main 함수가 점점 밑으로 쳐져서 찾기가 어려워지기 때문이다.
함수 정의 문법의 종류
리턴 | 파라미터 |
X | X |
X | O |
O | X |
O | O |
1. 리턴 X, 파라미터 X
단순 출력만 하는 기능을 사용할 때 쓰는 함수이다.
뒤에 파라미터에 void를 사용하지 않아도 된다.(단, java에선 쓰면 안 된다.)
파라미터에 아무것도 쓰지 않으면 void로 인식한다.
그러니 우리는 안 쓰는 것으로 습관을 만들어가야 한다.
앞에 리턴타입은 생략불가능하다!!!
2. 리턴 X, 파라미터 O
이렇게 파라미터를 2개로 설정해서 사용이 가능하다.
또 함수가 다르면 변수 이름이 같더라도 에러가 나지 않는다.
(보통 개발자들은 각각 다른 함수에 같은 변수 이름을 쓴다고 한다.)
이렇게 여러 개의 매개변수를 가질 수도 있다.
그러나 매개변수를 쓸 때, 자료형 선언과 같이 같은 자료형이라고 하더라도 줄여서 쓸 순 없다.
또 main함수에 넣는 매개변수의 개수와 자료형이
원래 함수의 매개변수의 갯수와 자료형과 일치해야 한다.(순서도)
3. 리턴 O, 파라미터 X
리턴은 값을 반환받다. 즉 되돌려받다라는 것이다. main함수에서 새로운 함수로 갔다가
다시 값을 가지고 main함수로 돌아온다는 것이다.
여기서 보면 aaa라는 int형 함수이 있다. 여기서 int형이 된 것은 return 값이 정수이기 때문이다.
이때 main함수를 보면 이 return 값을 받기 위해서 n이라는 자료형에다가 넣어준 것을 볼 수 있다.
그래야 return값을 main에서 사용할 수 있기 때문이다.
int n = 3+ 5;처럼
n = aaa(); 으로 return 값을 넣어주었다.
그럼 이것을 왜 사용할까?
이렇게 특정한 값을 받아서 다시 main 함수에서 사용할 때가 있기 때문이다.
input 함수를 만들어 키보드를 통해 입력받은 값을
return 하였다.
그리고 main 함수에서 이 return 값을 받아 출력하였다.
이런 방식으로 사용할 때 return값이 필요하다.
이렇게 함수를 사용해서 코딩을 했을 때
main함수를 보면 가독성이 매우 좋고 깔끔하다.
우리는 지금까지 void main()을 사용했다.
그러나 c언어 책을 보면
int main(void)를 사용하는 경우가 많다.
main 함수는 운영체제 즉, 윈도우즈, 리눅스, 맥 과 서로 주고받는 것이다.
그래서 int main() 함수 끝에는
return 0; 을 하여 제대로 프로그램이 끝났다고 전달하는 것이다.
(참고로 return 값이 -1이 전달되면 에러라고 한다.)
함수의 특이사항
- main 함수에만 다른 함수를 쓸 수 있는 것이 아니다.
사진에서도 볼 수 있듯
aaa라는 함수 안에 bbb라는 함수를 넣어
main에서 aaa만 호출해도 bbb까지 출력이 가능하다.
- return 값은 오직 하나만 가능하다.!(only one)
즉
int kkk()
{
int a = 10;
int b = 20;
return a, b;
}
이런 경우는 불가능하다는 것이다. (c언어, java, kotlin 다 해당)
- return 다음에 코드를 쓰면 실행되지 않는다.
return이라는 것이 예전에 배운 반복문을 제어하는 break;나 continue; 와 같은 역할을 한다.
따라서 return 다음에 다른 코드를 써도 main 함수로 돌아가기 때문에 그다음에 쓴 코드는 실행되지 않는다.
ex)
void cal(int a)
{
if (a < 0) return;
printf("%d",a);
}
이 경우 a가 음수일 경우 main 함수로 돌아가게 되는 것이다.
변수의 종류
우선 모든 변수는 지역 혹은 전역 변수이다. 여기서 필요하다면 정적 변수
1. 지역(Local) 변수
{ } 영역 안에 선언한 변수 ▷ { } 안에서만 인식 ▷ 그 지역이 실행되면 생성, 그 지역이 종료되면 소멸
사진과 같이 선언된 함수 영역 안에서만 인식하는 변수이다.
2. 전역(Global) 변수
{ } 영역 밖에 선언한 변수 ▷ 어디서나 인식 ▷ 프로그램이 시작되면 생성, 프로그램이 종료되면 소멸
이처럼 전역 변수 g를 선언해 주면
모든 곳에서 사용이 가능하다.
하지만, int g=100; 같은 초기화는 가능하지만,
대입은 불가능하고 연산도 불가하다.
그렇다면 전역 변수를 사용하게 되면 파라미터를 사용하지 않아도 된다고 생각할 수 있다.
그러나 전역 변수를 너무 많이 사용하게 되면, 메모리를 쓸데없이 많이 차지할 수 있다.(비효율적이다.)
또 어디서 전역 변수를 건드렸는지 찾기도 힘들다.
또 하나 특이한 점이 전역변수를 선언 후 출력하면 0이 출력된다.
지역 변수는 선언만 하면 쓰레기 값이 나오는 것과는 다르다.
그리고 만일 동명의 지역변수와 전역변수가 존재한다면?
그 경우엔 지역변수가 우선시 된다.
3. 정적(Static) 변수
지역 +_전역
변수 이름 앞에 static이라는 키워드를 붙여줘야 선언이 된다.
정적전역변수로 사용하는 것은 드물다.
99%가 정적지역변수로 사용하는데,
그래서 정적변수라 말하면 정적지역변수라고 생각하면 된다.
정적변수를 선언하게 되면
전역변수처럼 인식된다.
그러나 다른 함수에선 사용할 수 없게 보호가 된 상태라고 생각하면 되겠다.
또 이 변수의 특징은
지역변수와는 달리 그 지역이 종료돼도 메모리에서 사라지지 않고 남아있게 된다.
지역변수의 경우 aaa함수가 끝나면 그 변수들은 다 사라진다.
하지만
static 변수를 사용하면
그 값이 전역변수처럼 남아있어서
값이 살아있게 된다.
(그럼 아마.. 누적 방문자수 같은 걸 쓸 때 이런 걸 쓰나 보다)
그리고 전역변수와는 달리
다른 곳에서 변수를 건드려서 원하는 결괏값이 안 나오는 상황도 방지할 수 있다.
지금은 변수가 2개지만 만약 변수가 10개가 넘어가게 된다면?
그리고 이런 에러를 범한다면?
쉽게 찾을 수가 없다.
전역변수를 이렇게 관리할 때 큰 불편을 초래한다.
그러나 정적변수는 변수가 몇 개냐에 따라 영향을 받지 않는다.
또 다른 함수에서 건드릴 수 없어서 에러가 날 확률도 낮을뿐더러
선언된 함수 부분에서만 고치면 되기 때문에 더 편하다.
※재귀 호출 (Recurcive Call)
이렇게 되면 무한히 aaa가 출력이 된다.
그럼 무한 루프인 while 혹은 for 문과 차이가 무엇일까?
이 경우엔 이렇게 무한히 aaa라는 새로운 메모리 영역을 만들게 된다.
그리하여 어느 순간엔 컴퓨터의 모든 메모리를 차지하게 되고
원래대로라면 에러가 나지만
발전한 비주얼 스튜디오는.. 에러가 나기 전에 멈춰버리게 해 버린다.
다만 이런 방식으로 사용하면
횟수를 조절할 수 있다.
데니스 리치(c언어 창조자)가 만들어둔 함수를 표준함수
(ex. printf, scanf...)
우리가 만드는 함수를 사용자 정의 함수
라고 한다.
그리고 이런 것을 모아둔 것을 라이브러리라고 한다.
'# 개발 > C언어' 카테고리의 다른 글
c언어 #7 - 배열, 문자열 (국비9일차) (0) | 2023.01.11 |
---|---|
c언어 연습문제 #7 (국비8일차) (0) | 2023.01.10 |
c언어 연습문제 #6 - 응용 (국비7일차) (0) | 2023.01.09 |
c언어 연습문제 #5 (국비7일차) (0) | 2023.01.09 |
c언어 연습문제 #4 (국비6일차) (0) | 2023.01.06 |