Computer Language/C

포인터의 기초

Ohjeonghak 2013. 10. 23. 13:11
반응형

포인터란?

포인터는 번지에 대한 기호화된 표현을 말한다. 즉, 포인터는 번지이다.

포인터는 4바이트의 메모리를 할당 받는다. 

포인터 변수에는 특정한 문자나 상수 값, 문자열이 들어가는 것이 아니라 바로 번지가 들어가는 것이다.

포인터 변수는 번지 이외에는 어떠한 것도 들어갈 수 없다.

 

int *a = 5; 의 경우 warning이 발생한다.

<리눅스에서 gcc의 경우>

warning 이유 -> initialization makes pointer from integer without a cast [enabled by default]

 

쓰레기값 주소를 가진 포인터에 값을 넣어서 그런듯 하다.

 

포인터 변수 정의

#include <stdio.h>

int main()
{
	//포인터 변수의 정의
    int * Pointer;  //변수의 type 오른쪽, 변수 이름의 앞에 '*'를 붙여 정의한다.

	//아래의 3개의 printf();문은 포인터 변수를 초기화 하지 않았으므로 쓰레기 주소값이 출력 될 것이다.
	printf("%p\n", Pointer);  //Pointer 변수가 할당된 메모리의 주소를 출력
	//#을 사용하면 주소를 표현할 때 앞에 "0x"가 출력된다. 주로 널 포인터를 표현할때 사용됨.

	printf("%#10x\n", Poin우ter);  //Pointer 변수가 할당된 메모리의 주소를 10자리까지 출력
	printf("%#010x\n", Pointer);   //Pointer 변수가 할당된 메모리의 주소를 10자리까지 출력하되 공백은 앞에 0으로 표현

	return 0;
}

 

포인터 변수의 크기와 변수 타입 지정 이유

일반적으로 변수의 크기는 타입에 따라서 결정 된다. 물론 타입의 정해진 크기는 운영체제 마다 다를 수 있다.

대부분 int형은 4바이트, float형은 4바이트, double형은 8바이트, char형은 1바이트 가 일반적이다.

하지만 포인터의 모든 변수는 타입이 int, float, double, char 상관없이 크기는 운영체제가 32비트인경우 4바이트 이다.

운영체제가 64비트인경우는 8바이트이다.

8 비트가 1바이트이고 4바이트는 32 비트이다. 즉, 4바이트면 2의 32승 만큼 표현이 가능하다.

(20억개 이상의 위치를 저장 가능.)

 

다음의 예로 위의 말을 확인 할 수 있다.

#include <stdio.h>

int main()
{
	int int_;
	float float_;
    double double_;
    char char_;
    printf(" int = %d\n float = %d\n double = %d\n char = %d\n",
    		sizeof(int_), sizeof(float_), sizeof(double_), sizeof(char_));

	int *int_p;
    float *float_p;
    double *double_p;
    char *char_p;
    
    printf(" int = %d\n float = %d\n double = %d\n char = %d\n",
    		sizeof(int_p), sizeof(float_p), sizeof(double_p), sizeof(char_p));

	return 0;
}

 

그렇다면 모두다 타입에 상관없이 4바이트 혹은 8바이트로 정해저 있다면 "왜 타입을 정해줘야 하는가?" 하는

의문이 생긴다. 그 이유는 포인터 변수는 주소값이 저장되어 있어 그 주소로 가서 주소에 담긴 값을 참조 하는데

여기서 타입에 따라 몇 바이트를 읽어 오는가 하는 것에 대한 것 때문이다.

 

&연산자, '*' 역참조 연산자

#include<stdio.h>

int main()
{
	int a = 5;
    int *Pointer_a;
    
    Pointer_a = &a;  //포인터 변수에 int형 변수 a의 주소를 저장.
    
    printf("%d\n", a);    //int 형 변수 a에 들어있는 5를 출력
    printf("%d\n", &a);   //int 형 변수 a의 주소를 출력
    
    printf("%d\n", Pointer_a);   //포인터 변수에 저장된 a의 주소가 출력
    printf("%d\n", &Pointer_a);  //포인터 변수의 주소를 출력
	
    //여기서 쓰이는 '*'는 주소에 저장된 값을 가져와 출력 한다.
    printf("%d\n", *Pointer_a);  //포인터 변수에 저장된 a의 주소에 담고 있는 값을 출력 (5가 출력됨)
	
    // &a == Pointer_a == &*Pointer 모두 변수 a의 주소와 같은 의미.
    printf("%#010x\n", &*Pointer_a);  //Pointer_a 변수 주소에 저장된 값인 a의 주소값을 가져와 출력함.
	
    return 0;
}

 

'*'역참조 연산자 주의 사항

#include <stdio.h>

int main()
{
	//int a;     //문제가 되는 부분을 해결하기 위해 시스템으로부터 사용할 수 있는 주소값을 할당받음.
    int *ptr;
    //ptr = &a;  //문제가 되는 부분을 해결하기 위해 포인터 변수에  변수 a의 주소값으로 초기화 해줌.
    *ptr = 1024;    (문제가 되는 부분)    
    
    printf("%d\n", *ptr);
    
    return 0;
}

 

위 코드는 컴파일 시엔 전혀 문제가 없다 하지만 실행하면 문제가 있다. 

문제가 되는 부분은 역참조 연산자에 의해 포인터 변수가 가르키는 값에 정수 1024를 넣었다. 하지만 지금 값을 가르키는 주소값이 시스템에서 할당받은 주소값이 아닌 임의의 쓰레기 주소값이기 때문에 그 주소값에서 가르키는 곳에 1024를

넣었다. 만약 다른 프로그램에서 쓰레기 주소값을 시스템에서 할당 받은 주소값으로 사용하고 있다고 한다면 주소값이 가르키는 1024를 참조함으로 문제가 된다.

 운이 좋아서 시스템이나 다른 프로그램에서 사용하지 않는 주소이면 문제가 되지 않을 수도 있다. 하지만 언제나 운이

좋은 상황이 될 수가 없기 때문에 문제가 된다. 그래서 이러한 치명적인 행위를 막기 위해 시스템은 세그멘테이션 오류를 발생 시키게 된다.

 

 

'*'역참조 연산자를 이용하여 일반변수처럼 연산하기

#include<stdio.h>

int main()
{
	int a = 5;
	int *ptr;
    
    ptr = &a;
    
    *ptr = *ptr + *ptr;  //포인터 변수 ptr에 저장된 주소가 가르키는 값에 포인터 변수
    
    //포인터 변수 ptr에 저장된 주소가 가르키는 값을 더하여 저장
    printf("%d\n", *ptr);
	
    return 0;
}

 

 

 

반응형