포인터를 사용하는 이유
이것이 정말 기본적인 질문이라는 것을 알지만, 저는 몇 가지 프로젝트를 고급 언어로 코딩한 후 기본적인 C++ 프로그래밍을 시작했습니다.
기본적으로 세 가지 질문이 있습니다.
- 일반 변수보다 포인터를 사용하는 이유는 무엇입니까?
- 포인터는 언제 어디서 사용해야 하나요?
- 어레이에서 포인터를 어떻게 사용합니까?
- 일반 변수보다 포인터를 사용하는 이유는 무엇입니까?
간단한 답변은 다음과 같습니다.하지 마세요;-) 포인터는 다른 것을 사용할 수 없는 경우에 사용합니다.이는 적절한 기능이 부족하거나 데이터 유형이 누락되거나 순수 성능을 위해 발생합니다.더 아래...
- 포인터는 언제 어디서 사용해야 하나요?
간단한 답변은 다음과 같습니다.다른 것은 사용할 수 없는 곳.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* a = "Hello";
int b = 120;
printf("Second char is: %s", b);
이것에 의해, 메모리 주소 120 에 기재되어 있는 모든 것이 인쇄되어 Null 문자가 검출될 때까지 인쇄가 계속됩니다.이 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 를 사용할 수 있지만 그 안에 무엇이 있는지 알 수 없다는 점에 유의하십시오.또, 2개의 printf()에 의해서 다른 주소가 할당되는 경우도 있습니다.메모리의 두 번째 할당이 첫 번째 할당과 같은 공간에서 실행되는 것은 보증되지 않기 때문입니다.
포인터를 사용하는 이유 중 하나는 호출된 함수에서 변수 또는 개체를 수정할 수 있기 때문입니다.
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;
}
- 포인터를 사용하면, 메모리내의 같은 공간을 복수의 장소에서 참조할 수 있습니다.즉, 한 위치에서 메모리를 업데이트할 수 있고 프로그램의 다른 위치에서 변경 내용을 볼 수 있습니다.또한 데이터 구조의 구성요소를 공유할 수 있으므로 공간을 절약할 수 있습니다.
- 주소를 취득해, 메모리내의 특정의 스폿에 전달할 필요가 있는 장소에는, 포인터를 사용할 필요가 있습니다.포인터를 사용하여 어레이를 탐색할 수도 있습니다.
- 배열은 특정 유형을 사용하여 할당된 연속 메모리 블록입니다.어레이 이름에는 어레이의 시작점 값이 포함됩니다.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
각 문자의 값을 취해서 1씩 늘리기 때문입니다.
포인터는 다른 변수에 대한 간접 참조를 얻는 한 가지 방법입니다.변수 값을 유지하는 대신 변수 주소를 알려줍니다.배열의 첫 번째 요소(주소)에 대한 포인터를 사용하면 다음 요소(다음 주소 위치)에 대한 포인터를 증가시켜 다음 요소를 빠르게 찾을 수 있기 때문에 어레이를 다룰 때 특히 유용합니다.
내가 읽은 포인터와 포인터 산술에 대한 최고의 설명은 K&R의 The C Programming Language에 있다.C++ 학습을 시작하기 위한 좋은 책은 C++ Primer입니다.
저도 한번 대답해보겠습니다.
포인터는 참조와 유사합니다.즉, 복사본이 아니라 원래 가치를 참조하는 방법입니다.
무엇보다 포인터를 많이 사용해야 하는 것은 임베디드 하드웨어를 취급하는 경우입니다.디지털 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++는 거의 모든 것을 할 수 있기 때문에 충분히 가능합니다.의도하지 않게 실행하는 것은 더 어려워지고, 의도하지 않은 버그가 얼마나 많은지 알면 놀랄 것입니다.
여기 제 답변서가 있습니다. 전문가가 되겠다고 약속하진 않겠지만, 제가 쓰려고 하는 도서관 중 하나에서 훌륭한 조언들을 찾았습니다.이 라이브러리(OpenGL:-를 사용하는 그래픽 API)에서는 정점 객체가 전달된 삼각형을 만들 수 있습니다.그리기 방법에서는 이러한 삼각형 객체를 사용합니다.내가 만든 정점 객체를 기반으로 그립니다.음, 괜찮아요.
그런데 정점 좌표를 바꾸면 어떻게 되나요?정점 클래스에서 moveX()로 이동하시겠습니까?자, 이제 삼각형을 업데이트해야 합니다. 정점이 이동할 때마다 삼각형을 업데이트해야 하기 때문에 더 많은 메서드와 성능을 추가해야 합니다.아직 별거 아니지만, 그렇게 좋진 않아요.
그럼 그물코에 꼭지점이나 삼각형이 몇 톤이나 있고그물코가 회전하고 움직이면 어떻게 될까요?이러한 정점을 사용하는 모든 삼각형과 장면의 모든 삼각형을 업데이트해야 합니다. 어떤 정점이 사용되는지 알 수 없기 때문입니다.컴퓨터 처리량이 엄청 높네요. 그리고 풍경 위에 메쉬가 여러 개 있으면 오, 세상에!이 꼭지점들은 항상 바뀌기 때문에 거의 모든 삼각형을 업데이트하고 있기 때문에 곤란합니다!
포인터를 사용하면 삼각형을 업데이트할 필요가 없습니다.
삼각형 클래스당 *Vertex 객체가 3개 있는 경우, 수십억 개의 삼각형에는 그 자체로 큰 3개의 정점 객체가 없기 때문에 공간을 절약할 수 있을 뿐만 아니라, 이러한 포인터는 정점이 얼마나 자주 변경되더라도 항상 정점을 가리킵니다.포인터가 같은 정점을 가리키기 때문에 삼각형이 변경되지 않고 업데이트 프로세스가 더 쉽게 처리됩니다.내가 당신을 혼란스럽게 했다면, 의심하지 않을 거예요. 전문가인 척하지 않고, 단지 내 의견을 토론에 쏟아 부을 뿐이에요.
C 언어에서의 포인터의 필요성에 대해서는, 여기서 설명합니다.
기본 개념은 데이터의 메모리 위치를 조작함으로써 언어의 많은 제한(배열, 문자열 사용, 함수 내 여러 변수 수정 등)을 제거할 수 있다는 것입니다.이러한 제한을 극복하기 위해 포인터가 C에 도입되었습니다.
또한 포인터를 사용하면 빅데이터 유형(예를 들어 필드가 많은 구조)을 함수에 전달하는 경우 코드를 더 빠르게 실행하고 메모리를 절약할 수 있습니다.이러한 데이터 타입의 카피를 송신하기 전에 작성하면, 시간이 걸려 메모리가 소비됩니다.프로그래머들이 빅데이터 유형에 대한 포인터를 선호하는 또 다른 이유다.
PS: 샘플 코드와 함께 제공된 링크를 참조하십시오.
포인터는 대부분 어레이(C/C++)입니다.메모리내의 주소이며, 필요에 따라서 어레이와 같이 액세스 할 수 있습니다( 「통상」의 경우).
항목의 주소이므로 크기가 작습니다. 주소 공간만 차지합니다.그들은 작기 때문에 행사에 보내는 것이 싸다.그런 다음 이 기능이 복사본이 아닌 실제 항목에서 작동하도록 허용합니다.
동적 스토리지 할당(예: 링크 목록)을 수행하려면 포인터를 사용해야 합니다. 포인터는 힙에서 메모리를 가져올 수 있는 유일한 방법이기 때문입니다.
왜냐하면 큰 물건을 복사하는 것은 시간과 기억을 낭비하기 때문이다.
C++에서는 서브타입의 다형을 사용하려면 포인터를 사용해야 합니다.이 투고를 참조해 주세요.C++ 포인터가 없는 다형성.
정말, 생각해보면, 이건 말이 돼요.서브타입 다형성을 사용할 경우 실제 클래스가 무엇인지 모르기 때문에 최종적으로 어떤 클래스 또는 서브클래스의 메서드 구현이 호출될지 미리 알 수 없습니다.
알 수 없는 클래스의 개체를 유지하는 변수를 갖는다는 이 생각은 할당된 공간의 양이 클래스에 직접 대응하는 스택에 개체를 저장하는 C++의 기본(포인트 없음) 모드와 호환되지 않습니다.주의: 클래스에 인스턴스 필드가 3개가 아닌 5개일 경우 더 많은 공간을 할당해야 합니다.
Note that if you are using '&' to pass arguments by reference, indirection (i.e., pointers) is still involved behind the scenes. The '&' is just syntactic sugar that (1) saves you the trouble of using pointer syntax and (2) allows the compiler to be more strict (such as prohibiting null pointers).
두 번째 질문입니다만, 일반적으로 프로그래밍을 할 때는 포인터를 사용할 필요가 없지만, 공개 API를 만드는 경우는 예외입니다.
사람들이 포인터를 대체하기 위해 일반적으로 사용하는 C++ 구조의 문제는 사용하는 툴셋에 따라 크게 달라지는데, 소스 코드에 필요한 모든 제어가 있으면 문제 없습니다.그러나 예를 들어 Visual Studio 2008을 사용하여 정적 라이브러리를 컴파일하여 Visual Studio 2010에서 사용하려고 하면 링커 er를 많이 얻을 수 있습니다.새 프로젝트가 이전 버전과 호환되지 않는 최신 버전의 STL과 연결되었기 때문에 이 오류가 발생합니다.DLL을 컴파일하여 다른 툴셋에서 사용하는 Import 라이브러리를 지정하면 프로그램이 뚜렷한 이유 없이 조만간 크래시되기 때문에 상황은 더욱 악화됩니다.
따라서 대용량 데이터 세트를 라이브러리에서 다른 라이브러리로 이동할 때 사용하는 것과 동일한 도구를 다른 사람에게 강제로 사용하지 않으려면 데이터를 복사해야 하는 기능에 대한 포인터를 어레이에 제공하는 것이 좋습니다.여기서 좋은 점은 C스타일의 배열일 필요도 없고 std::벡터를 사용하여 예를 들어 첫 번째 요소의 &vector[0] 주소를 지정하여 포인터를 제공하고 std:벡터를 사용하여 어레이를 내부적으로 관리할 수 있다는 것입니다.
C++에서 포인터를 다시 사용하는 또 다른 좋은 이유는 라이브러리와 관련되므로 프로그램 실행 시 로드할 수 없는 dll을 갖는 것을 고려하십시오.따라서 Import 라이브러리를 사용하면 의존성이 충족되지 않고 프로그램이 크래시됩니다.예를 들어 어플리케이션과 함께 dll에 퍼블릭 API를 지정하고 다른 어플리케이션에서 액세스하려는 경우입니다.이 경우 API를 사용하려면 dll을 해당 위치에서 로드하고(일반적으로 레지스트리 키에 있음), 함수 포인터를 사용하여 DLL 내의 함수를 호출할 수 있어야 합니다.때때로 API를 만드는 사람들은 도우미 함수를 포함한 .h 파일을 제공하기에 충분하지만 이 프로세스를 자동화하기 위해 필요한 모든 함수 포인터를 제공합니다.그러나 그렇지 않은 경우 Windows에서는 LoadLibrary와 GetProcAddress를 사용하고 UNIX에서는 dlopen과 dlsym을 사용하여 그것들을 얻을 수 있습니다(fu의 전체 시그니처를 알고 있는 것을 고려).네이션)
- 경우에 따라 공유 라이브러리(.)에 있는 함수를 사용하려면 함수 포인터가 필요합니다.DLL 또는 .so).여기에는 DLL 인터페이스가 제공되는 여러 언어로 작업이 포함됩니다.
- 컴파일러 만들기
- 함수 포인터의 배열, 벡터 또는 문자열 맵을 가지고 있는 과학적 계산기를 만들고 있습니까?
- 비디오 메모리를 직접 수정하여 독자적인 그래픽 패키지를 만듭니다.
- API 만들기!
- 데이터 구조 - 만들고 있는 특수 트리의 노드 링크 포인터
포인터에는 많은 이유가 있습니다.언어 간 호환성을 유지하려면 DLL에서 특히 C 이름 망글링을 사용하는 것이 중요합니다.
변수보다 포인터를 사용하는 한 가지 방법은 중복 메모리를 제거하는 것입니다.예를 들어, 크고 복잡한 객체가 있는 경우 포인터를 사용하여 각 참조에 대해 해당 변수를 가리킬 수 있습니다.변수를 사용하여 각 복사본에 대해 메모리를 복제해야 합니다.
포인터의 한 가지 용도(다른 사람의 투고에 이미 기재되어 있는 것은 언급하지 않습니다)는 할당하지 않은 메모리에 액세스 하는 것입니다.이것은 PC 프로그래밍에서는 그다지 유용하지 않지만 메모리 매핑 하드웨어 디바이스에 액세스하기 위한 임베디드 프로그래밍에서 사용됩니다.
옛날 DOS에서는 다음과 같은 포인터를 선언함으로써 비디오 카드의 비디오 메모리에 직접 액세스 할 수 있었습니다.
unsigned char *pVideoMemory = (unsigned char *)0xA0000000;
많은 임베디드 디바이스는 여전히 이 기술을 사용합니다.
여기에서는 C의 많은 기능이 의미가 있는 이유에 대해 조금 다르지만 통찰력 있는 견해를 제시합니다.http://steve.yegge.googlepages.com/tour-de-babel#C
기본적으로 표준 CPU 아키텍처는 Von Neumann 아키텍처입니다.메모리 내의 데이터 항목의 위치를 참조해, 그것을 사용해 계산을 실시하는 것은 매우 편리합니다.어셈블리 언어의 배리언트를 알고 있는 경우는, 이것이 저레벨에서 얼마나 중요한지를 금방 알 수 있습니다.
C++는 때때로 포인터를 관리하고 "참조"의 형태로 그 효과를 숨기기 때문에 포인터를 약간 혼란스럽게 만든다.스트레이트 C를 사용하는 경우 포인터의 필요성은 훨씬 더 명확해집니다.즉, 참조에 의한 콜의 실행은 다른 방법이 없고, 문자열을 저장하는 가장 좋은 방법이며, 어레이를 통해 반복하는 가장 좋은 방법입니다.
포인터는 하나의 "노드"를 다른 "노드"에 효율적으로 연결하거나 체인으로 연결하는 능력을 필요로 하는 많은 데이터 구조에서 중요하다.float와 같은 일반 데이터 유형보다 포인터를 "선택"할 수 없습니다. 두 데이터 유형에는 용도가 다를 뿐입니다.
포인터는 고성능 및/또는 콤팩트한 메모리 설치 공간이 필요한 경우에 유용합니다.
배열의 첫 번째 요소의 주소를 포인터에 할당할 수 있습니다.그러면 할당된 기본 바이트에 직접 액세스할 수 있습니다.어레이의 요점은 이 작업을 수행할 필요가 없도록 하는 것입니다.
java 및 C#에서는 모든 오브젝트 참조가 포인터입니다.c++에서는 포인터 위치를 보다 확실하게 제어할 수 있습니다.기억하라 큰 힘에는 큰 책임이 따른다.
언급URL : https://stackoverflow.com/questions/162941/why-use-pointers
'source' 카테고리의 다른 글
| 오류: Java: 잘못된 대상 릴리스: 11 - IntelliJ IDEA (0) | 2022.07.17 |
|---|---|
| 자바에서는 언제 varargs를 사용합니까? (0) | 2022.07.17 |
| vuetify에서 vuelidate 검증 관리 (0) | 2022.07.17 |
| vue - 최신 하위 경로 제거 (0) | 2022.07.17 |
| 비동기적이고 순차적으로 Vuex 작업 실행 - 이해가 안 되는 부분은 무엇입니까? (0) | 2022.07.17 |