7강 · 제5장 · 152~173쪽 · 약 70분
함수와 기억 클래스(2)
값/참조에 의한 자료 전달, 지역·전역 변수, auto·static·extern·register와 예제 프로그램 5-1~5-3을 익힙니다. (교재 제5장 152~173쪽)
학습 목표
- 값에 의한 전달과 참조에 의한 전달을 구분하고, swap 전후 원본이 달라지는 이유를 설명한다
- 지역변수·전역변수·블록 범위에서 같은 이름이 가려지는 규칙을 말한다
- auto·static·extern·register의 수명·범위·초깃값을 비교한다
- 재귀함수의 의미를 알고 factorial 예제를 실행한다
- 교재 예제 5-7~5-14와 예제 프로그램 5-1~5-3을 실행해 결과를 예측한다
왜 이 강이 필요한가?
6강에서 함수를 정의·호출하고, 값에 의한 전달로 swap이 원본을 바꾸지 못하는 것까지 봤습니다.
7강은 교재 제5장 152~173쪽이며, LMS 강의내용은 자료 전달 방법과 기억 클래스입니다.
- 자료 전달 방법 — 값에 의한 전달(5-7)과 참조에 의한 전달(5-8)
- 지역변수와 전역변수 — 선언 위치와 유효 범위(5-9~5-11)
- 기억 클래스 —
auto·static·extern·register(5-12~5-14) - 예제 프로그램 — 대소문자 변환, 재귀 factorial, 값/참조 비교
본문 C 예제는 실행 칸이 붙습니다. scanf가 필요한 곳은 sscanf로 교재 입력을 넣었습니다. 키보드는 맨 아래 종합 실습의 「표준 입력」을 쓰세요. 표기는 int main(void)입니다.
1. 함수의 자료 전달 방법
호출할 때와 돌아올 때, 실매개변수와 형식매개변수 사이에 자료가 오가는 방법은 둘입니다.
| 방법 | 무엇이 넘어가나 | 함수가 끝나면 |
|---|---|---|
| 값에 의한 전달 (call by value) | 값의 복사 | 형식매개변수를 바꿔도 원본은 그대로 |
| 참조에 의한 전달 (call by reference) | 주소 | 같은 기억 장소를 가리키므로 원본도 바뀔 수 있음 |
C의 기본은 값에 의한 전달입니다. 값은 여러 개 넘길 수 있지만, 복사본을 바꿔도 원본은 돌아오지 않습니다. 돌려받는 값은 보통 return 하나입니다.
1.1 값에 의한 자료 전달 (예제 5-7)
fcn1(10, 20)처럼 호출하면 10과 20이 형식매개변수로 복사됩니다. 함수가 쓰는 공간은 호출한 쪽과 다릅니다.
교재 5-7 — swap이 호출한 쪽의 a, b를 바꾸지 못함 (6강에서 본 예제를 다시 확인):
이 예제 실행
실행 결과가 여기에 표시됩니다.
실행: 호출 전 3, 5 → 함수 안 5, 3 → 호출 후 다시 3, 5.
의도는 서로 바꾸는 것이었지만, 복사본만 바뀌었습니다.
1.2 참조에 의한 자료 전달 (예제 5-8)
값이 아니라 그 값이 들어 있는 주소를 넘깁니다. 그러면 실매개변수와 형식매개변수가 같은 기억 장소를 가리킵니다.
- 호출할 때 실매개변수 앞에 주소 연산자
&—swap(&a, &b) - 형식매개변수는 포인터 —
int *x, int *y - 그 주소의 값에 접근할 때는
*x
scanf("%d", &n)이 &를 쓰는 이유도 같습니다(3강). 포인터 연산의 자세한 규칙은 8~9강입니다. 여기서는 “주소를 넘기면 원본을 바꿀 수 있다”만 잡으면 됩니다.
교재 5-8 — 같은 swap을 주소로 호출:
이 예제 실행
실행 결과가 여기에 표시됩니다.
실행: 호출 전 3, 5 → 함수 안 5, 3 → 호출 후 5, 3. 원본이 바뀝니다.
2. 지역변수와 전역변수
기억 클래스는 변수를 기억 공간의 어디에, 언제까지, 어떻게 초기화할지입니다. 자료형이 “몇 바이트·어떤 값”이라면, 기억 클래스는 유효 범위와 존속 기간(수명) 입니다.
선언 위치에 따라:
| 지역변수 (local) | 전역변수 (global) | |
|---|---|---|
| 선언 | 함수·블록 안 | 함수 밖(파일) |
| 보이는 곳 | 그 블록/함수만 | 선언 이후 프로그램 전체 |
| 매개변수 | 지역변수의 성질 | — |
같은 이름이면 지역이 전역을 가립니다. 전역은 파일 앞쪽에 두는 것이 좋습니다. 선언보다 앞에서는 아직 효력이 없기 때문입니다.
전역은 꼭 필요할 때만 씁니다. 어디서든 바뀌면 결과를 추적하기 어렵습니다. 지역을 쓰면 함수가 독립적이고, 디버깅이 쉽고, 기억 공간을 아낄 수 있습니다. 재귀도 지역변수가 있어야 구현이 자연스럽습니다.
2.1 예제 5-9 — 함수마다 다른 i
이 예제 실행
실행 결과가 여기에 표시됩니다.
실행: main i = 10 → fcn1 i = 20 → main i = 10. fcn1의 i = 20은 main의 i를 건드리지 않습니다.
2.2 예제 5-10 — 블록 안의 같은 이름
안쪽 중괄호는 새로운 블록입니다. 거기서 선언한 x는 바깥 x를 가리고, 블록이 끝나면 사라집니다. 바깥 y는 안쪽에서도 같은 변수입니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
실행: A : 2, 4 → B : 5, 5 → A : 2, 5. 안쪽 x = 5는 바깥 x를 바꾸지 않고, y++만 바깥에 남습니다.
2.3 예제 5-11 — 전역변수
함수 밖 int x;는 초기화하지 않으면 0입니다. 모든 함수에서 보입니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
실행: 1) x = 0 → 2) x = 1.
3. 기억 클래스의 종류
수명·초기화·범위를 정하는 지정자입니다.
형식: 기억클래스 자료형 변수명;
예: auto int n;
static int s;
extern char s[];
register int i;
3.1 자동변수 (auto)
함수(블록)가 시작될 때 스택에 만들어지고, 끝나면 사라집니다. auto는 적어도 되고, 지역변수는 보통 생략합니다. 초깃값은 쓰레기 값이므로 반드시 초기화하세요.
3.2 정적변수 (static) — 예제 5-12
static이면 컴파일 때 고정 공간이 생기고, 함수가 끝나도 값이 남습니다. 초기화는 한 번이며, 안 적으면 0입니다.
함수 안의 static은 전역처럼 값이 유지되지만, 그 함수 안에서만 보입니다. 다른 파일이 extern으로 가져갈 수 없습니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
실행: s는 1,2,3,4,5로 늘고 a는 매번 1입니다.
3.3 외부변수 (extern) — 예제 5-13
함수 밖에 둔 전역과 같습니다. 초깃값 0, 프로그램이 끝날 때까지 유지.
다른 점은 다른 파일에서 extern으로 그 이름을 가리킬 수 있다는 것입니다. 여러 .c가 변수를 공유할 때 씁니다.
교재는 5-13.c(정의)와 5-13_1.c(extern char s[];) 두 파일입니다. 이 사이트 실행기는 한 파일만 컴파일하므로, 아래는 한 파일로 합친 실행용입니다. 의미는 “s는 파일 전체에서 공유된다”입니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
두 파일로 쓸 때의 골격은 다음과 같습니다.
/* 5-13.c — 정의 */
char s[100];
void extern_ex(void);
/* 5-13_1.c — 다른 파일에서 참조 */
extern char s[];
void extern_ex(void) {
printf("%s\n", s);
}
로컬에서 두 파일을 함께 링크할 때: clang 5-13.c 5-13_1.c -o out
3.4 레지스터 변수 (register) — 예제 5-14
CPU 레지스터에 두면 메모리보다 빠를 수 있어, 반복 카운터에 쓰라는 것이 교재의 설명입니다. 성질은 자동변수와 같고, 전역으로는 못 씁니다. 레지스터 개수는 적으므로 요즘은 컴파일러가 알아서 넣고, register는 거의 무시됩니다.
교재 제약: 레지스터 폭을 넘는 형은 못 쓰고, 메모리에 없으므로 &변수는 오류라고 합니다. 현대 clang은 register를 무시해서 &가 되는 경우가 많습니다. 아래는 sizeof와 1~10의 합만 실행합니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
맥에서 흔히 num1 size = 4, num2 size = 8, 합 num2 = 55. 교재는 sizeof를 %d로 찍지만, 이 사이트는 %zu를 씁니다(2강).
3.5 한눈에 보기
| 클래스 | 예약어 | 위치 | 기억 | 초깃값 | 수명 | 범위 |
|---|---|---|---|---|---|---|
| 자동 | auto 또는 생략 | 함수·블록 안 | 동적(스택) | 미정(쓰레기) | 벗어나면 소멸 | 그 블록 |
| 정적 | static | 함수·블록 안 | 정적 | 0 | 프로그램 끝까지 | 그 블록만 |
| 정적(전역) | static | 함수 밖 | 정적 | 0 | 끝까지 | 그 파일 |
| 외부 | (정의) / extern | 함수 밖 등 | 정적 | 0(정의) | 끝까지 | 정의·참조한 파일 |
| 레지스터 | register | 함수·블록 안 | 동적 | 미정 | 소멸 | 그 블록 |
동적 = 필요할 때 자리를 잡음. 정적 = 실행 내내 같은 자리. 소멸 = 블록을 벗어나면 값 없음. 불멸 = 프로그램이 끝날 때까지 유지.
4. 예제 프로그램
예제 5-1 — 대·소문자 바꾸기
영문 대문자면 +32로 소문자, 소문자면 −32로 대문자(ASCII 차이 32, 2강). 숫자·기호는 그대로입니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
교재 결과: CSknou1004@KNOU.AC.KR
예제 5-2 — 재귀함수로 factorial
재귀함수는 자기 자신을 호출하는 함수입니다. n! = n × (n-1)!, 1! = 1. 교재는 1~8만 받습니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
5 → 120. line을 "4"로 바꾸면 24입니다.
예제 5-3 — 값 전달 vs 참조 전달
이 예제 실행
실행 결과가 여기에 표시됩니다.
값 호출 후에도 2, 4, 6. 참조 호출 후 0, 0, 0. by_value 안에서만 바꾸고 쓰지 않으면 컴파일러가 “안 쓰는 매개변수” 경고를 낼 수 있습니다. 그 경고가 곧 “원본과 무관한 복사본”이라는 뜻입니다.
5. 지금 실습할 것
아래는 값/참조 swap과 static 카운터를 한 파일에 모았습니다.
- 그대로 실행해 값 호출 후 원본이 그대로인지, 주소 호출 후 바뀌는지 확인
static_test를 5번 호출해s만 증가하는지 보기- (선택) 「표준 입력」에 문자열을 넣고 예제 5-1처럼 대소문자를 뒤집어 보기
- factorial의
5를6으로 바꿔 720인지 확인
코드 실습 (C)
실행 결과가 여기에 표시됩니다.