sourcetip

C/C++에서 포인터 '디레퍼런스'는 무엇을 의미합니까?

fileupload 2023. 5. 8. 22:24
반응형

C/C++에서 포인터 '디레퍼런스'는 무엇을 의미합니까?

설명과 함께 예시를 포함해 주시기 바랍니다.

기본 용어 검토

어셈블리를 프로그래밍하지 않는 한 일반적으로 프로세스 메모리의 두 번째 바이트를 나타내는 1, 세 번째 바이트를 나타내는 2, 네 번째 바이트를 나타내는 3 등 숫자 메모리 주소를 포함하는 포인터를 구상하는 이 좋습니다.

  • 0과 첫 번째 바이트는 어떻게 되었습니까?나중에 설명하겠습니다. 아래의 널 포인터를 참조하십시오.
  • 포인터가 저장하는 내용과 메모리 및 주소가 연결되는 방식에 대한 보다 정확한 정의는 이 답변의 끝에 있는 "메모리 주소에 대한 자세한 내용 및 알 필요가 없는 이유"를 참조하십시오.

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

컴퓨터 언어에 따라 컴파일러나 인터프리터에 이제 포인터 개체의 (현재) 값에 관심이 있음을 알리는 표기법이 다릅니다. 아래에서는 C와 C++에 초점을 맞춥니다.

포인터 시나리오

다과같포은가에주인어터다고 C니합려면지와 같은 .p아래...

const char* p = "abc";

' ' '하는 데 데이터의 가...문자 'a', 'b', 'c'를 인코딩하는 데 사용되는 숫자 값을 가진 4바이트와 텍스트 데이터의 끝을 나타내는 0바이트가 메모리 어딘가에 저장되고 해당 데이터의 숫자 주소가p이러한 방식으로 C는 메모리에서 텍스트를 인코딩합니다. 를 ASCIIZ라고 합니다.

들어 및 "" " " 0x1000" "에 있는 "p메모리 내용은 다음과 같습니다.

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.

포인터 참조 해제

▁charact▁top 점, 참취소에 대한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_

멀티바이트 데이터 유형

포인터를 사용하려면 컴퓨터 프로그램도 가리키는 데이터 유형에 대한 통찰력이 필요합니다. 데이터 유형이 나타내는 데 두 바이트 이상이 필요한 경우 포인터는 일반적으로 데이터에서 가장 낮은 숫자의 바이트를 가리킵니다.

좀 더 복잡한 예를 살펴보겠습니다.

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 추그가에 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로 설정되지는 .0,도 아니다boolsfalse포인터가 항상 다음으로 설정되지는 않습니다.NULL 것들은 "0/false/NULL"일 때 0됩니다.static 또는 해당) 정적 변수 또는 변수또는 (C++에해당만를예정화또는체적다수화행니합초제기또객는로)를 거칩니다.new T();그리고.new T(x, y, z);를 수행하는 , 포터를포함멤 T에대해제로초수반면행를는하기화한인버▁perform포인▁including는반,면-▁zero수,new T;그렇지 않음).

한할때할당또를 할당할 때.0,NULL그리고.nullptr포인터에 대한 포인터의 비트가 모두 재설정될 필요는 없습니다. 포인터가 하드웨어 수준에서 "0"을 포함하지 않거나 가상 주소 공간의 주소 0을 참조할 수 있습니다.컴파일러는 다른 것을 저장할 수 있습니다. 이유가 있다면, 하지만 무엇을 하든 - 만약 당신이 포인터를 비교한다면.0,NULL,nullptr또는 이들 중 하나가 할당된 다른 포인터가 있으면 비교가 예상대로 작동해야 합니다.따라서 컴파일러 수준의 소스 코드 아래에서 "NULL"은 잠재적으로 C 및 C++ 언어에서 약간 "마법적"입니다.

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

더 엄격하게, 초기화된 포인터는 다음 중 하나를 식별하는 비트 패턴을 저장합니다.NULL또는 (종종 가상) 메모리 주소입니다.

단순한 경우는 프로세스의 전체 가상 주소 공간에 대한 숫자 오프셋인 경우입니다. 더 복잡한 경우 포인터는 CPU "세그먼트" 레지스터나 비트 패턴으로 인코딩된 세그먼트 ID 방식에 따라 선택할 수 있는 특정 메모리 영역에 상대적일 수 있습니다.또는 주소를 사용하는 기계 코드 지침에 따라 다른 위치를 찾습니다.

예를 들어, 다음과 같습니다.int*된▁point를 가리키도록 적절하게 되었습니다.int는 - 후 - 주조 후 - 주조 후 - 주조 후일 수 있습니다.float*"는 "GPU" .int 더 수 (" 는변, , 그램를을위한더프뚜수그렷한메모것, ▁(숫를▁variable▁op▁is▁holding▁thecodes▁then▁it,▁value▁point▁once)로▁(▁the▁ofwith▁machine▁pointer▁cast▁into값▁for▁program▁to▁as▁and으다니▁numeric▁distinct▁a▁function▁might▁memory▁further습자변,수는▁used있▁the수킬int*사실상 이러한 다른 메모리 영역 내에서 임의의 잘못된 포인터입니다.

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

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

  • 배열의 요소에 대한 포인터를 얻는 경우 포인터 산술을 사용하여 배열의 다른 위치로 이동할 수 있습니다.또는 배열의 요소에 대한 다른 포인터와 비교하는 것이 합법적인 배열의 끝단 하나의 주소를 형성하는 것(또는 포인터 산술에 의해 동일한 끝단 하나의 값으로 유사하게 이동된 것); 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.. 

만약 책이 없다면, 사서는 소리를 지르기 시작하고 도서관을 닫으며, 두 명의 사람들이 사람들이 책이 없는 곳을 찾아간 원인을 조사하기 시작합니다.

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

포인터 기본 사항의 코드 및 설명:

참조 해제 작업은 포인터에서 시작하여 화살표를 따라 포인터에 액세스합니다.목표는 시점 상태를 보거나 시점 상태를 변경하는 것일 수 있습니다.포인터에 대한 참조 취소 작업은 포인터에 포인터가 있는 경우에만 작동합니다. 포인터를 할당하고 포인터를 가리키도록 설정해야 합니다.포인터 코드에서 가장 일반적인 오류는 포인터 설정을 잊어버리는 것입니다.코드의 오류로 인해 가장 일반적인 런타임 충돌은 실패한 참조 취소 작업입니다.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   
}

위의 답변들은 모두 실제 가치에 접근하는 것을 의미한다고 언급하고 있기 때문에 저는 이전의 답변들이 모두 틀렸다고 생각합니다.위키백과는 대신 올바른 정의를 제공합니다: 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-in-c-c

반응형