2017년 11월 21일 화요일

포인터와 레퍼런스(C++)

C 와 C++보다는 Fortran, Python을 주로 쓰다보니
여전히 pointer 나 reference 를 사용하는 C, C++은 어렵게 느껴진다.
기본적인 차이는 Fortran은 call by reference가 기본이라
사실은 언제나 pointer를 사용하는 셈이라는 것에 비해, C++은
call by value가 기본이기 때문에 Fortran처럼 사용하기 위해서는
함수에서 pointer를 사용해야 한다는 것이다.

포인터는 기본적으로 변수의 주소를 가리키는 것이라고는 알고 있지만,
가장 헷갈리는 것은 * 와 & 의 사용법과 함수에서의 input/output으로의 사용법이다.
문제를 더 복잡하게 만드는 것은 C/C++ 에서는 array와 C-string 을 pointer로
취급한다는 사실과 reference의 경우에는 implicit referencing과 dereference가
자동으로 일어난다는 점, 그리고 * 와 &가 문맥에 따라 다른 의미로 사용된다는
점이다. 이 때문에 포트란이나 파이쏜에 익숙한 내가 보기에는 일관되지 않은 사용법이
나타난다.

내가 이해하는 범위에서 포인터,레퍼런스 등의 사용법을 살펴보도록 하자.

(1) a, *a, &a 의 차이가 무엇일까?

일반적인 변수는 'int a' 와 같은 형태로 선언한다. 이 때, 컴파일러는 이 변수마다 주소를 할당하고 프로그램에서는 이 주소에 값을 저장한다. ( 집이 변수, 집 안의 물건이 변수값, 집의 주소 의 관계로 생각할 수 있다.) b=a 와 같은 명령은 집 a안의 물건을 집 b 에 복사하는 역할을 한다.

포인터는 'int* a_ptr' 과 같이 선언한다. 이 때, 'a_ptr'은 포인터로써 주소값을 가진다.
'*' 는 포인터(주소)가 가리키는 집안의 물건을 꺼내는 역할을 한다. (즉, '*' 는 포인터를 물건으로 바꾸는 역할을 한다.)

한편, '&'는 변수의 주소를 나타낸다. ' &a' 는 a 라는 변수의 주소를 준다.
(즉, '&'는 물건을 주소로 바꾸는 역할을 한다.)

int thing; // thing은 일반 변수(집) 이다.
int* thing_ptr ;// thing_ptr은 포인터(주소)로 선언한다.

thing  : 변수(집)
          thing = 4; // thing 에 숫자 4를 넣는다.

&thing : 변수 thing의 주소

thing_ptr : 포인터(주소)
          thing_ptr = &thing ;
          // &thing은 thing의 주소값이고,
           thing_ptr은 따라서 thing의 포인터가 된다.
           따라서 이후로는 thing과 *thing_ptr은 같은 것을 나타낸다.

*thing_ptr : 어떤 것(이 경우는 정수).
           other = *thing_ptr;
           // *thing_ptr은 thing_ptr 주소가 나타내는 변수(집)이므로,
           other라는 집에 thing_ptr이 가리키는 것을 넣는다.
           여기서, other는 정수값이 된다.

            *thing_ptr = 5; (?)
            // *thing_ptr은 thing_ptr 주소가 나타내는 변수(집)이므로,
                       thing 에 5라는 숫자를 넣는 역할을 한다. (?)

*thing :  thing은 포인터가 아니므로 틀린 문법.

&thing_ptr : 포인터의 포인터.

좀 더 정확한 pointer와 reference의 차이는 앞의 글 참조.

(주의?) c++의 character pointer 는 다른 포인터와 달리 string의 pointer 로 취급한다?

char some_characters[10] = "Hello";   // A simple set of characters
char *char_ptr = &some_characters[0];  // Pointer to a character
std::cout << some_characters << "\n" // output is "Hello"
std::cout << &some_characters << "\n"l //output is an address
std::cout << some_characters[0] << "\n"l //output is "H"
std::cout << &some_characters[0] << "\n"l //output is "Hello"
std::cout << char_ptr << '\n'; // output is "Hello"
                // So with string pointers, the string itself is printed.
std::cout << *char_ptr << "\n";      // output is "H"
std::cout << &char_ptr << "\n";  // output is an address

In a similar way, one can define string pointer directly,
```c++

char *test_ptr = "abcde"; // equivalent two step   
std::cout << "String pointer test= " << test_ptr << "\n"; //output is "abcde"
std::cout << " *test= " << *test_ptr << "\n";             //output is "a"      
std::cout << " &test= " << &test_ptr << "\n";             //output is an address  
```

(주의) c++의 pointer 와 array는 같이 방식으로 취급된다. 

char array[10] = "012345678";
char *array_ptr = &array[0];

array_ptr=&array[0];
array_ptr= array ; // these two lines are quivalent. 

When passing an array to a procedure, C++ will 
automatically change the array into a pointer

한편, string이 아닌 숫자의 array의 경우는

int array[10] // initialized as 0,1,2,3,4,5,6,7,8,9

std::cout << " array= " << array << "\n"; // output is an address
std::cout << "&array= " << &array << "\n"; //output is an address same as above
std::cout << "*array= " << *array << "\n"; //output is 0
std::cout << " array[1]= " << array[1] << "\n"; //output is 1
std::cout << "*array[0]= " << *array[0] << "\n"; // error ! this setence is wrong
std::cout << "&array[1]= " << &array[1] << "\n"; // output is an address

즉, array 는 array[0]의 위치를 가리키는 pointer 이다. (array와 &array[0]는 동일)

반면, array[0]나 array[1] 은 integer 이고, pointer가 아님. 

함수가 다음과 같이 정의 되었을 때
void init_array_1(int data[])
void init_array_2(int *data_ptr)

다음 둘은 같은 역할을 한다. 
init_array_1(array);
init_array_1(&array[0]);
그리고 
init_array_2(array)
도 비슷하게 사용가능하다.  





댓글 없음:

댓글 쓰기