배열의정의
배열이란?

배열은 동일한 타입을 가지는 변수들의 유한한 집합이다. 변수 선언문의 형태에서 []를 붙이고 선언할 개수 만큼을 쓴다.


int arrays[10] 과 같이 하면 int형 변수 10개를 선언해놓고 쓰는 것처럼 쓸 수 있다.

[] 괄호가 1개 있으면 1차원 배열, 2개 있으면 2차원 배열하는 식으로 늘어난다.


type은 어떤 타입의 변수들이 모여 있는지를 지정하는데, 정수형 변수의 모임이라면 int, 실수형 변수의 모임이라면 float 과 같이 적는다. 꼭 기본형만이 아니라 사용자 정의형 , 구조체등.. 타입 T가 있으면 T형 배열은 언제나 가능하다.


ar[5]를 선언했을 때 이처럼 5개의 공간이 할당된다 ar의 타입에 따라서 각 요소들의 타입이 결정된다. int ar[5]라고 선언했다면 위의 5개의 배열의 멤버들은 5개의 int 형 변수가 된다. 이때 각 요소는 ar[0] 과 같이 접근해서 변수처럼 다룰 수 있다.


배열의 특징

1. 배열의 요소의 번호인 첨자는 항상 0부터 시작한다. 따라서 크기가 5라면 1 ~ 5까지의 5개가 아니라 0부터 4까지의 배열이 생성된다.

2. 배열이 차지하는 총 메모리양은 배열의 크기 (개수)에 요소의 크기를 곱해서 구할 수 있다. 즉 배열의 총 크기는 sizeof(타입) * 개수이다.  int ar[5]의 경우 4바이트인 int이므로 4 * 5 로 20 바이트를 차지하게 된다.

3. 배열을 선언할 때 그 크기(개수) 값은 반드시 상수로 주어야한다. ar[i]와 같이 사용하는 것은 가능하지만 ar[i]와 같이 (i가 변수인 경우) 사용하는 것은 불가능하다. define 상수를 사용하여 선언하는 것은 가능하다.

4. c언어는 배열의 범위를 점검하지 않는다. 이것은 배열의 특징이 아니라 c언어와 다른 언어와 구별되는 특징으로.. 컴파일러는 ar[5]의 길이가 ar[4]까지라는 것을 알고 있지만.. ar[9] = 1234; 와 같은 코드 역시 에러나 경고를 띄우지 않고 컴파일 된다. 이유는 배열의 신속함을 떨어트리지 않기 위해 컴파일러가 점검하지 않도록 하였기 때문이다.


다차원 배열

2차원 배열은 첨자 두 개를 사용하는 배열이다. 3차원은? 3개.. 이런 식이다.

int ar[3][6] 과 같이 선언하면 2차원 배열이다.


실제로는 선형 구조이기 때문에 일직선으로 연결되어 있다.

[][][][][][][][]][][][][][][][]... 하는 식으로 연결되어 18개의 공간을 6개씩 3분할 하는 형태를 띄고 있다.


배열은 (혹은 구조체) 커다란 크기를 가질 수 있는데..  잡히는 공간에 따라 가질 수 있는 크기가 다르다. 지역에 선언된 배열(구조체)은 1mb 전후의 stack 공간의 크기 만큼이 한계이며 (char형으로 100만개 좀 넘게 선언하면 멈춘다) 전역으로 선언할 경우 컴퓨터의 사양등에 따라 다르지만 기가 단위 까지도 가능하다.


배열명

배열의 이름은 무슨 기능을 할까? arr[0] 이나 arr[3]과 같이 사용하지 않고 arr만 쓴다면?

배열의 이름이 단독으로 사용되면 배열의 시작 번지 값을 가지는 포인터 상수이다.

그러니까 그냥.. 해당 이름에 배열의 첫번째 요소의 주소(번지)라고 보면 된다.


arr은 &arr[0]과 같다.


이 때문에 배열은 배열의 이름에 대하여 어떤 값을 대입받거나 할 수 없다. 배열의 첫 번째 위치를 저장하는 주소이므로.. 해당 주소를 바꾸거나 하면 안되는 것이다. (참조하고 있는 메모리 공간의 위치를 유실하게 되어버린다.) 따라서 그것은 바꿀 수 없게 되어 있다.

두개의 배열 arr와 ar1이 존재할 때.

arr = ar1 과 같은 문장은 성립하지 않는다.


배열 초기화

변수에 적용되는 모든 규칙은 배열에도 그대로 적용된다. 그래서 변수에 적용되는 모든 규칙이 배열에도 똑같이 적용된다. 배열 선언에 사용되는 기억 부류 지정자도 일반 변수와 동일하며 그 효과도 완전히 동일하다. (전역 배열은 정적 메모리 영역인 data 영역에 할당되는 반면, 지역 배열은 stack에 할당된다!)

따라서 지역 배열은 초기화를 해주지 않았다면 지역변수와 동일하게 쓰레기 값이 들어 있게 된다.


배열 초기화

int ar[5] = {4,8,3,4,-1}; 처럼 선언과 동시에 초기화를 하면 메모리를 할당 받음과 동시에 초기화 값들로 메모리를 쵀운다.

초기화를 할때 int ar[5] = {3,5,78,32,2,1,2} 과 같이 []안에 선언한 개수와 선언한 요소의 개 수가 맞지 않는 경우는 에러가 발생한다.

컴파일러는 int ar[] = {3,5,78,32,2,1,2} 과 같은 방식을 지원한다. 이렇게 선언하면 해당 요소의 개수에 맞는 크기의 배열을 생성해준다.

int ar[500] = { 1,2,3 }

과 같이 '요소의 총 개수보다 선언한 초기 값이 적은 경우' 에는  비어 있는 뒤 쪽은 0으로 전부 초기화된다. 간단히 전부 0으로 하고 싶다면 int ar[] = {0}; 과 같이 써주면 된다.

정리하자면 초기 값이 많으면 에러 , 적으면 나머지는 0으로 , 배열 크기를 안쓰면 초기값의 개수에 맞춰서 배열이 생성된다.


다차원 배열을 초기화하는 경우에는 크게 다르지 않다.

 

int ar[2][3]={1,2,3,4,5,6};

이것은 다음과 같이 초기화된다.

 

왜 일렬로 했는데 되냐면.. 어디까지나 배열은 선형구조이다. 위와 같은 경우 6개의 메모리로 이루어진 길다란 선을 2등분 해놓은 것에 지나지 않기 때문이다. 하지만 이런 초기화 방법은 두 구간을 분류하여 볼 수 없으므로.. int ar[2][3]={{1,2,3},{4,5,6}}; 의 방식을 보다 더 많이 사용한다.


초기 값이 모자라는 경우 int ar[2][3]={{1},{4,5,6}}; 와 같이 해주었다면,[0][1] , [0][2]번째 요소들은 0으로, 나머지의 값만을 초기화하게 된다.

단 {}를 생략한 int ar[2][3]={1,4,5,6}; 의 경우.. 순서대로 채워져 [1][1]과 [1][2]가 0이 된다.


초기 값 개수가 남는 경우는 역시 에러이다. 처음 본 상황 말고도

int ar[2][3]={{1,2},{4,5,6,7}}; 같은 상황도 에러다. 물론
int ar[2][3]={1,2,4,5,6,7}; 가 되면 에러가 아니게 된다.


2차원 배열도 1차원 배열과 마찬가지로 배열의 크기를 생략할 수 있되 1차 첨자의 크기만 생략 가능하며 나머지 첨자는 반드시 밝혀야 한다.

 int ar[][3]={{1,2,3},{4,5,6}};


배열의 활용

1. 불규칙한 정보를 저장하기에 적합하다.

2. 재사용할 정보의 저장에도 유리한데, 여러 변수를 선언할 필요 없이 배열 하나로 저장할 수 있기 때문이다.

3.룩업 테이블을 작성할 수 있다.


미리 계산된 값

연산을 통해서 일일히 결과를 얻는 것은 꽤 오랜 시간이 걸리는 일이기도 하다. 따라서 연산의 결과를 배열에 저장해놓고, 그 값이 필요한 상황에 배열의 값을 가져다 쓰는 방식을 사용하면 상당한 속도적 이득을 볼 수 있다.

'프로그래밍 > 프로그래밍 공부' 카테고리의 다른 글

11장 배열과 포인터  (0) 2015.03.02
10장 포인터  (0) 2015.03.01
9장 배열  (0) 2015.02.28
8장 표준함수  (0) 2015.02.28
7장 기억 부류  (0) 2015.02.27
6장 함수  (0) 2015.02.27
Posted by GENESIS8

댓글을 달아 주세요

컴파일러는 공통적으로 자주 사용되는 기능들을 표준 함수들로 제공한다

 ANSI C 표준은 C 컴파일러가 제공해야 하는 함수의 목록과 원형, 그리고 구체적인 기능까지도 규정하고 있으므로 이 표준을 따르는 컴파일러는 반드시 표준이 지정한 바대로 라이브러리를 제공해야 하는 의무를 지며 사용자들은 이식성을 걱정할 필요없이 표준 함수를 자유롭게 사용할 수 있게 되었다.


수학함수

math.h를 인클루드 하면 사용할 수 있다. 수학 함수는 수학적인 계산을 하는 함수들이다.


삼각함수

sin , cos , tan ( 삼각 함수 )

asin , acos , atan ( 삼각함수의 역함수 )

sinh , cosh , tanh ( 쌍곡선 함수 )

여기서 삼각함수가 받아들이는 인수는 각도(degree)가 아니라 호도(radian)이다.

호도를 각도로 바꾸고 싶으면 2π를 곱해주면 된다.


지수 함수

지수 함수는 거듭승이나 제곱근, 로그 따위의 값을 구하는 함수들이다.실수 차원에서 계산을 하기 때문에, 취하는 인수나 리턴 값은 모두 정밀도가 높은 double형이다.

sqrt x의 (제곱근) , pow(x의 y승), log(자연 대수) , log10 (상용 대수), exp( 자연 대수 exp) , hypot( 직삼각형의 사변 길이) 들이 있다.


정수화 함수

정수화 함수는 실수형 데이터에서 정수부만을 취하는.. 즉 소수점 이하의 소수부를 잘라버리는 함수이다. 소수부를 자른다고 해서 결과가 정수가 되는 것은 아니며, 리턴 값은 여전히 실수이다. 다만 소수부분만을 0으로 만드는 것이다.

floor는 소수점 이하를 버리고 정수부만을 취하는 반면

ceil은 소수점 이하를 올림해서 정수부를 1 더 증가시킨다.


절대 값 함수

절대 값 함수는 인수의 타입에 따라 세 가지가 준비되어있다.

각각 abs , labs (long) , fabs(double)이다.


난수 함수

난수(random number)란 무작위로 만들어지는 알 수 없는 값이다. 마치 주사위를 던졌을 때 어떤 수가 나올 지 알 수 없는 것 처럼 말이다.

난수를 만드는 함수는

int rand(void)와 void srand(unsigned int seed) 이다.

rand 함수는 0 ~ RAND_MAX(일반적으로 32767) 사이의 무작위 수를 하나 생성해 낸다.

하지만 진정한 의미에서 난수라고 할 수는 없는데.. 난수이긴 한데 나오는 순서가 일정하기 때문에 생성되는 값도 항상 같다. 그래서 그것을 변화시키는 데 사용되는 것이 srand 함수이다.

srand함수는 난수의 시작점을 제공하며 이 시작점을 기준으로 하여 난수를 발생시킨다. 하지만 시작점이 동일하면 난수 역시 동일해지게 되는 데.. 예측가능성을 막기 위해서 주로 시간을 준다.

srand( (unsigned) time (NULL) );

time 함수는 현재의 시간을 나타내는 정수 값을 리턴하는데.. 이 값을 시작점으로 사용하면 프로그램이 실행될 때마다 난수의 값이 매번 달라질 수 있다. time함수의 대용으로는 API의 GetTickCount를 사용할 수 있다.


난수의 생성

random 함수를 응용하여 여러 유형의 난수를 생성할 수 있다.

1. 0 ~ n 사이의 난수 생성시 가장 큰 값은 n-1이다. (n 값을 입력해도 n 값이 나오지는 않는다.)

2. 만들어내는 난수의 최소 값은 항상 0으로 고정되어 있다.

rand()%10 + 1 // 1 ~ 10 사이의 난수

rand()%10 + 10 // 10 ~ 19 사이의 난수

생성된 난수에 상수를 더하면 난수의 범위가 평행이동 된다.

3. 난수 사이의 간격은 난수를 곱한 후 곱을 사용한다. 이때 범위를 지정하는 인수는 곱해주는 수를 미리 나누어 구해야한다. 만약 0 ~ 100미만의 '짝수'중 하나를 구하고자 한다면 다음과 같이 한다.

rand()%(100/2)*2

100/2는 50이므로 0 ~ 49 사이의 값이 생성되고 2를 곱하면 0~ 98이 된다.

4. 실수 난수가 필요하다면 먼저 충분한 크기의 정수 난수를 구하고, 필요한 유효 자리 수 만큼 10의 거듭승으로 나눈다.

rand()%100 / 10.0

생성된 0 ~ 99 사이의 정수를 10.0으로 나누어 0.0 ~ 9.9까지의 값이 나오게 된다. 소수점 몇번째 자리 까지를 구하느냐에 따라서 값을 다르게 넣으면 되는데   0 ~ 1000까지의 값을 100.0으로 나누면 소수점 두번째 자리까지 구할 수 있게 된다.

5. 분리된 범위의 난수도 생성가능하다.

(random()%5+5) * ( (rand()%2==0) ? 1 : -1) + 9

0 ~ 4. 사이의 난수 + 14가 되어 14 ~ 18의 난수가 될 지,

0 ~ 4사이의 값이 될 지 나눌 수 있다.

6. 전혀 연관성이 없는 수들 중 하나를 택하여 난수로 선택할 수도 있다.

3, 7 , 12 , 15중 하나를 선택하고 싶다면

do{

i = rand()%10;

} while (i != 3 && i != 7 && i != 12 && i != 15);

// 위의 네 숫자가 아닌 경우 계속해서 새로 값을 넣는다.


시간 함수

컴퓨터 안에는 시계가 내장되어 있어 항상 시간을 유지하고 있는데.. 시간을 필요로 할 경우 시간 함수로 이 값을 조사할 수 있다. 시간과 관련된 가장 기본적인 함수는 현재 시간을 구하는 tjme 함수이다.

time_t , _time64

 time 함수는 자정 (00:00), 1970, 1 월 1 일 UTC (협정 세계시) 이후 경과 된 시간을 초 단위로 반환합니다.

    time_t t;
     time(&t);  혹은     t = time(NULL); 와 같이 초기화

이렇게 해주어야 시간 변수에 시간 ㄱ밧이 들어간다.

다만 시간 자체는 UTC이므로.. 우리가 사용하는 우리 나라의 시간과는 좀 다르다. ( 9시간 차이)

printf("현재 시간은요 %s", ctime(&t) );

ctime 함수를 사용하면 UTC로 된 시간을 지역에 맞게 조정해줄 뿐더러 문자열로 바꾸어준다!


tm 구조체

tm

{

int    tm_sec   seconds 0, 61
int    tm_min   minutes 0, 59
int    tm_hour  hour 0, 23
int    tm_mday  day of month 1, 31
int    tm_mon   month of year 0, 11
int    tm_year  years since 1900 
int    tm_wday  day of week 0, 6 (Sunday = 0) 
int    tm_yday  day of year 0, 365
int    tm_isdst daylight savings flag 

}

 

멤버

설명

tm_sec

(0~59)

tm_min

(0~59)

tm_hour

시간(0~23)

tm_mday

날짜(1~31)

tm_mon

(0~11)

tm_year

1990 이후 경과 년수

tm_wday

요일(0~6). 0 일요일

tm_yday

년중 날짜(0~365)

tm_isdst

일광 절약 시간과의

 


void main()

{

     time_t t;

     tm *pt;

     time(&t);

     pt=localtime(&t);

     printf("현재 시간 %d년 %d월 %d일 %d시 %d분 %d초입니다.\n",

          pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,

          pt->tm_hour,pt->tm_min,pt->tm_sec);;

}

localtime을 써서 time_t을 시간 구조체 tm에 맞게 바꾸어주면 위와 같이 사용할 수 있다.


기타 시간 함수

clock_t clock(void);

이 함수는 프로그램이 실행을 시작한 후의 경과된 시간(process time)을 조사한다.

실행 후의 경과 시간 자체는 별로 쓸 데가 없는듯 하지만, 두 작업 시점간의 시간을 계산하거나 일정한 시간 만큼 특정 작업을 계속하고 싶을 때 clock 함수가 조사하는 시간이 기준점으로 사용될 수 있다.


double difftime(time_t time1 , time_t time2);

difftime 은 두 개의 시간을 인수로 전달하면 두 시간의 차이를 리턴한다. 단위가 초 단위이기 때문에 정밀한 계산에는 부적합하다.







'프로그래밍 > 프로그래밍 공부' 카테고리의 다른 글

10장 포인터  (0) 2015.03.01
9장 배열  (0) 2015.02.28
8장 표준함수  (0) 2015.02.28
7장 기억 부류  (0) 2015.02.27
6장 함수  (0) 2015.02.27
5장 연산자  (0) 2015.02.27
Posted by GENESIS8

댓글을 달아 주세요

기억 부류(storage class) // storage : 저장 ② 보관 ③ 창고 ④ 비축

 

지역 변수

전역변수와 지역변수.

기억부류란 변수가 저장되는 위치에 따라 결정되는 변수의 여러가지 성질을 의미한다. 변수가 어디에 생성되는가에 따라 통용 범위와 파괴 시기 등의 특징이 결정된다. 이 내용은 C의 문법 체계를 이해하는 데 상당히 중요한 비중을 차지하므로.. 숙독하여 완전히 이해하도록하자. 라고 적혀있다.

 

기억 부류에는 다음 4가지 종류가 존재한다.

 

기억 부류

전역

지역

정적

레지스터

지정자

extern

auto

static

register

저장 장소

정적 데이터 영역

스택

정적 데이터 영역

CPU 레지스터

선언 위치

함수의 외부

함수의 내부

함수의 내부

함수의 내부

통용 범위

프로그램 전체

함수의 내부

함수의 내부

함수의 내부

파괴 시기

프로그램 종료시

함수 종료시

프로그램 종료시

함수 종료시

초기값

0으로 초기화

초기화되지 않음

0으로 초기화

초기화되지 않음

 

먼저 지역변수와 전역변수를 비교하자면..

1. [저장 장소] 변수의 선언 위치가 다르다. 전역 변수는 함수 외부에 선언하고, 지역 변수는 함수 내부에서 선언한다. 

2. [통용 범위] 통용 범위란 변수가 사용될 수 있는 범위를 의미하는데.. 전역변수는 프로그램 전체가 공유한다. 단.. 자신이 선언된 이후에만 사용될 수 있다. 선언되기도 전부터 사용되는 것은 불가능하다. 반면 지역변수는 선언된 특정한 함수 / 지역안 에서만 작동한다. 그 밖에서는 존재할 수 없다. 지역을 벗어나면서 자동으로 소멸하게 된다.

3. [파괴 시기] 변수는 값을 기억하기 위해 메모리를 할당 받아 사용한다. 변수를 다 사용했다면 파괴하게 되는 데.. 이는 변수가 차지하고 있던 메모리를 회수한다는 의미이다. 전역 변수는 프로그램에 속해있고.. 모든 함수에서 사용 가능해야 하기 때문에.. 프로그램이 종료되기 전까지는 계속 존재하다가 프로그램이 종료될 때 파괴된다. 반면 지역 변수는.. 특정 지역(함수 등) 내부에서만 쓰이기 때문에.. 해당 지역이 끝나면 파괴된다.

4. [저장 장소] 변수가 메모리 상에 기억되는 장소가 다르다. 전역 변수는 한번 정해진 메모리 위치에 계속 남아 있어야 하므로.. 정적 데이터 영역 (data 영역)에 생성된다. 정적 데이터 영역이란 프로그램의 코드 바로 다음에 위치하는 실행파일의 한 부분인데, 프로그램이 실핼될 때 메모리로 로드되어 실행 중에 계속 유지된다. 반면 지역변수는 프로그램 실행 중에 생성과 파괴를 반복하므로 임시 메모리 영역인 스택(stack)에 생성된다.


 5. 초기화 여부가 다르다. 전역 변수는 별도의 초기식이 없더라도 0으로 초기화된다. (BSS 공간) 반면 지역 변수는 초기화를 해주지 않으면 쓰레기 값(garbage)이 들어 있는 상태가 된다. 전역변수와 달리 계속해서 생성과 파괴를 반복하기 때문에.. 매번 변수를 초기화하면 그만큼 실행 속도가 느려지기 때문에 초기화되지 않는 것이다.


지역 변수의 장점

지역 변수는 함수 내부에서만 사용할 수 있고, 함수가 끝나면 파괴되는데 비해 전역변수는 모든 함수에서 자유롭게 쓸 수 있고 프로그램이 실행 중인 동안은 유지된다. 그렇다면 지역변수가 없이 전역변수만 쓰는 것이 좋을까? 사실 지역변수가 없는 언어도 있고.. 지역 변수 없이도 얼마든지 프로그램을 작성할 수 있다.

어셈블리에서는 변수라는 개념자체가 없고 모든 것이 메모리 주소이기 때문에 모든 값은 전역이다. 고전 언어에도 지역 변수란 것이 없지만.. 근대적인 언어들은 모두 지역변수를 지원한다. 왜 지역변수를 지원하는가 하면.. 프로그램의 구조화에 큰 도움을 주고. 유지 , 보수를 쉽게 해주는 등의 장점이 있기 때문이다.


1. 함수의 독립성을 높인다. 프로그램은 함수로 구성되고 함수는 프로그램의 부품이다. 함수는 불가피한 경우를 제외하고는 가급적이면 독립적으로 스스로 작동할 수 있도록 만들어야 재활용에 유리하다. 부품끼리 공유하는 것(전역 변수)이 많아지다 보면 의존 관계를 가지게 되므로.. 서로 얽히고 섥혀서 좋지 않은 구조를 만들어낸다. 함수를 재활용하는 일은 흔한 일이고 생산성 향상을 위해서도 재활용해야한다.

2. 디버깅 효율을 향상시킨다. 전역변수는 통용 범위가 프로그램 전체인 반면, 지역 변수는 특정 위치로 한정되기 때문에 디버깅하기가 아주 쉽다. 지역변수가 말썽을 부린다면 해당 지역만 디버깅하면 되기 때문이다.

3. 지역변수는 메모리를 절약한다. 함수가 호출될 때만 생성되어, 종료된 즉시 파괴되므로.. 계속해서 유지되는 전역변수보다 메모리를 절약할 수 있다.

4. 재귀호출이나 상호 호출 같은 특별한 기법은 지역변수가 있어야만 사용할 수 있다.


외부변수

extern 선언은 전역변수를 의미한다. main보다 앞 쪽에 있는 경우 extern 선언을 생략할 수 있으나, 그렇지 않은 경우 선언해주어야한다. extern 선언은 블록 내에만 외부변수의 존재를 알리는 특징이 있다.


정적변수

정적 변수는 지역변수와 전역변수의 특징을 모두 가지는 특별한 기억부류이다.

1. 선언 위치는 지역 변수와 마찬가지로 함수의 선두이다.

2. 통용 범위는 지역변수와 마찬가지로 함수 내부로 국한된다.

3. 저장 장소는 전역 변수가 저장되는 정적 데이터 영역이다.

4. 정적 데이터 영역에 저장되므로 프로그램 실행 중에 항상 존재한다.

5. 초기값 지정이 없으면 0으로 초기화되고 프로그램 실행시 단 한번만 초기화된다.


기억 장소는 전역적이고, 통용범위는 지역적이다.

이 말은 함수 외부에 static을 선언해도 같은데, 외부에 선언된 static 변수를 외부 정적 변수라고 한다. 외부에 선언되었다고해서 전역 변수가 된 것이 아니라, 통용 범위가 '해당 모듈'이 되었을 뿐이다. 따라서 함수 밖에 선언되었다 할지라도.. 다른 모듈은 static으로 선언된 변수를 인식하지 못한다.

 

레지스터 변수

레지스터 변수는 CPU의 레지스터에 저장된다. 아주 적은 개수 밖에 없지만 무척 빠르다. register 를 붙이면 되며, 전역변수에는 사용이 불가하다.


그러나 c++은 register 지정자를 완전히 무시하며, 전역 최적화 옵션에 따라 자동으로 레지스터형 변수를 관리한다. 레지스터형 변수는 메모리에 저장되는 것이 아니므로 &연산자를 사용할 수 없다. 만약 한번이라도 & 연산자를 사용할 경우.. 이를 에러처리로 하지 않고, 이 변수를 지역변수화 해버린다.


정적 함수(static function)

기억 부류는 주로 변수에 대해서 적용되지만 사실 함수도 기억 부류를 가진다. 함수에는 전역이니 지역이니 하는 개념은 존재하지 않으며, 레지스터 형 기억 부류 역시 존재하지 않는다. c의 함수는 모두 수평적인 관계이며, 어떤 함수를 다른 함수의 지역 함수로 선언하는 것은 허용하지 않는다. 따라서 c의 함수들은 원칙적으로 전역 이다.

단 정적 함수는 존재하는데 정적 함수는 정적변수와 마찬가지로. 특정 모듈에서만 사용할 수 있다. 외부에서 그 이름을 알 수 없도록 해야하는 이유는.. 외부 정적 변수와 마찬가지로.. 이름 충돌을 방지하기 위해서 이다.


통용 범위

변수나 함수, 태그 같은 명칭은 상호 구분되어야 하므로.. 중복되어서는 안된다.

논리에 모호함은 있어서 안되기 때문에.. 명칭은 절대로 중복되어서는 안된다. 단 다른 지역에 있다면 같은 이름을 가져도 상관없다.


단.. 같은 명칭의 전역변수와 지역변수가 함께 존재할 경우.. 이렇듯 통용범위가 겹쳐있는 경우에는.. 보다 좁은 범위를 가지는 명칭에게 우선권을 줌으로써 모호한 상황을 극복한다.


이름이 겹치지 않게 하기 위해서 지역을 붙여 사용할 수 있다.


블록 범위

지역변수란 사실 { } 괄호안의 블록에 선언된 변수를 의미하며 변수가 선언된 블록 내부에서만 통용된다.


선언과 정의

 

 

역할

메모리

정보의 완전성

중복 가능성

선언

알린다.

사용 안함

불완전해도

가능

정의

생성한다.

할당

항상 완전해야

불가능

 

  선언(Declaration) - 컴파일러에게 대상에 대한 정보를 알린다. 함수가 어떤 인수들을 전달받으며 어떤 타입을 리턴하는지를 알리는 원형 선언이 대표적인 선언이다. 컴파일러에게 정보만 제공하는 것이므로 본체를 가지지 않으며 실제 코드를 생성하지도 않는다. 그래서 다음처럼 여러 번 중복되어도 상관없다.

 정의(Definition) - 대상에 대한 정보로부터 대상을 만든다. int i; 정의문에 의해 4바이트를 할당하며 int Max(int, int) { } 정의로부터 함수의 본체를 컴파일하여 코드를 생성한다. 정의는 변수의 타입, 함수의 인수 목록을 컴파일러에게 알려 주기도 하므로 항상 선언을 겸한다. 그래서 함수를 호출부보다 더 앞쪽에서 정의하면 컴파일러가 이 함수의 본체를 만들면서 모든 정보를 파악할 수 있으므로 별도의 원형 선언을 하지 않아도 된다. 정의는 실제 대상을 만들어 내기 때문에 중복되어서는 안된다.

 

설계 원칙

1. 함수의 이름을 최대한 설명적으로 작성하여 이름만으로 무엇을 하는 함수인지, 어떻게 쓰는 것인지도 알 수 있도록 한다. 마치 함수의 이름이 주석인 것처럼 해야 한다.

2. 두 번 이상 중복된 코드는 반드시 함수로 분리한다.

3. 반복되지 않더라도 한 단위로 볼 수 있는 작업은 함수로 만든다.

4. 함수는 한 번에 하나의 작업만 해야 한다

5. 입력과 출력이 직관적이고 명확해야 한다.

6. 함수는 자체적으로 에러 처리를 해야 한다. 함수는 독립된 작업을 하며 재사용 가능한 부품이므로 그 자체로서 완벽하게 동작할 수 있어야 한다.



'프로그래밍 > 프로그래밍 공부' 카테고리의 다른 글

9장 배열  (0) 2015.02.28
8장 표준함수  (0) 2015.02.28
7장 기억 부류  (0) 2015.02.27
6장 함수  (0) 2015.02.27
5장 연산자  (0) 2015.02.27
4장 제어문  (0) 2015.02.27
Posted by GENESIS8

댓글을 달아 주세요