stxxp

C pointer 보고서 본문

Hacking

C pointer 보고서

stxxp 2020. 6. 24. 13:55

#1 pointer의 정의 및 선언 방법

pointer는 "어떠한 값이 가지고 있는 주소"를 말합니다.

 

포인터 또는 포인터 변수라고도 부르며 이를 사용하면 다양한 자료형 변수들의 접근 및 조작이 쉬워집니다. 마찬가지로 연속으로 저장된 데이터인 배열의 각 데이터에 접근 및 조작을 쉽게 할 수 있습니다.

 

만약 포인터가 없다면 어떻게 될까요?

수많은 함수들은 포인터를 거쳐 서로 여러 가지 값을 주고받으며 코드가 길어지면 길어질수록, 한 프로그램 안에 사용되는 함수가 많아질수록 포인터의 역할이 매우 중요해집니다.

그렇기 때문에 포인터 없이 프로그램을 작성한다면 그것은 구현하기 어렵고 유연하거나 효율적이지 못한 프로그램이 됩니다. 그만큼 포인터의 역할은 중요합니다.

 

 

쉽게 생각해보면 우편물을 주고받는 과정 속에서 포인터는 마치 우편배달 기사와 같은 역할을 합니다.

 

우리가 편지를 우체국에 부치면 우체국에서 편지를 보내고자 하는 주소를 확인한 후에 우편배달 기사가 해당 목적지까지 우편물을 전달합니다.

이 과정 속에서 우편배달 기사가 있기 때문에 우리는 직접 우편물을 전달할 필요가 없고 반송 역시 직접 할 필요가 없어집니다.  

 

#include <stdio.h>
int main(){
	int *a = NULL;
    int num = 7;
    
    a = &num;
    printf("포인터 a가 가지고 있는 주소값은 %d입니다.", a);
    return 0;
}

포인터 변수는 선언을 할 때 *위치에 관계없이 변수에 *를 붙여 선언하며 ex) int *a= NULL;

변숫값을 저장할 때에는 저장할 변수의 이름 앞에 &를 붙여줍니다. ex) a = &num;

 

 

 

 

 

#2 pointer 연산

포인터의 연산자는 제한이 많습니다.

 

포인터끼리 서로 대입할 수 있으나 포인터끼리의 사칙연산은 아무 의미가 없어 적용이 불가능하고 (단, 뺼셈은 두 포인터의 상대적인 거리를 나타냄)

정수와의 연산은 가능하지만 실수와의 연산은 허용하지 않습니다.

 

 

---가능한 연산---

뺼셈 : 두 포인터 사이의 거리를 나타낼 수 있음(-)

 

비교 1 : 같은 배열을 가리키는지 확인할 수 있음(==,!=)

 

비교 2 : 같은 배열을 가리키는 포인터끼리 가진 값을 비교할 수 있음(>, >=, <, <=)

 

정수의 덧셈&뺼셈 : 포인터에 정수를 더하거나 뺄 수 있음(+int, -int)

 

* : 변수를 선언할 때 포인터임을 알려줌

 

& : 포인터 변수에게 새 주소를 할당할 수 있음

 

 

---주의할 점---

▲ 포인터에 직접 메모리 주소를 입력할 수 없음(error)

 

▲ 포인터에 지정해 줄 변수의 주소를 모르겠다면 0 또는 NULL을 사용해 값을 초기화해준다. 

 

▲ 수식(printf("hello world!"))에 포인터 적용이 불가능하다.

 

▲ 포인터와 포인터가 가리키는 변수의 자료형이 일치하게 사용해야 한다.

 

 

 

 

 

#3 pointer 처리 방식

위 그림에서 포인터 안에 세 개의 변수 num_01 = 10, num_02 = 20, num_03 = 30이 저장되면 그 주소값이 해당하는 만큼의 메모리를 차지하여 공간을 구별하면 각각의 공간에 10, 20, 30이라는 숫자가 저장된 주소값이 메모리 상에서 동작하는 방법을 간단하게 설명하고 있습니다.                                                                                                                                                                  사진 출처 : http://tcpschool.com

 

포인터는 변수를 불러오거나 저장하기 위해 데이터를 불러오는 과정에서 변수의 주소를 전달합니다.

 

모든 변수는 메모리에 그 값이 저장되기 때문에 포인터는 이러한 각 메모리의 공간을 구별합니다. 따라서 포인터에 int형 데이터를 저장하면 실제 그 값이 저장되는 것이 아니라 int형 데이터가 들어갈 주소 값이 저장되는 것입니다.

우리는 이 과정에서 포인터의 크기가 모두 같다는 것을 알 수 있습니다. 

 

---컴퓨터 내에서의 쓰임---

컴퓨터가 처리할 일이 있음(데이터 보유)

CPU가 데이터를 불러오려고 함

포인터는 해당 데이터가 있는 메모리를 알려 데이터를 빼옴

CPU가 데이터를 가공한 후, 다시 메모리로 돌려놓으려 함

포인터가 데이터를 어느 위치에 저장할 것인지 결정함

해당 메모리 위치로 데이터가 저장됨


● 할당 malloc() : 데이터 공간을 할당받는다.

 

● 재할당 realloc(): 이미 할당된 메모리 공간의 크기를 조정한다.

 

● 해제 free() : 더 이상 쓰지 않는 메모리 공간을 반환한다.

 

 

 

 

#4 pointer의 활용

포인터는 쓰임이 유용하고 많이 사용되기 때문에 그만큼 다양하게 활용되고 있는 편입니다. 

 

#include <stdio.h>
int main(){
	int a[2] = {1, 2};
    int b[3] = {3, 4, 5};
    int c[5] = {6, 7, 8, 9, 10};
    int *arr[3] = {a, b, c};
}

배열 => 첫 번째 요소 numArr[0]의 주소값만을 가지고 있음 => 따라서 주소값인 배열은 포인터에 저장할 수 있음 / 츨처 : http://dojang.io

우선, 포인터 배열 안에 또 다른 배열을 대입할 수 있습니다.

 

위의 코드에서 arr 포인터 배열을 출력하면 배열 a, b, c에 있는 값이 차례대로 출력되는데 출력은 for문을 이용해 출력할 수 있고 arr 포인터 배열이 각각 배열 a, b, c에 접근하는 방식입니다. 

 

※arr[0][0]은 arr 포인터 배열의 0번째 값인 a배열의 0번째 값을 의미하는데 arr 포인터 배열과 a배열의 충돌을 막기 위해 for문을 돌려 for[i][j]의 형태로 출력해야 합니다.

 

위와 비슷한 방법으로 배열 전체를 가리키는 포인터와 구조체 포인터 배열을 사용할 수 있으며 구조체 포인터는 포인터가 메모리를 적게 차지하는 것을 이용해 구조체 배열을 훨씬 쉽게 관리할 수 있게 된다고 합니다.

 

배열 전체를 가리키는 포인터는 

 

int *a[2] = {1, &arr};

 

이런 식으로 &연산자를 붙여 배열 전체를 저장할 수 있습니다. 

'Hacking' 카테고리의 다른 글

Codegate 2018, BaskinRobbins31  (0) 2020.09.01
NX-bit 예제 풀기 (with ASLR ON)  (0) 2020.08.27
NX-bit 예제 풀기  (0) 2020.08.25
간단한 바이너리 분석하기  (0) 2020.07.12
C언어 코드 분석  (0) 2020.07.02