C언어

9)포인터

SleeveStar 2021. 1. 30. 17:42
반응형

메모리 주소 지정 방식

 

운영체제는 메모리 주소를 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