초보자에게 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 행에서 포인터가 가리키는 값을 가져 오는 단항 연산자로 사용됩니다. 다른 두 가지가 맞습니까?
그러나이 "설명"은 초보자에게 전혀 도움이되지 않습니다. 미묘한 차이를 지적함으로써 새로운 개념을 소개합니다. 이것을 가르치는 올바른 방법이 될 수 없습니다.
Kernighan과 Ritchie는 어떻게 설명했습니까?
단항 연산자 *는 간접 또는 역 참조 연산자입니다. 포인터에 적용되면 포인터가 가리키는 객체에 액세스합니다. […]
포인터 ip의 선언은
int *ip
니모닉으로 만들어졌습니다. 그것은 표현*ip
이 정수 라고 말합니다 . 변수 선언 구문은 변수가 나타날 수있는 표현식 구문과 유사합니다 .
int *ip
"" *ip
를 반환하는 것처럼 읽을 int
까요? 그런데 왜 선언 후 과제가 그 패턴을 따르지 않습니까? 초보자가 변수를 초기화하려면 어떻게해야합니까? int *ip = 1
(읽기 : *ip
는를 반환 int
하고 int
is는 1
) 예상대로 작동하지 않습니다. 개념적 모델은 일관된 것처럼 보이지 않습니다. 여기에 뭔가 빠졌습니까?
학생들이 *
다른 상황 에서 상징 의 의미를 이해 하려면 먼저 상황이 실제로 다르다는 것을 이해해야합니다. 일단 문맥이 다르다는 것을 이해하면 (즉, 과제의 왼쪽과 일반 표현의 차이) 차이가 무엇인지 이해하기에는 너무 큰인지 적 도약이 아닙니다.
먼저 변수 선언에 연산자를 포함 할 수 없다고 설명하십시오 ( 변수 선언에 -
또는 +
기호 를 넣으면 단순히 오류가 발생 함 을 보여줌 ). 그런 다음 표현식 (예 : 할당의 오른쪽)에 연산자가 포함될 수 있음을 보여줍니다. 학생이 표현식과 변수 선언이 완전히 다른 상황이라는 것을 이해하도록하십시오.
문맥이 다르다는 것을 이해하면 *
기호가 변수 식별자 앞에 변수 선언에 있을 때 '이 변수를 포인터로 선언'을 의미 한다고 설명 할 수 있습니다 . 그런 다음 표현식에서 단항 연산자로 사용될 때 *
기호는 '역 참조 연산자'이며 이전 의미가 아니라 '주소의 값'을 의미 한다고 설명 할 수 있습니다 .
학생을 진정으로 확신시키기 위해 C의 제작자는 역 참조 연산자를 의미하는 기호를 사용할 수 있었지만 (즉, @
대신 사용할 수 있음 ) 어떤 이유로 든 디자인 사용을 결정했다고 설명합니다 *
.
대체로 상황이 다르다는 것을 설명 할 방법이 없습니다. 학생이 상황이 다르다는 것을 이해하지 못하면 그 *
상징이 다른 것을 의미 하는 이유를 이해할 수 없습니다 .
속기 이유 :
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
(ANint
)에 대한 별칭foo
(도를int
).
초보자에게 C 포인터 구문을 도입 할 때는 처음에 이러한 스타일의 포인터 선언을 지정에서 분리하고, 포인터의 기본 개념이 일단 사용되면 혼동 가능성에 대한 적절한 경고와 함께 결합 된 속기 구문 만 소개하는 것이 도움이 될 수 있습니다. C는 충분히 내재화되었습니다.
선언의 부족
선언과 초기화의 차이점을 아는 것이 좋습니다. 변수를 타입으로 선언하고 값으로 초기화합니다. 동시에 둘 다하면 정의라고합니다.
1.
int a; a = 42;
int a;
a = 42;
우리는 선언int
이름 을 . 그런 다음 값을 지정하여 초기화합니다 42
.
2.
int a = 42;
우리는 선언 과 int
이름 을 하고 그것에게 그것은으로 초기화되는 값 (42)을 제공합니다 42
. 정의.
3.
a = 43;
우리가 변수를 사용할 때 우리는 그 변수를 조작 한다고 말합니다 . a = 43
할당 작업입니다. 변수 43에 숫자 43을 할당합니다.
말함으로써
int *bar;
bar 를 int에 대한 포인터로 선언 합니다 . 말함으로써
int *bar = &foo;
bar 를 선언 하고 foo 주소로 초기화합니다 .
bar 를 초기화 한 후에는 동일한 연산자 인 별표를 사용하여 foo 값에 액세스하고 작동 할 수 있습니다 . 운영자가 없으면 포인터가 가리키는 주소를 액세스하고 조작합니다.
그 외에도 나는 그림을 말하게했다.
뭐
무슨 일이 일어나고 있는지에 대한 간단한 ASCIIMATION. (여기서 일시 중지하려는 플레이어 버전 )
두 번째 진술 int *bar = &foo;
은 다음과 같이 메모리에서 그림으로 볼 수 있습니다.
bar foo
+-----+ +-----+
|0x100| ---> | 1 |
+-----+ +-----+
0x200 0x100
이제 주소 가 포함 된 bar
유형의 포인터 입니다 . 단항 연산자 를 사용하면 pointer를 사용하여 'foo'에 포함 된 값을 검색하는 것을 연기합니다 .int
&
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
여기에 대한 답변과 의견을 보면 문제의 구문이 초보자에게 혼란을 줄 수 있다는 일반적인 합의가있는 것 같습니다. 그들 대부분은 다음 라인을 따라 무언가를 제안합니다.
- 코드를 표시하기 전에 다이어그램, 스케치 또는 애니메이션을 사용하여 포인터 작동 방식을 설명하십시오.
- 구문을 제시 할 때 별표 기호의 두 가지 역할을 설명하십시오 . 많은 튜토리얼에서 해당 부분이 누락되거나 회피됩니다. 혼란이 뒤 따릅니다 ( "초기화 포인터 선언을 선언과 나중 과제로 나눌 때 *를 제거해야합니다."– comp.lang.c FAQ ) 대체 방법을 찾고 싶었지만 이것이 다음과 같습니다. 가는 길.
차이점을 강조하기 위해 int* bar
대신 쓸 수 있습니다 int *bar
. 이는 K & R "선언 모방 사용"접근 방식을 따르지 않지만 Stroustrup C ++ 접근 방식을 따르지 않음을 의미합니다 .
*bar
정수로 선언하지 않습니다 . 우리는로 선언 bar
합니다 int*
. 같은 줄에서 새로 생성 된 변수를 초기화하려면 bar
, 아닌을 다루는 것이 분명합니다 *bar
.int* bar = &foo;
단점 :
- 다중 포인터 선언 문제 (
int* foo, bar
vsint *foo, *bar
)에 대해 학생에게 경고해야합니다 . - 당신은 상처 의 세계 를 위해 그들을 준비해야합니다 . 많은 프로그래머들은 변수 이름 옆에 별표가 표시되기를 원하며 스타일을 정당화하기 위해 많은 시간이 걸릴 것입니다. 그리고 많은 스타일 가이드가이 표기법을 명시 적으로 적용합니다 (Linux 커널 코딩 스타일, NASA C 스타일 가이드 등).
편집 : 제안 된 다른 접근 방식 은 K & R "mimic"방법을 사용하지만 "shortshort"구문을 사용하지 않는 것입니다 ( 여기 참조 ). 같은 줄에서 선언과 할당 을 생략 하자마자 모든 것이 훨씬 더 일관성있게 보일 것입니다.
그러나 조만간 학생은 포인터를 함수 인수로 다루어야합니다. 그리고 리턴 타입으로서의 포인터. 그리고 함수를 가리키는 포인터. 당신은 사이의 차이를 설명해야합니다 int *func();
및 int (*func)();
. 조만간 문제가 발생할 것이라고 생각합니다. 아마 나중이 빠를수록 좋습니다.
K & R 스타일이 선호 int *p
되고 Stroustrup 스타일이 선호 되는 이유가 있습니다 int* p
. 둘 다 각 언어에서 유효하며 같은 의미이지만 Stroustrup이 다음과 같이 말합니다.
"int * p;"중에서 선택 그리고 "int * p;" 옳고 그름에 관한 것이 아니라 스타일과 강조에 관한 것입니다. C는 표현을 강조했다; 선언은 종종 필요한 악에 지나지 않습니다. 반면에 C ++은 유형에 중점을 둡니다.
자, 여기서 C를 가르치려고 노력하고 있기 때문에, 당신은 그 유형보다 표현을 강조해야한다는 것을 암시 할 것입니다. 그러나 어떤 사람들은 다른 사람보다 한 가지 강조점을 더 빨리 잡을 수 있습니다.
따라서 어떤 사람들int*
은 a가 다른 것과 다르다는 생각으로 시작하기가 더 쉽다는 것을 알게 될 것 int
입니다.
누군가가 빠르게 용도가 그것을보고의 방법 grok 수없는 경우 int* bar
가지고 bar
있는 int가 아닌 것 같은,하지만에 대한 포인터를 int
, 그들은 신속하게이 볼 수 *bar
있다 뭔가 일 까지를 bar
, 나머지는 따를 것이다. 일단 그렇게하면 나중에 C 코더가 선호하는 이유를 나중에 설명 할 수 있습니다 int *bar
.
아님 모든 사람이 먼저 개념을 이해하는 한 가지 방법이 있다면 처음에는 아무런 문제가 없었을 것입니다. 한 사람에게 개념을 설명하는 가장 좋은 방법은 다른 사람에게 그것을 설명하는 가장 좋은 방법은 아닙니다.
tl; dr :
Q : 초보자에게 C 포인터 (선언 대 단항 연산자)를 설명하는 방법은 무엇입니까?
A :하지 마십시오. 초보자를위한 포인터를 설명하고 C 구문으로 포인터 개념을 나타내는 방법을 보여줍니다.
나는 C 프로그래밍 초보자에게 포인터를 설명하는 데 최근에 기쁨을 느꼈으 며 다음과 같은 어려움에 부딪쳤다.
C 구문 IMO는 끔찍하지는 않지만 훌륭하지도 않습니다. 포인터를 이미 이해하고 있거나 배우는 데 도움이된다면 큰 방해가되지 않습니다.
따라서 포인터를 설명하는 것으로 시작하여 실제로 이해해야합니다.
상자와 화살표 다이어그램으로 설명하십시오. 16 진수 주소가 없으면 관련이없는 경우 다른 상자 또는 Nul 기호를 가리키는 화살표를 표시하십시오.
의사와 설명 : 그냥 쓰기 foo는 주소 및 바에서 저장된 값을 .
그런 다음 초보자가 포인터가 무엇인지, 그리고 왜, 어떻게 사용하는지 이해하면; 그런 다음 C 구문에 대한 매핑을 보여줍니다.
나는 K & R 텍스트가 개념적 모델을 제공하지 않는 이유는 그들이 이미 포인터를 이해 했기 때문이며 아마도 당시의 다른 모든 유능한 프로그래머도 그랬다고 가정했을 것입니다. 니모닉은 잘 이해 된 개념에서 구문으로의 매핑을 상기시켜줍니다.
이 문제는 C를 배우기 시작할 때 다소 혼란 스럽다.
시작하는 데 도움이되는 기본 원칙은 다음과 같습니다.
C에는 몇 가지 기본 유형 만 있습니다.
char
: 1 바이트 크기의 정수 값.short
: 2 바이트 크기의 정수 값.long
: 크기가 4 바이트 인 정수 값.long long
: 8 바이트 크기의 정수 값.float
: 크기가 4 바이트 인 정수가 아닌 값.double
: 8 바이트 크기의 정수가 아닌 값.
각 유형의 크기는 일반적으로 표준이 아닌 컴파일러에 의해 정의됩니다 .
정수 유형
short
,long
및long long
일반적으로 다음에 있습니다int
.그러나 반드시 필요한 것은 아니며
int
. 없이 사용할 수 있습니다 .또는 state 만 할 수는
int
있지만 컴파일러마다 다르게 해석 될 수 있습니다.이를 요약하면 다음과 같습니다.
short
와 동일short int
하지만 반드시 동일 하지는 않습니다int
.long
와 동일long int
하지만 반드시 동일 하지는 않습니다int
.long long
와 동일long long int
하지만 반드시 동일 하지는 않습니다int
.주어진 컴파일러에서
int
중 하나입니다short int
또는long int
나long long int
.
어떤 유형의 변수를 선언하면 해당 변수를 가리키는 다른 변수를 선언 할 수도 있습니다.
예를 들면 다음과 같습니다.
int a;
int* b = &a;
본질적으로 각 기본 유형마다 해당 포인터 유형이 있습니다.
예를 들면 다음
short
과 같습니다short*
.변수를 "보는"방법에는 두 가지가 있습니다
b
(아마도 초보자에게 혼란을 줄 수 있습니다) .b
유형의 변수로 간주 할 수 있습니다int*
.*b
유형의 변수로 간주 할 수 있습니다int
.
따라서 어떤 사람들은 선언
int* b
하고 다른 사람들은 선언int *b
합니다.그러나 문제의 사실은이 두 선언이 동일하다는 것입니다 (공백은 의미가 없습니다).
당신이 중 하나를 사용할 수있는
b
정수 값에 대한 포인터로, 또는*b
실제 뾰족한 정수 값으로.뾰족한 값을 얻을 수 있습니다 :
int c = *b
.그리고 지정된 값을 설정 (쓰기) 할 수 있습니다
*b = 5
.포인터는 이전에 선언 한 일부 변수의 주소뿐만 아니라 모든 메모리 주소를 가리킬 수 있습니다. 그러나 지정된 메모리 주소에있는 값을 가져 오거나 설정하려면 포인터를 사용할 때주의해야합니다.
예를 들면 다음과 같습니다.
int* a = (int*)0x8000000;
여기에는
a
메모리 주소 0x8000000을 가리키는 변수가 있습니다 .이 메모리 주소가 프로그램의 메모리 공간 내에 매핑되지 않으면
*a
, 메모리 액세스 위반으로 인해 사용하는 모든 읽기 또는 쓰기 작업 으로 인해 프로그램이 중단 될 수 있습니다.의 값을 안전하게 변경할 수
a
있지만의 값을 변경하는 데 매우주의해야합니다*a
.유형
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;
}
그들이 각 라인에 출력이 될 것으로 예상 한 것을 알려주고, 프로그램을 실행하고 무엇이 나오는지 확인하게하십시오. 그들의 질문을 설명하십시오 (알몸 버전은 확실히 몇 가지를 요구하지만 나중에 스타일, 엄격 성 및 이식성에 대해 걱정할 수 있습니다). 그런 다음, 그들의 생각이 지나친 생각에서 흐릿 해 지거나 점심 식사 후 좀비가되기 전에 값을 취하는 함수와 포인터를 취하는 동일한 함수를 작성하십시오.
내 경험상 "이런 식으로 인쇄되는 이유는 무엇입니까?" 험프 (Hump)를 누른 다음 , 수업이 이해하기 쉬울뿐 아니라 스틱 잉 / 배열 처리와 같은 기본 K & R 자료의 전제로 실습을 통해 기능 매개 변수에 유용한 이유 를 즉시 보여줍니다.
다음 단계에 설명을 얻는 것입니다 당신이 방법 i[0]
에 관한 것이다 &i
. 그들이 그렇게 할 수 있다면, 그들은 그것을 잊지 않을 것이고, 당신은 구조체에 대해 조금이라도 미리 이야기 할 수 있습니다.
상자와 화살표에 대한 위의 권장 사항도 좋지만 메모리가 어떻게 작동하는지에 대한 완전한 토론으로 빠져 나올 수 있습니다. 이는 어떤 시점에서 발생해야하지만 즉시 당장 방해 할 수있는 대화입니다. : C에서 포인터 표기법을 해석하는 방법
표현식 의 유형 *bar
은 int
; 따라서 변수 (및 표현식) 의 유형은 bar
입니다 int *
. 변수에는 포인터 유형이 있으므로 초기화 프로그램에도 포인터 유형이 있어야합니다.
포인터 변수 초기화와 할당 사이에 불일치가 있습니다. 그것은 어려운 방법으로 배워야 할 것입니다.
개 이상에 *
적용 되는 첫 번째로 읽으십시오 .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;
이것은 구문과 시맨틱 사이의 관계가 무엇인지 분명해야합니다.
이미 여러 가지 역할이 있다는 점에 주목했다.
초보자가 물건을 이해하는 데 도움이되는 또 다른 간단한 아이디어가 있습니다.
"="에는 여러 역할이 있다고 생각하십시오.
할당이 선언과 같은 줄에 사용될 때는 임의의 할당이 아니라 생성자 호출로 생각하십시오.
당신이 볼 때 :
int *bar = &foo;
거의 다음과 같습니다.
int *bar(&foo);
괄호는 별표보다 우선하므로 "& foo"는 "* bar"보다는 "bar"에 훨씬 더 직관적으로 귀속됩니다.
문제가 구문 인 경우 템플릿 / 사용시 동등한 코드를 표시하는 것이 도움이 될 수 있습니다.
template<typename T>
using ptr = T*;
이것은 다음과 같이 사용될 수 있습니다
ptr<int> bar = &foo;
그런 다음 일반 / C 구문을이 C ++ 전용 방법과 비교하십시오. const 포인터를 설명 할 때도 유용합니다.
혼란의 원인은 *
기호가 사용되는 사실에 따라 기호가 C에서 다른 의미를 가질 수 있다는 사실에서 발생합니다. 초보자를위한 포인터를 설명하기 위해, *
다른 맥락에서 의 기호 의 의미를 설명해야합니다.
선언에서
int *bar = &foo;
*
심볼은 간접 연산자하지 . 대신 bar
컴파일러 bar
에 대한 포인터int
임을 알리는 유형을 지정하는 데 도움이됩니다 . 반면, 명령문에 *
표시 될 때 기호 ( 단항 연산자 로 사용되는 경우 )는 간접 처리를 수행합니다. 따라서 진술
*bar = &foo;
자체가 아닌 foo
객체에 주소를 할당하기 때문에 잘못되었습니다 .bar
bar
"int * 막대로 작성하면 별이 실제로 식별자의 일부가 아닌 유형의 일부라는 것이 더 분명해집니다." 그래서 그렇습니다. 그리고 Type과 비슷하지만 하나의 포인터 이름에만 해당됩니다.
"물론 이것은 int * a, b와 같은 직관적이지 않은 것들에 대해 다른 문제를 야기합니다."
나는 며칠 전에이 질문을 보았고 Go 블로그에서 Go의 유형 선언에 대한 설명을 읽었습니다 . C 형 선언을 설명하는 것으로 시작합니다.이 답변은 이미 완료된 답변이 더 있다고 생각 하더라도이 스레드에 추가하는 데 유용한 리소스처럼 보입니다.
C는 선언 구문에 대해 독특하고 영리한 접근 방식을 취했습니다. 특별한 구문으로 타입을 설명하는 대신, 선언 될 아이템과 관련된 표현식을 작성하고 그 표현식이 어떤 타입을 가질 것인지를 명시합니다. 그러므로
int x;
x를 int로 선언합니다. 표현식 'x'는 int 유형을 갖습니다. 일반적으로 새 변수의 유형을 작성하는 방법을 알아 보려면 기본 유형으로 평가되는 해당 변수와 관련된 표현식을 작성한 다음 기본 유형을 왼쪽에, 표현식을 오른쪽에 놓으십시오.
따라서 선언
int *p; int a[3];
'* p'는 int 타입을 가지고 있기 때문에 p는 int를 가리키는 포인터이고 a [3] (어레이의 크기로 펀칭 된 특정 인덱스 값은 무시)이 타입을 가지고 있기 때문에 a는 int 배열입니다 int.
(이 포인터를 함수 포인터 등으로 확장하는 방법을 설명합니다.)
이것은 내가 전에 생각하지 않은 방법이지만 구문의 과부하를 설명하는 매우 간단한 방법처럼 보입니다.
Here you have to use, understand and explain the compiler logic, not the human logic (I know, you are a human, but here you must mimic the computer ...).
When you write
int *bar = &foo;
the compiler groups that as
{ int * } bar = &foo;
That is : here is a new variable, its name is bar
, its type is pointer to int, and its initial value is &foo
.
And you must add : the =
above denotes an initialization not an affectation, whereas in following expressions *bar = 2;
it is an affectation
Edit per comment:
Beware : in case of multiple declaration the *
is only related to the following variable :
int *bar = &foo, b = 2;
bar is a pointer to int initialized by the address of foo, b is an int initialized to 2, and in
int *bar=&foo, **p = &bar;
bar in still pointer to int, and p is a pointer to a pointer to an int initialized to the address or bar.
Basically Pointer is not a array indication. Beginner easily thinks that pointer looks like array. most of string examples using the
"char *pstr" it's similar looks like
"char str[80]"
But, Important things , Pointer is treated as just integer in the lower level of compiler.
Let's look examples::
#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;
}
Results will like this 0x2a6b7ed0 is address of 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
So, Basically, Keep in mind Pointer is some kind of Integer. presenting the Address.
I would explain that ints are objects, as are floats etc. A pointer is a type of object whose value represents an address in memory ( hence why a pointer defaults to NULL ).
When you first declare a pointer you use the type-pointer-name syntax. It's read as an "integer-pointer called name that can point to the address of any integer object". We only use this syntax during decleration, similar to how we declare an int as 'int num1' but we only use 'num1' when we want to use that variable, not 'int num1'.
int x = 5; // an integer object with a value of 5
int * ptr; // an integer with a value of NULL by default
To make a pointer point to an address of an object we use the '&' symbol which can be read as "the address of".
ptr = &x; // now value is the address of 'x'
As the pointer is only the address of the object, to get the actual value held at that address we must use the '*' symbol which when used before a pointer means "the value at the address pointed to by".
std::cout << *ptr; // print out the value at the address
You can explain briefly that '' is an 'operator' that returns different results with different types of objects. When used with a pointer, the '' operator doesn't mean "multiplied by" anymore.
It helps to draw a diagram showing how a variable has a name and a value and a pointer has an address (the name) and a value and show that the value of the pointer will be the address of the int.
A pointer is just a variable used to store addresses.
Memory in a computer is made up of bytes (A byte consists of 8 bits) arranged in a sequential manner. Each byte has a number associated with it just like index or subscript in an array, which is called the address of the byte. The address of byte starts from 0 to one less than size of memory. For example, say in a 64MB of RAM, there are 64 * 2^20 = 67108864 bytes . Therefore the address of these bytes will start from 0 to 67108863 .
Let’s see what happens when you declare a variable.
int marks;
As we know an int occupies 4 bytes of data (assuming we are using a 32-bit compiler) , so compiler reserves 4 consecutive bytes from memory to store an integer value. The address of the first byte of the 4 allocated bytes is known as the address of the variable marks . Let’s say that address of 4 consecutive bytes are 5004 , 5005 , 5006 and 5007 then the address of the variable marks will be 5004 .
Declaring pointer variables
As already said a pointer is a variable that stores a memory address. Just like any other variables you need to first declare a pointer variable before you can use it. Here is how you can declare a pointer variable.
Syntax: data_type *pointer_name;
data_type is the type of the pointer (also known as the base type of the pointer). pointer_name is the name of the variable, which can be any valid C identifier.
Let’s take some examples:
int *ip;
float *fp;
int *ip means that ip is a pointer variable capable of pointing to variables of type int . In other words, a pointer variable ip can store the address of variables of type int only . Similarly, the pointer variable fp can only store the address of a variable of type float . The type of variable (also known as base type) ip is a pointer to int and type of fp is a pointer to float . A pointer variable of type pointer to int can be symbolically represented as ( int * ) . Similarly, a pointer variable of type pointer to float can be represented as ( float * )
포인터 변수를 선언 한 후 다음 단계는 유효한 메모리 주소를 할당하는 것입니다. 선언 직후에는 가비지 값이 포함되어 메모리의 아무 곳이나 가리킬 수 있으므로 유효한 메모리 주소를 할당하지 않고 포인터 변수를 사용해서는 안됩니다. 할당되지 않은 포인터를 사용하면 예기치 않은 결과가 발생할 수 있습니다. 심지어 프로그램이 중단 될 수도 있습니다.
int *ip, i = 10;
float *fp, f = 12.2;
ip = &i;
fp = &f;
출처 : thecguru 는 지금까지 내가 찾은 가장 간단하지만 자세한 설명입니다.
'Programing' 카테고리의 다른 글
IE 8 : 배경 크기 수정 (0) | 2020.06.22 |
---|---|
노드에서 stdin을 한 줄씩 읽는 방법 (0) | 2020.06.22 |
$ routeParams가 해결 기능에서 작동하지 않습니다 (0) | 2020.06.22 |
존재하는 경우 BackStack에서 조각을 재개하는 방법 (0) | 2020.06.22 |
C # : 상속 된 이벤트 발생 (0) | 2020.06.22 |