본문 바로가기
혼공단 12기(혼공C)

[혼공C] 6주차 포인터

by 눈 떠 보니 공대생 2024. 8. 18.

주차 진도 기본 숙제 추가 숙제
6주차(8.12~8.18) Chapter 9 포인터의 핵심 내용을 정리하고 공유하기 CH09 도전 실전 예제(p289) 풀고 인증하기

<기본 숙제:  포인터의 핵심 내용을 정리하고 공유하기 >

① 포인터: 메모리 주소 저장하는 변수.

② 포인터의 값 = 포인터가 가리키는 변수의 주소

③ 간접 참조 연산자/포인터 연산자(*): 포인터가 가리키는 변수를 사용할 때(포인터 통해 변수에 접근할 때)

④ 포인터의 크기: 저장할 주소의 크기에 따라 결정됨

포인터끼리 대입 가능: 가리키는 주소의 자료형이 같을 때 / 또는 형 변환을 통해 자료형을 같게 만들어주면 가능

<추가 숙제: Ch09 도전 실전 예제(p289) 풀고 인증하기>

[코드]

#include <stdio.h>

void sawp(double* pa, double* pb); // 두 실수를 바꾸는 함수
void line_up(double* maxp, double* midp, double* minp);

int main() {

	double max, mid, min;

	printf("실수값 3개 입력: ");
	scanf("%lf %lf %lf", &max, &mid, &min);

	line_up(&max, &mid, &min);
	printf("정렬된 값 출력: %.1lf, %.1lf, %.1lf\n", max, mid, min);

	return 0;
}

void sawp(double* pa, double* pb) {
	double temp;

	temp = *pa;
	*pa = *pb;
	*pb = temp;
}

void line_up(double* maxp, double* midp, double* minp) {
	if (*maxp < *midp) {
		sawp(maxp, midp); // *maxp와 *midp 정렬 완료
	}
	if (*maxp < *minp) {
		sawp(maxp, minp); //*maxp와 *minp 정렬 완료
	}
	if (*midp < *minp) {
		sawp(midp, minp); //*midp와 *minp 정렬 완료
	}
}

[실행 결과]


Chapter 9. 포인터

1. 포인터의 기본 개념

 

변수: 선언된 블록 {} 내에서만 사용 가능 → 포인터 이용해 사용 범위 외부에서도 변수에 접근 가능

1) 메모리의 주소

메모리 주소: 메모리의 위치 식별. 바이트 단위

e.g) int a;

주소값 0 1 10 11 12 13
메모리        a가 저장된  메모리  공간   

2) 주소 연산자

주소: 변수가 할당된 메모리 공간의 시작 주소 주소 연산자(&)로 접근

[코드]

#include <stdio.h>

int main() {
	int a;
	double b;
	char c;

	printf("int형 변수의 주소 : %u\n", &a);
	printf("double형 변수의 주소 : %u\n", &b);
	printf("char형 변수의 주소 : %u\n", &c);

	return 0;
}

[실행 결과]

3) 포인터와 간접 참조 연산자

포인터: 메모리 주소 저장하는 변수.

간접 참조 연산자/포인터 연산자(*): 포인터가 가리키는 변수를 사용할 때(포인터 통해 변수에 접근할 때)

[코드]

#include <stdio.h>

int main() {
	int a;
	int* pa; // int형 변수를 가리키는 포인터 선언

	pa = &a; // 포인터에 a의 주소 대입
	*pa = 10; // 포인터로 변수 a에 10 대입

	printf("포인터로 a값 출력 : %d\n", *pa);
	printf("변수명으로 a값 출력 : %d\n", a);

	return 0;
}

[실행 결과]

 

, 포인터 pa의 값 = 변수 a의 주소

*pa == a

4) 여러 가지 포인터 사용해 보기

[코드]

#include <stdio.h>

int main() {
	int a = 10, b = 15, total;
	double avg;
	int *pa = &a, *pb = &b;
	int* pt = &total; // pt → total: 포인터 pt는 변수 total을 가리킨다
	double* pg = &avg; // pg → avg: 포인터 pg는 변수 avg를 가리킨다

	*pt = *pa + *pb; 
	/* 
	pt가 가리키는 변수(total)에
	pa가 가리키는 변수(a)의 값 + pb가 가리키는 변수(b)의 값 대입
	*/ 
	*pg = *pt / 2.0; // pg가 가리키는 변수(avg)에 pt가 가리키는 변수(total) / 2.0 대입

	printf("두 정수의 값 : %d %d\n", *pa, *pb);
	printf("두 정수의 합 : %d\n", *pt);
	printf("두 정수의 평균 : %.1lf\n", *pg);

	return 0;
}

[실행 결과]

5) const를 사용한 포인터

const 포인터: 포인터가 가리키는 변수의 값을 간접 참조를 통해서는 바꿀 수 없음(, 포인터를 이용해 변수의 값을 바꿀 수 없음). 변수의 값을 직접 바꾸는 것은 가능.

[코드]

#include <stdio.h>

int main() {
	int a = 10, b = 20;
	const int* pa = &a; // 포인터 pa는 변수 a를 가리킨다

	printf("변수 a의 값 : %d\n", *pa); // 포인터를 간접 참조해 a 출력
	pa = &b; // 포인터가 변수 b를 가리키게 한다
	printf("변수 b의 값 : %d\n", *pa); // 포인터를 간접 참조해 b 출력
	pa = &a; // 포인터가 변수 a를 가리키게 한다
	a = 20; // a를 직접 참조해 값을 바꾼다
	printf("변수 a 값: %d\n", *pa); // 포인터를 간접 참조해 바뀐 a값 출력

	return 0;
}

[실행 결과]

2. 포인터 완전 정복을 위한 포인터 이해하기

포인터의 특징

① 변수의 주소 저장

② 포인터끼리 대입 가능

③ 대입 연산 기준 엄격

1) 주소와 포인터의 차이

주소: 메모리 저장 공간의 시작 주소 값 자체(상수)

포인터: 주소를 저장하는 또 다른 메모리 공간(변수)

→ 여러 개의 포인터가 하나의 변수를 동시에 가리키는 일도 가능

e.g.

int a;
int *pa, *pb, *pc;
pa = pb = pc = &a;

2) 주소와 포인터의 크기

포인터의 크기: 저장할 주소의 크기에 따라 결정됨

[코드]

#include <stdio.h>

int main() {
	char ch;
	int in;
	double db;

	char* pc = &ch;
	int* pi = &in;
	double* pd = &db;

	printf("char형 변수의 주소 크기: %d\n", sizeof(&ch));
	printf("int형 변수의 주소 크기: %d\n", sizeof(&in));
	printf("double형 변수의 주소 크기: %d\n", sizeof(&db));

	printf("char * 포인터의 크기: %d\n", sizeof(pc));
	printf("int * 포인터의 크기: %d\n", sizeof(pi));
	printf("double * 포인터의 크기: %d\n", sizeof(pd));

	printf("char * 포인터가 가리키는 변수의 크기: %d\n", sizeof(*pc));
	printf("int * 포인터가 가리키는 변수의 크기: %d\n", sizeof(*pi));
	printf("double * 포인터가 가리키는 변수의 크기: %d\n", sizeof(*pd));

	return 0;
}

[실행 결과]

3) 포인터의 대입 규칙

(1) 가리키는 변수의 형태가 같을 때만 대입

e.g. 허용되지 않는 포인터의 대입

#include <stdio.h>

int main() {
	int a = 10;
	int* p = &a; // 포인터 p: int형 변수 a의 주소 저장
	double* pd;

	pd = p; // 포인터 p값(int형 변수의 주소)을 포인터 pd(double형 변수를 가리킴)에 대입
	printf("%lf\n", *pd); // pd가 가리키는 변수의 값 출력

	return 0;
}

(2) 형 변환을 사용한 포인터의 대입은 가능

#include <stdio.h>

int main() {
	double a = 3.4;
	double* pd = &a; // pd가 double형 변수 a를 가리키도록
	int* pi;
	pi = (int*)pd; // pd 값을 int로 변환해 pi에 대입

	printf("%p\n", pi);

	return 0;
}

4) 포인터를 사용하는 이유

임베디드 프로그래밍(하드웨어 제어하는 소프트웨어 만듦), 동적 할당한 메모리에 접근 등을 위해 포인터 필요!

(1) 두 변수의 값을 바꾸며 포인터 이해하기

e.g. 포인터를 사용한 두 변수의 값 교환

[코드]

#include <stdio.h>

void VarSwap(int a, int b);
void PointSwap(int* pa, int* pb);

int main() {
	int a = 10, b = 20;
	printf("바뀌기 전 - a: %d, b: %d\n", a, b);

	// 일반 변수로는 값 교환이 불가함
	VarSwap(a, b); //a, b의 값을 복사해서 전달
	printf("일반 변수 - a: %d, b: %d\n", a, b);

	// 포인터 이용해 두 변수의 값 교환
	PointSwap(&a, &b);
	printf("포인터 이용해 변수의 값 교환 - a: %d, b: %d\n", a, b);

	return 0;

}

void VarSwap(int a, int b) {
	int temp;

	temp = a;
	a = b;
	b = temp;
}

void PointSwap(int* pa, int* pb) {
	int temp;
	
	temp = *pa;
	*pa = *pb;
	*pb = temp;
}

[실행 결과]

'혼공단 12기(혼공C)' 카테고리의 다른 글

[혼공C] 회고록  (0) 2024.08.18
[혼공C] 5주차 배열  (0) 2024.08.06
[혼공C] 4주차 함수  (0) 2024.07.28
[혼공C] 3주차 선택문, 반복문  (3) 2024.07.20
[혼공C] 2주차 변수와 데이터 입력, 연산자  (2) 2024.07.14