C++

[강의] 10월 1일 수업정리

k-codestudy 2024. 10. 1. 17:42

함수와 const의 연관성과 간단하게 함수에서의 배열에 대한 수업을 진행하였다.

 

Const

#include <iostream>

int main()
{
	const int* p{};

	*p = 0;
	p = 0;
}

 

1. *p = 0;

  •  p가 가리키는 값을 변경하려고 시도하는 것.
  • const int *p의 경우 상수를 가리키는 포인터를 의미하는 것이므로, p(포인터)가 가리키는 메모리 위치에 저장된 값을 변경하는 것은 금지되기에 컴파일 오류가 일어나게 된다.

2. p = 0;

  • 이 줄은 포인터 p 자체의 값을 변경하는 것이므로 즉, 포인터 p가 다른 주소를 가리키도록 설정
  • const int *p에서 p는 값이 상수인 것이지 포인터 자체는 상수가 아니다. 그렇기에 포인터 p가 가리키는 위치를 변경하는 것은 허용되기에 문법적으로 올바르다.
  1.  

요약 : 

  • *p = 0;는 값을 변경하려고 해서 오류가 발생합니다. ( p가 가리키는 값이 읽기 전용이기 때문 )
  • p = 0;는 포인터 자체를 변경하는 것이므로 허용됩니다. ( 포인터는 쓰기 가능 )

즉, 변수를 기준으로 수식어가 나왔을 때 const가 존재할 경우 읽기 전용  const가 존재하지 않다면 쓰기 전용이라는 개념이다.

 

2. const int* p와 int const* p의 차이점

const int *p{};
int const *p{};

두 구문의 차이점은?

  • 두 구문은 동일한 의미를 갖는다.
  • const는 변수의 읽기 전용 성격을 지정하는데, const가 앞에 오거나 뒤에 오더라도 p가 가리키는 값은 변경되지 않는다는 의미를 가지게 된다.
  • 원래 const는 자료형 뒤에 위치해야 하지만, const의 경우 최종 자료형의 경우 예외적으로 앞에 적을 수 있다.

 

 

Cosnt는 왜 사용을 하는가?

  • 포인터를 사용할 때 값(내용물)을 변경하고 싶지 않은 경우
    ( 예시 : const int* p => 읽기 전용 (전달하기 위한 값) )
  • 내가 이 함수 인수에 자료형을 사용했을 때 서로 간에 어떤 식으로 주고받는 지를 결정하는데 가장 중요한 것
  • 또한 포인터가 하는 일이 많기 때문에 포인터가 가리키는 값이 읽기 전용인지 쓰기 가능한지를 명확히 표현 을 해야 하기 때문에 const의 사용이 중요하다.

 

예시)

#include <iostream>

void rectangleArea(int nWight, int nHeight, int* pArea);

int main()
{
	int nArea{};

	rectangleArea(5, 4, &nArea);
	printf("%d\n", nArea);
}

void rectangleArea(int nWight, int nHeight, int* pArea)
{
	*pArea = nWight * nHeight;
}

프로토 타입 선언:  void rectangleArea(int nWight, int nHeight, int* pArea); 

  • 함수가 어떤 매개 변수를 받을지, 반환 타입은 무엇인지 설명

함수 정의 : void rectangleArea(int nWight, int nHeight, int* pArea) { *pArea = nWight * nHeight; } :

  • 매개변수로 전달받은 nWidth, nHeight를 사용해 사각형의 면적을 계산하고, 그 결과를 포인터 pArea가 가리키는 주소에 저장한다.

함수 호출: rectangleArea(5, 4, &nArea) :

  • nWight = 5, nHeight = 4 값을 전달하고, pArea가 nArea의 주소를 가리키게 됨으로 함수 내부에서 *pArea = 5 * 4가 수행되고, nArea의 값이 20으로 변경된다.

 

포인터와 함수 호출 관련 개념 정리

  • 포인터를 전달하면 무조건 내용물을 바꾼다
    • 함수의 매개변수에 포인터가 사용되면, 해당 포인터가 가리키는 메모리의 값을 변경할 수 있다.
    • 변수명 앞에 수식어가 하나 붙어 있으면, 그 변수의 내용을 수정할 수 있음을 의미한다.
    • 예시: void func(int* p);
  • Call by Value vs. Call by Reference
    • call by value는 기본적으로 선언되면서 복사가 된다는 개념을 지니고 있다. 기본 자료형(int, float)인 경우 값만 복사되어도 무관하지만, 구조체나 클래스를 다룰 때는 포인터나 참조자를 사용하여 복사 비용을 줄일 수 있다.
    • C언어에서는 call by Value만 존재하며, 포인터를 전달하더라도 이는 포인터 자체의 값(주소)을 복사하는 것이다. 
      그렇기에 주소값을 전달하느 방식은 "참조에 의한 호출(call by reference)"라 오해할 수 있지만 실제로는 call by value이기에 혼동하지 않아야 한다
  • Call by Value (값에 의한 호출)
    • 일반적으로 const를 굳이 붙이지 않는다.
    • 이유:
      void func(int); -> 4바이트
      void func(const int); -> 8바이트
      const를 사용하면 불필요하게 메모리 사용량이 증가할 수 있다.
    • 하지만 const를 사용하는 경우도 존재하며, 사용 빈도가 낮을 뿐이다.

 

간단한 예제를 풀고 마무리해보겠다.

#include <iostream>

void add1(int n1, int n2, int* pResult);
void add2(const int * p1, const int* p2, int* pResult);

int main()
{
	int nData1{};
	int nData2{};
	int nResult{};

	scanf_s("%d", &nData1);
	scanf_s("%d", &nData2);

	add1(nData1, nData2, &nResult);
	printf("%d\n", nResult);

	add2(&nData1, &nData2, &nResult);
	printf("%d\n", nResult);
}

void add1(int n1, int n2, int* pResult)
{
	*pResult = n1 + n2;
}

void add2(const int* p1, const int* p2, int* pResult)
{
	*pResult = *p1 + *p2;
}

 

 

  1. add1 함수:
    • 인자로 두 정수(n1, n2)와 결과를 저장할 포인터(pResult)를 받는다.
    • 두 정수(n1, n2)의 값을 더한 결과를 포인터 pResult가 가리키는 메모리 위치에 저장.
    • 즉, 값 자체를 받아와서 더한 후 결과를 포인터로 전달한다.
  2. add2 함수:
    • 두 정수의 주소(p1, p2)와 결과를 저장할 포인터(pResult)를 받는다.
    • p1과 p2가 가리키는 값을 더한 결과를 pResult가 가리키는 메모리 위치에 저장.
    • 즉, 주소값을 받아와 해당 주소에 있는 값을 참조하여 더한 후, 결과를 포인터로 전달한다.

      핵심 정리
      • add1: 두 정수의 값을 받아서 그 값을 더한 후 포인터로 결과를 전달
      • add2: 두 정수의 주소를 받아 해당 주소의 값을 더한 후 포인터로 결과를 전달
      즉, 이 두 함수는 포인터를 사용하는 방식의 차이점(값 전달 vs. 주소 전달)을 보여준다.

'C++' 카테고리의 다른 글

[강의] 10월 4일 수업정리  (1) 2024.10.05
[강의] 10월 2일 수업정리  (1) 2024.10.03
[강의] 9월 27일 수업정리  (0) 2024.09.27
[강의] 9월 26일 수업정리  (1) 2024.09.27
[강의] 9월 25일 수업정리  (1) 2024.09.26