프로그래밍 언어/C++

2) 포인터와 레퍼런스

busy맨 2023. 11. 1. 19:42

1. 포인터

1) 변수의 주소

  • 포인터(pointer)
    • 변수의 주소를 나타냄
  • 변수의 주소
    • 변수가 포함하고 있는 제일 첫 번째 바이트의 주소
    • 변수의 주소는 변수 이름 앞에 &를 붙여줌
      • ex) a의 주소 -> &a
  • 포인터 변수
    • 주소값을 저장하는 변수
    • 포인터라 약칭

2) 포인터 변수의 선언 및 사용

  • 간접 참조 연산자 (*)
    • 포인터 변수가 가리키는 실제 변수의 값을 참조

#include <iostream>
using namespace std;

int main() 
{
    int n=10, m;
    char c='A';
    double d;
    
    int *p= &n; // p는 n의 주소값을 가짐
    char *q = &c; // q는 c의 주소값을 가짐
    double *r = &d; // r은 d의 주소값을 가짐
    
    *p = 25; // n에 25가 저장됨
    *q = 'A'; // c에 문자 'A'가 저장됨
    *r = 3.14; // d에 3.14가 저장됨
    m = *p + 10; // p가 가리키는 값(n 변수값)+10을 m에 저장
    
    cout << n << ' ' << *p << "\n"; // 둘 다 25가 출력됨
    cout << c << ' ' << *q << "\n"; // 둘 다 'A'가 출력됨
    cout << d << ' ' << *r << "\n"; // 둘 다 3.14가 출력됨
    cout << m << "\n"; // m 값 35 출력
}

 

 

3) 배열과 포인터.

  • 배열 이름은 배열 메모리의 시작 주소로 다룸
  • 주소를 이용한 원소 참조
in nArray[10];

*(nArray+i)==nArray[i];

 

 

  • 일반적인 방법을 사용한 원소의 탐색
#include<iostream>
using namespace std;

int main()
{
	int nArray[10];
    
    //배열을 탐색하며 값을 넣음
    for(int i=0;i<10;i++)
    {
    	nArray[i]=i;
        // *(nArray+i)=i 와 동일
    }
}
  • 포인터를 사용한 원소의 탐색
#include<iostream>
using namespace std;

int main()
{
	int nArray[10];
    int* p=&nArray[0];
    
    //배열을 탐색하며 값을 넣음
    for(int i=0;i<10;i++)
    {
    	*(p+i)=i;
    }
}

 

4) 포인터 배열

  • 포인터 변수들을 배열 요소로 갖는 배열

  • 문자열 포인터 배열
    • 문자열들을 효율적으로 저장하기 때문에 많이 사용되는 포인터 배열
    • 문자열 상수는 문자열의 시작 주소
#include <iostream>
using namespace std;

int main()
{
    const char *ptr_ary[5];
    
    ptr_ary[0]="dog";
    ptr_ary[1]="elephant";
    ptr_ary[2]="horse";
    ptr_ary[3]="tiger";
    ptr_ary[4]="lion";
    
    for(int i=0; i<5; i++)
    {
    	cout << ptr_ary[i]<<“\n”);
    }
    return 0;
}

 

2. 레퍼런스(참조)

1) 레퍼런스(Reference) 선언

  • 참조자 & 사용
  • 이미 존재하는 변수에 대한 다른 이름 선언
    • 참조 변수는 이름만 생기며 새로운 공간을 할당하지 않는다
    • 초기화로 지정된 기존의 변수 공유

 

 

#include <iostream>
using namespace std;

int main() 
{
    cout << "i" << '\t' << "n" << '\t' << "refn" << endl;
    
    int i = 1;
    int n = 2;
    
    int &refn = n; // 참조 변수 refn 선언. refn은 n에 대한 별명
    n = 4; 
    
    refn++; // refn=5, n=5
    cout << i << '\t' << n << '\t' << refn << endl;
    
    refn = i; // refn=1, n=1
    refn++; // refn=2, n=2
    cout << i << '\t' << n << '\t' << refn << endl;
    
    int *p = &refn; // p는 n의 주소를 가짐
    *p = 20; // refn=20, n=20
    cout << i << '\t' << n << '\t' << refn << endl;
}

  • const 레퍼런스
    • const 키워드를 함께 사용하면 레퍼런스가 참조하는 변수의 값을 변경 불가
    • 레퍼런스는 참조하는 변수에 읽기만 가능하다
int data = 100;
const int &ref = data;

cout << ref; // cout << data;의 의미
ref = 200; // const 레퍼런스는 변경할 수 없으므로 컴파일 에러
data = 200; // data를 직접 변경하는 것은 가능하다.

 

3. 함수에서의 인자 전달

1) 함수의 인자 전달

  1. Call by Value
    • 값에 의한 전달
    • 함수를 호출할 때 넘겨준 인자를 함수 안에서 사용만 하고 변경하지 않을 때
  2. Call by Reference
    • 포인터에 의한 전달이나 레퍼런스에 의한 전달
    • 함수를 호출할 때 넘겨준 인자를 함수 안에서 변경해야 할 때

 

  • Ex) swap() 함수

변수를 넘겨준 경우와 포인터를 넘겨준 경우
레퍼런스를 넘겨준 경우

 

2) 함수의 인자 전달 방법 - 포인터

  • 함수의 매개변수를 포인터 타입으로 정의
  • 인자를 넘겨줄 때는 결과 값을 담고 싶은 변수의 주소를 넘겨줌
  • 함수 안에서 결과를 넘겨줄 때는 매개변수가 가리키는 곳에 값을 넣어줌
void GCD_LCM(int a, int b, int* pgcd, int* plcm)	//매개변수 타입을 포인터 형으로 선언
{
    . . .
    *pgcd = 5; 	// pgcd는 gcd를 가리키고 있으므로 gcd의 실제값이 바뀜
}
int main()
{ 	
	. . .
    GCD_LCM(28, 35, &gcd, &lcm);	//변수의 주소를 넘겨준다
    . . .
}

 

3) 함수의 인자 전달 방법 - 레퍼런스

  • 함수의 매개변수를 레퍼런스 타입으로 정의
  • 인자를 넘겨줄 때는 결과 값을 담고 싶은 변수를 그대로 넘겨줌
  • 함수 안에서 결과를 넘겨줄 때는 매개변수에 값을 넣어줌
void GCD_LCM(int a, int b, int& pgcd, int& plcm)	//매개변수를 레퍼런스 타입으로 선언
{
    . . .
    pgcd = 5; 	// pgcd는 gcd의 별명이므로 gcd의 실제값이 바뀜
}
int main()
{
    . . .
    GCD_LCM( 28, 35, gcd, lcm);	//변수 그대로 함수에 넘겨줌
    . . .
}

 

4) 함수의 인자 전달 방법 - 1차원 배열

  • 배열 전체를 한 번에 보낼 수 없으므로, 배열의 시작 주소를 보냄
  • call by reference 방식으로 전달
void UsingArray(int arr[]) { // 또는 int arr[3], int *arr
    . . .
    cout << arr[0] << *(arr+1) << “\n”;
}
int main() 
{
    int arr1[3] = {1,2,3};
    UsingArray(arr1); 
    UsingArray(arr1+1); 
    UsingArray(&arr[2]);
    . . .
}

 

5) 함수의 인자 전달 방법 - 2차원 배열

  • 1차원 배열과 동일한 방법
  • 호출된 함수에서는 몇 개의 원소가 있는지 알 수 있도록 함
    • 1차원 원소의 개수는 절대로 생략 X(=열의 개수에 해당하는 부분 삭제 X)
void Using2DArray(int arr[][3]) { // 또는 int arr[5][3]	1차원 원소 부분 생략 불가
	. . . 
}

int main() 
{
    int array2[5][3] = {{ 1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}, {13, 14, 15}};
    Using2DArray(array2);
    . . .
}

 

6) 참조 리턴

  • 함수는 반드시 값을 리턴
    • 기본 타입 값: int, char, double 등
    • 포인터 값
  • 참조 리턴
    • 변수 등과 같이 현존하는 공간에 대한 리턴
      • 변수의 값을 리턴하는게 아님

#include <iostream>
using namespace std;

char& find(char s[], int index) 
{
	return s[index]; // 참조 리턴
}

int main() 
{
    char name[] = "Mike";
    cout << name << endl;
    
    find(name, 0) = 'S'; // name[0]='S'로 변경
    cout << name << endl;
    
    char& ref = find(name, 2); 
    ref = 't'; // name = "Site"
    cout << name << endl;
}

result

'프로그래밍 언어 > C++' 카테고리의 다른 글

4) 클래스와 객체의 기본  (1) 2023.11.01
3) 개선된 함수 기능  (0) 2023.11.01
1) C++ 프로그래밍의 기본  (2) 2023.11.01
22.05.27) C++  (0) 2023.01.15
22.05.10) C++  (0) 2023.01.15