기초단계/c언어
2022.11.10-2 포인터
춘핑이
2022. 11. 10. 16:03
6.포인터
[철수] : 101호 -> 컴퓨터상의 메모리공간의 주소(101은 예시)
[영희] : 201호
[민수] : 301호
각 문앞에 암호가 걸려있음.
int 철수 = 1;
int 영희 = 2;
int 민수 = 3;
printf("철수네 주소 : %d, 암호 : %d\n", &철수, 철수);
printf("영희네 주소 : %d, 암호 : %d\n", &영희, 영희);
printf("민수네 주소 : %d, 암호 : %d\n", &민수, 민수);
//매번 다르게 위치가 나옴6.1 미션맨
//첫 번째 미션 : 아파트의 각 집에 방문하여 문에 적힌 암호 확인
int * 미션맨; // * 찍으면 포인터 변수임.
미션맨 = &철수; // 미션맨 철수의 주소를 가지게 선언
printf("미션맨이 방문하는 곳의 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);
//철수 주소를 알고있어서 그 암호를 아는거임. 미션맨 정수형변수의 주소값을 통해서 그 int값을 알수있음.
미션맨 = &영희;
printf("미션맨이 방문하는 곳의 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);
미션맨 = &민수;
printf("미션맨이 방문하는 곳의 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);
미션맨 = &철수;
*미션맨 = *미션맨 * 3; //*미션맨 자체가 처음 주소의 값이기때문에 거기에 *3을 하는거임.
printf("미션맨이 암호를 바꾼 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);
미션맨 = &영희;
*미션맨 = *미션맨 * 3;
printf("미션맨이 암호를 바꾼 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);
미션맨 = &민수;
*미션맨 = *미션맨 * 3;
printf("미션맨이 암호를 바꾼 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);결론 : 포인터변수는 int든 char든 주소값 아는 변수에 찾아가서 값을 바꾸거나 주소도 알 수 있음.
6.2 스파이
//미션맨이 바꾼암호에서 2를빼라
스파이
=> 누군가의 아파트 주소 같은 주소 값을 가르키게 되는것
미션맨
int* 스파이 = 미션맨;
printf("\n...스파이가 미션 수행하는 중...\n\n");
스파이 = &철수;
*스파이 = *스파이 - 2; //철수 = 철수-2
printf(" 스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);
스파이 = &영희;
*스파이 = *스파이 - 2;
printf(" 스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);
스파이 = &민수;
*스파이 = *스파이 - 2;
printf(" 스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);
printf("\n 철수 영희 민수는 집에와서 확인해보니 번호가 봐뀌어서 깜놀\n");
printf("철수네 주소 : %d, 암호 : %d\n", &철수, 철수);
printf("영희네 주소 : %d, 암호 : %d\n", &영희, 영희);
printf("민수네 주소 : %d, 암호 : %d\n", &민수, 민수);//포인터란 변수의 주소값을 가지고 그 값을 바꿀수있음.
//참고로 미션맨이 사는 곳의 주소는 &미션맨으로 확인 얘들도 각 변수이기때문임!
printf("미션맨의 주소 : %d", &미션맨);
printf("스파이의 주소 : %d", &스파이);6.3 배열과 포인터의 관계?
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));
//arr자체는 처음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));
}
//포인터하고 배열이 연결되어서 각 배열의 값도 바꿔버렸음. *ptr=arr[]이라고 볼수잇다.
//(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]);
// *& 아무것도 없는 것과 같다. &는 주소이며 *은 그주소의 값이기때문에 *&는 서로 상쇄된다
printf("arr[0]의 실제 값 : %d\n", *&*&*&*&*&*&arr[0]);
printf("arr[0]의 실제 값 : %d\n", arr[0]); //위아래 값 같음6.4 swap
//함수 선언 및 정의
void swap(int a, int b)
{
printf("swap함수내 a의 주소 : %d\n", &a);
printf("swap함수내 b의 주소 : %d\n", &b);
int temp = a;
a = b;
b = temp;
printf("Swap 함수 내 a : %d, b : %d\n", a, b);
//임시로 temp에 a값을 넣음 그리고 b에 temp를 넣기
}
//실행
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) -> 값만 복사한다는 의미
//a의 주소와 함수내에서 주소는 서로 다름주소값을 넘기면? 메모리 공간에 있는 주소값 자체를 넘기면..?
//함수 선언 및 정의
void swap_addr(int * a, int * b)
{
int temp = *a;
*a = *b;
*b = temp;
printf("주소값 전달 함수 내 a : %d, b : %d\n", *a, *b);
}
//실행
printf("Swap 함수전 => a : %d, b : %d\n", a, b);
swap_addr(&a, &b);
printf("Swap 함수후 => a : %d, b : %d\n", a, b);
//a와 b값이 아예 바뀜배열일때 arr2 => 주소 그 자체 &필요없음.
//함수 선언 및 정의
void changeAarry(int * ptr)
{
ptr[2] = 50;
}
//실행
int arr2[3] = { 10,20,30 };
//changeAarry(arr2); ==
changeAarry(&arr2[0]);
for (int i = 0; i < 3; i++)
{
printf("%d\n", arr2[i]);
}6.5 프로젝트 물고기 물 주기
//물고기가 6마리 있음.
// 이들은 어항에 살고 있는데 사막임.
// 사막이 너무더워 물이 아주 빨리 증발함.
// 물이 다 증발하기 전에 부지런히 어항에 물을줘서 물고기를 살려줘
// 물고기는 시간이 지날수록 커져서 나중에 냠냠
int level;
int arrayFish[6];
int * cursor; //피쉬를 가리키며 뭐를 물줄지 함수
void initData();
void printFishes();
void decreaseWater(long elapsedTime);
int main(void)
{
long startTime = 0; //게임 시작 시간
long totalElapsedTime = 0; //총 경과시간
long prevElapsedTime = 0; //직전 경과 시간(최근에 물을 준 시간 간격)
int num; //몇번 어항에 물을 줄것인지 사용자 입력
initData();
cursor = arrayFish; // cursor[0] .. cursor[1]
startTime = clock(); //현재 시간을 millisecond(1000분의 1초)
while (1) //1쓰면 무한반복
{
printFishes();
printf("몇 번 어항에 물을 주시겠어요?");
scanf_s("%d", &num);
//입력값체크
if (num < 1 || num>6)
{
printf("\n입력값이 잘못되었습니다\n)");
continue;
}
totalElapsedTime = (clock() - startTime) / CLOCKS_PER_SEC; //초단위로 나눠 알려줌
printf("총 경과 시간 : %d 초\n", totalElapsedTime);
//직전 물 준 시간(마짐가으로 물 준 시간) 이후로 흐른 시간
prevElapsedTime = totalElapsedTime - prevElapsedTime;
printf("최근 경과 시간 : %d 초\n", prevElapsedTime);
//어항의 물을 감소 (증발)
decreaseWater(prevElapsedTime);
//사용자가 입력한 어항에 물을 준다.
// 1. 어항의 물이 0이면? 물을 못 준다.
if (cursor[num - 1] <= 0)
{
printf("%d번 물고기는 이미 죽었습니다. 물을 주지 않습니다\n", num);
}
//2. 어항의 물이 0이 아닌경우? 물을 준다. 100을 넘지 않는지 체크
else if (cursor[num - 1] + 1 <= 100)
{
//물을 준다
printf("%d번 어항에 물을 줍니다. \n", num);
cursor[num - 1] += 1;// cursor[num - 1] = cursor[num - 1] + 1
}
//레벨업을 할 건지 확인(레벨업은 20초마다 한번씩 수행)
if (totalElapsedTime / 20 > level - 1)
//만약15초면 0.몇이라 0으로봄 0>0이라 안바뀜 20초면 1이되니 1>0이라 렙업
{
//레벨업
level++; // level : 1 -> level : 2
printf("\n***축 레벨업 %d레벨에서 %d레벨로 업그레이드***\n\n", level -1, level);
// 최종레벨 : 5
if (level == 5)
{
printf("\n\n축하합니다. 최고 레벨을 달성하였습니다. 게임을 종료합니다.\n\n");
exit(0);
}
}
//모든 물고기가 죽었는지 확인
if (checkFishAlive() == 0)
{
//물고기 모두 사망
printf("모든 물고기가 사망..\n");
exit(0);
}
else
{
//하나라도 살아잇음
printf("물고기가 아직 살아있어요!\n");
}
prevElapsedTime = totalElapsedTime;
// 10초 -> 15초 (5초:prevElapsedTime->15초) -> 25초 (10초..?)
}
return 0;
}
void initData()
{
level = 1; //게임 레벨(1~5)
for (int i = 0; i < 6; i++)
{
arrayFish[i] = 100; //어항의 물높이 (0~100)
}
}
void printFishes()
{
printf("%3d번 %3d번 %3d번 %3d번 %3d번 %3d번\n", 1, 2, 3, 4, 5, 6);
//%3d면 3칸먹고 숫자표기 '번' 두자리 먹음 3+ 2+ 1 빈칸=6칸
for (int i = 0; i < 6; i++)
{
printf(" %4d ", arrayFish[i]);
//앞뒤1칸씩 2 + %4d 4칸 빈칸6칸
}
printf("\n\n");
}
void decreaseWater(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;
} 
2022.11.10 리뷰
포인터 정신나갈거같음. 주소가 있다는 것 자체는 이해했으나 어렵다.
c언어 제외하고 포인터는 없음. 가비지 콜렉터가 알아서 주소를 정리해줌
배우는게 늘어나면서 여러가지 응용을 해야햐서 코드가 점점 복잡해진다.
설계가 중요하다는 것을 알겠고 위에서부터 하나씩 내려가면 된다.
오늘도 중요한 것은 꺾이지 않는 마음