메모리 주소 지정 방식
운영체제는 메모리 주소를 1바이트 단위로 관리한다.
32비트 윈도우 운영체제의 경우 0~4,294,967,295번지까지 1바이트 단위로 주소가 매겨져 있으므로
메모리를 사용하려면 반드시 사용할 주소를 지정해야 하고 메모리가 1바이트 단위로만 사용되는 것은 아니기 때문에
프로그래머가 메모리를 사용할 때 한번에 읽거나 저장할 크기를 명시해야 한다.
*64비트에서 한 메모리주소의 크기는 8바이트이다
예를들어 100번지, 101번지 이렇게 두 개 바이트를 사용하고 싶다면
'100번지부터 2바이트 크기만큼 메모리를 사용하겠다'라는 형식으로 표기해 주어야 한다.
직접 주소 지정 방식
메모리를 사용할 때 프로그래머가 사용할 메모리 주소를 직접 적는 방식이다.
mov word ptr[00000066h], 0412h (0412h 값을 ptr[00000066h]에 word단위로 대입하라.)
C언어의 '변수' 문법과 같다.
주의할점 : 함수 안에 선언한 변수는 해당 함수에서만 사용할 수 있고, 다른 함수에 선언한 변수가 메모리에 존재해도 문법적으로 접근할 수 없다.
간접 주소 지정 방식
간접 주소 지정 방식은 사물함이라는 매개체를 이용해 주소를 간접적으로 명시한다.
예시) 102번지에 4바이트 크기의 '주소'가 저장되어 있는데 이 주소에 가서 '값' 1042를 2바이트 크기로 대입하라.
#include <stdio.h> void Test(short data) { short soft = 0x0000; (16진수를 표기할 때에는 앞에 0x를 붙여준다.) soft = data; } void main() { short tips = 0x0005; Test(tips); } |
위와 같이 Test 함수를 호출할 때 tips 변수 값이 data 변수에 대입됨.
포인터
포인터 변수는 일반 변수와 다르게 * 기호를 추가로 사용하여 다음과 같인 선언한다.
short *ptr - short = 자료형, * = 포인터 변수임을 나타내는 기호, ptr = 포인터 변수 이름
포인터 변수는 자료형을 선언하지 않아도 무조건 크기가 4바이트로 정해져있기 때문에 크기를 적을 필요가 없다
*앞의 자료형은 포인터 변수가 가리키는 대상의 자료형을 말한다.
(*의 두가지 역할은 포인터를 선언하는 것이 첫번째, 해당 주소의 값을 확인할 때 사용하는 것이 두번째이다.)
변수가 저장된 메모리 공간의 주소 얻기
short birthday;
short = *ptr;
ptr = &birthday; /*변수 앞에 &연산자를 사용하여 변수의 주소를 구할 수 있다.*/
* 키워드의 또 다른 이름, 번지 지정 연산자
short birthday; /*short형 변수 birthday를 선언함*/
short = *ptr; /*포인터가 가리키는 대상의 크기가 2바이트인 포인터 변수를 선언함*/
ptr = &birthday; /*birthday 변수의 주소를 ptr 변수에 대입함*/
*ptr = 1042; /*ptr에 저장된 주소에 가서 값 1042를 대입함, 즉 birthday = 1042*/
두 변수의 값 서로 바꾸기
int start = 96, end = 5;
if(start > end) {
end = start;
start = end;
}
위 와 같이 코드를 작성한다면 start와 end값이 바뀌는게 아니라 모두 96의 값이 된다.
이 문제를 해결하려면 값을 임시로 보관하는 변수를 하나 더 추가해야 한다.
int start = 96, end = 5;
int temp;
if(start > end) {
temp = end; (temp = 5)
end = start; (end = 96)
start = temp; (start = 5)
}
결과적으로 start는 5가되고 end는 그대로 96이 됨.
직접 주소 지정 방식으로 변수 값 교환하기
void Swap(int a, int b) { int temp = a; a = b; b = temp; } void main() { int start = 96, end = 5; printf("before : start = %d, end = %d\n", start, end); if (start > end) { Swap(start, end); } printf("after : start = %d, end = %d\n", start, end); } |
이와같은 예제에서 사용한 방법으로는 main 함수의 start, end값을 변경할 수 없기 때문에 다른 함수의 지역 변수 값을 변경할 수 있는 포인터 문법을 사용해서 이 문제를 해결해야 한다.
간접 주소 지정 방식으로 변수 값 교환하기
void Swap(int *pa, int *pb) { int temp = *pa; //temp에 start의 값을 대입 *pa = *pb; // start에 end의 값을 대입 *pb = temp; // end에 start의 값을 대입 } void main() { int start = 96, end = 5; printf("before : start = %d, end = %d\n", start, end); if (start > end) { Swap(&start, &end); //start와 end의 값을 바꾸기 위해서 Swap을 호출함 } printf("after : start = %d, end = %d\n", start, end); } |
포인터를 사용할 때 자주 발생하는 실수들
char *ptr;
ptr = &data; // 첫번째 표현
*ptr = 2; // 두번째 표현
위와같이 포인터 변수 prt을 선언했다면 ptr이라고 사용할 수도 있고 *ptr이라고도 사용할 수 있기때문에
*연산자를 사용해야 하는 곳에 누락하는 문제가 발생하기도 한다.
실수유형1. *pa = *pb; 코드를 *pa = pb;라고 적거나 pa = *pb;처럼 잘못 적을 수 있다. 하지만 이와 같은 오류는
컴파일러가 번역할 때 두 변수의 자료형이 맞지 않는다
실수유형2. 실수로 *연산자를 아예 쓰지 않고 pa = pb; 라고 잘못 적으면 상황이 달라진다. 왜냐하면 양쪽의 자료형이 int *로 같아서 컴파일러가 번역할 때 오류로 잡아주지 않기 때문이다.
그래서 실행은 되지만 원하지 않는 결과가 출력된다.
const란, constant의 약자로 "변함없는" 이라는 뜻으로 변수앞에 붙이면 값과 주소를 변경할 수 없게 만든다.
const 키워드를 사용하는 여러가지 방법이 있다.
int * const p;
p앞에 const 키워드를 사용했기 때문에 p가 가지고 있는 주소를 변경하면 번역할 때 오류가 발생한다.
int data = 5, temp = 0;
int *const p = &data;
*p = 3; // p 변수가 저장하고 있는 주소에 가서 3을 대입하면 data 변수의 값이 3으로 변경됨
p = &temp // 오류발생 : 변수p에 const 속성이 적용되어 p에 저장된 주소는 변경할 수 없음
const int *p;
p가 주소에 접근할 때 사용하는 크기 앞에 const 키워드를 사용했기 때문에 *p를 사용하여 대상의 값을 변경하면 번역할 때 오류가 발생한다.
int data = 5;
const int *p = &data; // 변수 p는 data 변수의 주소를 저장함
*p = 3; //오류 발생 : 변수 p가 가리키는 대상에 const 속성이 적용되어 대상의 값을 변경할 수 없음
const int *const p;
자신과 대상에 모두 const 키워드를 사용했기 때문에 p가 가지고 있는 주소를 바꾸거나 *p를 사용하여 대상의 값을 바꾸면 번열할 때 오류가 발생한다.
'C언어' 카테고리의 다른 글
10) 표준 입력 함수 - getchar, gets (0) | 2021.02.25 |
---|---|
9-1) 포인터 변수의 주소 연산 (0) | 2021.02.08 |
8) 배열 (0) | 2021.01.24 |
7) 지역 변수와 전역 변수 (0) | 2021.01.22 |
5)반복문 (0) | 2021.01.14 |