c++ - 할당 - 배열 포인터 사용 이유




포인터를 사용하는 이유는 무엇입니까? (12)

  1. 포인터를 사용하면 여러 위치에서 메모리의 동일한 공간을 참조 할 수 있습니다. 즉, 한 위치에서 메모리를 업데이트 할 수 있으며 프로그램의 다른 위치에서 변경 내용을 볼 수 있습니다. 또한 데이터 구조에서 구성 요소를 공유 할 수있어 공간을 절약 할 수 있습니다.
  2. 포인터를 가져 와서 메모리의 특정 지점으로 주소를 전달해야하는 곳에 포인터를 사용해야합니다. 포인터를 사용하여 배열을 탐색 할 수도 있습니다.
  3. 배열은 특정 유형으로 할당 된 인접한 메모리 블록입니다. 배열의 이름에는 배열의 시작 지점 값이 포함됩니다. 1을 더하면 두 번째 지점으로 이동합니다. 이렇게하면 배열 액세스에 사용할 명시 적 카운터가 없어도 배열을 아래로 슬라이드하는 포인터를 증가시키는 루프를 작성할 수 있습니다.

다음은 C의 예제입니다.

char hello[] = "hello";

char *p = hello;

while (*p)
{
    *p += 1; // increase the character by one

    p += 1; // move to the next spot
}

printf(hello);

인쇄물

ifmmp

각 문자에 대한 값을 가져 와서 하나씩 증가시키기 때문입니다.

나는 이것이 정말로 기본적인 질문이라는 것을 알고 있지만, 고급 언어로 된 몇 개의 프로젝트를 코딩 한 후에 기본적인 C ++ 프로그래밍을 시작했다.

기본적으로 세 가지 질문이 있습니다.

  1. 일반 변수보다 포인터를 사용하는 이유는 무엇입니까?
  2. 언제 포인터를 사용해야합니까?
  3. 배열에 포인터를 어떻게 사용합니까?

C ++에서 하위 유형 polymorphism 을 사용하려면 사용자 포인터를 사용해야합니다. 이 게시물을 참조하십시오 : 포인터가없는 C ++ 다형성 .

정말로, 당신이 그것에 대해 생각할 때 이것은 의미가 있습니다. 하위 유형 다형성을 사용할 때 궁극적으로 실제 클래스가 무엇인지 모르기 때문에 메소드의 구현이 호출 될 클래스 또는 서브 클래스를 미리 알 수 없습니다.

알 수없는 클래스의 객체를 보유하는 변수를 갖는이 아이디어는 스택에 객체를 저장하는 C ++의 기본 (비 포인터) 모드와 호환되지 않습니다. 할당 된 공간의 양은 클래스에 직접 해당합니다. 참고 : 클래스에 3 개의 인스턴스 필드와 5 개의 인스턴스 필드가 있으면 더 많은 공간을 할당해야합니다.

참조로 인수를 전달하기 위해 '&'를 사용하면 간접 참조 (즉, 포인터)가 여전히 배후에 포함됩니다. '&'는 (1) 포인터 구문을 사용하는 데 따른 번거 로움을 줄이고 (2) 컴파일러에서 널 포인터를 금지하는 것과 같이 더 엄격하게 처리 할 수 ​​있도록하는 구문 상 설탕입니다.


C의 많은 기능이 이해되는 이유는 약간 다르지만 통찰력이 있습니다. http://steve.yegge.googlepages.com/tour-de-babel#C

기본적으로 표준 CPU 아키텍처는 폰 노이만 아키텍처이며, 메모리에서 데이터 항목의 위치를 ​​참조하고 그러한 머신에서 산술 연산을 수행하는 것이 대단히 유용합니다. 어셈블리 언어의 변형을 알고있는 경우, 이것이 낮은 수준에서 얼마나 중요한지 빠르게 알 수 있습니다.

C ++은 포인터를 약간 혼란스럽게 만듭니다. 때로는 포인터를 관리하고 "참조"형태로 그 효과를 숨기기 때문입니다. 스트레이트 C를 사용하는 경우 포인터에 대한 필요성이 훨씬 더 분명합니다. 참조별로 호출 할 수있는 다른 방법은 없습니다. 문자열을 저장하는 가장 좋은 방법이며, 배열을 반복하는 가장 좋은 방법입니다.


나도 이것을 시도하고 대답 해 보자.

포인터는 참조와 유사합니다. 즉, 사본이 아니라 원본 값을 참조하는 방법입니다.

무엇보다 먼저 임베디드 하드웨어를 다루는 경우 일반적으로 포인터 를 많이 사용해야 하는 곳이 있습니다 . 어쩌면 디지털 IO 핀의 상태를 토글해야 할 수도 있습니다. 어쩌면 인터럽트를 처리하고 특정 위치에 값을 저장해야 할 수도 있습니다. 너는 그림을 얻는다. 그러나 하드웨어를 직접 다루지 않고 사용할 유형에 대해 궁금한 점이 있다면 읽어보십시오.

포인터를 일반 변수와 비교하여 사용하는 이유는 무엇입니까? 클래스, 구조 및 배열과 같은 복잡한 유형을 처리 할 때 대답이 명확 해집니다. 일반적인 변수를 사용한다면, 결국 복사를하게 될 수도 있습니다 (컴파일러는 어떤 상황에서는이를 방지 할 수있을만큼 똑똑하고 C ++ 11도 도움이됩니다 만, 지금은 그 논의에서 벗어날 것입니다).

이제 원래 값을 수정하려는 경우 어떻게됩니까? 다음과 같이 사용할 수 있습니다.

MyType a; //let's ignore what MyType actually is right now.
a = modify(a); 

그게 잘 작동하고 포인터를 사용하는 이유를 정확히 모르는 경우 포인터를 사용하면 안됩니다. "아마 더 빠를 것"이라는 이유에 유의하십시오. 자신의 테스트를 실행하고 실제로 더 빠르다면 테스트를 사용하십시오.

그러나 메모리를 할당해야하는 문제를 해결한다고 가정 해 봅시다. 메모리를 할당 할 때 할당을 해제해야합니다. 메모리 할당이 성공적 일 수도 있고 성공적 일 수도 있습니다. 포인터 가 유용하게 사용되는 곳입니다. 포인터사용하면 할당 된 객체의 존재 여부를 테스트 할 수 있으며 포인터를 참조 해제하여 메모리가 할당 된 객체에 액세스 할 수 있습니다.

MyType *p = NULL; //empty pointer
if(p)
{
    //we never reach here, because the pointer points to nothing
}
//now, let's allocate some memory
p = new MyType[50000];
if(p) //if the memory was allocated, this test will pass
{
    //we can do something with our allocated array
    for(size_t i=0; i!=50000; i++)
    {
        MyType &v = *(p+i); //get a reference to the ith object
        //do something with it
        //...
    }
    delete[] p; //we're done. de-allocate the memory
}

이것은 포인터를 사용하는 이유의 핵심입니다. 참조는 참조하는 요소가 이미 있다고 가정합니다 . 포인터는 그렇지 않습니다.

포인터를 사용하는 다른 이유는 포인터가 참조하기 전에 존재했던 데이터 유형이기 때문입니다. 따라서 라이브러리를 사용하여 더 잘 알고있는 것을 수행하게되면 많은 라이브러리가 포인터를 사용한다는 것을 알게 될 것입니다. 단순히 그 라이브러리가 얼마나 오래 있었는지 (많이 있습니다. 그들 중 C ++ 전에 쓰여졌다).

라이브러리를 사용하지 않은 경우에는 포인터를 사용하지 않도록 코드를 디자인 할 수 있지만 포인터가 언어의 기본 유형 중 하나라는 점을 고려할 때 포인터를 사용하는 것이 빠르면 빠를수록 휴대용 C + + 기술이 될 것입니다.

유지 보수성 관점에서 포인터를 사용할 때 유효성을 테스트하고 유효하지 않거나 유효하지 않다고 생각할 때 케이스를 처리해야합니다. 그 가정이 깨지면 프로그램이 충돌하거나 악화 될 것입니다. 다른 방법으로, 포인터를 사용하여 선택하는 것은 코드가 복잡해 지거나 무언가가 고장 났을 때 더 많은 유지 보수 작업을 수행 하고 포인터가 소개하는 메모리 손상과 같은 전체 오류 클래스에 속하는 버그를 추적하려고 시도하는 것입니다.

따라서 모든 코드를 제어한다면 포인터를 사용하지 말고 참조를 사용하여 가능한 경우 const로 유지하십시오. 이렇게하면 개체의 수명에 대해 생각하게되고 결국 코드를 ​​더 쉽게 이해할 수있게됩니다.

이 차이점을 기억하십시오. 참조는 본질적으로 유효한 포인터입니다. 포인터가 항상 유효한 것은 아닙니다.

그렇다면 잘못된 참조를 만드는 것이 불가능하다는 말입니까? 아닙니다. C ++은 거의 모든 것을 할 수 있기 때문에 완전히 가능합니다. 무의식적으로하는 것이 더 어렵습니다. 의도하지 않은 버그가 얼마나 많은지 놀랄 것입니다. :)


두 번째 질문에 관해서는 일반적으로 프로그래밍하는 동안 포인터를 사용할 필요가 없지만 공용 API를 만들 때 한 가지 예외가 있습니다.

사람들이 일반적으로 포인터를 대체하기 위해 사용하는 C ++ 구조의 문제는 소스 코드에서 필요한 모든 제어 기능을 사용할 때 잘 사용하는 도구 세트에 크게 의존하지만 Visual Studio 2008로 정적 라이브러리를 컴파일하는 경우 Visual Studio 2010에서 사용하려고하면 새 프로젝트가 이전 버전과 호환되지 않는 STL의 최신 버전과 연결되어 있기 때문에 많은 링커 오류가 발생합니다. DLL을 컴파일하고 사람들이 다른 툴셋에서 사용하는 가져 오기 라이브러리를 제공하는 경우 상황이 더 이상 나빠지거나 조만간 프로그램이 중단 될 수 있기 때문에 상황이 더욱 복잡해집니다.

한 라이브러리에서 다른 라이브러리로 대용량 데이터 세트를 옮길 목적으로 다른 사용자가 사용하는 것과 동일한 도구를 사용하도록 강요하고 싶지 않은 경우 데이터를 복사해야하는 함수에 대한 배열에 대한 포인터를 제공하는 것을 고려할 수 있습니다 . 좋은 점은 C 스타일의 배열 일 필요조차 없다는 것입니다. std :: vector를 사용할 수 있고, 예를 들어 첫 번째 요소와 벡터 [0]의 주소를 지정하여 포인터를주고 사용할 수 있습니다 내부적으로 배열을 관리하기위한 std :: vector.

C ++에서 포인터를 사용하는 또 다른 좋은 이유는 라이브러리와 관련이 있으며, 프로그램이 실행될 때로드 할 수없는 DLL을 고려해야합니다. 따라서 가져 오기 라이브러리를 사용하면 종속성이 만족스럽지 않고 프로그램이 충돌합니다. 예를 들어, 응용 프로그램과 함께 dll에 공개 API를 제공하고 다른 응용 프로그램에서 공용 API에 액세스하려는 경우입니다. 이 경우 API를 사용하려면 dll을 해당 위치에서로드해야합니다 (일반적으로 레지스트리 키에 있음). 그런 다음 함수 포인터를 사용하여 DLL 내부의 함수를 호출 할 수 있어야합니다. 때로는 API를 만드는 사람들이이 프로세스를 자동화하고 필요한 모든 함수 포인터를 제공하는 도우미 함수가 포함 된 .h 파일을 제공하기에 충분히 유용하지만 그렇지 않은 경우 Windows에서 LoadLibrary 및 GetProcAddress를 사용할 수 있으며 dlopen과 유닉스에서 dlsym을 사용하여 (함수의 전체 서명을 알고 있다고 생각할 때)


변수에 대한 포인터를 사용하는 한 가지 방법은 필요한 중복 메모리를 제거하는 것입니다. 예를 들어 어떤 복잡한 객체가 큰 경우 포인터를 사용하여 각 참조에 대해 해당 변수를 가리킬 수 있습니다. 변수를 사용하면 각 복사본에 대한 메모리를 복제해야합니다.


자바와 C #에서 모든 객체 참조는 포인터입니다. C ++의 것은 포인터가 가리키는 곳을 더 잘 제어 할 수 있다는 것입니다. 큰 힘으로 큰 책임이 따른다는 것을 기억하십시오.


장소 전체에 큰 물체를 복사하면 시간과 기억이 낭비되기 때문입니다.


포인터는 동적 힙 영역의 데이터 할당 및 검색에서 성능이 향상되기 때문에 사용됩니다.


포인터는 하나의 "노드"를 다른 노드와 효율적으로 연결하거나 연결하는 기능이 필요한 많은 데이터 구조에서 중요합니다. float와 같은 일반적인 데이터 유형에 대해 포인터를 "선택"하지 않으면 단순히 다른 목적이 있습니다.

포인터는 고성능 및 / 또는 소형 메모리 영역이 필요한 곳에서 유용합니다.

배열의 첫 번째 요소의 주소를 포인터에 할당 할 수 있습니다. 그러면 기본 할당 바이트에 직접 액세스 할 수 있습니다. 배열의 요점은 당신이 이것을 할 필요가 없다는 것입니다.


한 포인터 사용 (다른 사람들의 게시물에서 이미 다룬 내용은 언급하지 않음)은 할당하지 않은 메모리에 액세스하는 것입니다. 이것은 PC 프로그래밍에별로 도움이되지 않지만 임베디드 프로그래밍에서 메모리 매핑 하드웨어 장치에 액세스하는 데 사용됩니다.

옛날 DOS에서, 당신은 포인터를 선언함으로써 비디오 카드의 비디오 메모리에 직접 접근 할 수있었습니다 :

unsigned char *pVideoMemory = (unsigned char *)0xA0000000;

많은 임베디드 장치가 여전히이 기술을 사용합니다.


  • 경우에 따라 공유 라이브러리 (.DLL 또는 .so)에있는 함수를 사용하려면 함수 포인터가 필요합니다. 여기에는 종종 언어 인터페이스를 제공하는 언어 전반에 걸친 작업이 포함됩니다.
  • 컴파일러 만들기
  • 함수 포인터의 배열 또는 벡터 또는 문자열 맵이있는 과학 용 계산기를 만드는 중입니까?
  • 비디오 메모리를 직접 수정하려고 시도합니다 - 자신의 그래픽 패키지 만들기
  • API 만들기!
  • 데이터 구조 - 만들고있는 특수 트리에 대한 노드 링크 포인터

포인터에 대한 많은 이유가 있습니다. 언어 간 호환성을 유지하려면 DLL에서 C 이름 맹 글링이 특히 중요합니다.





pointers