왜 포인터를 사용합니까? [닫은]


356

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

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

  1. 왜 일반 변수에 포인터를 사용합니까?
  2. 언제 어디서 포인터를 사용해야합니까?
  3. 배열에 포인터를 어떻게 사용합니까?

5
이 질문 에서 전에 토론하십시오 희망이 도움이됩니다!
Doug T.

4
책 목록은 stackoverflow.com/questions/388242/…를 참조하십시오 . Java 후에 Accelerated C ++가 매우 유용하다는 것을 알았습니다 .
Jabba

163
우리는 모든 사람에게 집의 사본을주는 것보다 집에 주소를주는 것이 더 쉽기 때문에 포인터를 사용합니다.
Rishi Dua

14
@RishiDua 그것은 내가 만난 포인터에 대한 가장 좋은 단일 설명입니다. 그 주셔서 감사합니다, 내 이해 :) 증가
조쉬

2
둘 이상의 값 / 객체를 반환하려는 경우에도 포인터를 사용할 수 있습니다.
Gaurav

답변:


172
  • 왜 일반 변수에 포인터를 사용합니까?

짧은 대답은 :하지 마십시오. ;-) 포인터는 다른 것을 사용할 수없는 곳에서 사용됩니다. 적절한 기능 부족, 데이터 유형 누락 또는 순수한 성능 때문입니다. 더 아래에 ...

  • 언제 어디서 포인터를 사용해야합니까?

여기에 짧은 대답은 : 다른 것을 사용할 수없는 곳입니다. C에서는 문자열과 같은 복잡한 데이터 유형을 지원하지 않습니다. "참조로"변수를 함수에 전달하는 방법도 없습니다. 그것은 포인터를 사용해야하는 곳입니다. 또한 거의 모든 것, 링크 된리스트, 구조체 멤버 등을 가리 키도록 할 수 있습니다. 그러나 여기에 들어 가지 마십시오.

  • 배열에 포인터를 어떻게 사용합니까?

적은 노력과 많은 혼란으로. ;-) int와 char 같은 간단한 데이터 타입에 대해 이야기하면 배열과 포인터 사이에는 거의 차이가 없습니다. 이러한 선언은 매우 유사하지만 동일하지는 않습니다. 예를 들어 sizeof다른 값을 반환합니다.

char* a = "Hello";
char a[] = "Hello";

이런 식으로 배열의 모든 요소에 도달 할 수 있습니다

printf("Second char is: %c", a[1]);

배열이 요소 0으로 시작하기 때문에 인덱스 1

아니면 똑같이 할 수 있습니다

printf("Second char is: %c", *(a+1));

printf에게 문자를 인쇄하고 싶다고 알려주기 때문에 포인터 연산자 (*)가 필요합니다. *가 없으면 메모리 주소 자체의 문자 표현이 인쇄됩니다. 이제 캐릭터 자체를 대신 사용하고 있습니다. % c 대신 % s를 사용했다면 printf에게 'a'에 1을 더한 메모리 주소의 내용을 인쇄하도록 요청했을 것입니다 (위의 예에서). *를 입력하지 않아도됩니다. 앞에서 :

printf("Second char is: %s", (a+1)); /* WRONG */

그러나 이것은 두 번째 문자를 인쇄 한 것이 아니라 null 문자 (\ 0)를 찾을 때까지 다음 메모리 주소의 모든 문자를 인쇄 한 것입니다. 그리고 이것은 상황이 위험 해지기 시작하는 곳입니다. 실수로 % s 포맷터가있는 char 포인터 대신 정수 유형의 변수를 인쇄하려고하면 어떻게됩니까?

char* a = "Hello";
int b = 120;
printf("Second char is: %s", b);

메모리 주소 120에서 찾은 것을 인쇄하고 널 문자가 발견 될 때까지 인쇄를 계속합니다. 이 printf 문을 수행하는 것은 잘못되고 불법이지만, 포인터는 실제로 많은 환경에서 int 유형이므로 어쨌든 작동합니다. 대신 sprintf ()를 사용하고이 방법으로 너무 긴 "char array"를 다른 변수에 할당하면 특정 제한된 공간 만 할당되면 발생할 수있는 문제를 상상해보십시오. 아마도 메모리에 다른 것을 덮어 쓰게되어 프로그램이 중단 될 수 있습니다 (행운이 있다면).

아, 그리고 선언 할 때 char 배열 / 포인터에 문자열 값을 할당하지 않으면 값을 제공하기 전에 충분한 양의 메모리를 할당해야합니다. malloc, calloc 또는 이와 유사한 것을 사용합니다. 이것은 배열에서 하나의 요소 / 하나의 단일 메모리 주소 만 가리 키도록 선언했기 때문입니다. 여기 몇 가지 예가 있습니다 :

char* x;
/* Allocate 6 bytes of memory for me and point x to the first of them. */
x = (char*) malloc(6);
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* Delete the allocation (reservation) of the memory. */
/* The char pointer x is still pointing to this address in memory though! */
free(x);
/* Same as malloc but here the allocated space is filled with null characters!*/
x = (char *) calloc(6, sizeof(x));
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* And delete the allocation again... */
free(x);
/* We can set the size at declaration time as well */
char xx[6];
xx[0] = 'H';
xx[1] = 'e';
xx[2] = 'l';
xx[3] = 'l';
xx[4] = 'o';
xx[5] = '\0';
printf("String \"%s\" at address: %d\n", xx, xx);

할당 된 메모리의 free ()를 수행 한 후에도 변수 x를 계속 사용할 수 있지만 그 안에 무엇이 있는지 모릅니다. 또한 두 번째 printf ()는 다른 주소를 제공 할 수 있습니다. 두 번째 메모리 할당이 첫 번째와 동일한 공간에서 수행된다는 보장이 없기 때문입니다.


8
120이 포함 된 예가 잘못되었습니다. % s가 아닌 % c를 사용하므로 버그가 없습니다. 소문자 x 만 인쇄합니다. 또한 포인터가 int 유형이라는 후속 주장은 포인터에 익숙하지 않은 C 프로그래머에게 제공하는 매우 나쁜 조언입니다.
R .. GitHub 중지 지원 얼음

13
-1 잘 시작했지만 첫 번째 예가 잘못되었습니다. 아니요, 동일하지 않습니다. 첫 번째 경우 a는 포인터이고 두 번째 경우 a는 배열입니다. 내가 이미 언급 했습니까? 이건 같은게 아니야! 스스로 확인하십시오 : sizeof (a)를 비교하고 새 주소를 배열에 할당하십시오. 작동하지 않습니다.
sellibitze

42
char* a = "Hello";char a[] = "Hello";동일하지 않습니다, 그들은 매우 다르다. 하나는 포인터를 다른 하나는 배열로 선언합니다. 를 시도 sizeof하면 차이가 보입니다.
Patrick Schlüter

12
"이 printf 문을 수행하는 것은 잘못되거나 불법이 아닙니다". 이것은 명백한 잘못입니다. 이 printf 문에는 정의되지 않은 동작이 있습니다. 많은 구현에서 액세스 위반이 발생합니다. 포인터는 실제로 int 유형이 아니며 실제로 포인터입니다 (그리고 다른 것은 없습니다).
Mankarse

19
-1, 당신은 여기에 너무 많은 사실을 얻었습니다. 나는 당신이 공감하거나 허용되는 답변 상태를받을 자격이 없다고 말하는 것입니다.
asveikau

50

포인터를 사용하는 한 가지 이유는 호출 된 함수에서 변수 또는 객체를 수정할 수 있기 때문입니다.

C ++에서는 포인터보다 참조를 사용하는 것이 좋습니다. 참조는 본질적으로 포인터이지만 C ++은 어느 정도 사실을 숨기고 마치 값으로 전달하는 것처럼 보입니다. 이를 통해 호출 의미를 전달하는 의미를 수정하지 않고도 호출 함수가 값을받는 방식을 쉽게 변경할 수 있습니다.

다음 예를 고려하십시오.

참조 사용 :

public void doSomething()
{
    int i = 10;
    doSomethingElse(i);  // passes i by references since doSomethingElse() receives it
                         // by reference, but the syntax makes it appear as if i is passed
                         // by value
}

public void doSomethingElse(int& i)  // receives i as a reference
{
    cout << i << endl;
}

포인터 사용하기 :

public void doSomething()
{
    int i = 10;
    doSomethingElse(&i);
}

public void doSomethingElse(int* i)
{
    cout << *i << endl;
}

16
null 참조를 전달할 수 없다는 점에서 참조가 더 안전하다고 언급하는 것이 좋습니다.
SpoonMeiser

26
네, 아마도 참조를 사용하는 것의 가장 큰 장점 일 것입니다. 지적 해 주셔서 감사합니다. 말장난 없음 :)
trshiv

2
반드시 null 참조를 전달할 수 있습니다 . null 포인터를 전달하는 것만 큼 쉽지 않습니다.
n0rd

1
@ n0rd와 일치합니다. null 참조를 전달할 수 없다고 생각하면 잘못되었습니다. 널 (null) 참조보다 매달려있는 참조를 전달하는 것이 더 쉽지만 궁극적으로는 충분히 충분할 수 있습니다. 참고 문헌은 엔지니어가 발에 총을 쏘지 못하도록 막는 총알이 아닙니다. 그것을 참조하십시오 .
WhozCraig

2
@ n0rd : 명시 적으로 정의되지 않은 동작입니다.
Daniel Kamil Kozar

42
  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

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


because it takes the value for each character and increments it by one. ASCII 표현입니까?
Eduardo S.

28

포인터는 다른 변수에 대한 간접 참조를 얻는 한 가지 방법입니다. 변수 의 을 유지하는 대신 주소 를 알려줍니다 . 이것은 배열을 다룰 때 특히 유용합니다. 배열의 첫 번째 요소 (주소)에 대한 포인터를 사용하면 포인터를 다음 주소 위치로 증가시켜 다음 요소를 빠르게 찾을 수 있습니다.

내가 읽은 포인터 및 포인터 산술에 대한 가장 좋은 설명은 K & R의 The C Programming Language에 있습니다. C ++ 학습을 시작하기에 좋은 책은 C ++ Primer 입니다.


1
감사합니다! 마지막으로 스택 사용의 이점에 대한 실질적인 설명! 배열의 위치에 대한 포인터가 포인터에 대한 @ 값에 액세스하는 성능을 향상 시킵니까?

이것은 아마도 내가 읽은 최고의 설명 일 것입니다. 사람들은 "과도하게 복잡한"것들을 가지고 있습니다 :)
Detilium

23

이것도 시도하고 대답하겠습니다.

포인터는 참조와 유사합니다. 다시 말해, 그것들은 사본이 아니라 원래 값을 참조하는 방법입니다.

무엇보다도, 일반적으로 포인터 를 많이 사용해야 하는 곳은 임베디드 하드웨어를 다룰 때 입니다. 디지털 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 ++ 기술을 이식 할 수 있습니다.

유지 관리 성 관점에서 포인터를 사용할 때 유효성을 테스트하고 유효하지 않은 경우를 처리해야하거나 유효하지 않다고 가정하고 사실을 받아 들여야한다고 언급해야합니다. 가정이 깨지면 프로그램이 충돌하거나 더 나빠질 것입니다. 달리 말하면, 포인터로 선택하는 것은 코드가 복잡하거나 문제가 발생할 때 더 많은 유지 보수 노력을 기울이는 것입니다. 포인터가 메모리 손상과 같이 포인터가 유발하는 전체 클래스에 속하는 버그를 추적하려고합니다.

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

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

그래서 잘못된 참조를 만드는 것이 불가능하다는 말입니까? C ++로 거의 모든 작업을 수행 할 수 있기 때문에 가능합니다. 우연히하는 것이 더 어려우며 의도하지 않은 버그 수에 놀랄 것입니다. :)


본질적으로 포인터 사용을 피할 수있는 메모리 매핑 된 IO를위한 멋진 래퍼 클래스를 작성할 수 있습니다.
einpoklum

13

다음은 약간 다르지만 C의 여러 기능이 이해되는 이유에 대한 통찰력있는 정보입니다. http://steve.yegge.googlepages.com/tour-de-babel#C

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

C ++은 때때로 포인터를 관리하고 "참조"의 형태로 그 효과를 숨기므로 포인터를 약간 혼란스럽게 만듭니다. C를 직접 사용하는 경우 포인터가 필요합니다. 참조로 호출 할 수있는 다른 방법은 없으며 문자열을 저장하는 가장 좋은 방법이며 배열을 반복하는 가장 좋은 방법입니다.


12

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

DOS 시절에는 다음에 대한 포인터를 선언하여 비디오 카드의 비디오 메모리에 직접 액세스 할 수있었습니다.

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

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


길이를 유지하는 스팬과 같은 포인터를 사용하는 이유가 훨씬 더 적합합니다. 요즘 그것은 gsl::span, 그리고 곧 될 것입니다 std::span.
einpoklum

10

대부분의 경우 포인터는 배열 (C / C ++)입니다. 메모리의 주소이며 원하는 경우 배열처럼 액세스 할 수 있습니다 ( "일반"경우).

항목의 주소이므로 크기가 작습니다. 주소의 공간 만 차지합니다. 크기가 작기 때문에 함수로 보내는 것이 저렴합니다. 그런 다음 해당 기능이 사본이 아닌 실제 항목에서 작동하도록합니다.

동적 스토리지 할당 (예 : 링크 된 목록)을 수행하려면 포인터를 사용하는 것이 유일한 방법이기 때문에 포인터를 사용해야합니다.


8
포인터가 배열이라고 말하는 것은 오해의 소지가 있다고 생각합니다. 실제로 배열 이름은 배열의 첫 번째 요소에 대한 const 포인터입니다. 배열이 의미하지 않는 것처럼 임의의 지점에 액세스 할 수 있기 때문에 ... 액세스 위반이 발생할 수 있습니다. :)
rmeador

2
포인터는 배열이 아닙니다. comp.lang.c FAQ 의 섹션 6을 읽으십시오 .
Keith Thompson

포인터는 실제로 배열이 아닙니다. 또한 원시 배열에는 많이 사용되지 않습니다. 확실히 C ++ 11 및 std::array.
einpoklum

@einpoklum - 포인터 참조 운영에 상당와 배열을 통해 반복 될 배열에 가까운만큼도 ... :) 있습니다 -이 답변은 2008 년에 기록 된 때 C ++ 11 릴리스에서 삼년 멀리이었다
워렌

@warren : 포인터는 배열이 아니며 배열에 가깝습니다. 사람들에게 그들이 비슷하다고 말하는 것은 교육적으로 부적절합니다. 또한 포인터와 동일한 유형이 아니며 크기 정보를 유지하는 배열에 대한 참조를 가질 수 있습니다. 여기
einpoklum

9

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

포인터는 고성능 및 / 또는 컴팩트 메모리 공간이 필요한 경우에 유용합니다.

배열에서 첫 번째 요소의 주소를 포인터에 할당 할 수 있습니다. 그러면 기본 할당 된 바이트에 직접 액세스 할 수 있습니다. 배열의 요점은이 작업을 수행하지 않아도되는 것입니다.


9

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


이것이 포인터가 아닌 참조 (또는 대부분 참조 래퍼)를 사용해야하는 이유입니다.
einpoklum

6

당신이 하위 유형 사용하려는 경우 C ++에서 다형성을 , 당신은 포인터를 사용 할 수 있습니다. 이 게시물을보십시오 : 포인터가없는 C ++ 다형성 .

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

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


참조로 인수를 전달하기 위해 '&'를 사용하는 경우 간접적 (즉, 포인터)이 여전히 장면에 관여합니다. '&'는 (1) 포인터 구문을 사용하는 데 따르는 어려움을 덜어주고 (2) 컴파일러가 더 엄격한 (널 포인터 금지) 허용하는 구문 설탕입니다.


아니, 당신은하지 않습니다 포인터를 사용하는 - 당신이 참조를 사용할 수 있습니다. 그리고 "포인터가 비하인드 스토리 뒤에 있습니다"라고 쓰면 의미가 없습니다. goto지시 사항은 또한 대상 기계의 지시 사항에서 뒤에서 사용됩니다. 우리는 여전히 그것들을 사용한다고 주장하지 않습니다.
einpoklum

@ einpoklum-reinstateMonica 실행할 객체 집합이있는 경우 각 요소를 임시 변수에 차례로 할당하고 해당 변수에 대해 다형성 메서드를 호출하면 참조를 리 바인드 할 수 없으므로 포인터가 필요합니다.
Sildoreth

파생 클래스에 대한 기본 클래스 참조가 있고 해당 참조에 대한 가상 메소드를 호출하면 파생 클래스의 대체가 호출됩니다. 내가 잘못?
einpoklum

@ einpoklum-reinstateMonica 맞습니다. 그러나 참조되는 개체를 변경할 수 없습니다. 따라서 해당 객체의 목록 / 세트 / 배열을 반복하는 경우 참조 변수가 작동하지 않습니다.
Sildoreth

5

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


4
그리고 포인터가 어떻게 도움이 되나요? 이 대답은 .. 꽤 쓸모 그래서 나는 스택과 힙 사이의 차이를 모르는 자바 나 닷넷에서 오는 사람을 생각
매트 Fredriksson

참조로 전달할 수 있습니다. 복사가되지 않습니다.
Martin York

1
@MatsFredriksson-큰 데이터 구조를 전달 (복사)하고 결과를 다시 복사하는 대신 RAM의 위치를 ​​가리킨 다음 직접 수정하십시오.
John U

따라서 큰 물체를 복사하지 마십시오. 아무도 당신이 그것에 대한 포인터가 필요하다고 말하지 않았습니다.
einpoklum

5

여기 내 대답이 있는데, 전문가가 될 것을 약속하지는 않지만, 내가 작성하려고하는 라이브러리 중 하나에서 포인터가 훌륭하다는 것을 알았습니다. 이 라이브러리 (OpenGL :-의 그래픽 API)에서 정점 객체가 전달 된 삼각형을 만들 수 있습니다. draw 메소드는이 삼각형 객체를 취합니다. 내가 만든 정점 객체를 기준으로 그립니다. 글쎄요.

그러나 정점 좌표를 변경하면 어떻게됩니까? 정점 클래스에서 moveX ()를 사용하여 이동합니까? 자, 이제 삼각형을 업데이트해야합니다. 버텍스가 움직일 때마다 삼각형을 업데이트해야하기 때문에 더 많은 메소드를 추가하고 성능이 낭비되고 있습니다. 여전히 큰 문제는 아니지만 그렇게 크지는 않습니다.

이제, 수많은 정점과 수많은 삼각형의 메쉬가 있고 메쉬가 회전하고 움직이고 있다면 어떻게해야합니까? 어떤 정점이 어떤 정점을 사용하는지 모르기 때문에 이러한 정점을 사용하는 모든 삼각형과 장면의 모든 삼각형을 업데이트해야합니다. 그것은 컴퓨터를 엄청나게 많이 사용합니다. 풍경 위에 메쉬가 여러 개 있다면 오 세상에! 이 정점이 항상 변경되기 때문에 거의 모든 프레임을 거의 모든 프레임으로 업데이트하기 때문에 문제가 있습니다!

포인터를 사용하면 삼각형을 업데이트하지 않아도됩니다.

삼각형 클래스 당 3 개의 * Vertex 객체가있는 경우, 거대한 삼각형에는 3 개의 꼭짓점 객체가 없기 때문에 공간을 절약 할 수있을뿐만 아니라이 포인터는 항상 의도 한 꼭짓점을 가리 킵니다. 정점이 얼마나 자주 변경되는지 포인터가 여전히 동일한 정점을 가리 키기 때문에 삼각형은 변경되지 않으며 업데이트 프로세스가보다 쉽게 ​​처리됩니다. 내가 당신을 혼란스럽게한다면 의심의 여지가 없습니다. 전문가 인 척하지 않고 단지 2 센트를 토론에 던져 넣습니다.


4

C 언어로 된 포인터의 필요성은 여기 에 설명되어 있습니다.

기본 아이디어는 데이터의 메모리 위치를 조작하여 언어의 많은 제한 (예 : 배열, 문자열 사용 및 함수의 여러 변수 수정)을 제거 할 수 있다는 것입니다. 이러한 한계를 극복하기 위해 포인터가 C로 도입되었습니다.

또한 포인터를 사용하면 큰 필드 유형 (예 : 많은 필드가있는 구조)을 함수에 전달하는 경우 코드를 더 빠르게 실행하고 메모리를 절약 할 수 있습니다. 전달하기 전에 이러한 데이터 유형을 복사하면 시간이 걸리고 메모리가 소비됩니다. 이것이 프로그래머가 빅 데이터 유형에 대한 포인터를 선호하는 또 다른 이유입니다.

PS : 샘플 코드에 대한 자세한 설명은 제공된 링크를 참조하십시오 .


질문은 C ++에 관한 것이며,이 답변은 C에 관한 것입니다.
einpoklum

아니요, 질문에 c AND c ++ 태그가 지정되었습니다. c 태그는 관련이 없지만 처음부터 여기에 있습니다.
Jean-François Fabre

3

Java 및 C #에서 모든 객체 참조는 포인터이며, C ++의 점은 포인터 위치를 더 잘 제어 할 수 있다는 것입니다. 큰 힘으로 큰 책임을진다는 것을 기억하십시오.


1

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

사람들이 포인터를 대체하기 위해 일반적으로 사용하는 C ++ 구문의 문제점은 사용하는 툴셋에 따라 크게 달라 지지만, 소스 코드에 대해 필요한 모든 제어권을 가지면 정적 라이브러리를 Visual Studio 2008로 컴파일하는 경우 Visual Studio 2010에서 사용하려고하면 새 프로젝트가 이전 버전과 호환되지 않는 최신 버전의 STL과 연결되어 있기 때문에 많은 링커 오류가 발생합니다. DLL을 컴파일하고 사람들이 다른 툴셋에서 사용하는 가져 오기 라이브러리를 제공하면 상황이 더 나빠질 것입니다.

따라서 한 라이브러리에서 다른 라이브러리로 큰 데이터 세트를 이동하기 위해 다른 사용자가 사용하는 동일한 도구를 사용하지 못하게하려면 데이터를 복사하는 함수에 대한 배열에 대한 포인터를 고려할 수 있습니다. . 이것에 대한 좋은 부분은 C 스타일 배열 일 필요조차 없다는 것입니다. std :: vector를 사용하고 예를 들어 첫 번째 요소 & vector [0]의 주소를 제공하여 포인터를 제공하고 사용할 수 있습니다 std :: vector를 사용하여 배열을 내부적으로 관리합니다.

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


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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.