포인터 설명에 대한 포인터
나는 포인터에 대한 포인터가 어떻게 작동하는지에 대한 이 튜토리얼을 따르고 있었다.
관련 구절을 인용하겠다.
int i = 5, j = 6, k = 7; int *ip1 = &i, *ip2 = &j;
이제 우리는 설정할 수 있다.
int **ipp = &ip1;
그리고
ipp
을 가리키다ip1
어느 점을 가리키는지i
.*ipp
이다ip1
그리고**ipp
이다i
, 또는 5. 익숙한 상자-화살표기법으로 상황을 다음과 같이 설명할 수 있다.만약 그때 우리가 말한다면
*ipp = ip2;
우리는 다음을 가리키는 포인터를 바꿨다.
ipp
(음,)ip1
의 사본을 포함하려면ip2
, 그래서 ()ip1
) 이제 가리키다j
:
제 질문은:왜 두번째 사진에서,ipp
여전히 가리키고 있는ip1
그러나 그렇지 않다ip2
?
중요한 비유는 잠시 잊어버려라.포인터에 진짜 들어 있는 것은 메모리 주소다.그&
"주소" 연산자 - 즉, 객체를 기억하여 주소를 반환한다.그*
오퍼레이터는 포인터가 가리키는 물체를 당신에게 준다. 즉, 주소를 포함하는 포인터가 주어지면, 그것은 그 메모리 주소에 있는 물체를 반환한다.그래서 당신이 할 때*ipp = ip2
, 당신이 하고 있는 것은*ipp
에 있는 주소로 물건을 받다.ipp
어느 것이ip1
그리고 나서 에 할당한다.ip1
에 저장된 가치.ip2
,의 .j
.
간단히
&
-->..> 주십시요.
*
->> 가가곡:
내 개인적인 의견은 화살이 있는 사진이 이쪽을 가리키거나 포인터를 더 이해하기 어렵게 만든다는 것이다.그것은 그들을 어떤 추상적이고 신비로운 실체처럼 보이게 만든다.그들은 그렇지 않다.
컴퓨터의 다른 모든 것들과 마찬가지로 포인터는 숫자다."점자"라는 이름은 "주소를 포함하는 변수"라는 화려한 표현방식에 불과하다.
그러므로, 컴퓨터가 실제로 어떻게 작동하는지 설명함으로써 여러 가지를 휘젓고 다닐 수 있도록 하겠다.
우리에겐...int
, 그것은 그 이름을 가지고 있다.i
그리고 값 5.이것은 기억 속에 저장되어 있다.기억 속에 저장되어 있는 모든 것 처럼, 주소가 필요해, 그렇지 않으면 찾을 수 없을 거야.라고 하자.i
는 는 0x12345678로 되어있다.j
값 6은 그 직후에 끝난다.32비트 CPU에서 int가 4바이트, 포인터가 4바이트라고 가정하면 변수는 다음과 같이 물리적 메모리에 저장된다.
Address Data Meaning
0x12345678 00 00 00 05 // The variable i
0x1234567C 00 00 00 06 // The variable j
이제 우리는 이 변수들을 지적하고 싶다.인트로 가는 포인터를 하나 만들면int* ip1
, 그리고 하나int* ip2
컴퓨터의 모든 것들과 마찬가지로, 이 포인터 변수들도 기억의 어딘가에 할당된다.메모리에 있는 다음 인접 주소로 끝나는 경우, 바로 다음 주소에서 끝나는 것으로 가정해 보십시오.j
이전에 할당된 변수의 주소를 포함하도록 포인터를 설정하십시오.ip1=&i;
및 (i의 ip1에 따라 "사") 및ip2=&j
일은 행간에 일어나는 일은 다음과 같다.
Address Data Meaning
0x12345680 12 34 56 78 // The variable ip1(equal to address of i)
0x12345684 12 34 56 7C // The variable ip2(equal to address of j)
그래서 우리가 얻은 것은 단지 숫자들이 들어 있는 4바이트의 메모리 덩어리였습니다.어디에도 신비한 화살이나 마법의 화살은 보이지 않는다.
0x12345680에 사서도 0x12345680이 들어 알int
또는int*
차이점은 우리 프로그램이 이 주소에 저장된 콘텐츠를 어떻게 사용하는가이다.(우리 프로그램의 임무는 실제로 CPU에게 이 숫자로 무엇을 해야 하는지 알려주는 것이다.)
그리고 나서 우리는 다음 단계로 나아가야 한다.int** ipp = &ip1;
다시, 우리는 기억의 덩어리만 얻는다.
Address Data Meaning
0x12345688 12 34 56 80 // The variable ipp
그 패턴은 정말 익숙해 보인다.그러나 숫자를 포함하는 또 다른 4바이트 덩어리.
자, 위의 가상의 작은 RAM의 메모리 덤프가 있다면, 우리는 수동으로 이 포인터들이 가리키는 곳을 확인할 수 있을 겁니다.주소지에 저장되어 있는 것을 엿본다.ipp
변수에 따라 0x12345680의 내용을 찾으십시오. 그 는 물론 입니다.ip1
저장된다.그 주소로 가서 내용을 확인하고 주소지를 찾을 수 있다.i
그리고 마침내 우리는 그 주소로 가서 5번을 찾을 수 있다.
ipp의 내용물을 가져가면*ipp
포인터 변수의 주소를 얻을 것이다.ip1
. 글로써*ipp=ip2
ip2를 ip1로 하다.ip1=ip2
어느 경우든, 우리는 얻을 수 있을 것이다.
Address Data Meaning
0x12345680 12 34 56 7C // The variable ip1
0x12345684 12 34 56 7C // The variable ip2
(이러한 예는 대형 엔디안 CPU에 대해 제시되었다.)
C 태그의 대부분의 초급 문항과 마찬가지로, 이 문항은 첫 번째 원리로 돌아가면 답할 수 있다.
- 포인터는 가치의 일종이다.
- 변수는 값을 포함한다.
- 그
&
연산자는 변수를 포인터로 변환한다. - 그
*
연산자는 포인터를 변수로 변환한다.
(기술적으로 나는 "변수"가 아닌 "lvalue"라고 말해야 하지만, 변이 가능한 저장 위치를 "변수"로 설명하는 것이 더 명확하다고 느낀다.)
그래서 우리는 변수를 가지고 있다:
int i = 5, j = 6;
int *ip1 = &i, *ip2 = &j;
수식ip1
포인터가 들어 있다.그&
운영자가 돌다.i
포인터로 변환하면 해당 포인터 값이ip1
그래서.ip1
에 대한 포인터를 포함하고 있다.i
.
수식ip2
포인터가 들어 있다.그&
운영자가 돌다.j
포인터 안으로 들어가 그 포인터에는ip2
그래서.ip2
에 대한 포인터를 포함하고 있다.j
.
int **ipp = &ip1;
수식ipp
포인터가 들어 있다.그&
운영자가 변수 변환ip1
포인터로 변환하면 해당 포인터 값이ipp
그래서.ipp
에 대한 포인터를 포함하고 있다.ip1
.
지금까지의 이야기를 요약해 보자.
i
5개 포함j
6개 포함ip1
에 대한 정보를 포함함.i
"ip2
에 대한 정보를 포함함.j
"ipp
에 대한 정보를 포함함.ip1
"
이제 우리는 말한다.
*ipp = ip2;
그*
연산자는 포인터를 다시 변수로 변환한다.우리는 의 가치를 가져온다.ipp
, 즉 "에 대한 의무"이다.ip1
그리고 그것을 변수로 바꾼다.어떤 변수? ip1
물론이지!
그러므로 이것은 단순히 다른 표현방법이다.
ip1 = ip2;
그래서 우리는 의 가치를 가져온다.ip2
뭐야?"에 대한 유혹.j
". 포인터 값을 에 할당한다.ip1
그렇게ip1
이제 에 대해 "가급적"이다.j
"
우리는 단지 한 가지를 바꾸었을 뿐이다: 의 가치.ip1
:
i
5개 포함j
6개 포함ip1
에 대한 정보를 포함함.j
"ip2
에 대한 정보를 포함함.j
"ipp
에 대한 정보를 포함함.ip1
"
왜 그럴까?
ipp
여전히 가리키다ip1
아닌 것 같다ip2
?
변수는 할당하면 변경된다.할당량을 세십시오. 할당량보다 더 많은 변수가 변경될 수 없습니다,먼저 다음 위치에 할당i
j
ip1
ip2
그리고ipp
. 그런 다음 에 할당하십시오.*ipp
우리가 본 바로는 "에 대한 유혹"과 같은 의미 입니다.ip1
". 할당하지 않았으므로ipp
두 번째, 변하지 않았어!
이 바고 다면 을 .ipp
그러면 당신은 실제로 에 할당해야 할 것이다.ipp
:
ipp = &ip2;
예를 들어.
왜냐하면 당신이 가리키는 값을 변경했기 때문이다.ipp
의 가치가 없다ipp
그래서.ipp
여전히 가리키고 있다.ip1
)ipp
)ip1
의 가치는 이제 와 같다ip2
의 가치, 그래서 그들은 둘 다 지적한다.j
.
다음 내용:
*ipp = ip2;
다음 항목과 동일함:
ip1 = ip2;
제 질문은:두 번째 그림에서 ipp는 ip1을 가리키지만 ip2는 가리키지 않는 이유는 무엇인가?
멋진 그림을 그려놨으니, 멋진 아스키아트를 만들어 볼게.
@Robert-S-Barnes가 대답에서 말한 것처럼: 포인터는 잊어버리고, 무엇을 가리키는지는 잊어버리되, 기억의 관점에서 생각해 보라.기본적으로 anint*
하고 을 의미한다.int**
변수의 주소를 포함하는 변수의 주소.그런 다음 포인터의 대수학을 사용하여 값 또는 주소에 액세스할 수 있다.&foo
수단address of foo
그리고*foo
수단value of the address contained in foo
.
그래서 포인터가 기억을 다루는 것이기 때문에, 실제로 그 "무형"을 만드는 가장 좋은 방법은 포인터 대수학이 기억력에 무엇을 하는지 보여주는 것이다.
여기 프로그램의 메모리(예의 목적을 위해 단순화됨)가 있다.
name: i j ip1 ip2 ipp
addr: 0 1 2 3 4
mem : [ | | | | ]
초기 코드를 실행할 때:
int i = 5, j = 6;
int *ip1 = &i, *ip2 = &j;
당신의 기억력은 다음과 같다.
name: i j ip1 ip2
addr: 0 1 2 3
mem : [ 5| 6| 0| 1]
저기에서 볼 수 있다.ip1
그리고ip2
의 주소를 얻는다.i
그리고j
그리고ipp
여전히 존재하지 않는다.주소는 특별한 유형으로 저장된 정수일 뿐이라는 것을 잊지 마십시오.
그런 다음 선언하고 정의하십시오.ipp
예를 들면 다음과 같다.
int **ipp = &ip1;
기억나는 게 있어
name: i j ip1 ip2 ipp
addr: 0 1 2 3 4
mem : [ 5| 6| 0| 1| 2]
그리고 나서, 당신은 저장된 주소의 값을 변경한다.ipp
에되어 있는 입니다.ip1
:
*ipp = ip2;
그 프로그램의 기억은
name: i j ip1 ip2 ipp
addr: 0 1 2 3 4
mem : [ 5| 6| 1| 1| 2]
N.B.: as.int*
특별한 타입인데, 나는 항상 같은 라인에 여러 개의 포인터를 선언하는 것을 피하고 싶다.int *x;
또는int *x, *y;
표기법은 오해의 소지가 있다.나는 쓰는 것을 더 좋아한다.int* x; int* y;
HTH
이 암호 조각이 도움이 되기를 바란다.
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int i = 5, j = 6, k = 7;
int *ip1 = &i, *ip2 = &j;
int** ipp = &ip1;
printf("address of value i: %p\n", &i);
printf("address of value j: %p\n", &j);
printf("value ip1: %p\n", ip1);
printf("value ip2: %p\n", ip2);
printf("value ipp: %p\n", ipp);
printf("address value of ipp: %p\n", *ipp);
printf("value of address value of ipp: %d\n", **ipp);
*ipp = ip2;
printf("value ipp: %p\n", ipp);
printf("address value of ipp: %p\n", *ipp);
printf("value of address value of ipp: %d\n", **ipp);
}
출력:
할당 사항 참고:
ipp = &ip1;
결과ipp
을 가리키다ip1
.
때문에ipp
을 가리키다ip2
우리는 비슷한 방식으로 변화해야 한다.
ipp = &ip2;
우리가 하고 있지 않은게 분명해대신, 우리는 주소의 가치를ipp
.
다음 작업을 수행함
*ipp = ip2;
우리는 단지 에 저장된 가치를 대체하는 것이다.ip1
.
ipp = &ip1
, 라는 뜻이다.*ipp = ip1 = &i
자, 이제.*ipp = ip2 = &j
.
그렇게*ipp = ip2
본질적으로 와 같다ip1 = ip2
.
ipp = &ip1;
다음 할당으로 인해 값이 변경되지 않음ipp
이것이 그것이 여전히 지적하는 이유다.ip1
.
당신이 하는 일*ipp
, 즉, 와 함께.ip1
는 사실을 바꾸지 않는다.ipp
을 가리키다ip1
.
왜냐하면 네가 말할 때
*ipp = ip2
당신은 '목표가 가리키는 것'이ipp
' 라는 기억의 방향을 가리키다ip2
가리키고 있다.
마마마ipp
가리키기 위해ip2
.
참조 취소 연산자를 추가하는 경우*
포인터로 리디렉션하면 포인터에서 가리키는 객체로 리디렉션된다.
예:
int i = 0;
int *p = &i; // <-- N.B. the pointer declaration also uses the `*`
// it's not the dereference operator in this context
*p; // <-- this expression uses the pointed-to object, that is `i`
p; // <-- this expression uses the pointer object itself, that is `p`
따라서 다음과 같다.
*ipp = ip2; // <-- you change the pointer `ipp` points to, not `ipp` itself
// therefore, `ipp` still points to `ip1` afterwards.
원한다면ipp
을 가리키다ip2
, 라고 말해야 할 것이다.ipp = &ip2;
하지만, 이것은 떠날 것이다.ip1
여전히 가리키고 있는i
.
당신이 설정한 바로는,
ipp = &ip1;
자, 이제 그만둬라.
*ipp = *&ip1 // Here *& becomes 1
*ipp = ip1 // Hence proved
다음과 같이 표시되는 각 변수에 대해 합의하십시오.
type : (name, adress, value)
그래서 당신의 변수는 이렇게 표현되어야 한다.
int : ( i , &i , 5 ); ( j , &j , 6); ( k , &k , 5 )
int* : (ip1, &ip1, &i); (ip1, &ip1, &j)
int** : (ipp, &ipp, &ip1)
의 가치로서ipp
이다&ip1
따라서 다음과 같은 결과가 다음과 같다.
*ipp = ip2;
&ip1
의 값어치가 있는ip2
그 은 ,그것은 은.ip1
변경됨:
(ip1, &ip1, &i) -> (ip1, &ip1, &j)
그렇지만ipp
여전히:
(ipp, &ipp, &ip1)
그래서 그 가치는ipp
가만히&ip1
말은 그대를 있다는 ip1
.
왜냐하면 당신이 포인터를 바꾸고 있기 때문이다.*ipp
라는 뜻이다.
ipp
(varaiable name)------ 안으로 들어가십시오.- 안쪽에
ipp
의 주소 입니다.ip1
. - 지금 당장
*ipp
그러니 (내부)로 가라.ip1
.
이제 우리는 할 수 있다.ip1
.*ipp
(즉,ip1
) =ip
2.
ip2
의 주소를 포함하다.j
.so .soip1
ip ip는 ip2(즉즉, j의 주), WE ARE NOT ShANGE의 될 것이다.ipp
내용이야, 그게 다야.
*ipp = ip2;
다음을 암시한다.
할당하다ip2
에 의해 지적된 변수에.ipp
는 다음과 따라서 이는 다음과 같다.
ip1 = ip2;
만약 당신이 주소를 원한다면ip2
에 저장되다ipp
, 간단히 다음과 같이 하십시오.
ipp = &ip2;
자, 이제.ipp
을 가리키다ip2
.
ipp
포인터 유형 객체에 대한 포인터 값을 유지할 수 있다(즉, 포인터를 가리킴).할 때
ipp = &ip2;
그 다음ipp
변수(주소)의 주소를 포함하며, 이 주소는 ().&ip2
포인터 형식의 .이제 의 화살은ipp
두 번째 사진에서는 을 가리킬 것이다.ip2
.
위키는 이렇게 말한다.
그*
연산자는 포인터 변수에 대해 작동하며, 포인터 주소의 값에 해당하는 l-값(초과값)을 반환한다.이것을 포인터 비참조라고 한다.
적 *
을 교환하다.ipp
이를 l-값의 형식에 대한 포인터로 변환 해제한다.참조 해제된 l-값*ipp
에 대한 유형의 포인터로, 그것은 의 주소를 저장할 수 있다.int
자료를 타이핑하다진술 후
ipp = &ip1;
ipp
의 주소를 가지고 있다ip1
그리고*ipp
(i
라고 말할 수 있다.*ipp
의 가명이다.ip1
. 둘 다**ipp
그리고*ip1
의 가명이다i
.
함으로써
*ipp = ip2;
*ipp
그리고ip2
두 지점 모두 동일한 위치를 가리키지만ipp
여전히 가리키고 있다.ip1
.
무엇*ipp = ip2;
실제로 그것은 의 내용을 복사하는 것이다.ip2
)j
~에게ip1
)(as)*ipp
의 별칭이다.ip1
)), 사실상 두 가지 포인터를 모두 만드는 것ip1
그리고ip2
동일한 객체를 가리킴(j
).
따라서 두 번째 그림에서 의 화살표는 의 값을 변경하기 위해 어떤 수정도 수행되지 않는 동안 계속 가리키고 있다.
참조URL: https://stackoverflow.com/questions/21604946/pointer-to-pointer-clarification
'IT이야기' 카테고리의 다른 글
VueJ를 사용하여 요소를 동적으로 컴파일 및 마운트s (0) | 2022.04.16 |
---|---|
V-텍스트 필드 자동 완성 값이 v-model 값을 설정하지 않음 (0) | 2022.04.16 |
C에서 무료와 몰록은 어떻게 작동하는가? (0) | 2022.04.16 |
C와 C++에서 다르게 작동하는 열거형 상수 (0) | 2022.04.16 |
vue 구성 요소의 CSRf 토큰 (0) | 2022.04.14 |