Call by Value와 Call by Reference

Programming/C/C++ 2010/06/01 23:44


1. value와 reference는 무슨 뜻인가?
먼저, value와 reference를 네이버 영어사전으로 검색해 보겠습니다.

value는 '가치'라는 뜻이 먼저 나오고, 마지막 부분에 "수학용어"로서 '값'이라는 뜻이 있다고 나옵니다.


reference는 '참조'라는 뜻이 많이 쓰이는 편이어서 통합검색부분에 바로 나오는 것 같습니다.

우리가 "지뢰를 모두 안전하게 찾으면 이기는 게임"의 특성을 잘 살려 "지뢰찾기"라고 이름을 짓듯이, 컴퓨터 용어를 지을 때 역시 관련된 특성을 영어로 잘 살리려 할 것입니다. 그래서 Call by Value와 Call by Reference를 알아보기 전에 핵심단어(value와 reference)의 사전적 의미를 알아본 것입니다.
Call by Value는 영어 그대로 값(Value)에 의한(by) 호출(Call)이고, Call by Reference역시 영어 그대로 참조(Reference)에 의한(by) 호출(Call)입니다.

2. Call by Value
Call by Value는 우리말로 "값에 의한 호출"이라는 의미로, 어떤 함수를 호출할 때 전달인자(Parameter)로 데이터 자체를 전달하는 호출 방법입니다.

2.1 스왑함수(Swap Function)의 구현 1
어떤 변수의 값을 서로 바꾸는 작업을 "스왑 한다."라고 합니다. 이는 프로그램을 만들 때 빈번히 일어나는 경우로서, 다음과 같은 작업을 거쳐야 합니다.


사람이야 머리로 두 자료(자료1, 자료2)의 위치를 바꿀 수 있지만, 컴퓨터는 바보(?)라서 임시저장공간이 반드시 있어야 합니다. 위 그림에서 숫자가 매겨진 것이 작업의 순서입니다. 값을 바꿀 자료 두 개(자료1, 자료2)에 대하여

1. "자료1"을 임시저장공간에 복사합니다.
2. "자료2"를 "자료1"에 복사합니다.
3. 임시저장공간에 저장된 "자료1"과 동일한 내용의 자료를 "자료2"에 복사합니다.
4. 필요에 따라 임시저장공간을 제거합니다.

와 같은 작업이 이루어지면 두 자료의 위치가 바뀝니다. 임시저장공간이 있어야 하는 까닭은 2번 과정을 통해 자료1의 내용이 손실되기 때문입니다.
이 내용을 바탕으로 스왑함수를 Call by Value로 구현해보겠습니다.
01./*
02.Call by Value Example 1
03.Programmed by EffortKim
04.*/
05.#include <iostream>
06. 
07.void Swap(int data1, int data2)
08.{
09.int temp;
10. 
11.temp=data1;
12.data1=data2;
13.data2=temp;
14.}
15. 
16.int main()
17.{
18.int a=10, b=20;
19. 
20.std::cout<<"Before\na : "<<a<<", b : "<<b<<std::endl;
21.std::cout<<"Swap Function is called.\n";
22.Swap(a, b);
23.std::cout<<"After\na : "<<a<<", b : "<<b<<std::endl;
24.return 0;
25.}

그럴듯하게 모양이 나오는 것 같습니다. 이 예제는 main함수에 선언된 a와 b의 값을 바꾸기 위하여 Swap함수를 만들고, 이를 전달해 값을 바꾸도록 접근하고 있습니다. 다음은 결과입니다.


아니!!! a와 b의 값이 바뀌어야 하는데, 바뀌고 있지 않습니다.

2.2 Call by Value의 방식
2.1에서 Swap함수를 제대로 구현하지 못했습니다. 위의 결과가 그것을 입증하고 있는데요. 그것은 "Call by Value가 값을 전달하기 때문."이라고 설명할 수 있습니다. 위 예제에서는 변수 a와 b를 바꿀 수 있는 어떤 정보를 주지 않고, a값과 b값 자체를 전달하고 있습니다. 그러므로 a와 b의 값은 바뀌지 않습니다. 즉, Swap함수에서는 변수 a와 b의 값이 아닌, data1과 data2의 값이 교환됩니다. 다음 그림을 보면 이해가 빠를 것입니다.


위 예제에서는 변수 a와 b에 대한 정보(주소값)는 주지 않고 a와 b의 값인 10과 20만 주었습니다. data1과 data2는 "아싸가오리!"라고 외치면서 매개변수로 받았을 것입니다. 그리고 그들(data1과 data2)의 값이 바뀌고 끝이 납니다. 이 때, 변수 a와 b에 대한 정보를 주지 않았으니 변수 a와 b의 값을 교환 하고 싶어도 할 수 없게됩니다. 즉, 교환이 일어나는 메모리 주소는 0x0001과 0x0002가 아닌, 0x0003과 0x0004가 됩니다.
Call by Value는 어떤 함수의 전달인수에 특정 값 자체를 전달하는 방식으로, 특정 값 자체를 전달하다 보니 데이터 자체가 큰 경우 전달하는데 오랜시간이 걸립니다. 대신, 함수의 전달인수로 사용된 데이터 자체는 보호됩니다.
가령, 어떤 무시무시한 악당(갑자기 세균맨이 떠오르네요.)이 위의 스왑함수를 개조하여 스왐함수 내의 data1과 data2에 1을 더하는, 누가 악당 아니랄까봐 정말 악당같은 짓을 행하였습니다. 그래도 data1과 data2의 값만 변할 뿐, main함수 내에 있는 변수 a와 b는 변하지 않습니다.

3. Call by Reference
Call by Value를 통해 Call by Reference에 대해 예측하신 분들이 계셨을 것입니다. Call by Reference는 우리말로 "참조에 의한 호출"로서, 어떤 특정한 값이 아닌 그 값에 대한 정보(이를테면 데이터가 저장된 메모리 번지가 값에 대한 정보라고 할 수 있습니다.)를 전달하는 방식입니다.
2.2의 그림을 이용하자면, Call by Value가 변수 a와 b의 값인 10과 20을 전달했다면, Call by Reference는 변수 a와 b의 메모리 번지인 0x0001과 0x0002를 전달하는 방식이라고 보시면 됩니다.

3.1 스왑함수(Swap Function)의 구현 2
위의 2.1에서 교환되지 않았던 스왑함수를 고쳐보겠습니다.
01./*
02.Call by Reference Example 1
03.Programmed by EffortKim
04.*/
05.#include <iostream>
06. 
07.void Swap(int* data1, int* data2)
08.{
09.int temp;
10. 
11.temp=(*data1);
12.(*data1)=(*data2);
13.(*data2)=temp;
14.}
15. 
16.int main()
17.{
18.int a=10, b=20;
19. 
20.std::cout<<"Before\na : "<<a<<", b : "<<b<<std::endl;
21.std::cout<<"Swap Function is called.\n";
22.Swap(&a, &b);
23.std::cout<<"After\na : "<<a<<", b : "<<b<<std::endl;
24.return 0;
25.}

2.1에서 data1과 data2가 int형이었던 반면, 이번 예제는 int*형이 되었습니다. 먼저 실행 결과 보겠습니다.


우리가 원하는 모양이 되었습니다. Swap함수를 호출하였더니 a와 b의 값이 바뀌었습니다. 아시는 분은 다 아시겠지만, Swap함수에 변수 a와 b 자체를 전달한 것이 아닌, a와 b의 주소값을 전달하여 a와 b에 접근할 수 있도록 하였습니다. 즉, Swap함수 내에서는 data1과 data2의 값을 바꾸는 것이 아닌, data1과 data2가 가리키는 값(a와 b)을 바꾸기 때문에 변수 a와 b의 교환이 일어납니다. 이를 그림으로 표현하면 다음과 같습니다.


우리가 실질적으로 바꾸어야 할 메모리 주소 공간은 0x0001과 0x0002이므로 이 두 주소값을 전달하여 이를 참조(reference)하여 변수 a와 b의 값을 교환할 수 있도록 유도하는 것이 목적입니다.

3.2 C++의 문법 - 레퍼런스(Reference)
사실, 3.2에는 Call by Reference의 방식에 대해 설명하려고 했습니다만, 3.1에서 충분히 설명한 것 같아 C++의 문법 중 하나인 레퍼런스에 대해 설명하겠습니다.
변수이름은 할당된 메모리 공간의 이름과 같습니다. 그래서, 원래는 메모리 주소를 직접 입력하여 메모리에 접근하여야 하지만, 이는 매우 번거롭고 비효율적인 방법이므로, C와 C++는 메모리 공간에 이름을 붙여 이 이름을 부르면 해당 메모리에 접근하도록 하였습니다.
레퍼런스란, 이름을 부여하는 것입니다. 변수를 선언할 때는 메모리 공간을 할당하면서 그 메모리 공간의 이름을 부여하지만, 레퍼런스는 이미 할당된 메모리 공간에 이름만 추가합니다.
쉽게 말해, 어떤 광고에서 어떤 배우가 한 말처럼 "이미 차려진 밥상에 밥숟가락만 얹었을 뿐"에서 밥숟가락이 레퍼런스가 되는 것입니다.
레퍼런스는 이미 할당된 메모리 공간에 대해서만 이름을 추가적으로 부여할 수 있도록 하는 것이기 때문에, 레퍼런스르 선언할 때에는 반드시 변수이름을 대입하도록 합니다. 레퍼런스를 선언할 때에는 &연산자를 사용합니다.
1.// declaration and initialization of variable
2.int a=10;
3.// declaration and initialization of reference
4.int& refa=a;
5.// .......

위 소스코드에서 refa가 레퍼런스입니다. 이 둘을 선언한 다음부터는 a와 refa는 동일한 변수입니다. 이들의 주소값을 조사해도 같은 주소가 나오고, a값이 변하면 refa값도 변합니다.(그 반대도 성립합니다.)
이것을 이용하면, 위의 스왑함수 예제 2(포인터 버전)를 레퍼런스 버전으로 수정할 수 있겠습니다.
01./*
02.Call by Reference Example 2
03.Programmed by EffortKim
04.*/
05.#include <iostream>
06. 
07.void Swap(int& data1, int& data2)
08.{
09.int temp;
10. 
11.temp=data1;
12.data1=data2;
13.data2=temp;
14.}
15. 
16.int main()
17.{
18.int a=10, b=20;
19. 
20.std::cout<<"Before\na : "<<a<<", b : "<<b<<std::endl;
21.std::cout<<"Swap Function is called.\n";
22.Swap(a, b);
23.std::cout<<"After\na : "<<a<<", b : "<<b<<std::endl;
24.return 0;
25.}

레퍼런스는 변수와 동일하므로 포인터와 같이 주소 참조 연산자(*)를 사용하지 않아도 됩니다. 또한, 초기화 할 때 변수 자체를 대입하므로 전달인수로 주소 역참조 연산자(&)를 사용하지 않아도 됩니다. (이 상황에선 사용하면 안됩니다.) 그러므로 소스코드가 포인터 버전에 비하여 깨끗합니다.

3.3 포인터냐!! 레퍼런스냐!! 그것이 문제로다!!!
Call by Reference를 구현할 때 포인터를 사용할 것인지, 레퍼런스를 사용할 것인지 고민하는 경우가 생깁니다. 두가지 방법에 대한 장단점을 소개할 것이니, 이를 보고 스스로 판단 해 보시길 바랍니다.

먼저, 포인터를 이용했을 경우 전달하는 값이 주소값이므로 &연산자를 사용하거나, 포인터를 사용해 인수로 넘겨주어야 합니다. 이를 통해 값의 변경이 있을 것임을 명시적으로 알려주는 셈이 됩니다. 특히, &연산자를 사용하여 변수의 주소를 넘길 경우엔 대놓고 "값을 변경할 것입니다."라고 광고하는 효과를 얻게됩니다. 이렇게 명시적으로 자료의 변경이 있을 것이라고 알려주면 개발자는 이를 보고 에러를 쉽게 찾아내고 디버그 하기가 수월 할 것입니다. 단, 코드가 지저분해지고(주소 참조 연산자, 주소 역참조 연산자를 모두 사용해야 하기 때문입니다.) 할당되지 않은 메모리 공간을 참조할 수 있는 잠재적인 오류가 숨어있습니다.
그리고, 레퍼런스를 이용했을 경우 변수처럼 사용하다 보니, 메모리를 직접적으로 참조하지 않아 할당되지 않은 메모리 공간을 참조할 가능성은 포인터에 비해 줄어듭니다. 코드도 포인터를 사용했을 경우보다는 더 간결해지기도 합니다. 그러나, 어떤 함수의 전달인수로 레퍼런스를 요하는 경우, 그냥 변수 이름만 적어주면 되기 때문에 이 함수가 지금 전달하려는 값을 변경할 것인지, 변경하지 않을 것인지 함수를 해석하기 전에는 알 수 없습니다. 그러므로 변경되면 안되는 변수를 잘못넘겨주어 변경되게 하는 경우에는 속수무책으로 당하기 쉽상입니다. 이런 경우는 대부분 문법적인 오류는 없기 때문에 컴파일러나 링커에 의해서 에러를 찾지는 못하는 경우가 많고, 디버깅을 통해서 알아내야 하는 부분입니다. 또한, 위의 예제에서 Swap(a, b);만 가지고는 이 Swap함수의 전달인수가 레퍼런스인지, 그냥 값인지 알 수 없습니다. 물론,Swap이라는 이름은 값을 변경할 것이라고 알려주긴 하지만, 만일 이름이 Swap이 아닌 Func나 F일 경우에는 선언부나 정의부를 보지 않는이상 값이 변경될 것인지, 변경되지 않을 것인지 알 수 없습니다.

이를 통해 어떤 방법을 써야 할 지 생각해 보셨나요? 위 문제는 Call by Reference에서가 아닌, 어느 경우에나 발생할 수 있는 경우입니다. 그래서 많은 자료에서 위 문제를 많이 언급하고 있습니다. 경우에 따라 좋은 방법을 쓰는 것이 좋겠지요? ^_^ 좋은게 좋은겁니다.

4. 끝마치면서
간략하게 Call by Value와 Call by Reference에 대해 알아보는 시간을 가졌습니다. 이는 매개변수에 값을 전달할 것인가, 값에 대한 참조를 전달할 것인가에 대한 "전달 방법"입니다. 문법적 내용이 아니라는 뜻입니다. 위에서 두 방법을 알아보았을 때 Call by Value와 Call by Reference를 위한 특벌한 문법내용을 언급한 적은 없습니다. 기본적인 문법내용을 토대로 만들어 낸 것입니다. 그러므로 다른 언어(JAVA, C#등)에서도 적용할 수 있는 방법입니다.
단, Viaual Basic에서는 포인터나 그에 상응하는 문법 내용이 없기 때문에 Call by Value와 Call by Reference를 위한 문법이 따로 존재하는 것으로 알고 있습니다. 이에 대한 자세한 정보는 MSDN 페이지인


을 참고하세요.

'Development > C/C++' 카테고리의 다른 글

[LPSTR, LPCSTR, LPTSTR, LPCTSTR , LPWSTR, LPCWSTR 의 의미‎]  (0) 2012.08.19
[C언어 문법: Bit field (콜론 연산자)]  (0) 2012.06.16
[Event]  (0) 2011.12.01
[Semaphore]  (0) 2011.12.01
[Mutex]  (0) 2011.12.01
Posted by cyj4369
,

startProject 수행 후 수정하지도 않은 파일에 대해 다음과 같은 에러가 날 수 있다.




startProject로 project1을 만든 후 건들지도 않았던 ../src/geekos/idt.c에서 에러가 발생했다.

이 경우 nasm 어셈블러에 문제가 생긴 경우일 수도 있다. 다시 설치해주자.


















nasm 설치



nasm은 GeekOS 컴파일에 필요한 어셈블러입니다. (홈페이지 : http://www.nasm.us/)
최신버전은 호환성에 문제가 있어 2.08대 버전을 사용해야 합니다. 홈페이지로 들어가 Download 링크를 누른 후, 2.08 디렉토리의 linux 디렉토리에서 nasm-2.08-1.i386.rpm을 다운로드합니다.


설치 패키지를 다운로드 한 후, 우분투에서 설치 가능한 패키지로 변환하기 위해 alien을 사용합니다. alien은 다음 명령어로 설치할 수 있습니다.

sudo apt-get install alien


 alien을 설치했다면, 다음 명령어를 입력하여 다운로드한 *.rpm 패키지를 *.deb 패키지로 변환합니다.

sudo alien -k nasm-2.08-1.i386.rpm

 
 변환이 완료되면 다음과 같이 nasm-2.08-1_i386.deb 파일이 생성됩니다.

 
다음, 생성된 설치 패키지를 설치합니다.

sudo dpkg -i nasm-2.08-1_i386.deb

 

'Development > GeekOS' 카테고리의 다른 글

[startProject하기]  (0) 2012.04.25
[GeekOS 과제를 위한 환경설정]  (0) 2012.03.16
Posted by cyj4369
,

[아스키코드표]

참고로 스페이스는 32번...

백스페이스는 8...

 뉴라인(Line Feed)은 10...


'Development > Java' 카테고리의 다른 글

[숫자 입력받기(scanner)]  (0) 2012.05.20
[String형 문장을 이을때는...]  (0) 2012.04.28
[아스키코드 출력]  (0) 2012.04.27
[String에서 한 글자씩 읽기/추출하는 방법]  (0) 2012.04.27
[StringBuffer]  (0) 2012.04.19
Posted by cyj4369
,

본인이 가장 자주 쓰는녀석은 이런 형식이다
String buf = "str";
String plus = buf + "plus";
System.out.println(plus);

근데 포퍼먼스 책에 보니 StringBuffer 를 사용하여
.append(""); 를 사용하라고한다

책에 내용을 보면 문자열 붙이기에서 StringBuffer 는 String보다 수백배 빠르다고한다
느끼지못하는 수백배이겠지만 쌓이다보면 느려진다는것을 느낄지도...

'Development > Java' 카테고리의 다른 글

[숫자 입력받기(scanner)]  (0) 2012.05.20
[아스키코드표]  (0) 2012.04.28
[아스키코드 출력]  (0) 2012.04.27
[String에서 한 글자씩 읽기/추출하는 방법]  (0) 2012.04.27
[StringBuffer]  (0) 2012.04.19
Posted by cyj4369
,

자바로 아스키 코드 (ASCII Code)를 화면에 출력하는 프로그램입니다.

아스키 7번 코드는 삑하는 비프음(Beep)코드이기에, 이 프로그램을 실행하면 삑하는 소리가 나는데, 놀랄 필요 없습니다.

파일명: Foo.java

public class Foo {
  public static void main(String args[]) {

    for (char c = 0; c <= 255; c++)
      System.out.format("%c = 0x%02X (%3d)%n", c, (int) c, (int) c);

  }
}


어떤 문자의 아스키 코드를 얻기 위해서는, 그 문자를 (int) 로 캐스팅한 후, System.out.format()으로 출력하면 됩니다.



실행 결과:


웹에 표현하기 힘든 특수문자들이 많이 나옵니다. 그래서 다음의 코드표는, 키보드로 입력할 수 있는 문자만 표시했습니다.
0x20 등으로 된 것은 16진수이고, 괄호() 안에 든 숫자는 10진수입니다.
참고로, 0x20 은 공백문자 즉 스페이스(Space)의 아스키 코드입니다.
... 생략

  = 0x20 ( 32)
! = 0x21 ( 33)
" = 0x22 ( 34)
# = 0x23 ( 35)
$ = 0x24 ( 36)
% = 0x25 ( 37)
& = 0x26 ( 38)
' = 0x27 ( 39)
( = 0x28 ( 40)
) = 0x29 ( 41)
* = 0x2A ( 42)
+ = 0x2B ( 43)
, = 0x2C ( 44)
- = 0x2D ( 45)
. = 0x2E ( 46)
/ = 0x2F ( 47)
0 = 0x30 ( 48)
1 = 0x31 ( 49)
2 = 0x32 ( 50)
3 = 0x33 ( 51)
4 = 0x34 ( 52)
5 = 0x35 ( 53)
6 = 0x36 ( 54)
7 = 0x37 ( 55)
8 = 0x38 ( 56)
9 = 0x39 ( 57)
: = 0x3A ( 58)
; = 0x3B ( 59)
< = 0x3C ( 60)
= = 0x3D ( 61)
> = 0x3E ( 62)
? = 0x3F ( 63)
@ = 0x40 ( 64)
A = 0x41 ( 65)
B = 0x42 ( 66)
C = 0x43 ( 67)
D = 0x44 ( 68)
E = 0x45 ( 69)
F = 0x46 ( 70)
G = 0x47 ( 71)
H = 0x48 ( 72)
I = 0x49 ( 73)
J = 0x4A ( 74)
K = 0x4B ( 75)
L = 0x4C ( 76)
M = 0x4D ( 77)
N = 0x4E ( 78)
O = 0x4F ( 79)
P = 0x50 ( 80)
Q = 0x51 ( 81)
R = 0x52 ( 82)
S = 0x53 ( 83)
T = 0x54 ( 84)
U = 0x55 ( 85)
V = 0x56 ( 86)
W = 0x57 ( 87)
X = 0x58 ( 88)
Y = 0x59 ( 89)
Z = 0x5A ( 90)
[ = 0x5B ( 91)
\ = 0x5C ( 92)
] = 0x5D ( 93)
^ = 0x5E ( 94)
_ = 0x5F ( 95)
` = 0x60 ( 96)
a = 0x61 ( 97)
b = 0x62 ( 98)
c = 0x63 ( 99)
d = 0x64 (100)
e = 0x65 (101)
f = 0x66 (102)
g = 0x67 (103)
h = 0x68 (104)
i = 0x69 (105)
j = 0x6A (106)
k = 0x6B (107)
l = 0x6C (108)
m = 0x6D (109)
n = 0x6E (110)
o = 0x6F (111)
p = 0x70 (112)
q = 0x71 (113)
r = 0x72 (114)
s = 0x73 (115)
t = 0x74 (116)
u = 0x75 (117)
v = 0x76 (118)
w = 0x77 (119)
x = 0x78 (120)
y = 0x79 (121)
z = 0x7A (122)
{ = 0x7B (123)
| = 0x7C (124)
} = 0x7D (125)
~ = 0x7E (126)

... 생략




자바는 유니코드가 기본이기에, 실은 위의 코드도 유니코드입니다. 그런데 유니코드의 첫부분은 아스키 코드와 똑같기에, 0xFF (=255) 까지만 출력하면 아스키 코드가 나오는 것입니다.

'Development > Java' 카테고리의 다른 글

[아스키코드표]  (0) 2012.04.28
[String형 문장을 이을때는...]  (0) 2012.04.28
[String에서 한 글자씩 읽기/추출하는 방법]  (0) 2012.04.27
[StringBuffer]  (0) 2012.04.19
[static]  (0) 2012.04.19
Posted by cyj4369
,

charAt: String에서 한 글자씩 읽기/추출하는 방법


소스 파일명: Example.java
public class Example {
  public static void main(String[] args) {

    // 문자열 정의
    String s = "MP3 플레이어";


    // 한 글자씩 화면에 출력
    for (int i = 0; i < s.length(); i++) {
      System.out.println( s.charAt(i) );
    }

/* 출력 결과:

M
P
3






*/


    // 괄호에 넣어 한 글자씩 출력
    for (int i = 0; i < s.length(); i++) {
      System.out.format("[%c] ", s.charAt(i) );
    }
    // 출력 결과: [M] [P] [3] [ ] [플] [레] [이] [어]




    System.out.println(); // 줄바꿈

  }
}

'Development > Java' 카테고리의 다른 글

[String형 문장을 이을때는...]  (0) 2012.04.28
[아스키코드 출력]  (0) 2012.04.27
[StringBuffer]  (0) 2012.04.19
[static]  (0) 2012.04.19
[배열 복사]  (0) 2012.04.09
Posted by cyj4369
,

startProject하기


1. /usr/local/bin 에다가 startProject명령을 넣어준다.

2. startProject project0

3. startProject project1 ~/바탕화면/geekos/src project0


Posted by cyj4369
,

[StringBuffer]

Development/Java 2012. 4. 19. 18:13

스트링 버퍼는, 바이너리 스트링의 연결 연산자 + 를 구현하기 위해서 compiler 로 사용됩니다. 예를 들어, 다음의 코드

     x = "a" + 4 + "c"
 

(은)는, 이하의 동등한 코드로서 컴파일 됩니다.

     x = new StringBuffer(). append("a"). append(4). append("c")
                           . toString()
 
새로운 스트링 버퍼 (초기 상태에서는 하늘)를 작성해, 각 연산자의 스트링 표현을 스트링 버퍼에 차례로 추가하고 나서, 스트링 버퍼의 내용을 스트링 으로 변환합니다. 이것에 의해, 작성되는 일시적인 스트링의 전체양을 줄일 수가 있습니다.

StringBuffer 의 기본적인 오퍼레이션에는,append 메소드 및 insert 메소드가 있어, 이러한 메소드는 어떤 종류의 데이터도 받는 것이 할 수 있도록 overload 되어 있습니다. 메소드는 각각 주어진 데이터를 효율적으로 스트링 으로 변환해, 스트링중의 문자를 스트링 버퍼에 추가 또는 삽입합니다. append 메소드는 항상, 버퍼의 말미에게 줄 수 있던 문자를 추가해,insert 메소드는 지정된 위치에 문자를 추가합니다.

예를 들어,z 를, 현재 "start" 를 포함한 스트링 버퍼 오브젝트라고 보는 경우,z.append("le") 는 스트링 버퍼의 내용이 "startle" 가 되도록(듯이) 변경하는데 대해,z.insert(4, "le") 라고 하는 메소드 호출은 스트링 버퍼의 내용이 "starlet" 가 되도록(듯이) 작용합니다.

일반적으로, sb 가 StringBuffer 의 인스턴스를 참조하고 있는 경우,sb.append(x) 는 sb.insert(sb.length(),  x) 와 같은 결과가 됩니다.

각 스트링 버퍼에는 capacity가 있습니다. 스트링 버퍼에 포함되는 스트링의 길이가 capacity를 초과 하지 않는 한, 새로운 내부 버퍼 배열을 할당할 필요는 없습니다. 내부 버퍼가 오버플로우 하는 경우, 자동적으로 capacity가 증가합니다.




append (boolean b) 
          boolean 인수의 스트링 표현을 이 스트링 버퍼에 추가합니다.
append (char c) 
          char 인수의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (char[] str) 
          char 배열 인수의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (char[] str, int offset, int len) 
          char 배열 인수의 부분 배열의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (double d) 
          double 인수의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (float f) 
          float 인수의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (int i) 
          int 인수의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (long l) 
          long 인수의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (Object  obj) 
          인수 Object 의 스트링 표현을 이 스트링 버퍼에 추가합니다.
 append (String  str) 
          이 스트링 버퍼에 스트링을 추가합니다.
delete (int start, int end) 
          이 StringBuffer 의 부분 스트링내의 문자를 모두 삭제합니다.

'Development > Java' 카테고리의 다른 글

[아스키코드 출력]  (0) 2012.04.27
[String에서 한 글자씩 읽기/추출하는 방법]  (0) 2012.04.27
[static]  (0) 2012.04.19
[배열 복사]  (0) 2012.04.09
[시간 측정]  (0) 2012.04.08
Posted by cyj4369
,

[static]

Development/Java 2012. 4. 19. 14:36

함수안에 선언된 변수는 그 함수를 빠져 나가면 사라진다. 할당되었던 메모리는 해제되고 저장되어 있던 값도 사라진다. 이러한 특성 때문에 자동변수(auto variable) 이라고 부르기도 한다. 그 함수 내에서만 유효하다고 해서 지역변수라고 부르기도 한다. 따라서 그 함수로 들어올 때 마다 변수가 다시 메모리 할당된다. 

그래서 함수간 또는 파일간에 변수 값을 공유하고자 할 때는 전역변수(global variable) 또는 정적변수(static variable)를 사용하는데 이 두 변수간의 차이를 정확히 이해를 하고 사용해야 한다. 

전역변수와 정적변수는 lifetime은 동일하다. 즉, 해당 프로그램이 죽을 때까지 한번 할당된 변수 메모리와 값은 유지된다는 점이다. 반면에 scope는 서로 다르다.  전역변수는 해당 프로그램(실행파일 기준)의 어느 함수, 어느 파일에서도 접근이 가능한 반면 정적변수는 변수가 선언된 파일이나 함수내에서만 접근이 가능하다. 

scope에 대한 예를 들면  a 파일에 선언되어 있는 static 변수는 a파일에서는 어느곳에서나 접근이 가능하지만 b파일 에서는 읽을 수가 없다. (file scope) 동일 파일 속에서도  a() 함수 속에서 선언된 static 변수는 a()의 어느곳에서도 접근할 수 있지만 b() 함수 에서는 접근할 수 없는 것이다. (function scope)  반면에 global 변수는 프로그램내의  어느 파일, 어느 함수에서도 읽을 수 있다. 

lifetime 에 대하여 고찰해 보면 한번 선언된 전역변수와 정적변수의 값은 프로그램(프로세스)가 죽을 때까지 계속 유지된다. 따라서 미들웨어에 의해 프로세스가 통제되는 프로젝트의 경우 프로세스가 죽지 않고 항상 살아있기 때문에 매번 거래가 시작될 때 반드시 변수를 초기화 해 주어야 한다. 초기화를 빼먹을 경우 이전 거래에서 사용했던 변수 값들이 그대로 보존되어 있기 때문에 잘못된 결과를 초래할 수 있기 때문이다.

특히 국방, 금융권, 원자력과 같은 크리티컬한 사이트의 프로젝트에서는 예기치 않은 대형사고가 발생될 수 있기 때문에 각별히 신경써서 사용해야 할 것이다.  

-------------------

이러한 개념은 extern 함수와 static 함수에도 똑같이 적용된다. static 함수는 해당 파일 내에서만 호출될 수 있다. 그러나 extern 함수는 다른 파일 속에서도 호출될 수 있는 것이다. 보통 extern 함수 앞에는 extern 이란 말을 생략하기도 한다. 따라서 static 이 붙지 않은 것은 extern 함수라고 간주하면 될 것이다.  





---예제---

static 변수: 해당 클래스의 모든 인스턴스들에 의해 공유되는 변수

class Thing {

  static int count;     // static 변수 이 변수는 각 객체들 사이에서 공유된다.

  String name;

  Thing(String name) {

    this.name = name;

    ++count;  }

}

class StaticVariable {

  public static void main(String args[]) {

    Thing t1 = new Thing("Bowling Ball");

    System.out.println(t1.name + " " + t1.count);

    Thing t2 = new Thing("Ping Pong Ball");

    System.out.println(t2.name + " " + t2.count);

    Thing t3 = new Thing("Football");

     System.out.println(t3.name + " " + t3.count);  }

}



static 변수를 사용시 객체를 생성하지 않고 클래스명과 직접 사용 가능(전역 변수 기능)

class StaticBag {

  static boolean flag;

  static int i, j = 2, k = 3, l, m;

  static double array[] = { -3.4, 8.8e100, -9.2e-100 };

  static String s1, s2 = new String("Hello");}

class StaticBagTest {

  public static void main(String args[]) {

    System.out.println(StaticBag.flag);

    System.out.println(StaticBag.i);

    System.out.println(StaticBag.j);

    System.out.println(StaticBag.k);

    for(int i = 0; i < StaticBag.array.length; i++)

      System.out.println(StaticBag.array[i]);

    System.out.println(StaticBag.s1);

    System.out.println(StaticBag.s2);  }

}



'Development > Java' 카테고리의 다른 글

[String에서 한 글자씩 읽기/추출하는 방법]  (0) 2012.04.27
[StringBuffer]  (0) 2012.04.19
[배열 복사]  (0) 2012.04.09
[시간 측정]  (0) 2012.04.08
[랜덤함수 사용법]  (0) 2012.04.08
Posted by cyj4369
,

[배열 복사]

Development/Java 2012. 4. 9. 01:55

package doTest;
public class IDLCTest_new {
        public static void main(String[] args) {
                char [] test1 = {'g','o','o','d'};
                char [] test = new char[16];
                
                test=(char[]) test1.clone();

                System.out.println("length:"+test.length);
                
                System.out.println(test);
                System.out.println("/"+test+"/"); // 멀티플... 형태로 표현하는곳에선 char[] 배열이 아닌 String 타입을 써야한다.
                
                System.out.print("/");
                System.out.print(test);
                System.out.println("/");                
        }
}

'Development > Java' 카테고리의 다른 글

[StringBuffer]  (0) 2012.04.19
[static]  (0) 2012.04.19
[시간 측정]  (0) 2012.04.08
[랜덤함수 사용법]  (0) 2012.04.08
[자바에서 sleep]  (0) 2011.12.27
Posted by cyj4369
,