programing

초보자에게 C 포인터(선언 대 단항 연산자)를 어떻게 설명합니까?

copyandpastes 2022. 7. 17. 23:02
반응형

초보자에게 C 포인터(선언 대 단항 연산자)를 어떻게 설명합니까?

최근 C프로그래밍 초보자에게 포인트에 대해 설명하게 되어 기쁘게 생각합니다만, 다음과 같은 곤란에 부딪힙니다.포인터 사용법을 이미 알고 있다면 전혀 문제가 되지 않을 수 있지만, 다음 예를 명확하게 살펴보십시오.

int foo = 1;
int *bar = &foo;
printf("%p\n", (void *)&foo);
printf("%i\n", *bar);

완전 초보자에게는 놀라운 결과가 나올지도 모른다.2번 줄에서는 막 *bar를 &foo로 선언했는데, 4번 줄에서는 *bar가 &foo가 아니라 실제로 foo라고 합니다!

혼란은 * 기호의 모호함에서 비롯된다고 할 수 있습니다.2행에서는 포인터를 선언하기 위해 사용됩니다.4행에서는 포인터가 가리키는 값을 가져오는 단항 연산자로 사용됩니다.두 가지가 다르죠, 그렇죠?

그러나 이 "설명"은 초보자에게 전혀 도움이 되지 않는다.미묘한 차이를 지적함으로써 새로운 개념을 도입한다.이런 식으로 가르칠 순 없어

커니건과 리치는 어떻게 설명했나요?

단항 연산자 *는 간접 연산자 또는 역참조 연산자입니다. 포인터에 적용하면 포인터가 가리키는 개체에 액세스합니다.[…]

IP ''int *ip는 니모닉을 으로, '으로 되어 있습니다.*ip는 int 입니다.변수의 선언 구문은 변수가 표시될 수 있는구문을 모방합니다.

int *ip.*ip 반환하다int 왜 는 그 않는 그런데 왜 선언 이후의 과제는 그 패턴을 따르지 않는 거죠?초보자가 변수를 초기화하려면 어떻게 해야 합니까? int *ip = 1 (판독:*ip 반환하다intint1하지 않습니다가 예상대로 동작하지 않습니다.개념 모델이 일관성이 없어 보입니다.가가뭘 ?트 ???


편집: 여기답변요약하려고 했습니다.

속기가 다음과 같은 이유:

int *bar = &foo;

이 예에서는, 다음과 같이 잘못 해석하기 쉽기 때문에, 혼란스러울 수 있습니다.

int *bar;
*bar = &foo;    // error: use of uninitialized pointer bar!

실제 의미는 다음과 같습니다.

int *bar;
bar = &foo;

변수 선언과 할당을 분리하여 다음과 같이 작성하면 혼동이 발생하지 않으며, K&R 인용문에 설명된 사용 ↔ 선언 병렬화가 완벽하게 작동합니다.

  • 번째 합니다.bar「」라고 하는 것*bar는 입니다.int.

  • 에는 ''가 할당되어 있습니다.foo로로 합니다.bar, 만들기, 만들기*bar)int의 입니다.foo)int를 참조해 주세요.

초보자에게 C 포인터 구문을 도입할 때는 처음에 포인터 선언을 할당에서 분리하는 이 스타일을 고수하고 C에서의 포인터 사용의 기본 개념이 적절히 내부화된 후에 (혼란 가능성에 대한 적절한 경고와 함께) 조합된 속기 구문을 도입하는 것이 도움이 될 수 있습니다.

선언 부족

선언과 초기화의 차이를 알 수 있어 좋습니다.변수를 유형으로 선언하고 값으로 초기화합니다.두 가지를 동시에 하면 정의라고 부르는 경우가 많습니다.

1. int a; a = 42;

int a;
a = 42;

우리는 선언한다inta라는 이름을 붙였습니다.그런 다음 값을 지정하여 초기화합니다.42.

2. int a = 42;

선언합니다.inta라는 이름을 붙이고 42라는 값을 부여합니다.로 초기화됩니다.42 ★★★★★★ 。

3. a = 43;

우리가 변수를 사용할 때, 우리는 그 변수들을 수술한다고 말한다. a = 43는 할당 조작입니다.43번입니다.

라고 말함으로써

int *bar;

bar가 int에 대한 포인터임을 선언합니다.라고 말함으로써

int *bar = &foo;

바를 선언하고 foo 주소로 초기화합니다.

바를 초기화하면 동일한 연산자 아스타리스크를 사용하여 foo 값에 액세스하여 조작할 수 있습니다.오퍼레이터가 없으면 포인터가 가리키는 주소에 액세스하여 조작합니다.

그 외에도 나는 그림을 말하게 했다.

뭐?

진행 상황을 간략화한 ASCIIMATION(일시정지 등을 원할 경우 플레이어 버전)

          ASCIIMATION

이 ''의 의미를 할 수 있도록 하기 *다른 맥락에서의 기호, 그들은 먼저 그 맥락이 실제로 다르다는 것을 이해해야 한다.일단 그들이 맥락이 다르다는 것을 이해하면(즉, 과제의 왼쪽과 일반적인 표현의 차이) 차이가 무엇인지 이해하는 것은 너무 큰 인지적 비약이 아니다.

선언에 연산자를 할 수 은, 「변수 선언」이 「를.- ★★★★★★★★★★★★★★★★★」+변수 선언의 기호는 단순히 오류를 발생시킵니다).그런 다음 식(예: 할당 오른쪽에 있음)에 연산자가 포함될 수 있음을 보여 줍니다.식과 변수 선언은 완전히 다른 두 가지 맥락이라는 것을 학생들이 이해하도록 합니다.

하면 '어울리다'라고 할 때 '어울리다'라고 수요.*기호는 변수 식별자 앞에 있는 변수 선언에 있으며, '이 변수를 포인터로 지정'을 의미합니다.연산자로 된다, 이렇게 할 수 요.*기호는 '참조 해제 연산자'로, 이전 의미가 아닌 '주소의 값'을 의미합니다.

당신의 학생을 진정으로 납득시키기 위해, C의 창조자들은 디레퍼런스 연산자를 의미하기 위해 어떤 기호도 사용했을 수 있다고 설명합니다.@대신) 어떤 이유로든 설계 결정을 내렸기 때문에*.

대체로 맥락이 다르다는 것을 설명할 방법이 없다.만약 학생이 다른 맥락을 이해하지 못한다면, 그들은 왜 다른 맥락을 이해하지 못하는지 이해할 수 없다.*심볼은 다른 것을 의미할 수 있습니다.

여기에 있는 답변과 코멘트를 보면, 문제의 구문이 초보자에게는 혼란스러울 수 있다는 일반적인 합의가 있는 것 같습니다.이들 대부분은 다음과 같은 방법을 제안합니다.

  • 코드를 표시하기 전에 다이어그램, 스케치 또는 애니메이션을 사용하여 포인터가 어떻게 작동하는지 설명하십시오.
  • 구문을 제시할 때는 아스타리스크 기호의 두 가지 역할을 설명하십시오.많은 튜토리얼이 누락되었거나 해당 부분을 회피하고 있습니다.('초기화된 포인터 선언을 선언과 나중에 할당으로 나눌 때 잊지 말고 *"– comp.lang.c FAQ를 삭제해야 합니다) 다른 접근방식을 찾고 싶었지만, 이것이 최선의 방법인 것 같습니다.

쓰셔도 됩니다.int* bar대신int *bar차이점을 강조합니다.즉, K&R의 「사용을 모방한 선언」의 어프로치가 아니고, Stroustrup C++ 어프로치를 채용합니다.

신고하지 않습니다.*bar정수가 됩니다.선언합니다.bar가 되다int*새로 생성된 변수를 같은 행에서 초기화하려면 다음 문제를 처리하고 있는 것이 분명합니다.bar,것은 아니다.*bar.int* bar = &foo;

결점:

  • 다중 포인터 선언 문제에 대해 학생에게 경고해야 합니다(int* foo, barint *foo, *bar).
  • 상처의 세계에 대비해야 해많은 프로그래머들이 변수 이름 옆에 있는 별표를 보고 싶어하며, 그들은 자신의 스타일을 정당화하기 위해 많은 시간을 필요로 합니다.또한 많은 스타일 가이드가 이 표기법을 명시적으로 적용합니다(Linux 커널 코딩 스타일, NASA C 스타일 가이드 등).

편집: 지금까지 제안되어 온 다른 접근법은 K&R의 "모방적" 방식을 택하는 것이지만, "간단한" 구문(여기 참조)을 사용하지 않는 것입니다.선언과 과제를 같은 줄에서 생략하면 모든 것이 훨씬 더 일관성 있게 보일 것이다.

그러나 조만간 학생들은 포인터를 함수 인수로 다루어야 할 것이다.반환 유형으로서의 포인터.그리고 함수에 대한 포인터.이 두 가지 차이점을 설명해야 합니다.int *func();그리고.int (*func)();조만간 일이 엉망이 될 것 같아요.그리고 어쩌면 빠를지언정 나중보다는 나을지도 모른다.

우주에는 악마가 있는 것 같아요.

(초보자뿐만 아니라 나 자신을 위해서도) int *bar = &foo; 대신 int *bar = &foo; 라고 쓰고 싶다.

이것은 구문과 의미론 사이의 관계가 무엇인지 분명히 할 것이다.

ints는 물체와 플로트 등이라고 설명하겠습니다.포인터는 값이 메모리 내의 주소를 나타내는 오브젝트 유형입니다(따라서 포인터는 기본값이 NULL이 됩니다).

포인터를 처음 선언할 때는 type-pointer-name 구문을 사용합니다.이는 "모든 정수 객체의 주소를 가리킬 수 있는 정수 포인터 착신자 이름"으로 읽힙니다.이 구문은 int를 'int num1'로 선언하는 방법과 마찬가지로 declation 중에만 사용합니다.단, int num1이 아닌 해당 변수를 사용하는 경우에는 'num1'을 사용합니다.

int x = 5; // 값이 5인 정수 개체

int * ptr; // 기본값이 NULL인 정수

오브젝트의 주소를 포인터로 가리키기 위해 "주소"로 읽을 수 있는 "&" 기호를 사용합니다.

ptr = &x; // now value는 'x'의 주소입니다.

포인터는 객체의 주소일 뿐이므로 해당 주소로 유지되는 실제 값을 얻으려면 포인터 앞에 사용할 때 "*" 기호를 사용해야 합니다.

std::cout < * ptr; // 주소의 값을 출력합니다.

'는 다양한 유형의 개체로 다른 결과를 반환하는 'operator'임을 간략하게 설명할 수 있습니다. 포인터와 함께 사용하면 " 연산자는 더 이상 "승수 기준"을 의미하지 않습니다.

이것은 변수에 이름과 값이 있고 포인터에 주소(이름)와 값이 있는 방법을 나타내는 다이어그램을 그리는 데 도움이 되며 포인터의 값이 int의 주소가 되는 것을 나타냅니다.

두 번째 스테이트먼트int *bar = &foo;그림으로 기억하면 다음과 같이 볼 수 있다.

   bar           foo
  +-----+      +-----+
  |0x100| ---> |  1  |
  +-----+      +-----+ 
   0x200        0x100

지금이다bar유형의 포인터입니다.int주소 포함&foo. 단항 연산자 사용*포인터를 사용하여 'foo'에 포함된 값을 검색할 수 있습니다.bar.

편집: 초심자를 대상으로 한 저의 접근법은memory address변수의

Memory Address:모든 변수에는 OS에 의해 제공되는 변수와 관련된 주소가 있습니다.int a;,&a변수 주소입니다.a.

에서 기본 변수 유형에 대한 설명을 계속합니다.C~하듯이,

Types of variables:변수는 각 유형의 값을 포함할 수 있지만 주소는 포함할 수 없습니다.

int a = 10; float b = 10.8; char ch = 'c'; `a, b, c` are variables. 

Introducing pointers:위의 변수와 같이 예를 들어

 int a = 10; // a contains value 10
 int b; 
 b = &a;      // ERROR

할당할 수 있습니다.b = a하지만 아니다b = &a, 이후 변수b값은 유지할 수 있지만 주소는 지정할 수 없습니다.따라서 포인터가 필요합니다.

Pointer or Pointer variables :변수가 주소를 포함하는 경우 이를 포인터 변수라고 합니다.사용하다*선언에서 포인터임을 알립니다.

• Pointer can hold address but not value
• Pointer contains the address of an existing variable.
• Pointer points to an existing variable

K&R스타일이 좋아하는 이유가 있어요.int *p그리고 스트루스트럽 스타일은 호의적이다.int* p; 둘 다 각 언어에서 유효(같은 의미)하지만 Stroustrup의 표현대로라면 다음과 같습니다.

"int*p;"와 "int*p;" 사이의 선택은 옳고 그름이 아니라 스타일과 강조에 관한 것입니다.C는 표현을 강조했다; 선언은 종종 필요악에 지나지 않는다고 여겨졌다.반면 C++는 활자에 큰 비중을 두고 있다.

여기서 C를 가르치려고 하면그 타입의 표현을 좀 더 강조해야 하지만어떤 사람들은 다른 사람보다 더 쉽게 강조점을 찾을 수 있습니다.그것은 언어보다는 그들에 관한 것입니다.

따라서 어떤 사람들은 더 쉽게 시작할 수 있다는 것을 알게 될 것이다.int*다른 것과 다르다int그리고 거기서부터.

만약 누군가가 그것을 보는 방법을 재빨리 찾아낸다면int* bar가지기 위해barint가 아니라 포인터로서int그러면 금방 알 수 있을 거예요*bar한테 무슨 짓을 하고 있bar, 생길 것이다.일단 그걸 했어요 왜 C녹음되가 선호되는 것 나중에 설명할 수 있다.int *bar.

아니면 아닐지도. 만약 모든 사람들 먼저 당신에게 첫번째 장소에서 어떤 문제 없었을 거 이 개념을 이해하는 방법 중의 하나며 가장 훌륭한 길 한 사람에게 그것을 설명하는 것이 반드시 가장 좋은 방법은 다른 그 일을 설명해.

tl;dr:

Q: 초보자에게 C 포인터(선언 대 단항 연산자)를 어떻게 설명합니까?

A: 하지 마세요.초보자에게 포인터를 설명하고 포인터 개념을 C 구문으로 표현하는 방법을 보여줍니다.


최근 C프로그래밍 초보자에게 포인트에 대해 설명하게 되어 기쁘게 생각합니다만, 다음과 같은 곤란에 부딪힙니다.

IMO의 C 구문은 나쁘지는 않지만 훌륭한 것도 아닙니다.이미 포인터를 이해하고 있다면 큰 장애도 아니고 학습에 도움이 되는 것도 아닙니다.

따라서, 우선 포인터에 대해 설명하고, 고객이 실제로 이해하고 있는지 확인합니다.

  • 상자 및 화살표 다이어그램으로 설명합니다.16진수 주소 없이 할 수 있습니다.관련되지 않은 경우 다른 상자 또는 nul 기호를 가리키는 화살표를 표시하기만 하면 됩니다.

  • 의사 코드로 설명합니다.foo의 주소바에 저장된 값을 쓰면 됩니다.

  • 그런 다음 초보자가 포인터가 무엇인지, 그 이유와 사용법을 이해하면 C 구문에 대한 매핑을 보여줍니다.

K&R 텍스트가 개념 모델을 제공하지 않는 이유는 그들이 이미 포인터를 이해하고 있었기 때문이며, 아마도 그 당시 유능한 프로그래머들도 모두 알고 있었을 것이라고 생각합니다.니모닉은 잘 알려진 개념에서 구문에 대한 매핑을 상기시킵니다.

이 문제는 C를 배우기 시작할 때 다소 혼란스럽습니다.

시작하는 데 도움이 될 수 있는 기본 원칙은 다음과 같습니다.

  1. C에는 몇 가지 기본 유형만 있습니다.

    • char: 사이즈가 1바이트인 정수값.

    • short: 사이즈가 2바이트인 정수값.

    • long: 사이즈가 4바이트인 정수값.

    • long long: 사이즈가 8바이트인 정수값.

    • float: 크기가 4바이트인 비표준값.

    • double: 크기가 8바이트인 비표준 값.

    각 유형의 크기는 일반적으로 표준이 아닌 컴파일러에 의해 정의됩니다.

    정수형short,long그리고.long long보통 다음에 이어집니다.int.

    단, 필수는 아닙니다.또, 이 기능을 사용하지 않고,int.

    또는, 다음과 같이 기술할 수 있습니다.int하지만 컴파일러마다 다르게 해석될 수 있습니다.

    요약하면 다음과 같습니다.

    • short와 같다short int하지만 꼭 같은 것은 아니다int.

    • long와 같다long int하지만 꼭 같은 것은 아니다int.

    • long long와 같다long long int하지만 꼭 같은 것은 아니다int.

    • 특정 컴파일러에서는int어느 쪽인가short int또는long int또는long long int.

  2. 특정 유형의 변수를 선언하는 경우 해당 변수를 가리키는 다른 변수를 선언할 수도 있습니다.

    예를 들어 다음과 같습니다.

    int a;

    int* b = &a;

    기본적으로 각 기본 유형에 대응하는 포인터 유형도 있습니다.

    예를 들어 다음과 같습니다.short그리고.short*.

    변수를 "조사"하는 두 가지 방법이 있습니다.b (대부분의 초보자들도 혼란스러울 것이다.)

    • 고려하실 수 있습니다.b활자의 변수로int*.

    • 고려하실 수 있습니다.*b활자의 변수로int.

    그러므로, 어떤 사람들은 선언할 것이다.int* b단, 다른 사람들은 선언합니다.int *b.

    그러나 문제는 이 두 선언이 동일하다는 것이다(공간은 무의미하다).

    둘 중 하나를 사용할 수 있습니다.b정수 값에 대한 포인터 또는*b실제 포인트 정수값으로 표시됩니다.

    포인트 값을 얻을 수 있습니다(읽을 수 있습니다.int c = *b.

    또한 포인트 값을 설정(쓰기)할 수 있습니다.*b = 5.

  3. 포인터는 이전에 선언한 일부 변수의 주소뿐만 아니라 모든 메모리 주소를 가리킬 수 있습니다.단, 포인터를 사용할 때는 포인트의 메모리주소에 있는 값을 취득 또는 설정하려면 주의가 필요합니다.

    예를 들어 다음과 같습니다.

    int* a = (int*)0x8000000;

    여기 변수가 있습니다.a메모리 주소 0x8000000을 가리키고 있습니다.

    이 메모리 주소가 프로그램의 메모리 공간 내에 매핑되지 않은 경우,*a메모리 액세스 위반으로 인해 프로그램이 크래시 될 가능성이 높습니다.

    의 값을 안전하게 변경할 수 있습니다.a, 그러나 당신은 매우 조심해야 합니다.*a.

  4. 유형void*사용할 수 있는 대응하는 「값 타입」이 없는 것은 예외입니다(즉, 선언할 수 없습니다).void a이 타입은 메모리주소에 대한 일반적인 포인터로서만 사용되며, 그 주소에 존재하는 데이터의 타입은 지정하지 않습니다.

조금 더 자세히 살펴보는 것이 더 쉬워질 수 있습니다.

#include <stdio.h>

int main()
{
    int foo = 1;
    int *bar = &foo;
    printf("%i\n", foo);
    printf("%p\n", &foo);
    printf("%p\n", (void *)&foo);
    printf("%p\n", &bar);
    printf("%p\n", bar);
    printf("%i\n", *bar);
    return 0;
}

각 라인에서 예상되는 출력을 알려주고 프로그램을 실행하여 결과를 확인하도록 합니다.고객의 질문에 대해 설명합니다(나체 버전은 확실히 몇 가지 질문을 유도하지만, 스타일, 엄격함, 휴대성에 대해서는 나중에 걱정할 수 있습니다).그 후, 지나친 생각으로 머리가 멍해지기 전에, 혹은 점심 후의 좀비가 되기 전에, 값을 취하는 함수와 포인터를 받는 함수를 써 주세요.

지금까지의 경험으로 보면, 「이렇게 인쇄하는 이유는 무엇입니까?」라고 하는 것을 극복하고, 곧바로 기능 파라메타에 도움이 되는 이유를 실전 조작(스트링 해석이나 배열 처리등의 기본적인 K&R 소재의 서곡으로서)에 의해서 알 수 있습니다.이것에 의해서, 학습은 의미가 있을 뿐만 아니라, 확실히 실현됩니다.

다음 단계는 그들이 당신에게 설명하도록 하는 것입니다.i[0]에 관계하다&i만약 그들이 그렇게 할 수 있다면, 그들은 그것을 잊지 않을 것이고, 당신은 구조물에 대해 이야기하기 시작할 수 있습니다. 조금이라도 빨리, 단지 그것이 받아들여질 수 있도록.

상자와 화살표에 대한 위의 권장 사항도 좋지만, 기억의 원리에 대한 본격적인 논의로 이어질 수도 있습니다.이것은 어느 시점에서 반드시 일어나야 하는 이야기이지만, 바로 눈앞의 포인트인 C의 포인터 표기법을 해석하는 방법에 대해 주의를 분산시킬 수 있습니다.

의 유형 *barint따라서 변수 유형(및 식)barint *변수에는 포인터 타입이 있기 때문에 이니셜라이저에도 포인터 타입이 필요합니다.

포인터 변수 초기화 및 할당 사이에 불일치가 있습니다.그것은 단지 어려운 방법으로 학습해야 할 것입니다.

첫 번째로 읽는 게 낫겠다*에 적용하다.int이상.bar.

int  foo = 1;           // foo is an integer (int) with the value 1
int* bar = &foo;        // bar is a pointer on an integer (int*). it points on foo. 
                        // bar value is foo address
                        // *bar value is foo value = 1

printf("%p\n", &foo);   // print the address of foo
printf("%p\n", bar);    // print the address of foo
printf("%i\n", foo);    // print foo value
printf("%i\n", *bar);   // print foo value
int *bar = &foo;

Question 1: 의 개요bar?

Ans: (입력할) 포인터 변수입니다.int포인터는 유효한 메모리 위치를 가리키고 나중에 단일 연산자를 사용하여 참조 해제(*bar)해야 합니다.*해당 위치에 저장된 값을 읽습니다.

Question 2: 의 개요&foo?

Ans: foo는 유형의 변수입니다.int유효한 메모리 위치와 오퍼레이터로부터 취득한 위치에 저장되어 있습니다.&그래서 지금 우리가 가지고 있는 것은 몇 가지 유효한 메모리 위치입니다.&foo.

즉, 포인터가 필요로 하는 것은 유효한 메모리 위치이며, 그 위치는 다음과 같습니다.&foo초기화는 양호합니다.

포인터bar는 유효한 메모리 위치를 가리키고 있으며, 이 위치에 저장되어 있는 값은 참조 해제일 수 있습니다. *bar

*가 선언과 표현에서 다른 의미를 갖는 초심자를 지적해야 합니다.아시다시피 식 중 *는 단항 연산자이고 * 선언은 연산자가 아니며 단지 타입과 조합하여 컴파일러가 포인터 타입임을 알 수 있는 구문의 일종입니다.초보자라면 '*'의 의미가 다릅니다.*의 의미를 이해하려면 *가 어디에 사용되는지 알아봐야 합니다.

*에는 여러 역할이 있다는 것은 이미 알고 있습니다.

초보자가 사물을 이해하는 데 도움이 될 수 있는 또 다른 간단한 아이디어가 있습니다.

"="에는 여러 가지 역할도 있다고 생각합니다.

할당이 선언과 같은 회선에 사용되는 경우 임의의 할당이 아닌 컨스트럭터 호출로 간주합니다.

표시되는 경우:

int *bar = &foo;

이는 다음과 거의 동등하다고 생각합니다.

int *bar(&foo);

괄호는 별표보다 우선하므로 "&foo"는 "*bar"가 아닌 "bar"에 훨씬 쉽게 귀속됩니다.

구문에 문제가 있는 경우 템플릿/사용 시 동등한 코드를 표시하는 것이 도움이 될 수 있습니다.

template<typename T>
using ptr = T*;

이것은 다음에, 다음과 같이 사용할 수 있습니다.

ptr<int> bar = &foo;

그런 다음 일반/C 구문을 이 C++만의 접근법과 비교합니다.이것은 또한 상수 포인터를 설명하는 데에도 유용합니다.

혼란의 원인은 ...라는 사실에서 비롯된다.*기호는 사용되는 사실에 따라 C에서 다른 의미를 가질 수 있습니다.초보자에게 포인터를 설명하려면*다른 맥락에서 기호를 설명해야 합니다.

선언문에

int *bar = &foo;  

*기호는 간접 연산자아닙니다.대신, 다음 유형의 지정에 도움이 됩니다.bar컴파일러에게 통지하다bar대한 포인터입니다.반면, 스테이트먼트에 표시되는 경우는,*symbol(단항 연산자로 사용되는 경우)은 간접 처리를 수행합니다.따라서 성명서는

*bar = &foo;

주소가 할당되어 있기 때문에 틀릴 수 있습니다.foo라는 취지로bar가리키다, 가리키다bar그 자체입니다.

"아마도 int* 막대로 쓰면 별이 식별자의 일부가 아니라 실제로 그 유형의 일부라는 것을 알 수 있을 것입니다."그래서 나는 한다.그리고 Type처럼 침울하지만 포인터 이름은 하나뿐입니다.

"물론 이로 인해 int* a, b와 같은 의도하지 않은 문제에 직면하게 됩니다."

며칠 전 이 질문을 보고 우연히 바둑 블로그에서 바둑의 활자 선언에 대한 설명을 읽고 있었다.먼저 C타입 선언의 계정을 제공하는 것으로 시작합니다.이것은 이 스레드에 추가할 수 있는 유용한 자원이라고 생각되지만, 이미 더 완전한 답변이 있다고 생각됩니다.

C는 선언 구문에 대해 특이하고 현명한 접근법을 취했습니다.특별한 구문을 사용하여 유형을 설명하는 대신 선언할 항목에 관련된 식을 작성하고 해당 식의 유형을 지정합니다.따라서

int x;

x가 int임을 선언합니다.식 'x'의 타입은 int입니다.일반적으로 새 변수의 유형을 어떻게 써야 하는지 알아보려면 해당 변수가 포함된 식을 기본 유형으로 평가한 다음 기본 유형을 왼쪽에 놓고 식을 오른쪽에 놓습니다.

따라서 선언문은

int *p;
int a[3];

'*p'는 int 타입이므로 p는 int로의 포인터이며, a[3](특정 인덱스 값 포함, 배열의 크기로 판트됨)는 int 타입이므로 a는 int의 배열임을 나타냅니다.

(이러한 이해를 기능 포인터 등으로 확장하는 방법에 대해 설명합니다.

이것은 지금까지 생각해 본 적이 없는 방법입니다만, 구문의 과부하를 설명하는 매우 간단한 방법인 것 같습니다.

여기서는 인간의 논리가 아닌 컴파일러의 논리를 사용하고 이해하고 설명해야 합니다(알겠습니다만, 여기서는 컴퓨터를 모방해야 합니다).

글을 쓸 때

int *bar = &foo;

컴파일러는 다음과 같이 그룹화합니다.

{ int * } bar = &foo;

즉, 여기 새로운 변수가 있습니다.이 변수의 이름은 다음과 같습니다.bar타입은 int로의 포인터이며 초기값은 다음과 같습니다.&foo.

그리고 다음과 같이 추가해야 합니다.=위는 영향이 아닌 초기화를 나타내지만 다음 표현에서는*bar = 2;겉치레다

코멘트당 편집:

주의: 여러 선언이 있을 경우*는 다음 변수에만 관련되어 있습니다.

int *bar = &foo, b = 2;

bar는 foo 주소로 초기화되는 int에 대한 포인터이며, b는 2로 초기화되는 int입니다.

int *bar=&foo, **p = &bar;

bar in still pointer to int, p는 주소 또는 막대로 초기화된 int에 대한 포인터입니다.

기본적으로 포인터는 어레이 표시가 아닙니다.초보자라면 포인터가 배열처럼 생겼다고 생각하기 쉽습니다. 대부분의 문자열 예제는 를 사용합니다.

"char *pstr" 비슷한 모양입니다.

"char str[80]"

단, 중요한 것은 포인터는 컴파일러의 하위 레벨에서는 정수로 취급됩니다.

예를 들어 보겠습니다.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv, char **env)
{
    char str[] = "This is Pointer examples!"; // if we assume str[] is located in 0x80001000 address

    char *pstr0 = str;   // or this will be using with
    // or
    char *pstr1 = &str[0];

    unsigned int straddr = (unsigned int)pstr0;

    printf("Pointer examples: pstr0 = %08x\n", pstr0);
    printf("Pointer examples: &str[0] = %08x\n", &str[0]);
    printf("Pointer examples: str = %08x\n", str);
    printf("Pointer examples: straddr = %08x\n", straddr);
    printf("Pointer examples: str[0] = %c\n", str[0]);

    return 0;
}

이 0x2a6b7ed0은 str[]의 주소입니다.

~/work/test_c_code$ ./testptr
Pointer examples: pstr0 = 2a6b7ed0
Pointer examples: &str[0] = 2a6b7ed0
Pointer examples: str = 2a6b7ed0
Pointer examples: straddr = 2a6b7ed0
Pointer examples: str[0] = T

기본적으로 포인터는 일종의 정수입니다.주소를 표시합니다.

포인터는 주소 저장에 사용되는 변수입니다.

컴퓨터의 메모리는 순차적으로 배열된 바이트(바이트는 8비트로 구성됨)로 구성됩니다.각 바이트에는 배열의 인덱스 또는 첨자와 마찬가지로 바이트 주소라고 하는 번호가 관련되어 있습니다.바이트 주소는 0에서 메모리 크기보다 1 작은 값부터 시작합니다.예를 들어, 64MB의 RAM에는 64 * 2^20 = 67108864 바이트가 있습니다.따라서 이들 바이트의 주소는 0 ~67108863 으로 시작합니다.

enter image description here

변수를 선언하면 어떻게 되는지 살펴보겠습니다.

int 마크

int가 4바이트의 데이터를 점유하고 있는 것을 알고 있기 때문에(32비트 컴파일러를 사용하고 있는 경우), 컴파일러는 정수값을 저장하기 위해 메모리에서4바이트를 연속해서 예약합니다.할당된 4바이트의 첫 번째 바이트 주소는 변수 마크의 주소라고 합니다.4바이트 연속 주소가 5004, 5005, 5006, 5007이라고 하면 변수 마크의 주소는 5004가 됩니다.

포인터 변수 선언

이미 말했듯이 포인터는 메모리 주소를 저장하는 변수입니다.다른 변수와 마찬가지로 포인터 변수를 사용하기 전에 먼저 선언해야 합니다.포인터 변수를 선언하는 방법은 다음과 같습니다.

구문:data_type *pointer_name;

data_type은 포인터의 유형(포인터의 기본 유형이라고도 함)입니다.pointer_name은 변수의 이름으로, 임의의 유효한 C 식별자입니다.

몇 가지 예를 들어보겠습니다.

int *ip;

float *fp;

int *ip은 ip가 int 유형의 변수를 가리킬 수 있는 포인터 변수임을 의미합니다.즉, 포인터 변수 ip는 int형 변수의 주소만 저장할 수 있습니다. 마찬가지로 포인터 변수 fp는 float형 변수의 주소만 저장할 수 있습니다.변수 유형(기본 유형이라고도 함) ip는 int에 대한 포인터이고 fp 유형은 부동 포인터입니다. int에 대한 유형 포인터의 포인터 변수는 기호적으로 (int * )로 나타낼 수 있습니다. 마찬가지로 부동할 유형 포인터의 포인터 변수는 (플로트 * )로 나타낼 수 있습니다.

포인터 변수를 선언한 후 다음 단계는 포인터 변수에 유효한 메모리 주소를 할당하는 것입니다.선언 직후에 가비지 값이 포함되어 메모리의 어느 쪽을 가리키고 있을 가능성이 있기 때문에 포인터 변수를 사용할 때는 반드시 유효한 메모리주소를 할당해 주세요.할당되지 않은 포인터를 사용하면 예기치 않은 결과가 발생할 수 있습니다.프로그램이 크래시 될 수도 있습니다.

int *ip, i = 10;
float *fp, f = 12.2;

ip = &i;
fp = &f;

출처 : Thecguru는 지금까지 내가 발견한 것 중 가장 간단하고 상세한 설명입니다.

언급URL : https://stackoverflow.com/questions/27484168/how-to-explain-c-pointers-declaration-vs-unary-operators-to-a-beginner

반응형