티스토리 뷰
C언어 포인터
C언어 포인터에 대한 요약이다. Do it! C언어 입문(저자:김성엽) 이란 책을 통해 공부했으며, 책의 카테고리를 바탕으로 필자가 이해한 내용을 요약하는 글이다. 내용이 궁금하거나 찾아야 할 내용이 있으면, 필자가 정리한 글을 다시 보면서 복습하기위해 작성했다. 바로 아래에서 글을 확인하도록 하자.
포인터 들어가기 전에 32비트, 64비트 운영체제 장단점
32비트 운영체제는 RAM(메모리)을 4GB(기가바이트, 2^30)밖에 사용 못하지만 64비트 운영체제는 16EB(엑사바이트, 2^60)까지 사용할 수 있음. 내 시스템이 RAM을 4GB 이상 사용한다면 64비트 운영체제를 사용해야, 메모리를 100% 다 사용할 수 있는 것임. 하지만 64비트 운영체제를 쓰면 기본 처리 단위가 64비트라 기본적으로 메모리 사용량이 많음. 그리고 32비트 프로그램과 호환하기 위해 모듈까지 관리해야 해서 사양이 낮은 컴퓨터는 64비트 운영체제를 사용하면 오히려 손해임. (참고로 int형의 크기는 32비트 운영체제에서는 32비트고 64비트 운영체제에서는 64비트임.)
메모리 주소 지정 방식
32비트 윈도우 NT 운영체제의 경우 0~4,294,967,295번지까지 1바이트 단위로 주소가 매겨짐.
직접 주소 지정 방식
메모리를 사용할 때 프로그래머가 사용할 메모리 주소를 직접 적는 방식.
ex) 100번지에 0x0418 값을 2바이트에 할당해서 넣어줘.(메모리 주소를 표현할 때 C언어는 2비트를 지원 안 하기 때문에 16진수로 표현하는 게 번지(1바이트)에 할당되는 수가 눈에 보여서 편함)
어셈블리 언어(컴퓨터가 사용하는 기계어와 가장 가까운 언어)
/* 명령어 : mov // 대상 : word ptr[00000066h], // 원본 : 0412h */
mov word ptr[00000066h], 0412h
/* mov 는 move의 줄임말, [00000066h]라는 주소에 word(2바이트)크기로 0412h 값을 대입하라 */
/* 어셈블리어는 16진수를 표현할때 h를 붙임. (0412h) */
※기계어와 엄셈블리어
실행파일은 기계어(2진 숫자)로 구성되어 있음. 하지만 보기가 어렵기 때문에 형식은 그대로 유지되면서 숫자를 영단어로 변경해서 보여주는게 어셈블리(Assembly) 언어임. 성능 평가나 시스템 원리를 설명할 때 많이 사용함.
C언어에서 직접 주소 지정 방식의 한계
함수 안에 선언한 변수는 해당 함수에서만 사용할 수 있고, 다른 함수에 선언한 변수가 메모리에 존재해도 문법적으로 접근할 수 없음.
간접 주소 지정 방식
명령을 바꾸지 않고 데이터만 바꿔서 데이터를 저장할 변수를 바꿀 수 있음. 이것은 새로운 번역과 실행파일이 필요 없다는 뜻임. 그래서 프로그래머는 간접 주소 지정 방식을 활용을 잘할 필요가 있음.
※간접 주소 지정방식을 어셈블리어로
명령 | 대상 | 원본 |
mov | cx, | dword |
mov | word ptr[cx], | 0412h |
cx라는 곳에 dword(4바이트)의 주소값을 저장, cx에 저장된 주소에 해당하는 곳에 2바이트의 0412h를 저장.
(32비트 운영체제에서는 주소값이 4바이트임)
포인터
메모리 주소를 담을 수 있는 변수임.
포인터 변수 p는 크기가 무조건 32비트임(32비트 운용체제에서). short의 크기 2바이트는 포인터 변수가 가리키고 있는 주소의 2바이트를 읽거나 쓴다는 뜻임.
변수가 저장된 메모리 공간의 주소 얻기
short birthday;
short *ptr; /* 포인트변수 ptr 선언 */
ptr=&birthday; /* 포인트변수 ptr에 birthday변수의 주소를 넣음 */
변수가 위치한 메모리 주소 출력
#include <stdio.h>
void main()
{
short birthday;
short *ptr;
ptr = &birthday;
printf("birthday 변수의 주소는 %p 입니다. \n", ptr);
}
/* %p는 포인터가 가르키는 주소를 출력해줌. %08X로 출력해도 같은 결과지만,
주소는 unsigned int 자료형으로 넘겨주기때문에 형변환을 시켜줘야해서 %p가 훨씬 쉽고 좋음 */
*의 다른 이름, 번지 지정 연산자
short birthday;
short *ptr;
ptr=&birthday;
*ptr=1042;
/* 변수 ptr이 기리키는 주소에 1042를 넣는거임.
2번줄의 *는 포인터 변수를 선언할거라는 의미인데,
4번줄의 *는 ptr이 가리키는곳을 의미함 */
다른 변수의 주소를 사용하여 포인터로 값 대입하기
#include <stdio.h>
void main()
{
short birthday;
short *ptr;
ptr = &birthday;
*ptr=0x0412; /*변수 ptr이 가리키는 주소에 0x0412를 대입 */
printf("birthday = %d (0x%04X)\n", birthday, birthday);
}
/*결과화면 : brithday = 1042 (0x0412)*/
'ptr=' 형태는 포인터 변수에 주소를 저장함
short *ptr;
ptr=(short *)0x0000006c; /*포인터변수 ptr에 0x0000006c 주소를 대입함. */
/* 포인터 변수 ptr의 형은 (short *)임. 0x0000006c은 int형이여서 형변환 시킴. */
int birthday;
int *bp;
bp=&birthday;
/*여기서는 형변환을 안해도 되는 이유가.
birthday의 자료형이 int 이기때문에
보통 포인터의 자료형을 변수의 자료형과 일치시키는 경우가 많아서
birthday의 주소를 (int *)형으로 보냄*/
'*ptr=' 형태는 포인터가 가리키는 대상에 값을 저장함
short *ptr;
ptr=(short *)0x0000006C;
*ptr = 0x0412; /*주소 0x0000006C에 0x0412를 대입*/
※고정 주소를 직접 표기할 수는 없는가?
유효한 주소라면 사용할 수 있지만, 주소를 알아내기엔 초보 프로그래머가 알기가 힘듦. 안다면 사용해도 무방함.
포인터로 다른 함수에 선언한 변수 사용하기
#include <stdio.h>
void Test(short *ptr) /* 2. 포인터변수 ptr로 tips변수의 주소를 받음. 다른 함수에 있는 tips의 값을 변경가능 */
{
short soft = 0;
soft = *ptr; /* 3. tips 함수에 들어있는 값 5를 soft에 대입 */
*ptr =3; /* 4. tips에 3을 대입. 메모리 주소를 가저왔기 때문에 다른 함수에 있는 변수에도 값 대입가능*/
}
void main()
{
short tips = 5;
Test(&tips); /* 1. tips 변수의 주소를 매개변수로 보냄 */
}
포인터를 이용해 두 변수 값 바꾸기
#include <stdio.h>
void Swap(int *pa, int *pb) /*start, end의 주소를 매개변수로 받음 */
{
int temp = *pa; /*start에 있는 값을 temp에 저장 */
*pa = *pb; /*end에 있는 값을 start에 대입 */
*pb = temp; /*temp에 있는 값을 end에 대입 */
}
void main()
{
int start = 96, end = 5;
printf("before : start = %d, end = %d\n", start, end);
if(start>end){
Swap(&start,&end); /* Swap 함수로 start, end 변수의 주소를 매개변수로 보냄 */
}
printf("after : start = %d, end = %d\n", start, end);
}
/* 결과화면 before : start = 96, end = 5
after : start = 5, end = 96 */
위와 같은 방법을 직접 대입 방식으로 하려면 return 값으로 원래 불렀던 함수로 값을 반환해야 하는데, 지금처럼 값 2개를 교환하려면 반환 값이 2개가 있어야 하는데 return은 한번에 한개만 반환 가능.
포인터를 사용할때 자주 발생하는 실수
보통 포인터에 변수의 주소값을 넣으면, 그 주소값을 변경하는 일은 적다. 이를 미연에 방지하려면 const를 이용하면 됨.
int *cosnt p; */ 포인터변수 p에 저장된 주소값 변경했을시, 오류뜸. 최초에 넣을 때만 괜찮음. */
const int *p; */ 포인터변수가 가리키는 주소에 있는 값을 변경할때 오류가 뜸 */
const int *const p;
/* 포인터 변수에 저장된 주소를 변경하거나, 주소가 가리키는 값을 변경하면 오류뜸*/
포인터 변수의 주소 연산
short data = 0;
short *p = &data;
p = p + 1; /* data 주소의 번지가 100이라고 가정하면
p+1 을 하고 p에 들어간 값은 102번지임.
포인터 변수의 주소 연산은 크기가 중요한데
data 변수가 가리키는 번지에서 short로 알수 있듯이,
2바이트를 차지하고있음.
그래서 2바이트 이후인 102번지를 가르킴 */
char *p1 = (char *)100;
short *p2 = (short *)100;
int *p3 = (int *)100;
double *p4 = (double *)100;
p1++; /* 주소는 101이 됨*/
p2++; /*주소는 102가 됨*/
p3++; /*주소는 104가 됨*/
p4++; /*주소는 108이 됨*/
포인터가 가리킬 수 있는 크기와 실제 대상의 크기가 다른 경우
int data = 0;
short *p = (short *)&data;
/* data의 자료형이 int 여서 주소값을
(int *)로 넘겨주기때문에 형변환을 해야함. */
#include <stdio.h>
void main()
{
int data = 0x12345678; i;
char *p = (char *)&data;
for(i=0;i<4;i++){
printf("%X, ", *p); /* i=0일때 *p 은 p가 1바이트만 가르키니,
리틀엔디언 기법으로 78을 출력함 */
p++; /* i=0 일때 1바이트 출력할때 78을 출력한 뒤,
+1한 다음주소는 1바이트 뒤인 56을 가리키게됨*/
}
}
/* 출력화면 78, 56, 34, 12, */
void *형 포인터
void *p;
/* 주소값을 저장할 수는 있지만 해당 주소에서 사용하는 크기는 정해저있지 않음
사용할 메모리의 시작 주소는 알지만, 끝 주소는 아직 모름 */
int data = 0;
void *p = &data;
*(int *)p = 5;
/* 5를 4바이트 크기로 대입 // (void *)형은 대입할때
어떤 크기로 대입할지 정해줘야함 */
※NULL은 0번지를 의미함. 그래서 일반 변수는 초기화할 때 0을 대입하지만, 포인터 변수는 NULL을 사용해야 함.
void MyFuc(void *p, char flag) /* void *형으로 주소를 받으면
많은 매개변수가 필요없이 형변환만 하면됨 */
{
if(flag==1) *(char*)p=1;
else if(flag==2) *(short *)p=1;
/* flag로 2를 주면 2바이트인 (short *) 형으로 형변환하게 코딩함 */
else *(int *)p = 1;
}
void main()
{ short data = 5;
MyFunc(&data, 2);
}
void* 를 사용하여 대상 메모리의 크기 조절하기
#include <stdio.h>
int GetData(void *p_data, char type)
{
int result = 0;
if(type ==1) result = *(char *)p_data;
else if(type ==2) result =*(short *)p_data;
/* 1. p_data가 가리키는 주소의 크기를 2바이트로 정함 */
else if(type ==4) result =*(int *)p_data;
return result;
}
void main()
{
int data = 0x12345678;
/* 2. 2바이트를 지목당해서 리틀 엔디언 방식에의해
5678만 가리키게됨 ( 16진수는 1개당 4비트차지) */
printf("%X\n", GetData(&data,2));
}
/* 결과화면 5678 */
※형 변환은 void * 형식뿐만 아니라 모든 자료형에서도 사실 사용 가능함.
int data = 0x12345678;
char *p = (char *)&data;
*p = 5; /* data 값이 0x12345605 로 변경 */
*(short *)p = 0; /* data 값이 0x12340000으로 변경 */
글을 마음대로 배포하셔도 되지만, 출처(링크)는 반드시 남겨주시기 바랍니다.
'C언어' 카테고리의 다른 글
C언어 배열과 포인터 (0) | 2021.03.15 |
---|---|
C언어 표준 입력 함수 (0) | 2021.03.15 |
C언어 배열 (0) | 2021.03.12 |
C언어 지역 변수/전역 변수 (0) | 2021.03.12 |
C언어 반복문/시프트 연산자/비트 연산자 (0) | 2021.03.11 |
- Total
- Today
- Yesterday
- C언어정적메모리할당
- PHP작은따옴표
- 무효트래픽이의신청
- PHP이스케이프
- PHPhere문서
- 무효클릭신고양식
- C언어malloc함수
- PHPescapecharacter
- C언어malloc
- PHP문자열연결연산자
- PHP"'
- PHP'"
- C언어다차원포인터
- PHP큰따옴표
- C언어2차원포인터
- HTMLtag사용법
- C언어동적메모리할당
- html이미지넣기
- PHP마침표
- HTML태그사용법
- 이미지무료다운로드사이트
- PHP큰따옴표작은따옴표차이점
- PHPescaping
- PHP작은따옴표역할
- htmlTag
- C언어프로세스
- html이미지
- HTMLbestTag
- PHP'
- PHP이스케이핑
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |