C 언어 포인터 튜토리얼은 기본 입문 장 없이 지속적으로 업데이트할 수 있습니다.

머리말:

전체 텍스트는 가상 메모리로 시작하며 실수로 스 와이프하는 것에 대해 이야기하는 것은 매우 간단합니다. 가상 메모리

이 기사는 C 포인터에 대해서만 설명하고 "배열이 포인터와 관련된 이유"와 같은 포인터 사용도 포함하지만 배열, 함수, 호환성, 암시적 변환 등에 대한 자세한 내용은 다루지 않습니다. 설명, 만약 이 글에서 자세한 설명을 드리는 것은 모두에게 학습의 어려움만 가중시킬 뿐이고, 저 자신에게도 문제가 될 것입니다. C규격의 내용(C98~C20 포함 ) .해당 글을 내 말로 정리한 후 참고하면 C23 초안 내용도 일부 있을 것이다.C23과 새로운 표준을 사용하면 기사에 표시합니다.

새로 온 사람들을 위해 "변화하기 전에 잘못된 인식을 이해하도록 도와주세요 ..."라는 기사를 시작하는 사람들을 위해 그것을 읽고 인상을 깊게 할 수도 있습니다. 실수를 지적하고 싶은 거물들과 실무자들을 위해 기사에서 I (CSDN: 별이 빛나는 하늘 긴 밤 i) 첫 번째 튜토리얼 기사가 게시되었으며 그룹에서 답변을 받았습니다.

무단 재배포를 금합니다.


디렉토리: 완료되면 배치하십시오.


1장 포인터 시작하기(필독)

1.0 이론(모두 적합):

 

아마도 모든 사람이 C를 배울 때 포인터와 배열에 의해 던져졌을 것입니다. 특히 일부 "책/비디오, 심지어 자신이 생각하는 것"은 포인터를 배열과 동일시합니다. 이 경우에만 포인터가 배열이 아닌 첫 번째 요소로 암시적으로 변환 .

참고 보충 지식 포인트:

① 소수의 특수한 경우에만 lvalue(상수) 포인터가 아닌 첫 번째 요소를 가리키는 암시적 변환이 발생합니다.

②포인터는 함수나 다른 형태의 객체를 참조하는 객체 형태로 수식어가 추가될 수 있다. 포인터는 특정 null 포인터 값으로 표시되는 아무 것도 참조할 수 없습니다.

③ 널 포인터 ≠ 와일드 포인터, 이 두 포인터에 대해 간접 operator-dereference를 사용하지 마십시오.

T는 가상의 클래스입니다. 독자는 이 클래스에 대해 생각할 필요가 없습니다. 처리에 관한 것입니다. 실제로 사용될 때 독자는 대신 C 유형을 사용하도록 요청받습니다.

 

1.1 메모리와 객체

기본 지식 포인터 구문: 유형 * 포인터 이름;

먼저 정의문을 살펴보십시오.

T num=10; //T형 변수

/*널 포인터로 초기화된 T형 포인터*/

T* 바늘=NULL;

 

위의 문장은 다음 "메모리 모델"을 정의합니다(실제로 복잡합니다. ... 숫자는 생략을 의미합니다. 사실 두 객체가 서로 가깝거나 n 메모리의 차이가 있을 수도 있습니다).

 

7974b19b66aa4ad4b1e09f15dae5e329.jpg

이 그림에 따르면 변수 이름이 일치하는 주소를 가지고 있음을 알 수 있습니다.고급 언어에서 제공하는 기능 중 하나이며 세부 사항은 컴파일러와 시스템에서 처리합니다... 시간을 절약할 수 있기 때문입니다. 다음과 같이 주소를 기억하는 것은 매우 번거로운 일입니다.

8bit:(010101010)과 같이 10개의 8bit "기억 주소"를 설정하면 기억할 수 있지만 100이면 수첩에 적어둘 수 있고 더 많이 사용하면 2개를 사용합니다. -10진수 또는 16진법: 0xF7d, 0xF6d...

그러나 "16비트 메모리 주소"(힌트: 절대 int 클래스 크기가 아님)⁰, 예를 들어 "16비트 메모리 주소"(01100010 00011101)를 형성하는 방법에 대해 생각하지 않는다면

이 "16비트 메모리 주소"를 어떻게 기억합니까?

10등 하나는 기억하기 매우 번거롭다고 하지마시고 실제로는 프로그램에서 한자리수 int객체만 사용하시나요? ), long을 사용하도록 선택하면 long 유형은 "32비트 메모리 주소"가 될 수 있으며, 사용량을 초과하면 "64비트 메모리 주소"가 될 수 있습니다.

그래서 사람이 기억 못해서 "기억 주소" 대신에 영문자로 된 이름이 있는데 그게 더 편하지 않나요? 물론 우리에겐 중국어가 더 좋지만 C문은 영문자로 구성되어 있습니다. .물론 중국어 사용이 불가능한 것은 아니지만 권장하지 않으며 주제에서 벗어났습니다. (참고(간단히 말하면): 이러한 세부 사항은 OS와 컴파일러에서 제공하는 특정 추상화이며 C 언어에서 제공하는 추상화는 구문입니다.)

 

그리고 몇 가지 장점이 있습니다. "메모리 상태"는 시스템, 플랫폼에 따라 변경됩니다. 동일한 "메모리"가 프로그램으로 이동되더라도 다른 프로그램/하드웨어가 메모리를 점유하지 않는다는 것을 보장할 수 있습니까? 그리고 켜고 끌 때마다 "메모리 주소 테이블을 재생성합니다 ..."라고하며 세부 사항을 다루지 않을 이유가 여전히 많고 거의 개요를 벗어났습니다. (이것도 OS가 주는 추상화로 직접 조작에 비해 이해하고 사용하기 쉽다)

요약: 사람들이 쉽게 배울 수 있도록 하기 위해 천재들은 이 방법을 발명했는데, 연산 주소 대신 영문자를 사용하고, 메모리 주소 대신 문자를 사용하여(기계: 이진 주소, 인간 보기: 16진수에 해당) 컴파일러가 처리하도록 하고, 메모리 관리 및 작동 시스템이 처리될 때까지 기다리십시오. ¹


참고: ⁰ 절대 int 클래스 크기가 아님:

또한 표준이 유형의 크기를 절대적으로 정의하지 않기 때문에 표준은 다음을 보장합니다.

…크기의(짧은) <= 크기의(정수) <= 크기의(긴) <= 크기의(긴 긴)

int는 short 또는 equal보다 클 수 있으며 비트 4, 16, 32 또는 64를 사용하지 않으면 달라집니다. 동일한 비트 플랫폼에서도 시스템 때문에 다를 수 있습니다. , 컴파일러 등 상세하지 않습니다.

¹: 섹션 1.0의 그림 아래에 있는 모든 콘텐츠에 대한 보충 지식: 이 방법은 하드웨어에 영향을 미치지 않으며 하드웨어는 여전히 주소를 사용하여 메모리 위치에 액세스합니다.

추가 단어: 추상화의 개념은 매우 중요하며 하위 수준을 아는 것보다 더 실용적이라고 할 수 있습니다. (추상 이미지를 제인에게 설명하는 글을 올릴 예정인데 최근 시간이 없어서)


 

1.1 포인터 기초①

위의 두 문장에 이어 다음 단락은 다음과 같습니다.

needle=& num; // 할당, T 유형 num을 가리킴

이 문장에서 &는 간접 연산자로, 주소를 가져와서 개체의 주소를 빼는 것을 의미합니다.

메모리 모델:

f7fd9f18cf6a42dcbcd5b0059231aac4.jpg

 need의 내부 → num의 외부를 가리키는 것을 볼 수 있습니다. 이를 num을 가리키는 포인터라고 부르거나 num의 주소가 need 포인터 내부에 저장됩니다.

 

요약하다:

T num=10; //T형 변수

/*널 포인터로 초기화된 T형 포인터*/

T* 바늘=NULL;

바늘=& 숫자; 

위의 모든 진술은 다음과 같습니다.

①T형 바늘과 num 객체를 생성하고, *는 해당 객체가 포인터인지 판단하고, T형은 객체가 저장할 수 있는 T형 주소 값을 결정한다.

②Needl 포인터에 NULL을 할당하여 널 포인터로 만든다(이러한 포인터를 역참조하는 포인터는 정의되지 않은 동작을 유발하지 않음) 이러한 동작을 정의 선언 시 값을 할당할 때 "초기 값 할당"이라고 합니다.

③ 다음으로 간접 연산자 &를 이용하여 T 변수 num의 주소 값을 바늘에 대입하여 바늘이 num을 가리키도록 합니다.


1.2 포인터 기초②

이전 섹션 1.1에서는 "하나의 무거운" 포인터, 포인팅 방법(스토리지), num이라는 주소 및 NULL을 소개했으며, 이 섹션에서는 위 내용을 확장하여 포인터에 대해 이야기합니다.

1.2.0 역참조 포인터:

이전 섹션에서 & 간접 연산자 함수: 주소를 가져오면 이 섹션에서는 그의 친척을 소개합니다.

*바늘;

이 문장에서 *는 간접 연산자로 역참조, 객체의 주소 역참조, 주소에 있는 값을 의미합니다.

프로그램 세그먼트를 살펴보십시오.

T num=10; //T형 변수

/*널 포인터로 초기화된 T형 포인터*/

T* 바늘=NULL;

바늘=& 숫자; 

printf("숫자 주소:%p丨수 저장 값:%d\n",&num,num);

printf("바늘 포인터 주소:%p\n",&needle);

prinrf("바늘 저장값:%p\n",needle);

printf("바늘 저장 값 역참조: %d", *바늘);

가능한 실행 결과:

num 주소: 0xa59ebba4丨 num 저장 값: 10

바늘 포인터의 주소: 0xa59ebba0

바늘 저장 값: 0xa59ebba4

바늘에 의해 저장된 값은 역참조됩니다: 10

결과에 따르면 num 주소와 바늘에 저장된 주소가 동일하고(1.1절과 1.0절에서 논의한 바와 같이), 바늘 포인터는 초기에 널 포인터(NULL)인 후 주소를 할당받았음을 알 수 있다. 바늘이 num 객체의 주소(0xa59ebba4 )를 가리키고 포인터 자체도 자체 주소(0xa59ebba0)를 가짐을 의미합니다.

바늘을 역참조하면 num의 값이 표시됩니다. 1.0-1.1과 조합하여 생각하십시오. 그렇지 않은 경우 모델 다이어그램을 결합하여 직접 그려보십시오.

스스로 그리려고 노력하고, 당신은 당신 자신의 이해가 있어야 하고, 다른 사람의 이해는 항상 다른 사람의 이해이며, 당신은 그것을 단순히 사용할 수 있지만 당신은 그를 이해하지 못합니다.

 

참고: 0xa59ebba0과 0xa59ebba4의 차이는 4이지만 주소가 달라지는 것을 관찰할 수 있습니다. num 주소와 needle에 저장된 값은 바늘 포인터가 num 주소를 저장하기 때문에 동일해야 합니다. 자세한 내용은 1.0을 참조하십시오.

*이 코드에는 나중에 설명할 (void *)를 포함하는 암시적 변환이 있습니다.

1.2.1 "심층" 이해 주제:

위의 지식이 있으신 분들은 직접 문제를 풀어보시는 것이 좋을 것 같으니 잘 생각해보시고 이해가 되지 않는다면 그림을 그리거나 코드를 타이핑 해보시면 좋을 것 같습니다. (답은 이 질문의 끝에 있습니다)

① num의 값을 바꾸면 num을 가리키는 바늘이 바뀔까?

예를 들어 num=1;

②바늘의 값을 바꾸면 num이 바뀔지 생각해 보세요 이 바늘은 누구를 가리키며 바늘의 역참조 값은 무엇인가요?

예를 들어

Ti=0;

바늘= & 나;

③다음 작업을 수행한 후 i 값, num 값, 역참조 바늘 값 및 바늘 위치를 고려하십시오.

바늘= & 번호;

* 바늘 = 10;

바늘=&i;

i=5;

④ 다음과 같은 오류를 생각해보고 수정 사항을 지적하십시오(nu는 "로컬" 변수임).

나는 아니에요;

숫자=1,i=9;

바늘=NULL;

 

바늘=i;

printf("변수 i 주소%d\n", &needle);

num=nu+(*바늘);

 

printf("%d+%d=%d",*i,nu,num);

 

결과:

변수 i 주소 0x...

9+5=14

답변:

저를 클릭하시거나 https://blog.csdn.net/asd2387/article/details/129107668 팬을 보이게 만든 것에 대해 저를 비난하지 마세요.

 

 

 

아래 내용을 읽지 마십시오. 지금은 개요입니다.


1.3 const 한정자

const는 C 문의 키워드로 일종의 한정자에 속하며, volatile(컴파일러 최적화를 제한하는 한정자로서 일반적으로 사용되지 않고 논의되지 않습니다).

 1.3.0 const 기반 - 개체

const 의미 체계에 대한 기본적인 이해가 있는 경우 이 섹션(1.3.0)을 건너뛰고 간단한 사용법에 대해서만 이야기하십시오.

const로 정의된 변수는 읽을 수만 있습니다. 프로그램을 참조하십시오.

상수 정수 a=0;

정수 상수 b=1;

이 두 변수는 전체 프로그램이 실행 중일 때만 변경할 수 없는 값을 읽을 수 있으며 수정된 경우 컴파일러는 (잘못됨)과 같은 오류를 보고합니다.

a=5;

i=a;

a=i;

const는 변수 a와 b를 읽을 수만 있거나 해당 주소를 가져오는 "상수"로 정의하기 때문에 위의 세 문장은 허용되지 않습니다(선택 사항). "상수"를 큰따옴표로 묶은 이유는 1.3에 나와 있습니다 . .2 고급.

1.3.1 const 기반 - 포인터

const 및 포인터를 이해하는 사용자는 이 섹션(1.3.1)을 건너뛰십시오.

정수 i=1;

const int* q=&i;

int const* w=&i;

위의 두 문은 동일한 의미를 표현하며 의사 코드는 다음과 같이 설명합니다.

읽기 전용 정수 클래스* 포인터 q 할당 i 주소;

정수 클래스 읽기 전용 * 포인터 q는 i 주소를 할당합니다.

이해가 되나요 밝은 점인가요? , 그렇지 않다면 걱정하지 말고 분해 + 보조 단어를 설명하십시오.

읽기 전용 *q에 대한 포인터 

예, "*pointer"라는 문장을 읽기 전용으로 정의하는 것입니다! 즉, 포인터 역참조 작업은 읽기만 가능한 것으로 정의됩니다!

즉, 다음 사용법은 잘못되었습니다.

*q=2;

*w=i;

*q=*w;  

# 대부분의 사람들은 저와 같은 다른 글을 읽었을 것입니다. 위의 두 포인터 정의는 아마도 i를 읽기 전용으로 설정하는 것에 대해 이야기할 것입니다. 저는 C 구문에 대해서만 이야기하기 때문에 이에 동의하지 않습니다. 제 생각에는 const 한정자입니다. i를 직접 수정할 수 있다는 것이 명백하기 때문에 포인터를 건너뛰고 그가 가리키는 개체를 const로 설정하는 대신 포인터로 제한됩니다.

 

int* const r=NULL;

 정수 클래스 * 포인터 q 읽기 전용 할당 NULL;

 

int* const i=NULL;

 

1.3.2 고급 const(권장)

업데이트 1.3.1 업데이트↓

const 의미 체계는 lvalue 식에만 적용되며 컴파일러에게 개체가 읽기 전용 메모리에 배치되었음을 알려줍니다.

상해:

lvalue가 필요하지 않은 컨텍스트에서 const lvalue 식이 사용될 때마다 const 한정자가 손실됩니다!

const int* const CannontMaodify = NULL;

CannontMaodify가 c-한정자가 아닌 다른 포인터 개체를 사용하여 수정되고 간접 수정이 포인터에 의해 수정되지 않는 한 CannontMaodify를 직접 수정할 수 없습니다.

증명 프로그램 링크: 개인 에세이

 

 

 

1.4 함수 매개변수 및 값 전달

다음으로 함수 매개변수와 포인터의 관계에 대해 이야기하겠습니다. 제 장은 실용성과 단순성에 중점을 두므로 먼저 함수 매개변수와 포인터에 대해 이야기하겠습니다. 대부분의 책은 이 섹션을 배열과 포인터로 시작해야 합니다.

    함수 내용을 배우지 않으면 함수가 자세하게 설명되지 않는다고 걱정하지 마십시오.

 

 

 

 

 

 

 

 

 

1.5 포인터와 배열

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

추천

출처blog.csdn.net/asd2387/article/details/128911180