ref:http://blog.daum.net/coolprogramming/60
const는 컴파일러 상수로 변수의 값을 상수화하여 한번 값으로 할당된 메모리의 모든 비트를 변경 불가하게 만듭니다.
사용방법은 간단합니다.
void main( )
{
const int n = 10;
printf("%d %d\n", g, n);
}
- 500 10
자료형 선언 앞에 const키워드만 붙이면 됩니다. g와 n은 이제 변수(메모리변경가능)가 아니라 상수(메모리변경불가)로 취급됩니다.
만약 변경하려 하면 컴파일러 오류입니다.
void main( )
{
const int n = 10;
printf("%d %d\n", g, n);
g = 100; // 변경불가 컴파일러 에러~
n = 20; // 변경불가 컴파일러 에러~
}
에러~~
아래는 g와 n변수의 메모리 그림입니다.
상수 만드는 거야 const만 붙이면 되므로 아주 쉽죠?!
여기서 궁금합니다. const상수와 enum상수와 define 상수의 차이점이? 지금은 간단히 정리하고 넘어갑니다. 다음에..
- const상수 : 변수 메모리영역에 생성되며 변수이지만 컴파일러에 의해 변경이 불가능해 집니다.
- enum상수 : 상수이며 실행시 메모리이름 없는 실제 값 자체입니다.
- define상수 : 상수이며 전처리기에 의해 컴파일전에 값으로 치환됩니다.
지금은 어렵죠? 지금은 걍! 모두 상수다 알아 두세요!
const는 배열이나 포인터변수와 결합되어 엄청난 장점을 발휘합니다.
포인터 변수와 결합되어 사용될 때, 세 가지 정도로 나뉠 수 있습니다.
int n = 10; 변수가 있고 int* pn = &n; 과 같이 n의 주소를 pn이 가리킬 때
const int * pn = &n; ( int const * pn = &n ; 와 같은 코드 )
- *pn은 변경불가, pn은 변경가능
int * const pn = &n;
- *pn은 변경가능, pn은 변경불가
const int * const pn = &n;
- *pn은 변경불가, pn도 변경불가
이해하면 쉽습니다. const가 *pn 앞에 붙었나? ( const * pn ) 아니면 const가 pn 앞에 붙었나? ( * const pn)을 잘 보시면 됩니다.
{
int n = 10;
const int * pn1 = &n;
int * const pn2 = &n;
const int * const pn3 = &n;
*pn1 = 20; // 변경불가 컴파일러 에러~
pn1 = &n; // 변경가능 0
*pn2 = 20; // 변경가능 0
pn2 = &n; // 변경불가 컴파일러 에러~
*pn3 = 20; // 변경불가 컴파일러 에러~
pn3 = &n; // 변경불가 컴파일러 에러~
printf("%d %d %d\n", *pn1, *pn2, *pn3);
}
위 코드를 꼭 이해하시고 기억하세요. 예제 코드에서 자주 사용하게 됩니다.
위 예제를 그림으로 설명하면 아래와 같습니다.
마지막으로 const 사용 예제를 보고 const 마무리하도록 하겠습니다. 나머지는 프로그램 실습에서 경험하세요.
{
puts(str);
}
void PrintArray( const int * arr)
{
int i;
for( i = 0 ; i < 5 ; i++)
printf("%3d", arr[i]);
puts("");
}
void main( )
{
char *str = "Hello!";
int arr[5] = { 10, 20, 30, 40, 50};
PrintString( str );
PrintArray( arr );
}
- Hello!
10 20 30 40 50
함수와 포인터 부분을 공부했다면 예제는 어렵지 않게 이해할 수 있습니다.
함수의 매개변수 앞에 const가 있는 것을 잘 보세요. 위 예제는 const가 있든 없든 잘 돌아 갑니다. 그렇다면, 왜? const를 붙였을까요? 각 함수 내에서 문자열이나 배열의 요소를 변경하지 않기 위한 보장입니다. 위 예제는 만약 실수로 각 함수 내에서 str이나 arr을 사용하여 메모리 내용을 변경하려 한다면 컴파일 오류가 발생할 것이고 프로그래머는 실수를 빠르게 알 수 있을 것입니다. 위 내용에 대한 자세한 내용도 다음에 합니다. 입력 매개변수, 출력 매개변수에 대한 내용을 공부할 때 다시 하도록 하겠습니다.
2, 가변인자
가변인자를 사용하는 대표적인 함수가 printf(), scanf()함수입니다.
{
printf("hello!\n"); // 인자 하나(문자열)
printf("%d\n", 10); // 인자 둘 (문자열, 정수)
printf("%d %d\n", 10, 20); // 인자 셋 (문자열, 정수, 정수)
printf("double : %lf\n", 2.35); // 인자 둘 (문자열, 실수)
printf("%d + %d = %d\n", 10, 20, 30); // 인자 넷 (문자열, 정수, 정수, 정수)
}
- hello!
10
10 20
double : 2.350000
10 + 20 = 30
위 printf()함수의 인자를 보면 함수는 하나입니다. 하지만 인자들은 개수와 인자의 자료형이 서로 다릅니다. 이처럼 여러형태의 인자를 사용할 수 있는 함수를 가변인자 함수라 합니다.
우리도 printf()함수와 비슷한 가변인자 함수를 만들어 보도록 하겠습니다.
{
}
void main( )
{
Print( 1 );
Print( 1 , 2);
Print( 1 , 2, 3);
}
가변인자 함수는 위 예제 처럼 만듭니다. 컴파일 해 보면 문제 없이 잘 돌아갑니다.
가변인자 함수는 첫 번째 매개변수가 꼭 있어야하며 두번째 인자부터 ... 연산자를 사용할 수 있습니다.
첫 번째 인자가 없으면 함수 내부에서 인자들의 값을 찾을 수 없기 때문입니다.
가변인자 메커니즘은 함수에 인자들이 전달될 때 함수 호출 규칙에 따라 순서대로 절달된다는 것을 이용합니다.
아래 그림을 참고하세요. (이해가 어렵다면 사용자 함수절을 복습하세요)
그래서 첫번째 인자 n을 이용하여 모든 인자 값들을 접근할 수 있습니다. &n이 12fe78이고 n의 크기가 4byte이므로 다음 인자 값 2는 주소 12fe7c에 존재하며 세번째 인자값 3은 12fe80에 존재합니다.
첫 번째 매개변수를 이용하면 모든 인자 값을 접근하고 출력할 수 있습니다.
void Print(int n, ... ){
int *pn = &n;
for(int i = 0 ; i < 3 ; i++)
printf("%3d\n", pn[i]);
}
void main( )
{
Print( 1 , 2, 3);
}
- 1
- 2
- 3
그림을 이해했다면 결과는 쉽습니다.
보통 첫 번째 인자에 다음으로 들어오는 인자들의 여러가지 정보(인자의 자료형이나 개수)를 담아 모든 인자들을 접근할 수 있습니다.
void Print(int n, ... ){
int *pn = &n;
for(int i = 0 ; i <= n ; i++)
printf("%5d", pn[i]);
puts("");}
void main( )
{
Print( 0);
Print( 2 , 100, 200);
Print( 3 , 5, 6, 7);
Print( 4 , 21, 22, 23, 24);
Print( 5 , 50, 50, 50, 50, 50);
}
- 0
2 100 200
3 5 6 7
4 21 22 23 24
5 50 50 50 50 50
첫 번째 인자 n에 모든 인자의 개수를 전달하여 모든 값을 출력합니다.
현재까지 예제는 모두 4byte int형 인자의 크기를 갖는다는 전제하에 작성한 코드입니다. 만약 함수로 전달되는 인자들의 자료형이 서로 다르다면 구현하기 쉽지 않습니다. 그래서 가변인자를 조금 더 쉽게 사용할 수 있도록 C언어는 매크로 함수를 제공합니다.
그래서 위 예제는 아래 처럼 매크로 함수를 이용하여 바꿀 수 있습니다.
#include <stdio.h>#include <stdarg.h>
void Print(int n, ... )
{
va_list pn;
va_start(pn, n);
for(int i = 0 ; i < n ; i++)
printf("%5d", va_arg(pn, int) );
puts("");
va_end(pn);
}
void main( )
{
Print( 0);
Print( 2 , 100, 200);
Print( 3 , 5, 6, 7);
Print( 4 , 21, 22, 23, 24);
Print( 5 , 50, 50, 50, 50, 50);
}
100 200
5 6 7
21 22 23 24
50 50 50 50 50
va_list는 포인터 변수를 pn을 선언하고 va_start()함수는 pn 포인터 변수를 n인자 다음을 가리키도록 하고 va_arg()함수는 pn을 int만큼 이동시키고 현재 위치의 인자 값을 반환합니다. va_end()함수는 pn 포인터를 NULL로 만듭니다.
마지막으로 아래 예제를 완성해 보세요.
void main( ){
Print("Hello! \n");
Print("Hello! %d %d \n", 10, 20);
Print("Hello! %f %f \n"), 2.5, 3.5 );
}
'Programming > C,C++' 카테고리의 다른 글
간단한 thread 예제 (0) | 2017.04.16 |
---|---|
C++, const with function [펌] (0) | 2017.04.07 |
Stack (Double Linked), C++ (0) | 2017.04.07 |
Queue (Double Linked), C++ (0) | 2017.04.06 |
new delete + Heap overruns checker (0) | 2017.04.05 |