쉽게풀어쓴 C 언어 Express 제 9 장함수와변수
이번장에서학습할내용 변수의속성 전역, 지역변수 자동변수와정적변수 재귀호출 이번장에서는함수와변수와의관계를집중적으로살펴볼것이다. 또한함수가자기자신을호출하는재귀호출에대하여살펴본다.
변수의속성 변수의속성 : 이름, 타입, 크기, 값 + 범위, 생존시간, 연결 범위 (scope) : 변수가사용가능한범위, 가시성생존시간 (lifetime) : 메모리에존재하는시간연결 (linkage) : 다른영역에있는변수와의연결상태 생존시간 범위 연결 생성 3 x x 소멸
변수의범위 변수의범위 전역변수 지역변수 함수 함수 전역변수 지역변수 지역변수
전역변수와지역변수
지역변수 지역변수 (local variable) 는블록안에선언되는변수
지역변수선언위치 블록첫부분에서정의 int sub(void) int x; // 1... x = 100; int y; // 2 변수를함수의첫부분에선언하지않으셨군요. 컴파일오류입니다.
지역변수의범위 void sub1(void) y = 4; int y;... 지역변수는선언된블록을떠나면안됩니다.
이름이같은지역변수
지역변수의생존기간 int x; x 생성 블록 생존시간 소멸
지역변수예제 #include <stdio.h> int main(void) int i; 21 temp for(i = 0;i < 5; i++) int temp = 1; printf("temp = %d\n", temp); temp++; return 0; temp = 1 temp = 1 temp = 1 temp = 1 temp = 1 블록이시작할때마다생성되어초기화된다.
지역변수의초기값 #include <stdio.h> int main(void) int temp; printf("temp = %d\n", temp); 초기화되지않았으므로쓰레기값을가진다. temp = -858993460
함수의매개변수 int inc(int counter) counter++; return counter; 매개변수도일종의지역변수
함수의매개변수 #include <stdio.h> int inc(int counter); int main(void) int i; 10 10 i 11 i = 10; printf(" 함수호출전 i=%d\n", i); inc(i); printf(" 함수호출후 i=%d\n", i); return 0; int inc(int counter) counter++; return counter; 함수호출전 i=10 함수호출후 i=10 매개변수도일종의지역변수
전역변수 전역변수 (global variable) 는함수외부에서선언되는변수이다. 전역변수의범위는소스파일전체이다. int x = 123; void sub1() x = 456; 전역변수 void sub2() x = 789;
전역변수의초기값과생존기간 #include <stdio.h> int counter; // 전역변수 void set_counter(int i) counter = i; // 직접사용가능 int main(void) printf("counter=%d\n", counter); counter = 100; // 직접사용가능 printf("counter=%d\n", counter); * 전역변수의초기값 : 0 * 생존기간 : 프로그램시작부터종료 20 i 100 20 0 set_counter(20); printf("counter=%d\n", counter); return 0; counter=0 counter=100 counter=20
전역변수의사용 // 전역변수를사용하여프로그램이복잡해지는경우 #include <stdio.h> void f(void); 출력은어떻게될까요? int i; int main(void) for(i = 0;i < 3; i++) f(); return 0; void f(void) for(i = 0;i < 5; i++) printf("#\n"); ( O X ) ( O ) 03 21 45 6 i # # # # #
전역변수의사용 거의모든함수에서사용하는공통적인데이터는전역변수로한다. 일부의함수들만사용하는데이터는전역변수로하지말고함수의인수로전달한다.
같은이름의전역변수와지역변수 // 동일한이름의전역변수와지역변수 #include <stdio.h> int sum = 1; int main(void) // 전역변수 int sum = 0; // 지역변수 printf("sum = %d\n", sum); 지역변수가전역변수를가린다. 1 sum 0 sum < 전역변수 sum> < 지역변수 sum> return 0; sum = 0
중간점검 변수의범위는대개무엇으로결정되는가? 변수의범위에는몇가지의종류가있는가? 파일범위를가지는변수를무엇이라고하는가? 블록범위를가지는변수를무엇이라고하는가? 지역변수를블록의중간에서정의할수있는가? 똑같은이름의지역변수가서로다른함수안에정의될수있는가? 지역변수가선언된블록이종료되면지역변수는어떻게되는가? 지역변수의초기값은얼마인가? 함수의매개변수도지역변수인가? 전역변수는어디에선언되는가? 전역변수의생존기간과초기값은? 똑같은이름의전역변수와지역변수가동시에존재하면어떻게되는가?
생존기간 정적할당 (static allocation): 프로그램실행시간동안계속유지 자동할당 (automatic allocation): 블록에들어갈때생성 블록에서나올때소멸
생존기간 생존기간을결정하는요인 변수가선언된위치 저장유형지정자저장유형지정자 auto register static extern
저장유형지정자 auto int main(void) auto int sum = 0; int i = 0;...... 0 0 sum i 전부자동변수로서함수가시작되면생성되고끝나면소멸된다.
#include <stdio.h> void sub(void); 저장유형지정자 static int main(void) int i; for(i = 0;i < 3; i++) sub(); 자동지역변수 return 0; void sub(void) int auto_count = 0; static int static_count = 0; 01 20 31 auto_count auto_count++; static_count++; printf("auto_count=%d\n", auto_count); printf("static_count=%d\n", static_count); static_count 정적지역변수로써 static 을붙이면지역변수가정적변수로된다. auto_count=1 static_count=1 auto_count=1 static_count=2 auto_count=1 static_count=3
저장유형지정자 register register int i; for(i = 0;i < 100; i++) sum += i; CPU 안의레지스터에변수가저장됨
중간점검 저장유형지정자에는어떤것들이있는가? 지역변수를정적변수로만들려면어떤지정자를붙여야하는가? 변수를 CPU 내부의레지스터에저장시키는지정자는? 컴파일러에게변수가외부에선언되어있다고알리는지정자는? static 지정자를변수앞에붙이면무엇을의미하는가?
실습 : 로그인횟수제한 로그인시에제한된횟수만큼틀리면로그인시도를막는프로그램을작성하여보자.
id: 1111 pass: 1111 id: 1111 pass: 1111 id: 1111 pass: 1111 횟수초과 실행결과
알고리즘 while(1) 사용자로부터아이디를입력받는다. 사용자로부터패스워드를입력받는다. 만약로그인시도횟수가일정한도를넘었으면프로그램을종료한다. 아이디와패스워드가일치하면로그인성공메시지를출력한다. 아이디와패스워드가일치하지않으면다시시도한다.
소스 #include <stdio.h> #include <stdlib.h> #define SUCCESS 1 #define FAIL 2 #define LIMIT 3 int check(int id, int password); int main(void) int id, password, result; while(1) printf("id: \b\b\b\b"); scanf("%d", &id); printf("pass: \b\b\b\b"); scanf("%d", &password); result = check(id, password); if( result == SUCCESS ) break; printf(" 로그인성공 \n"); return 0;
소스 int check(int id, int password) static int super_id = 1234; static int super_password = 5678; static int try_count = 0; try_count++; if( try_count >= LIMIT ) printf(" 횟수초과 \n"); exit(1); if( id == super_id && password == super_password ) return SUCCESS; else return FAIL; 정적지역변수
저장유형지정자 extern extern1.c #include <stdio.h> 컴파일러에게변수가다른곳에서선언되었음을알린다. int x; extern int y; extern int z; int main(void) y = 20; z = 30; // 전역변수 // 현재소스파일의뒷부분에선언된변수 // 다른소스파일의변수 return 0; int y; // 전역변수 extern2.c int z;
연결
외부연결 전역변수를 extern 을이용하여서서로연결
linkage1.c 연결예제 #include <stdio.h> int all_files; // 다른소스파일에서도사용할수있는전역변수 static int this_file; // 현재의소스파일에서만사용할수있는전역변수 extern void sub(); int main(void) 연결 sub(); printf("%d\n", all_files); return 0; linkage2.c extern int all_files; void sub(void) all_files = 10; 10 0 10 0
함수앞의 static main.c #include <stdio.h> extern void f2(); int main(void) f2(); return 0; sub.c static void f1() printf("f1() 이호출되었습니다.\n"); void f2() f1(); printf("f2() 가호출되었습니다.\n"); Static 이붙는함수는파일안에서만사용할수있다.
저장유형정리 저장유형 키워드 정의되는위치 범위 생존시간 자동 auto 함수내부 지역 임시 레지스터 register 함수내부 지역 임시 정적지역 static 함수내부 지역 영구 전역 없음 함수외부 모든소스파일 영구 정적전역 static 함수외부 하나의소스파일 영구 외부참조 extern 함수외부 모든소스파일 영구
순환 (recursion) 이란? 알고리즘이나함수가수행도중에자기자신을다시호출하여문제를해결하는기법 팩토리얼의정의 1 n! n*( n 1)! n 1 n 2
팩토리얼구하기 팩토리얼프로그래밍 #2: (n-1)! 팩토리얼을현재작성중인함수를다시호출하여계산 ( 순환호출 ) int factorial(int n) if( n <= 1 ) return(1); else return (n * factorial(n-1) ); 3 n 3! 은? 3! 를계산하려면 3! = 3*2! 2! 를계산하려면 2! = 2*1! 1! 은 1 3! 는? 2! 는? 1! 는? 6 2 1
팩토리얼구하기 팩토리얼의호출순서 factorial(3) = 3 * factorial(2) = 3 * 2 * factorial(1) = 3 * 2 * 1 = 3 * 2 = 6 4 3 factorial(3) if( 3 >= 1 ) return 1; else return (3 * factorial(3-1) ); factorial(2) if( 2 >= 1 ) return 1; else return (2 * factorial(2-1) ); factorial(1) if( 1 >= 1 ) return 1;... 1 2
순환알고리즘의구조 순환알고리즘은다음과같은부분들을포함한다. 순환호출을하는부분 순환호출을멈추는부분 int factorial(int n) if( n == 1 ) return 1 순환을멈추는부분 else return n * factorial(n-1); 순환호출을하는부분 만약순환호출을멈추는부분이없다면?. 시스템오류가발생할때까지무한정호출하게된다.
피보나치수열의계산 #1 순환호출을사용하면비효율적인예 피보나치수열 0,1,1,2,3,5,8,13,21, 0 fib( n) 1 fib( n 2) fib( n 1) n 0 n 1 otherwise 순환적인구현 int fib(int n) if( n==0 ) return 0; if( n==1 ) return 1; return (fib(n-1) + fib(n-2));
피보나치수열의계산 순환호출을사용했을경우의비효율성 같은항이중복해서계산됨 예를들어 fib(6) 을호출하게되면 fib(3) 이 4 번이나중복되어서계산됨 이러한현상은 n 이커지면더심해짐 fib(6) fib(4) fib(5) fib(2) fib(3) fib(3) fib(4) fib(2) fib(3) fib(1) fib(2) fib(1) fib(2) fib(2) fib(3)
Q & A