포인터는 주소를 상징적으로 표현한 것입니다. 이를 통해 프로그램은 참조별 호출을 시뮬레이션하고 동적 데이터 구조를 생성 및 조작할 수 있습니다. 배열이나 기타 데이터 구조의 요소를 반복하는 것은 포인터의 주요 용도 중 하나입니다.
작업 중인 변수의 주소는 동일한 데이터 유형(예: int 또는 string)을 가리키는 포인터 변수에 할당됩니다.
자바 문자열 조인
통사론:
datatype *var_name; int *ptr; // ptr can point to an address which holds int data>
포인터를 사용하는 방법?
- 포인터 변수 정의
- 해당 변수의 주소를 반환하는 단항 연산자(&)를 사용하여 변수의 주소를 포인터에 할당합니다.
- 피연산자로 지정된 주소에 있는 변수의 값을 반환하는 단항 연산자(*)를 사용하여 주소에 저장된 값에 액세스합니다.
데이터 유형을 포인터와 연관시키는 이유는 데이터가 몇 바이트에 저장되어 있는지 알고 있습니다. . 포인터를 증가시키면 포인터가 가리키는 데이터 유형의 크기만큼 포인터가 증가합니다.
C++ // C++ program to illustrate Pointers #include using namespace std; void geeks() { int var = 20; // declare pointer variable int* ptr; // note that data type of ptr and var must be same ptr = &var; // assign the address of a variable to a pointer cout << 'Value at ptr = ' << ptr << '
'; cout << 'Value at var = ' << var << '
'; cout << 'Value at *ptr = ' << *ptr << '
'; } // Driver program int main() { geeks(); return 0; }> 산출
Value at ptr = 0x7ffe454c08cc Value at var = 20 Value at *ptr = 20>
참조 및 포인터
C++ 인수를 함수에 전달하는 방법에는 3가지가 있습니다.
- 가치별 호출
- 포인터 인수를 사용한 참조별 호출
- 참조 인수를 사용한 참조별 호출
// C++ program to illustrate call-by-methods #include using namespace std; // Pass-by-Value int square1(int n) { // Address of n in square1() is not the same as n1 in // main() cout << 'address of n1 in square1(): ' << &n << '
'; // clone modified inside the function n *= n; return n; } // Pass-by-Reference with Pointer Arguments void square2(int* n) { // Address of n in square2() is the same as n2 in main() cout << 'address of n2 in square2(): ' << n << '
'; // Explicit de-referencing to get the value pointed-to *n *= *n; } // Pass-by-Reference with Reference Arguments void square3(int& n) { // Address of n in square3() is the same as n3 in main() cout << 'address of n3 in square3(): ' << &n << '
'; // Implicit de-referencing (without '*') n *= n; } void geeks() { // Call-by-Value int n1 = 8; cout << 'address of n1 in main(): ' << &n1 << '
'; cout << 'Square of n1: ' << square1(n1) << '
'; cout << 'No change in n1: ' << n1 << '
'; // Call-by-Reference with Pointer Arguments int n2 = 8; cout << 'address of n2 in main(): ' << &n2 << '
'; square2(&n2); cout << 'Square of n2: ' << n2 << '
'; cout << 'Change reflected in n2: ' << n2 << '
'; // Call-by-Reference with Reference Arguments int n3 = 8; cout << 'address of n3 in main(): ' << &n3 << '
'; square3(n3); cout << 'Square of n3: ' << n3 << '
'; cout << 'Change reflected in n3: ' << n3 << '
'; } // Driver program int main() { geeks(); }> 산출
address of n1 in main(): 0x7fffa7e2de64 address of n1 in square1(): 0x7fffa7e2de4c Square of n1: 64 No change in n1: 8 address of n2 in main(): 0x7fffa7e2de68 address of n2 in square2(): 0x7fffa7e2de68 Square of n2: 64 Change reflected in n2: 64 address of n3 in main(): 0x7fffa7e2de6c address of n3 in square3(): 0x7fffa7e2de6c Square of n3: 64 Change reflected in n3: 64>
C++에서는 기본적으로 인수가 값으로 전달되며 호출된 함수의 변경 사항은 전달된 변수에 반영되지 않습니다. 호출된 함수에 의해 생성된 복제본에 변경 사항이 적용됩니다. 원본을 직접 수정하고(특히 거대한 개체나 배열을 전달할 때) 복제 오버헤드를 피하려면 참조별 전달을 사용합니다. 참조 인수가 포함된 참조별 참조에는 참조 및 역참조를 위한 서투른 구문이 필요하지 않습니다.
- C의 함수 포인터
- 함수에 대한 포인터
포인터로서의 배열 이름
안 정렬 name에는 상수 포인터처럼 작동하는 배열의 첫 번째 요소 주소가 포함됩니다. 즉, 배열 이름에 저장된 주소는 변경할 수 없습니다. 예를 들어, val이라는 배열이 있다면 발 그리고 &발[0] 서로 바꿔서 사용할 수 있습니다.
C++ // C++ program to illustrate Array Name as Pointers #include using namespace std; void geeks() { // Declare an array int val[3] = { 5, 10, 20 }; // declare pointer variable int* ptr; // Assign the address of val[0] to ptr // We can use ptr=&val[0];(both are same) ptr = val; cout << 'Elements of the array are: '; cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2]; } // Driver program int main() { geeks(); }> 산출
Elements of the array are: 5 10 20>
포인터 ptr이 함수에 인수로 전송되면 비슷한 방식으로 배열 val에 액세스할 수 있습니다. 포인터 대 배열
포인터 표현식과 포인터 산술
한정된 세트 산수 다음과 같은 포인터에 대해 작업을 수행할 수 있습니다.
퀵 정렬 알고리즘
- 증가 ( ++ )
- 감소 ( — )
- 포인터에 정수를 추가할 수 있습니다( + 또는 += ).
- 포인터에서 정수를 뺄 수 있습니다( – 또는 -= ).
- 두 포인터의 차이(p1-p2)
( 메모: 포인터 연산은 배열에서 수행되지 않으면 의미가 없습니다.)
C++ // C++ program to illustrate Pointer Arithmetic #include using namespace std; void geeks() { // Declare an array int v[3] = { 10, 100, 200 }; // declare pointer variable int* ptr; // Assign the address of v[0] to ptr ptr = v; for (int i = 0; i < 3; i++) { cout << 'Value at ptr = ' << ptr << '
'; cout << 'Value at *ptr = ' << *ptr << '
'; // Increment pointer ptr by 1 ptr++; } } // Driver program int main() { geeks(); }> 산출
Value at ptr = 0x7ffe5a2d8060 Value at *ptr = 10 Value at ptr = 0x7ffe5a2d8064 Value at *ptr = 100 Value at ptr = 0x7ffe5a2d8068 Value at *ptr = 200>
고급 포인터 표기법
2차원 숫자 배열에 대한 포인터 표기법을 고려하세요. 다음 선언을 고려하십시오
int nums[2][3] = { { 16, 18, 20 }, { 25, 26, 27 } };>일반적으로 nums[ i ][ j ]는 *(*(nums+i)+j)와 동일합니다.
포인터와 문자열 리터럴
문자열 리터럴은 null로 끝나는 문자 시퀀스를 포함하는 배열입니다. 문자열 리터럴은 문자 유형에 널 문자 종료를 더한 배열이며, 각 요소는 const char 유형입니다(문자열의 문자는 수정할 수 없으므로).
>
이는 geek에 대한 리터럴 표현으로 배열을 선언한 다음 첫 번째 요소에 대한 포인터가 ptr에 할당됩니다. geek이 주소 1800에서 시작하는 메모리 위치에 저장되어 있다고 가정하면 이전 선언을 다음과 같이 나타낼 수 있습니다.

포인터와 배열은 표현식에서 동일한 방식으로 동작하므로 ptr을 사용하여 문자열 리터럴의 문자에 액세스할 수 있습니다. 예를 들어:
char ptr = 0; char x = *(ptr+3); char y = ptr[3];>
여기서 x와 y 모두 1803(1800+3)에 저장된 k를 포함합니다.
누군가 안드로이드에서 당신을 차단했는지 확인하는 방법
포인터에 대한 포인터
C++에서는 데이터나 다른 포인터를 가리킬 수 있는 포인터에 대한 포인터를 만들 수 있습니다. 이 구문에는 포인터를 선언하는 동안 각 간접 참조 수준에 대해 단항 연산자(*)가 필요합니다.
char a; char *b; char ** c; a = ’g’; b = &a; c = &b;>
여기서 b는 'g'를 저장하는 char을 가리키고 c는 포인터 b를 가리킵니다.
공허 포인터
이는 유형이 없음을 나타내는 C++에서 사용할 수 있는 특별한 유형의 포인터입니다. 무효 포인터 유형이 없는 값(따라서 길이가 결정되지 않고 역참조 속성도 결정되지 않음)을 가리키는 포인터입니다. 즉, void 포인터는 모든 데이터 유형을 가리킬 수 있으므로 유연성이 뛰어납니다. 이러한 유연성에는 보상이 있습니다. 이러한 포인터는 직접 역참조될 수 없습니다. 역참조되기 전에 구체적인 데이터 유형을 가리키는 다른 포인터 유형으로 먼저 변환되어야 합니다.
C++ // C++ program to illustrate Void Pointer #include using namespace std; void increase(void* data, int ptrsize) { if (ptrsize == sizeof(char)) { char* ptrchar; // Typecast data to a char pointer ptrchar = (char*)data; // Increase the char stored at *ptrchar by 1 (*ptrchar)++; cout << '*data points to a char' << '
'; } else if (ptrsize == sizeof(int)) { int* ptrint; // Typecast data to a int pointer ptrint = (int*)data; // Increase the int stored at *ptrchar by 1 (*ptrint)++; cout << '*data points to an int' << '
'; } } void geek() { // Declare a character char c = 'x'; // Declare an integer int i = 10; // Call increase function using a char and int address // respectively increase(&c, sizeof(c)); cout << 'The new value of c is: ' << c << '
'; increase(&i, sizeof(i)); cout << 'The new value of i is: ' << i << '
'; } // Driver program int main() { geek(); }> 산출
*data points to a char The new value of c is: y *data points to an int The new value of i is: 11>
잘못된 포인터
포인터는 유효한 주소를 가리켜야 하지만 반드시 유효한 요소(예: 배열)를 가리킬 필요는 없습니다. 이를 유효하지 않은 포인터라고 합니다. 초기화되지 않은 포인터도 유효하지 않은 포인터입니다.
int *ptr1; int arr[10]; int *ptr2 = arr+20;>
여기서 ptr1은 초기화되지 않아 유효하지 않은 포인터가 되고, ptr2는 arr의 범위를 벗어났기 때문에 역시 유효하지 않은 포인터가 됩니다. (참고: 잘못된 포인터가 반드시 컴파일 오류를 발생시키는 것은 아닙니다)
NULL 포인터
ㅏ 널 포인터 잘못된 주소가 아니라 아무데도 가리키는 포인터가 아닙니다. 다음은 포인터를 NULL로 할당하는 두 가지 방법입니다.
int *ptr1 = 0; int *ptr2 = NULL;>
포인터의 장점
- 포인터는 코드를 줄이고 성능을 향상시킵니다. 문자열, 트리, 배열, 구조 및 함수를 검색하는 데 사용됩니다.
- 포인터를 사용하면 함수에서 여러 값을 반환할 수 있습니다.
- 이 외에도 포인터를 사용하면 컴퓨터 메모리의 메모리 위치에 액세스할 수 있습니다.
관련 기사:
문자열 포맷터
- 불투명 포인터
- 근거리, 원거리 및 거대한 포인터
퀴즈:
- 포인터 기본 사항
- 고급 포인터