초급편 3. 문자열 처리
포인터 토대가 된 책
문자열 처리
포인터는 현실적으로는 문자열을 처리 할 때 자주 사용된다.
char str [10] = { "this text"};
C 언어에서는 이상과 같이 초기화한다. 이 유형의 초기화는 DS에 10 개의 char가 필요한만큼 메모리를 확보한다. 확보 된 메모리의 시작 주소를 1000으로한다.그러면 메모리는 다음과 같다.
1000 0x74 (ASCII의 't') 1001 0x68 (ASCII의 'h') 1002 0x69 (ASCII의 'i') 1003 0x73 (ASCII의 's') 1004 0x20 (ASCII의 '') 1005 0x47 (ASCII의 ' t ') 1006 0x65 (ASCII의 'e') 1007 0x78 (ASCII의 'x') 1009 0x47 (ASCII의 't') 1010 0x00 (문자열의 종료 마커)
이 문자열을 화면에 표시하기위한 서브 루틴에 정보를 전달하는 것을 생각해 보자.
이 서브 루틴 호출을 다음과 같은 방법으로 실시한다.
CALL puts
이때 어떻게 서브 루틴에 필요한 정보를 전달할 수 있을까. 필요한 최소 정보 표시 할 문자열의 시작 주소 만 넘겨 주면되는 것이다. 왜냐하면 첫 번째 주소를 알고 있으면 문자가 '0'이 될 때까지 차례로 그 문자를 출력하면되는 것이다. 이 서브 루틴에서는 AX 레지스터에 표시 문자열의 선두 번지를 저장하고 CALL하면 좋게한다.
MOV AX, 1000 CALL puts
이때 AX 레지스터의 내용이다 1000가 어떤 숫자인지를 생각해 보자. 이것은 문자열 시작 주소를 나타내는 숫자이다. 그러나 지금까지는 "MOV AX, [1000]"와 같이 주소 참조왔다. 이 경우 그 주소의 내용에는 관심이없고 그 주소 자체를 서브 루틴에 전달하려는 것이다. 그래서 1000 번지의 주소를 마치 단순한 숫자처럼 취급하고, 그것을 레지스터에 저장하고 싶은 것이다. 이것이 포인터의 본질이다.
에서는이 서브 루틴 puts의 내용에 대해 살펴 보도록하자.
loop : MOV BX, AX] CMP BX 0 ; BX 레지스터가 0인지 확인 JZ RET ; BX 레지스터가 0이면, 서브 루틴에서 탈출 CALL display ADD AX 1 JMP loop ; loop 위치로 이동하기
서브 루틴 display는 BX 레지스터의 숫자를 문자 코드로 화면의 적당한 위치에 문자가 표현하는 문자를 표시한다. 이 어셈블리의 선두에있는 명령 "MOV BX, AX]"의 의미를 생각하게한다.
이것은 AX 레지스터의 값을 주소로 간주하여 그 주소의 내용을 BX 레지스터에 저장하는 것을 보여준다. 프로그램 3-1에서 연속으로 생각하면, 레지스터의 내용은 다음과 같습니다 온다.
MOV AX, 1000 ; AX = 1000 CALL puts MOV BX, AX] ; BX = 0x74 CMP BX 0 JZ RET CALL display ; ( 't'자를 표시) ADD AX, 1 ; AX = 1001 JMP loop MOV BX, AX] ; BX = 0x68 CMP BX 0 JZ RET CALL display ; ( 'h'자를 표시) ADD AX, 1 ; AX = 1002 JMP loop .......... ; 끝까지 비행 JMP loop MOV BX, AX] ; AX = 1010 -> BX = 0x00 CMP BX 0 ; 이제 조건이 성립 JZ RET ; 서브 루틴에서 탈출 .......... ; CALL puts의 다음 행
즉, AX 레지스터의 값을 1 씩 늘려가는 것으로, 전체 문자열을 한 글자 씩 접근 해 나갈 것이다. 이것이 포인터의 기본적인 사용법이다.
이상의 코드를 C 언어로 재 작성할하면 다음과 같이된다.
void main () { ............ puts ( "this text"); ............ } void puts (char * s) { while (* s! = '\ 0') { display (* s); s ++; } }
이 코드는 대략적으로 말해, s라는 변수가 AX 레지스터의 역할을하고있다. 따라서 변수 s는 포인터로 선언되어있다. 그래서이 함수를 호출 할 때 변수 s는 "this text"라는 문자열을 포함하는 메모리의 선두 번지가 들어있다. 그 수치를 주소로 간주하여 while 조건 중에서는 주소의 내용을 간접적으로 참조 먼저 0인지 여부를 확인하고있다. 0 아니면 display 함수에 대하여 그 주소의 내용 (문자를 표현하는 ASCII 코드)를 전달하고있다. 그리고 이번에는 변수 s의 값을 수치로 간주하여 1을 더하고있다.
이처럼 수치가있을 때에는 주소로 다루어 져있을 때에는 단순한 수치로 보이는 이것이 포인터의 양면성이다. 포인터로 선언 된 변수는 변수로 아무것도 수정하지 않으면 주소를 표현하는 수치로서 다루어 져 * 연산자로 정규화하면 그것이 간접 참조하는 것을 의미하며 그 값이 나타내는 주소의 내용을 표현 하게된다.이 구분을 정확하게 파악할 필요가있다.
과제
- C 언어에서 포인터를 표시하는 printf () 형식이있다. % d와 마찬가지로 % p를 사용하면 실제 포인터 값을 16 진수 값으로 표시한다. 이것을 사용하여 프로그램 3-3 포인터 s의 값을 표시 해보자.