본문 바로가기
c언어 개발일지

[나도 코딩 C언어] 포인터

by 노랑사랑팽이 2022. 8. 16.

✏️포인터

🔎 주소, 암호

#include <stdio.h>

int main(void)
{
	//포인터
	// [철수] 101호
	// [영희] 201호
	// [민수] 301호
	// 각 문 앞에 '암호'가 걸려 있음

	int 철수 = 1; //암호
	int 영희 = 2;
	int 민수 = 3;

	printf("철수네 주소 : %d, 암호 : %d\n", &철수, 철수);
	printf("영희네 주소 : %d, 암호 : %d\n", &영희, 영희);
	printf("민수네 주소 : %d, 암호 : %d\n", &민수, 민수);

	//미션맨 !
	// 첫번째 미션 : 아파트의 각 집에 방문하여 문에 적힌 암호 확인
	int* 미션맨; // 포인터 변수
	미션맨 = &철수;

	printf("미션맨이 방문하는 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);

	미션맨 = &영희;
	printf("미션맨이 방문하는 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);

	미션맨 = &민수;
	printf("미션맨이 방문하는 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);


	// 두번째 미션 : 각 암호에 3을 곱하라
	미션맨 = &철수;
	*미션맨 = *미션맨 * 3;
	printf("미션맨이  암호를 바꾼 곳 방문하는 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);

	미션맨 = &영희;
	*미션맨 = *미션맨 * 3;
	printf("미션맨이  암호를 바꾼 곳 방문하는 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);

	미션맨 = &민수;
	*미션맨 = *미션맨 * 3;
	printf("미션맨이  암호를 바꾼 곳 방문하는 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);


	// 스파이
	// 미션맨이 바꾼 암호에서 2를 빼라
	int* 스파이 = 미션맨;
	printf("\n ..... 스파이가 미션 수행하는 중 ... \n\n");
	스파이 = &철수;
	*스파이 = *스파이 - 2;
	printf("스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);


	스파이 = &영희;
	*스파이 = *스파이 - 2;
	printf("스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);

	스파이 = &민수;
	*스파이 = *스파이 - 2;
	printf("스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);


	printf("\n\n... 철수 영희 민수는 집에 오고서는 바뀐 비번을 보고 깜놀 ...\n\n");

	printf("철수네 주소 : %d, 암호 : %d\n", &철수, 철수);
	printf("영희네 주소 : %d, 암호 : %d\n", &영희, 영희);
	printf("민수네 주소 : %d, 암호 : %d\n", &민수, 민수);

	//참고로... 미션맨이 사는 곳의 주소는... &미션맨으로 확인
	printf("미션맨의 주소 : %d\n", &미션맨);
	printf("스파이의 주소 : %d\n", &스파이);

	return 0;
}

&영희 : 주소값

* 영희 : 지칭하는 값

스파이라는 명칭으로 영희 주소값에 접근해 값을 변경해도 그 값이 바뀌는 걸 확인 할 수 있다.

 

🔎 배열과 포인터

📌 *(arr + i) == arr[i]

*(arr + 0) == arr[0] == *arr

포인터를 활용하면 배열값의 일부도 바꿀 수 있다.

 

📌  *&는 서로 상쇄된다.

& 는 주소이며, * 는 그 주소의 값이기 때문에, *&arr[0] == arr[0]

#include <stdio.h>


// 배열과 포인터 관계
int main(void)
{
	//배열
	int arr[3] = { 5, 10, 15 };
	int* ptr = arr;

	for (int i = 0; i < 3; i++)
	{
		printf("배열 arr[%d]의 값 : %d\n", i, arr[i]);
	}
	for (int i = 0; i < 3; i++)
	{
		printf("포인터 ptr[%d]의 값 : %d\n", i, ptr[i]);
	}

	ptr[0] = 100;
	ptr[1] = 200;
	ptr[2] = 300;
	for (int i = 0; i < 3; i++)
	{
		//printf("배열 arr[%d]의 값 : %d\n", i, arr[i]);
		printf("배열 arr[%d]의 값 : %d\n", i, *(arr + i));
	}
	for (int i = 0; i < 3; i++)
	{
		//printf("포인터 ptr[%d]의 값 : %d\n", i, ptr[i]);
		printf("포인터 ptr[%d]의 값 : %d\n", i, *(ptr + i));
	}

	// *(arr + i) == arr[i] 똑같은 표현
	// arr == arr 배열의 첫번째 값의 주소와 동일 == &arr[0]
	printf("arr 자체의 값 : %d\n", arr);
	printf("arr[0] 의 주소 : %d\n", &arr[0]);

	printf("arr 자체의 값을 가지는 주소의 실제 값 : %d\n", *arr); // *(arr + 0)
	printf("arr[0] 의 주소 : %d\n", *&arr[0]); // *&는 아무것도 없는 것과 같다.
	// & 는 주소이며, * 는 그 주소의 값이기 때문에, 
	// *&는 서로 상쇄된다.

	return 0;
}

 

✏️ Swap

🔎 값을 바꿔주기

swap 함수를 이용해 값을 바꿔주는걸 시도했으나, 실패했다.

왜냐면, main내에 a,b 주소와 swap 함수 내 a,b주소가 상이하기 때문이다.

 

따라서, 값을 바꿔주기 위해서는 주소값을 함수에 전달해 값을 바꾸도록 해야한다.

함수는 받은 주소값을 활용해 포인터로 값을 바꿔줘야 한다.

#include <stdio.h>

void swap(int a, int b);
void swap_addr(int *a, int *b);

int main(void)
{
	//Swap
	int a = 10;
	int b = 20;
	printf("a의 주소 : %d\n", &a);
	printf("b의 주소 : %d\n", &b);
	// a와 b의 값을 바꾼다.
	printf("Swap 함수 전 a : %d, b : %d\n", a, b);
	swap(a, b);
	printf("Swap 함수 후 a : %d, b : %d\n", a, b);

	//값에 의한 복사 (Call by Value) -> 값만 복사한다는 의미.
	//주소값을 넘기면? 메모리 공간에 있는 주소값 자체를 넘기면
	printf("(주소값 전달)Swap 함수 전 a : %d, b : %d\n", a, b);
	swap_addr(&a, &b);
	printf("(주소값 전달)Swap 함수 후 a : %d, b : %d\n", a, b);

	return 0;
}

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

	//printf("함수 내 a의 주소 : %d\n", &a);
	//printf("함수 내 b의 주소 : %d\n", &b);

	//printf("Swap 함수 내 a : %d, b : %d\n", a, b);
}

void swap_addr(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

 

🔎 배열 값 바꿔주기

배열은 주소 전달해주지 않더라도 값이 잘 바뀐다.

다만, 함수에서는 포인터를 받아야 한다.

#include <stdio.h>

void chageArray(int* ptr);

int main(void)
{
	//배열일 때, arr -> 주소
	int arr2[3] = { 10, 20, 30 };
	chageArray(arr2); //chageArray(&arr2[0]);

	for (int i = 0; i < 3; i++)
	{
		printf("%d\n", arr2[i]);
	}

	// scanf 에서 &num의 의미와 동일

	return 0;
}

void chageArray(int* ptr)
{
	ptr[2] = 50;
}

✏️ 프로젝트

🔎 물고기 키우기

사막에서 물고기 키우는 걸로 시간이 경과되는 만큼 물이 증발된다.

그러므로 물고기는 물을 줘도 죽을 수 밖에 없는 환경...

#include<stdio.h>
#include<time.h>

// 물고기가 6마리가 있다.
// 이들은 어항에 살고 있는데, 사망이에요.
// 사막이 너무 더워서, 너무 건조해서 물이 아주 빨리 증발해요.
// 물이 다 증발하기 전에 부지런히 어항에 물을 줘서 물고기를 살려주세요~


int level;
int arrayFish[6];
int * cursor;
void iniDate();
void printfFishes();
void decreseWater(long elapsedTime);
int checkFishAlive();

int main(void)
{
	long startTime = 0; // 게임 시작 시간
	long totalElapseTime = 0; // 총 경과 시간
	long preElapsedTime = 0; // 작전 경과 시간(최근에 물을 준 시간 간격)

	int num; // 몇 번 어항에 물을 줄것인지. 사용자 입력
	iniDate();

	cursor = arrayFish; // cursor[0] .... cursor[1]

	startTime = clock(); // 현재 시간을 millisecond [1000분의 1초]단위로 반환
	while (1)
	{
		printfFishes();
		printf("몇 번 어항에 물을 주시겠어요?");
		scanf_s("%d", &num);

		//입력값 체크
		if (num < 1 || num >6)
		{
			printf("\n입력값이 잘못되었습니다.\n");
			continue;
		}

		//총 경과 시간
		totalElapseTime = (clock() - startTime) / CLOCKS_PER_SEC;
		printf("총 경과 시간 : %1d 초\n", totalElapseTime);

		//직전 물 준 시간 (마지막으로 물 준 시간) 이후로 흐른 시간
		preElapsedTime = totalElapseTime - preElapsedTime;
		printf("최근 경과 시간 : %1d 초\n", preElapsedTime);

		//어항의 물을 감소(증발)
		decreseWater(preElapsedTime);

		//사용가가 입력한 어항에 물을 준다.
		// 1. 어항의 물이 0이면? 물을 주지 않는다... 이미 물고기가 죽었음
		if (cursor[num - 1] <= 0)
		{
			printf("%d번 물고기는 이미 죽었습니다. 물을 주지 않습니다.\n", num);
		}

		//2. 어항의 물이 0이 아닌 경우? 물은 준다! 100을 넘지 않는지 체크
		else if (cursor[num - 1] + 1 <= 100)
		{
			//물을 준다.
			printf("%d번 어항의 물을 줍니다,\n\n", num);
			cursor[num - 1] += 1;
		}
		// 레벨업을 할 건지 확인 (레벨업은 20초마다 한번씩 수행)
		if (totalElapseTime / 20 > level - 1)
		{
			// 레벨업
			level++;
			printf("**** 축 레벨업 ! 기존 %d 레벨에서 %d 레벨로 업그레이드 ***\\n\n", level-1, level);

			// 최종 레벨 : 5
			if (level == 5)
			{
				printf("\n\n 축하합니다. 최고 레벨을 달성하였습니다. 게임을 종료합니다.");
				exit(0);
			}
		}

		// 모든 물고기가 죽었나 확인
		if (checkFishAlive() == 0)
		{
			// 물고기 모두 죽었다.
			printf("모든 물고기가... ㅠㅠ 흑흑...\n");
			exit();
		}
		else
		{
			//최소 한마리 이상의 물고기 살아있음
			printf("물고기가 아직 살아 있어요!\n");
		}

		preElapsedTime = totalElapseTime;

		// 10초 -> 15초 (5초 : preElapsedTime->15초)->25초 (10초?)
	}

	return 0;
}

void iniDate() 
{
	level = 1; // 게임 레벨(1~5)
	for (int i = 0; i < 6; i++)
	{
		arrayFish[i] = 100; // 어항의 물 높이 (0~100)
	}
}

void printfFishes()
{
	printf("%3d번 %3d번 %3d번 %3d번 %3d번 %3d번\n", 1,2,3,4,5,6);
	for (int i = 0; i < 6; i++)
	{
		printf("%  6d", arrayFish[i]);
	}
	printf("\n\n");
}

void decreseWater(long elapsedTime)
{
	for (int i = 0; i < 6; i++)
	{
		arrayFish[i] -= (level * 3 * (int)elapsedTime); //3 : 난이도 조절을 위한 값
		if (arrayFish[i] < 0)
		{
			arrayFish[i] = 0;
		}
	}
}

int checkFishAlive()
{
	for (int i = 0; i < 6; i++)
	{
		if (arrayFish[i] > 0)
			return 1; //참 True
	}
	return 0;
}

🍏 KEEP, 습관 중요한 것

함수에 주소값을 전달해야 한다는 점이 흥미로웠다.

컴퓨터가 변수에 값을 저장할 때, 항상 주소와 값이 형성된다는 점을 유의해야 한다.

 

🍎 PROBLEM, 이슈, 에러, 오류

이번 목차를 학습할때는 운이 좋게도 에러가 발생하지 않았다.

 

 🍉 TRY 시도

프로젝트는 다시 듣고 이해해 봐야 할듯하다.

프로젝트가 혼자 구현하긴 어렵다.

배열부터 좀 어렵다..ㅎㅎㅎ

댓글