포인터 및 동적할당 활용
포인터의 개념과 활용
포인터의 개념과 변수 선언
포인터의 개념 : 변수의 주소를 저장하는 변수
포인터 변수 선언
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
포인터와 배열
- 배열의 이름은 배열을 시작하는 주소임
- 배열의 이름은 포인터처럼 사용이 가능함
- 포인터는 배열처럼 사용이 가능함
#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()
함수를 통해 메모리 회수