본문으로 건너뛰기

포인터 및 동적할당 활용

포인터의 개념과 활용

포인터의 개념과 변수 선언

포인터의 개념 : 변수의 주소를 저장하는 변수

포인터 변수 선언

int *ip; // 포인터 변수 선언
float *ip2; // ..
double *ip3; // ..
char *ip4; // ..

int val = 10; // val에 10 대입
ip = &val // val의 주소를 ip에 대입

선언 시 *를 접미어로 사용하면 해당 변수는 주소를 저장할 수 있는 변수가 됨
출력 시 %d, %u, %p를 사용할 수 있다
%d == 정수의 범위
%u == unsigned int의 범위
%p == 16진수의 주소

#include <stdio.h>

int main(void) {
int *ip = NULL;
int val = 10;

printf("ip의 주소: %d \n ip의 값: %d\n", &ip, ip);
printf("val의 주소: %d \n val의 값: %d\n", &val, val);

printf("\n\n");

ip = &val;

printf("ip의 주소: %d \n ip의 값: %d\n", &ip, ip);
printf("val의 주소: %d \n val의 값: %d\n", &val, val);

return 0;
}
실행 결과 :
ip의 주소: 1876947680
ip의 값: 0
val의 주소: 1876947676
val의 값: 10

ip의 주소: 1876947680
ip의 값: 1876947676
val의 주소: 1876947676
val의 값: 10

주소 연산자 : 주소를 가져오는 연산자 &
간점참조 연산자 : 포인터 변수에 저장된 주소의 값을 가져오는 연산자 *

#include <stdio.h>
/*
int x = 10, y = 20;
int *ip;
- 포인터 변수 ip가 x의 주소를 저장하고, ip를 통하여 x값을 20으로 변환
- 포인터 변수 ip가 y의 주소를 저장하고, ip를 통하여 y값을 100으로 변환
- 최종 ip의 값(%u, %p 비교해 볼것)과 x, y의 값을 출력
*/
int main(void){
int x = 10, y = 20;
int *ip;

ip = &x;
*ip = 20;
printf("x의 값: %d\n", *ip);

ip = &y;
*ip = 100;
printf("y의 값: %d\n", *ip);
}

ip++; // ip가 가리키는 주소가 4byte 더해진다
(*ip)++; // ip가 가리키는 주소의 값에 1이 더해진다

#include <stdio.h>

void swap(int *, int *);

int main(void){
int i = 100, j = 200;
printf("i = %d, j = %d\n",i,j);

swap(&i, &j);
printf("i = %d, j = %d\n",i,j);
return 0;
}

void swap(int * i, int * j){
int temp;
printf("-------Swap Start-------\n");
printf("i = %d, j = %d\n", *i, *j);
temp = *i;
*i = *j;
*j = temp;
printf("i = %d, j = %d\n", *i, *j);
printf("-------Swap End-------\n");
}

실행 결과 :
i = 100, j = 200
-------Swap Start-------
i = 100, j = 200
i = 200, j = 100
-------Swap End-------
i = 200, j = 100

포인터와 배열

  1. 배열의 이름은 배열을 시작하는 주소임
  2. 배열의 이름은 포인터처럼 사용이 가능함
  3. 포인터는 배열처럼 사용이 가능함
#include <stdio.h>

int main(void){
int i, a[10] = {0};
int *pt;
pt = a;

printf("점수를 입력 10개 입력하세요.\n");

for(i = 0; i < 10; i++){
printf("pt = %d\n", pt + i);
scanf("%d", pt + i);
}

for(i = 0; i < 10; i++){
printf("a[%d] = %d", i, a[i]);
}
}
실행 결과 :
점수를 입력 10개 입력하세요.
pt = 1876947648
1
pt = 1876947652
2
pt = 1876947656
3
pt = 1876947660
4
pt = 1876947664
5
pt = 1876947668
6
pt = 1876947672
7
pt = 1876947676
8
pt = 1876947680
9
pt = 1876947684
0
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 9
a[9] = 0

함수 원형과 define 사용

#include <stdio.h>
#define MAX 7

void get_val(int *);

int main(void){
int i, a[MAX] = {0};

printf("함수 실행 전 a의 값\n");
for(i = 0; i < MAX; i++){
printf("a[%d] = %d\n", i, a[i]);
}

get_val(a);

printf("함수 실행 후 a의 값\n");
for(i = 0; i < MAX; i++){

printf("a[%d] = %d\n", i, a[i]);
}
}

void get_val(int * val){
int i;
printf("\n--- 함수 실행 --- \n");

printf("1 ~ %d 까지의 숫자를 입력해 보세요\n", MAX);
for(i = 0; i < MAX; i++){
printf("%d 번째 입력 =", i);
scanf("%d", &val[i]);
}
printf("\n--- 함수 종료 --- \n\n");
}
실행 결과 :
함수 실행 전 a의 값
a[0] = 0
a[1] = 0
a[2] = 0
a[3] = 0
a[4] = 0
a[5] = 0
a[6] = 0
>
--- 함수 실행 ---
1 ~ 7 까지의 숫자를 입력해 보세요
0 번째 입력 =1
1 번째 입력 =2
2 번째 입력 =3
3 번째 입력 =4
4 번째 입력 =5
5 번째 입력 =6
6 번째 입력 =7
--- 함수 종료 ---
>
함수 실행 후 a의 값
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
a[5] = 6
a[6] = 7

동적할당의 개념과 활용

프로그램 메모리 할당

  • 정적 할당

    • 프로그램이 시작되기 전 미리 정해진 크기의 메모리 확보
      • int hi; // 4byte
      • int hello[100] = {0}; // 4 * 100byte
        hello 배열 변수에 50개의 데이터만 들어가고 활용 된다면 == 메모리 낭비
  • 동적 할당

    • 프로그램 실행 중 동적으로 메모리 확보
    • free를 통하여 메모리 회수
    • 필요한 만큼만 할당이 가능함
    • int *pt = (int *)malloc(50 * sizeofI(int));
      • int : 자료형
      • pt : 메모리 시작주소를 저장할 포인터 변수
      • (int *) : 정수형으로 메모리 확보
      • malloc(50 * sizeof(int)) : int(4byte) * 50 만큼의 메모리 확보
    • free(pt);
      • 동적 할당한 메모리를 회수
      • pt는 할당한 메모리의 시작주소를 가리킴
    • 포인터나 배열처럼 활용이 가능함
    • free 함수 사용 시 #include <stdlib.h> 헤더파일 필요

예제

// N명의 학생 성적을 저장하기 이ㅜ해 동적 메모리를 할당하는 프로그램
#include <stdio.h>
#include <stdlib.h>
#define N 3

int main(void){
int _students, i;
students = (int _)malloc(N \* sizeof(int));

printf("%d 명의 학생 점수를 입력 합니다\n", N);
for(i = 0; i < N; i++){
printf("%d 번째 학생의 점수를 입력하세요:", i + 1);
scanf("%d", &students[i]);
}
printf("\n%d 명의 학생 점수를 출력 합니다.\n", N);
for(i = 0; i < N; i++){
printf("%d 번째 학생의 점수는:%d\n", i + 1, students[i]);
}

free(students);
return 0;
};
// 동적 메모리 할당이 안되는 경우도 있음 (메모리 부족)
if (str == NULL) {
printf("동적 메모리 할당 오류\n");
exit(1);
}
#include <stdio.h>
#include <stdlib.h>

int main(void){
int a[2][2] = {{11,22}, {33,44}};
int i, sum = 0;
int *p;
p = a[0]; // 2차원 배열에서는 첫번째 행의 주소를 가리켜야 함
for (i = 0; i < 4; i++){
sum += p[i]; // p[i] == *(p + i)
printf("p[%d] : %d\n", i, p[i]); // p[i] == *(p + i)
printf("sum : %d\n", sum);
}
printf("최종 sum : %d\n", sum);
return 0;
}
실행 결과:

p[0] : 11
sum : 11
p[1] : 22
sum : 33
p[2] : 33
sum : 66
p[3] : 44
sum : 110
최종 sum : 110

예제 2

int i = 10, j = 20, k = 30, i = 40;
i와 j값, j와 i값을 서로 변경하는 프로그램
포인터 변수를 반드시 사용할 것
사용자 정의 함수 만들기

#include <stdio.h>

void swap(int *, int *);

int main(void){
int i = 10, j = 20, k = 30, l = 40;
swap(&i, &j);
swap(&k, &l);

printf("i = %d\nj = %d\nk = %d\nl = %d\n",i,j,k,l);
}

void swap(int *a, int *b){
int temp;

temp = *a;
*a = *b;
*b = temp;
}
실행 결과:
i = 20
j = 10
k = 40
l = 30

주요 개념 정리

  • 포인터의 개념
    • 변수의 주소를 저장하는 변수
  • 포인터 변수 선언 방법
    • int *ip;
    • float *fp;
  • 주소연산자와 간접참조연산자
    • 주소연산자 : &i
    • 간접참조연산자 : *i
  • 포인터와 배열의 관계
    • 배열의 이름은 첫번째 메모리주소
    • 배열은 포인터처럼 사용이 가능하다
    • 포인터는 배열처럼 사용이 가능하다 p[n] == *(p + n)
  • 프로그램의 메모리 할당에 대하여 설명
    • 정적 할당 : 프로그램 실행 전 미리 정해진 크기를 확보
    • 동적 할당 : 프로그램 실행 시 malloc() 함수로 동적으로 메모리를 확보, free() 함수를 통해 메모리 회수