programing

포인터 '디레퍼런스'란 무슨 뜻입니까?

goodsources 2022. 7. 11. 21:33
반응형

포인터 '디레퍼런스'란 무슨 뜻입니까?

설명과 함께 예를 들어주세요.

기본 용어 검토

프로그래밍 어셈블리를 사용하지 않는 한 일반적으로는 숫자 메모리 주소를 포함하는 포인터를 예상하는 으로 충분합니다. 1은 프로세스 메모리의 두 번째 바이트, 2는 세 번째 바이트, 3은 네 번째 바이트 등을 나타냅니다.

  • 0과 첫 번째 바이트는 어떻게 되었습니까?음, 그것에 대해서는 나중에 이야기하겠습니다.아래의 null 포인터를 참조해 주세요.
  • 포인터가 무엇을 저장하고 메모리와 주소가 어떻게 관련되어 있는지에 대한 보다 정확한 정의는 이 답변의 끝에 있는 "메모리 주소에 대한 자세한 내용과 알 필요가 없는 이유"를 참조하십시오.

포인터가 가리키는 메모리의 데이터/값(숫자 인덱스가 있는 주소의 내용)에 액세스하려면 포인터를 참조 해제합니다.

컴파일러 또는 인터프리터에 대해 지적된 오브젝트의 (현재) 값에 관심이 있음을 나타내는 표기는 컴퓨터 언어마다 다릅니다.아래에서는 C와 C++에 초점을 맞춥니다.

포인터 시나리오

다음과 같은 포인터가 주어진 경우 C에서 고려합니다.p아래...

const char* p = "abc";

문자 'a', 'b', 'c' 및 텍스트 데이터의 끝을 나타내기 위해 사용되는 0바이트를 가진 4바이트는 메모리 어딘가에 저장되며, 그 데이터의 숫자 주소는 다음과 같이 저장된다.p이렇게 C가 메모리 내의 텍스트를 인코딩하는 방법을 ASCIIZ라고 합니다.

예를 들어 스트링 리터럴이 주소 0x1000에 있고p32비트 포인터의 0x2000 메모리 내용은 다음과 같습니다.

Memory Address (hex)    Variable name    Contents
1000                                     'a' == 97 (ASCII)
1001                                     'b' == 98
1002                                     'c' == 99
1003                                     0
...
2000-2003               p                1000 hex

주소 0x1000에는 변수 이름/식별자가 없지만 주소를 저장하는 포인터를 사용하여 문자열 리터럴을 간접적으로 참조할 수 있습니다.p.

포인터 참조 해제

글자를 참조하다p포인트: 참조 해제p다음 중 하나의 표기법을 사용합니다(C의 경우).

assert(*p == 'a');  // The first character at address p will be 'a'
assert(p[1] == 'b'); // p[1] actually dereferences a pointer created by adding
                     // p and 1 times the size of the things to which p points:
                     // In this case they're char which are 1 byte in C...
assert(*(p + 1) == 'b');  // Another notation for p[1]

포인터를 포인트 투 데이터 내에서 이동하여 참조할 수도 있습니다.

++p;  // Increment p so it's now 0x1001
assert(*p == 'b');  // p == 0x1001 which is where the 'b' is...

쓸 수 있는 데이터가 있는 경우 다음과 같은 작업을 수행할 수 있습니다.

int x = 2;
int* p_x = &x;  // Put the address of the x variable into the pointer p_x
*p_x = 4;       // Change the memory at the address in p_x to be 4
assert(x == 4); // Check x is now 4

위의 경우 컴파일 시에 다음과 같은 변수가 필요하다는 것을 알고 있어야 합니다.x이 코드는 컴파일러에 저장 장소를 지정하도록 요구하며 주소는 다음 웹 사이트를 통해 사용할 수 있도록 합니다.&x.

구조 데이터 구성원 참조 및 액세스

C에서 데이터 멤버를 가진 구조체의 포인터인 변수가 있는 경우 다음 명령을 사용하여 해당 멤버에 액세스할 수 있습니다.->역참조 연산자:

typedef struct X { int i_; double d_; } X;
X x;
X* p = &x;
p->d_ = 3.14159;  // Dereference and access data member x.d_
(*p).d_ *= -1;    // Another equivalent notation for accessing x.d_

멀티바이트 데이터 유형

포인터를 사용하기 위해 컴퓨터 프로그램은 가리키는 데이터 유형에 대한 통찰력도 필요로 합니다. 만약 그 데이터 유형이 표현하기 위해 1바이트 이상이 필요하다면, 포인터는 보통 데이터에서 가장 낮은 숫자의 바이트를 가리킵니다.

조금 더 복잡한 예를 보겠습니다.

double sizes[] = { 10.3, 13.4, 11.2, 19.4 };
double* p = sizes;
assert(p[0] == 10.3);  // Knows to look at all the bytes in the first double value
assert(p[1] == 13.4);  // Actually looks at bytes from address p + 1 * sizeof(double)
                       // (sizeof(double) is almost always eight bytes)
++p;                   // Advance p by sizeof(double)
assert(*p == 13.4);    // The double at memory beginning at address p has value 13.4
*(p + 2) = 29.8;       // Change sizes[3] from 19.4 to 29.8
                       // Note earlier ++p and + 2 here => sizes[3]

동적으로 할당된 메모리에 대한 포인터

프로그램이 실행되어 어떤 데이터가 할당되어 있는지 확인할 때까지 필요한 메모리의 양을 알 수 없는 경우가 있습니다.메모리 할당을 동적으로 할 수 있습니다.malloc주소를 포인터에 저장하는 것이 일반적입니다.

int* p = (int*)malloc(sizeof(int)); // Get some memory somewhere...
*p = 10;            // Dereference the pointer to the memory, then write a value in
fn(*p);             // Call a function, passing it the value at address p
(*p) += 3;          // Change the value, adding 3 to it
free(p);            // Release the memory back to the heap allocation library

C++ 에서는, 통상, 메모리 할당은, 다음과 같이 행해집니다.new연산자 및 할당 해제delete:

int* p = new int(10); // Memory for one int with initial value 10
delete p;

p = new int[10];      // Memory for ten ints with unspecified initial value
delete[] p;

p = new int[10]();    // Memory for ten ints that are value initialised (to 0)
delete[] p;

아래의 C++ 스마트 포인터도 참조해 주세요.

주소 손실 및 누수

대부분의 경우 포인터는 메모리 내의 데이터 또는 버퍼의 위치를 나타내는 유일한 지표가 될 수 있습니다.해당 데이터/버퍼의 계속적인 사용이 필요한 경우 또는 콜 기능이 필요한 경우free()또는delete메모리 누설을 방지하기 위해 프로그래머는 포인터의 복사본에서 작업을 수행해야 합니다.

const char* p = asprintf("name: %s", name);  // Common but non-Standard printf-on-heap

// Replace non-printable characters with underscores....
for (const char* q = p; *q; ++q)
    if (!isprint(*q))
        *q = '_';

printf("%s\n", p); // Only q was modified
free(p);

...혹은 변경사항의 반전을 신중하게 조정하거나...

const size_t n = ...;
p += n;
...
p -= n;  // Restore earlier value...
free(p);

C++ 스마트 포인터

C++에서는 스마트 포인터 개체를 사용하여 포인터를 저장하고 관리하는 것이 가장 좋습니다. 스마트 포인터의 소멸자가 실행될 때 자동으로 포인터 할당이 해제됩니다.C++11 표준 라이브러리는 할당된 객체에 대해 단일 소유자가 있는 경우 두 개를 제공합니다.

{
    std::unique_ptr<T> p{new T(42, "meaning")};
    call_a_function(p);
    // The function above might throw, so delete here is unreliable, but...
} // p's destructor's guaranteed to run "here", calling delete

...그리고 (참조 카운팅 사용) 주식 소유권에 대해서는...

{
    auto p = std::make_shared<T>(3.14, "pi");
    number_storage1.may_add(p); // Might copy p into its container
    number_storage2.may_add(p); // Might copy p into its container    } // p's destructor will only delete the T if neither may_add copied it

Null 포인터

주식회사,NULL그리고.0- C++에 추가nullptr- 포인터가 현재 변수의 메모리 주소를 보유하고 있지 않으며 포인터 산술에서 참조 또는 사용해서는 안 된다는 것을 나타내는 데 사용할 수 있습니다.예를 들어 다음과 같습니다.

const char* p_filename = NULL; // Or "= 0", or "= nullptr" in C++
int c;
while ((c = getopt(argc, argv, "f:")) != -1)
    switch (c) {
      case f: p_filename = optarg; break;
    }
if (p_filename)  // Only NULL converts to false
    ...   // Only get here if -f flag specified

C 및 C++ 에서는, 내장된 수치 타입이 반드시 디폴트인 것은 아닙니다.0,도 아니다bools로.false포인터가 항상 로 설정되어 있는 것은 아닙니다.NULL. 이 모든 것이 0/false/NULL로 설정됩니다.static변수 또는 (C++에만 해당) 정적 객체 또는 그 베이스의 직접 또는 간접 멤버 변수 또는 제로 초기화(예: 0 초기화).new T(); ★★★★★★★★★★★★★★★★★」new T(x, y, z);T 제로 합니다.new T;하지 않습니다).

「 」를 는,0,NULL ★★★★★★★★★★★★★★★★★」nullptr포인터에 포인터의 비트가 모두 리셋 되는 것은 아닙니다.하드웨어 레벨에서는 포인터가 「0」을 포함하지 않거나 가상 주소 공간의 주소 0을 참조할 수 없습니다.수 를 에 합니다.0,NULL,nullptr또는 이들 중 하나가 할당된 다른 포인터에서는 비교가 예상대로 동작해야 합니다.따라서 컴파일러 수준의 소스 코드 아래에 있는 "NULL"은 C 및 C++ 언어에서 약간 "만화"가 될 수 있습니다.

메모리 주소에 대한 자세한 내용과 알 필요가 없는 이유

엄밀하게 말하면, 포인터에는, 「하다」의 어느쪽인가를 패턴이 됩니다.NULL또는 (대개 가상) 메모리주소입니다.

심플한 경우는 프로세스 전체의 가상 주소 공간에 대한 수치 오프셋입니다.더 복잡한 경우 포인터는 특정 메모리 영역을 기준으로 할 수 있습니다.이 영역은 CPU가 CPU의 "세그먼트" 레지스터 또는 비트 패턴으로 인코딩된 어떤 종류의 세그먼트 ID를 기반으로 선택할 수 있습니다.또한 마하(mach)에 따라 다른 장소를 참조할 수도 있습니다.주소를 사용하여 명령을 코드화합니다.

를 들면, 「」라고 하는 은,int*to키도 to to to to to to to to to to to to int mouth - mouth에 후 - 변수 mouth - - -팅후 。float* "GPU"는 - "GPU"가 다릅니다.int 머신의 수 은 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」, 「」).int*이러한 다른 메모리 영역 내에서 사실상 랜덤하고 비활성화된 포인터).

C 및 C++와 같은 3GL 프로그래밍 언어는 이러한 복잡성을 숨기는 경향이 있습니다.

  • 컴파일러가 변수 또는 함수에 대한 포인터를 제공하는 경우, 자유롭게 참조를 해제할 수 있습니다(변수가 파괴/배치되지 않는 한). 특정 CPU 세그먼트 레지스터를 미리 복원해야 하는지, 아니면 별도의 기계 코드 명령을 사용해야 하는지는 컴파일러의 문제입니다.

  • 배열 내의 요소에 대한 포인터를 얻을 경우 포인터 산수를 사용하여 배열 내의 다른 곳으로 이동할 수도 있고 배열 내의 다른 요소에 대한 포인터(또는 포인터 산술에 의해 동일한 과거 끝 값으로 이동된 경우)와 비교할 수 있는 주소를 만들 수도 있습니다.또, C와 C에서도 마찬가지입니다.C++는 컴파일러가 '그냥 동작'하는 것에 달려 있습니다.

  • 공유 메모리 매핑 등 특정 OS 기능은 포인터를 제공할 수 있으며, 적절한 주소 범위 내에서 "그냥" 작동합니다.

  • 이러한 경계를 넘어 법적 포인터를 이동하거나 임의의 번호를 포인터에 캐스트하거나 관련 없는 타입에 캐스트하는 포인터는 일반적으로 정의되지 않은 동작이므로 상위 레벨의 라이브러리 및 애플리케이션에서는 피해야 합니다.그러나 OS, 디바이스 드라이버 등의 코드는 C 또는 C++ 규격에 의해 정의되지 않은 동작에 의존해야 할 수 있습니다.단, 이는 특정 구현 또는 하드웨어에 의해 잘 정의되어 있습니다.

포인터의 참조 해제란 포인터가 가리키는 메모리 위치에 저장된 값을 얻는 것을 의미합니다.연산자 *는 이를 위해 사용되며, 이를 역참조 연산자라고 합니다.

int a = 10;
int* ptr = &a;

printf("%d", *ptr); // With *ptr I'm dereferencing the pointer. 
                    // Which means, I am asking the value pointed at by the pointer.
                    // ptr is pointing to the location in memory of the variable a.
                    // In a's location, we have 10. So, dereferencing gives this value.

// Since we have indirect control over a's location, we can modify its content using the pointer. This is an indirect way to access a.

 *ptr = 20;         // Now a's content is no longer 10, and has been modified to 20.

포인터는 값에 대한 "참조"입니다.도서관 전화번호가 책을 참조하는 것과 같다.콜 번호를 물리적으로 통과시켜 그 책을 취득하고 있습니다.

int a=4 ;
int *pA = &a ;
printf( "The REFERENCE/call number for the variable `a` is %p\n", pA ) ;

// The * causes pA to DEREFERENCE...  `a` via "callnumber" `pA`.
printf( "%d\n", *pA ) ; // prints 4.. 

책이 없으면 사서는 소리를 지르기 시작하고 도서관을 폐쇄하고 몇 명의 사람들이 책이 없는 사람을 찾아내는 원인을 조사하게 됩니다.

간단히 말해, 비참조란 포인터가 가리키는 특정 메모리 위치에서 값에 액세스하는 것을 의미합니다.

Pointer Basics 코드 및 설명:

참조 해제 조작은 포인터에서 시작하여 포인터의 화살표를 따라 포인터에 액세스합니다.포인티 상태를 확인하거나 포인티 상태를 변경하는 것이 목표일 수 있습니다.포인터의 참조 해제 조작은 포인터에 포인터가 있는 경우에만 동작합니다.포인트를 할당하고 포인터를 포인트로 설정해야 합니다.포인터 코드의 가장 일반적인 오류는 포인터 설정을 잊어버린 것입니다.코드의 그 에러에 의해 발생하는 가장 일반적인 런타임크래시는 실패한 참조 해제 조작입니다.Java에서는 잘못된 참조 해제가 런타임 시스템에 의해 정중하게 플래그가 지정됩니다.C, C++ 및 Pascal과 같은 컴파일 언어에서는 잘못된 참조 해제 기능이 크래시되거나 어떤 경우에는 미묘하고 랜덤한 방법으로 메모리가 손상되기도 합니다.컴파일된 언어의 포인터 버그는 이러한 이유로 추적하기 어려울 수 있습니다.

void main() {   
    int*    x;  // Allocate the pointer x
    x = malloc(sizeof(int));    // Allocate an int pointee,
                            // and set x to point to it
    *x = 42;    // Dereference x to store 42 in its pointee   
}

이전 답변은 모두 잘못된 답변이라고 생각합니다.참조란 실제 값에 접근하는 것을 의미합니다.Wikipedia에서는 올바른 정의를 제공합니다.https://en.wikipedia.org/wiki/Dereference_operator

이 값은 포인터 변수에 대해 작동하며 포인터 주소의 값에 해당하는 l-값을 반환합니다.이것을 포인터 「참조 해제」라고 부릅니다.

즉, 포인터가 가리키는 값에 액세스하지 않고 포인터를 참조 해제할 수 있습니다.예를 들어 다음과 같습니다.

char *p = NULL;
*p;

값에 액세스하지 않고 NULL 포인터를 참조했습니다.또는 다음을 수행할 수 있습니다.

p1 = &(*p);
sz = sizeof(*p);

다시 말씀드리지만, 비참조입니다만, 값에 액세스 할 수 없습니다.이러한 코드는 크래시하지 않습니다.크래시는 무효 포인터로 데이터에 실제로 액세스 할 때 발생합니다.그러나 안타깝게도 표준에 따라 비활성 포인터를 참조하는 것은 실제 데이터를 건드리지 않더라도 정의되지 않은 동작(몇 가지 예외 있음)입니다.

즉, 포인터의 역참조란 포인터에 역참조 연산자를 적용하는 것을 의미합니다.이 연산자는 나중에 사용할 수 있도록 l-값을 반환합니다.

언급URL : https://stackoverflow.com/questions/4955198/what-does-dereferencing-a-pointer-mean

반응형