정보처리기사 > 프로그램 언어 활용 > 포인터

anonymous·2021년 5월 31일
0

정보처리기사

목록 보기
12/15

포인터와 포인터 변수

포인터

  • 다른 변수의 메모리 주소를 값으로 저장하는 변수.
  • 이걸로 프로그래머는 메모리를 직접 조작할 수 있고, 더 나은 성능을 달성하거나 저수준 하드웨어로 작업할 수 있음.
  • 포인터는 자바나 파이썬과 같은 상위 언어에서는 사용할 수 없는 수준의 메모리 제어 기능을 제공하는 C와 C++ 같은 언어에서 사용
  • 잘못 사용하면 메모리 누수나 충돌을 쉽게 일으킬 수 있어 주의해서 사용해야 함.
  • C 및 C++와 같은 언어의 포인터는 * 기호로 표시
  • 포인터의 일반적인 사용 사례 중 하나는 런타임에 메모리를 동적으로 할당. 프로그램은 스택 대신 힙에 메모리를 할당할 수 있음
  • 값이 아닌 참조로 객체를 전달하는 데에도 사용할 수 있다. 즉, 함수에 객체를 전달할 때마다 객체를 복사하는 대신 객체의 메모리 위치에 대한 포인터를 전달할 수 있다.
  • 메모리에 직접 액세스하기 때문에 소프트웨어 개발에서 오류와 취약성의 일반적인 원인이기도 함. 널 포인터 역참조 또는 버퍼 오버플로와 같은 포인터와 관련된 버그는 충돌 및 보안 익스플로잇으로 이어질 수 있음.
  • 그래서 이런 문제를 완화하기 위해 Java 및 Python과 같은 많은 최신 프로그래밍 언어에는 포인터를 통한 직접적인 메모리 조작의 필요성을 추상화하는 자동 메모리 관리 시스템이 있다. 그럼에도 저수준 언어나 성능이 중요한 애플리케이션의 경우 사용함.

프로그래밍에서 메모리 할당 이해

프로그램이 변수나 객체를 저장하기 위해 메모리를 할당할 때 스택이나 힙에 해당 메모리를 할당할 수 있음.

스택은 프로그램의 런타임 환경에 의해 암시적으로 관리되는 메모리의 일부.
함수가 호출되면 인자와 로컬 변수가 선입선출 순서로 스택에 푸시됨.

스택은 빠르고 효율적이라는 장점이 있지만, 스택의 크기에 따라 할당되는 메모리의 크기가 제한되는 단점이 있음.

반면 힙은 프로그램의 런타임 환경에서 자동으로 관리되지 않는 더 넓은 영역의 메모리. 대신, 프로그램은 malloc() 또는 new와 같은 함수를 사용하여 힙에서 메모리를 명시적으로 요청함.

힙을 사용하면 프로그램이 더 큰 메모리 블록을 요청하거나 필요에 따라 메모리를 동적으로 확장할 수 있어 유연한 메모리 할당이 가능함. 그러나 힙의 메모리에 액세스하는 건 스택의 메모리에 액세스하는 것보다 느리고 효율성이 떨어질 수 있음.

프로그램이 포인터를 사용하여 힙에 메모리를 동적으로 할당하는 경우, 메모리가 더 이상 필요하지 않을 때 메모리가 적절하게 초기화되고 해제되는지 확인하는 것은 프로그래머의 책임. 메모리를 제대로 해제하지 않으면 메모리 누수가 발생하여 프로그램이 점차적으로 메모리가 부족해지고 충돌이 발생할 수 있음.


C++로 만든 예제:
큰 정수 배열을 저장해야 하는 프로그램이 있다고 가정. malloc() 함수를 사용하여 힙에 배열의 메모리를 할당하도록 선택할 가능.

int* array_ptr;
int array_size = 1000;
array_ptr = (int*) malloc(array_size * sizeof(int));

위 코드에서는 'array_ptr'이라는 정수 포인터를 선언하고 배열의 크기를 1000 정수로 지정.
다음 malloc() 함수를 사용하고 반환된 값을 정수 포인터로 형변환하여 array_ptr의 힙에 메모리를 할당함.

한 가지 주의할 점은 malloc()을 사용하여 힙에 메모리를 할당해도 할당된 메모리는 초기화되지 않는다는 점.
따라서 배열을 사용하기 전에 명시적으로 초기화해야 함. 루프를 사용하여 배열을 순회하고 그 값을 초기화할 수 있음:

for (int i=0; i<array_size; i++) {
	array_ptr[i] = i * 2;
}

위 코드에서는 배열의 인덱스에 2를 곱하고 첫 번째 값을 0으로 하여 배열 값을 초기화.
배열을 사용한 후에는 메모리 누수를 방지하기 위해 메모리를 해제하는 것이 중요함:

free(array_ptr);

위 코드에서는 free() 함수를 사용하여 array_ptr에 할당된 메모리를 할당 해제함.

메모리를 올바르게 할당하고 해제하는 방법을 이해하면 메모리 누수와 같은 문제를 방지하고 프로그램 성능을 최적화할 수 있다.

예제

#include <stdio.h>

int main()
{
  int a =50;
  int *b; // 포인터 변수 b 선언
  b = &a; // a 변수가 저장된 위치를 포인터 변수 b에 저장
  *b = *b + 20; // b 포인터 변수 값에 +20 즉 그 공간에 있던 a 변수의 값을 20 더하기

  printf("%d, %d", a, *b);
  // 결과 : 70, 70

  return 0;
}

포인터와 배열

배열을 포인터 변수에 저장 후 포인터로 배열에 접근 가능

배열 표기 방법a[0]a[1]a[2]
포인터 표기 방법*(a+0)*(a+1)*(a+2)

예제)

#include <stdio.h>

int main()
{
    int a[5];
	int i;
	int *p;
    
	for(i=0; i<5; i++){
		a[i] = i + 10;
	};
	
    p=a;
	
    for(i=0; i<5; i++){
		printf("%d ", *(p+i));
	} ;

    return 0;
}

결과

10 11 12 13 14 

사용자 정의 함수

사용자가 필요에 따라 만들어서 사용할 수 있고 중복 코드 입력을 줄여준다.

#include <stdio.h>
void func(int i, int j); // 사용자 정의 함수 선언.     

int main()
{
    int a = 3, b = 12;
    func(a,b);
    printf("%d, %d\n", a, b);
}

void func(i,j) // 리턴 값, 함수명, 인수 값
int i, j;
{
	i *= 3;
    j /= 3;
    printf("%d, %d\n" , i, j);
}

// 결과
// 9, 4
// 3, 12
profile
기술블로거입니다

0개의 댓글