3.5 포인터
● 포인터의 개념, 포인터와 관련된 연산자, 다양한 포인터
포인터 : 다른 변수의 주소를 가지고 있는 변수.
* 연산자 - 간접참조 연산자 (역참조 연산자)
&연산자 - 주소 연산자
int a = 100;
int *p;
p = &a; //a의 주소를 p에 저장.
*p = 200 // p가 가르키는 주소의 값을 200으로 변경
printf("a= %d",a); // 결과값 : a= 200
int *p 외에 float *pf, char *pc처럼 다양한 자료형에 대한 포인터를 선언할 수 있다.
● 널 포인터
널 포인터: 어떤 객체도 가리키지 않는 포인터. 포인터를 사용하는 코드를 작성할 때 포인터가 널 포인터인지
점검하는 예외처리가 필요하다.
if( p == NULL ){ //C언어에서는 널 포인터를 NULL이라는 매크로로 표시
fprint(stderr,"널 포인터 오류");
return;
}
이와 같은 예외처리는 널 포인터를 간접참조하려 하는 경우를 방지한다.
● 함수 매개변수로 포인터 사용하기
void swap(int *px, int *py){
int tmp;
tmp = *px;
*px = *py;
*py = tmp;
}
매개변수로 포인터를 받으면 함수 밖의 외부 변수의 값을 변경할 수 있다.
● 배열과 포인터
배열과 포인터의 관계 : 배열의 이름은 배열의 시작부분을 가리키는 포인터
- 배열의 이름이 있는 곳을 배열의 첫 번째 요소의 주소로 대치.
- 배열의 이름이 포인터이기 때문에 매개변수로 배열을 사용할 땐 포인터를 사용하는 것과 같다.
따라서 배열을 매개변수로 사용하는 함수에선 원본 배열의 내용을 변경한다.
- 함수 호출 시에 배열을 복사하는 것이 아닌 주소로 직접 접근해서 다루기 때문에
메모리 공간과 함수 호출 시간 측면에서 효율적
♠ 94p Quiz
01 double get_distance(Point p1, Point p2){} --> A
double get_distance(Point *p1, Point *p2){} --> B
A는 두 구조체(즉 두 점)를 받아서 두 점 사이의 거리를 계산한 뒤 거리를 반환하는 데 사용한다.
B는 외부에서 두 점을 받아올 필요 없이 함수 내에서 임의로 두 점을 정해서 거리를 반환할 수 있다.
02 포인터의 포인터, 즉 더블 포인터는 기존의 포인터가 가리키고 있는 대상을 바꾸고 싶을 때 사용한다.
3.6 동적 메모리 할당
배열과 같은 자료형을 사용할 때 임의로 정한 메모리 공간을 사용하면 정해진 크기보다 더 큰 입력은
처리하지 못하고 더 작은 입력은 공간을 낭비한다는 문제점이 있다.
● 동적 메모리 할당: 필요한 만큼의 메모리를 운영체제로부터 할당받아서 사용하고 사용이 끝난 후 반납하는 기능
int *p;
p= (int*)malloc(sizeof(int)); // 1. 동적 메모리 할당
*p = 100; // 2. 동적 메모리 사용
free(p); // 3. 동적 메모리 반납
- 동적 메모리는 힙(heap) 공간에 할당된다.
1. sizeof() 함수를 통해 알아낸 변수나 타입의 크기를, malloc함수를 통해 메모리 블록을 할당받은 뒤에
(int*)로 형변환을 해준다.
★ 시스템의 메모리 부족으로 인해 malloc()의 반환값이 NULL인지 항상 검사해야 한다.
2. 동적 메모리는 포인터로만 사용할 수 있다.
3. malloc() 함수를 통해 할당받은 메모리 블록을 운영체제에 반환한다.
free()를 통해 반환한 포인터 값은 메모리 공간이 없으므로 이후에 접근할 수 없다.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
int main(){
int *p;
p = (int*)malloc(SIZE * sizeof(int));
if(p == NULL){ // malloc() 반환값이 NULL인지 검사
fprintf(stderr,"메모리 부족");
exit(1);
}
for(int i=0; i<SIZE;i++){
p[i]=i; // 동적 메모리 사용
printf("%d ",p[i]);
}
free(p); // 동적 메모리 반납
return 0;
}
● 구조체와 포인터
포인터를 통해 구조체의 멤버에 접근할 때는 (*ps).i 보다 ps->i 라고 쓰는 것이 더 편리하다.
앞선 동적할당 개념과 합친 예제를 작성해 본다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[10];
int age;
}student;
int main(){
student *s;
s = (student*)malloc(sizeof(student));
if(s==NULL){
fprintf(stderr,"메모리 부족");
exit(1);
}
strcpy(s->name,"Park");
s->age = 20;
printf("%s의 나이는 %d\n",s->name,s->age);
free(s);
return 0;
}
♠ 97p Quiz
01 malloc()을 할 때 double의 크기를 sizeof()를 통해 구하지 않았다.
'CS > Data Structure' 카테고리의 다른 글
[C언어로 쉽게 풀어쓴 자료구조] 연습문제 2강 (0) | 2023.10.21 |
---|---|
[C언어로 쉽게 풀어쓴 자료구조] 연습문제 1강 (0) | 2023.10.21 |
[C언어로 쉽게 풀어쓴 자료구조] Chapter3. 배열, 구조체, 포인터 (1) (0) | 2023.10.21 |
[C언어로 쉽게 풀어쓴 자료구조] Chapter2. 순환 (0) | 2023.10.14 |
[C언어로 쉽게 풀어쓴 자료구조] Chapter1. 자료구조와 알고리즘 (0) | 2023.10.12 |