포인터에 대한 가장 자세한 설명

바늘

1. 포인터 변수의 정의

C 언어에는 일반 변수(콘텐츠 변수)와 주소 변수(포인터 변수)를 포함하여 두 종류의 변수가 있습니다. 일반 변수(콘텐츠 변수)는 콘텐츠를 저장하고 주소 변수(포인터 변수)는 주소를 저장합니다.

  1. 정의된 형식

格式: type * 포인터 변수 이름

//普通变量
int a;
//地址变量
int *a;

메모:

① 정의변수(일반변수, 포인터변수)는 앞에 타입명이 있어야 한다.

② 포인터 변수를 정의할 때 포인터 변수 이름 앞의 기호는 "*"포인터 타입의 변수가 현재 정의되어 있음을 나타냅니다.“*”~ 아니다포인터 변수 이름의 일부는 플래그일 뿐입니다.

③ 포인터 변수는 주소를 저장하기 위해 특별히 사용되며 포인터 변수에 직접 정수를 할당하는 것은 금지되어 있습니다.

  1. 포인터 변수에 대한 참조

“&”주소 연산자를 사용하면 &일반 변수의 주소를 연산자를 통해 꺼낼 수 있습니다
.
*포인터 연산자, *포인터 변수가 가리키는 일반 변수의 값을 꺼낼 수 있습니다
. (일반 변수를 간접적으로 참조)

예:

#include<stdio.h>
int main(){
    
    
	int a=4,b=0;
	int *p,*q,*t;
	p=&a;    //取出变量a的地址
	b=*p;
	 
	printf("a=%d\nb=%d\n*p=%d\n",a,b,*p);
	printf("\n\n\n");
	printf("a的地址为:%p\nb的地址为:%p\np的地址为:%p",&a,&b,p);
	return 0;	
}
//运行结果:
a=4
b=4
*p=4
a的地址为:000000000062FE14
b的地址为:000000000062FE10
p的地址为:000000000062FE14
--------------------------------
Process exited after 0.0017 seconds with return value 0

작동 다이어그램:

여기에 이미지 설명 삽입

메모:

① 공통 변수에 "point"에 대한 포인터 변수를 할당할 수 있습니다(포인터 변수=&공통 변수).

②C 언어에서 올바른 접근 방식은 포인터 변수가 먼저 특정 저장 단위를 가리키도록 한 다음 포인터 변수를 사용하여 가리키는 저장 단위를 참조하는 것입니다.

③ 변수 이름(일반 변수, 포인터 변수)은 모두 저장 단위의 값을 나타냅니다.

④ 포인터 변수 p가 변수 a를 가리키면 변수 a의 주소를 포인터 변수 p에 대입한다.

⑤ 모든 포인터 변수는 메모리에 할당된 바이트 수가 동일합니다.

//关于第五条的解释
#include<stdio.h>
int main(){
    
    
	int *p;
	double *q;
	float *t;
	char *r;
	printf("\t int *p = %d\n",sizeof(p));
	printf("\t double *q = %d\n",sizeof(q));
	printf("\t float *t = %d\n",sizeof(t));
	printf("\t char *r = %d\n",sizeof(r));
	return 0;	
}

작업 결과:

여기에 이미지 설명 삽입

2. 배열 포인터

배열 요소는 일반 변수와 동일하므로 배열 요소를 가리키는 포인터 변수를 정의하는 것은 일반 변수를 가리키는 포인터 변수를 정의하는 것과 완전히 동일합니다.

int *p;
int a[10];
//a는 배열의 첫 번째 주소, 즉 a <=> &a[0];
p=a; 동등한 p=&a[0];
p=a+1 동등한 p= &(a+1)

배열 이름은 배열의 첫 번째 주소입니다.

//上述等价的实例
#include<stdio.h>
int main(){
    
    
	int a[10];
	int *p,*q;
	p=&a[1];
	q=a+1; 
	printf("%p\n",p);
	printf("%p\n",q);
}

작업 결과:

여기에 이미지 설명 삽입

메모:

① C언어에서 배열 이름은 배열의 첫 번째 주소를 나타내며 주소 상수라고 규정되어 있습니다.

②포인터 변수가 배열의 요소를 가리키면 포인터 변수는 1씩 증가한 후 배열의 다음 요소를 가리키고, 포인터 변수가 1씩 감소하면 배열의 이전 요소를 가리킨다.

③ 포인터 변수가 배열을 가리키는 경우 배열 뒤나 포인터 변수 뒤에 첨자 연산([])을 사용할 수 있다.

④ 두 포인터 변수가 같은 배열을 가리키는 경우 두 포인터 변수의 크기를 다음과 같이 비교할 수 있습니다.

⑤ 형식 매개변수의 배열은 "배열명"의 값은 변경할 수 있지만 실제 배열명의 값은 변경할 수 없기 때문에 실제 배열이 아닌 포인터 변수입니다.

⑥ 형식 매개변수가 배열 또는 포인터 변수인 경우 형식 매개변수를 통해 함수에서 실제 매개변수의 값을 변경할 수 있습니다.

예 1:

여기에 이미지 설명 삽입

답변 및 분석:

여기에 이미지 설명 삽입

예 2:

//运行结果是什么?
#include<stdio.h>
int main() {
    
    
	int *p,a[3];
	p=a;  //将数组a的首地址,赋值给指针p 
	for(int i=0; i<3; i++) {
    
    
		scanf("%d",p++); //因为数组名就是地址,所以不用加取地址符 
	}
	printf("\n\n");
	
	for(p=a;p<a+3;){
    
      //将数组a的首地址,赋值给指针p 
		printf("%d ",*p++); //没输出一次,就向后移动一位 
	} 
	return 0;
}

작업 결과:

여기에 이미지 설명 삽입

3. 다차원 배열을 가리키는 포인터 변수

Ⅰ.포인터와 포인터의 차이점

예: 에서 int a[3]추가 a+1되는 것은 요소이고 int a[3][4], a+1추가되는 것은 아래 그림과 같이 행입니다.
여기에 이미지 설명 삽입

기억하다:

① 열 포인터만 "실제로" 요소를 가리킵니다. 즉, 요소를 가리키는 저장 단위입니다.
② 1차원 배열 이름은 열 포인터를 나타내고 2차원 배열 이름은 행 포인터를 나타냅니다.

참고: a가 2차원 배열이면 다음이 있습니다.

a+i행 포인터, 즉 전체 행을 가리킨다. 여기에 1을 더하면 다음 줄을 가리킵니다.

② 와 *(a+i)동일 a[i]하게 요소를 가리키는 컬럼 포인터이다.

*(a+i)+ja[i]+j와 동일하며 둘 다 a[i][j]요소의 주소를 나타냅니다. 즉 와 &a[i][j]동일합니다. *(a+i)+j= a[i]+j= &a[i][j].

*(*(a+i)+j), *(a[i]+j), (*(a+i))[j]a[i][j]동일은 모두 요소 를 나타냅니다 a[i][j].

예 1:

다음 정의가 주어 int w[2][3]지면 w에 대한 잘못된 참조는 다음과 같습니다.

A, *(w[0]+2)B, *(w+1)[2]C, w[0][0]D, *(w[1]+2)E,w[1]+2

분석: A는 w[0][2]Yes의 요소를 나타내고 C는 요소 w[0][0]D는 Yes의 요소를 나타내고 w[1][2]E는 Yes의 요소를 나타냅니다. &w[1][2]즉, E는 요소가 아니라 주소입니다.

w[0][0]B에서 w는 주소를 나타내 므로 w+1은 한 줄 아래로 이동하는 것, *(w+1)[2]즉 두 줄 아래로 이동하는 것을 의미하므로 표현된 w[3][0]요소이지만 int w[2][3]B가 범위를 벗어났기 때문입니다.

예 2:

int a[3][4]; int *p=&a[0][3];

하지만:

p+1 요소를 가리킵니까?

p+4 요소를 가리킵니까?

p-2는 요소를 가리킵니까?

일반적으로 2차원 배열 요소의 주소를 얻는 데 사용됩니까?

아래와 같이 분석합니다.

여기에 이미지 설명 삽입

예 3:

2차원 배열 인쇄 a[4][4](for 루프는 하나만 사용할 수 있음)

#include<stdio.h>
int main() {
    
    
	int a[4][4] = {
    
    
		{
    
    1, 2, 3, 4},
		{
    
    5, 6, 7, 8},
		{
    
    9, 10, 11, 12},
		{
    
    13,14,15,16}
	};
	int *p;
	for(p=a[0]; p<a[0]+12; p++) {
    
    
		printf("%d ",*p);
	}
	return 0;
}

작업 결과:

여기에 이미지 설명 삽입

m 요소의 1차원 배열에 대한 포인터 변수

Ⅱ .m개의 요소로 구성된 1차원 배열을 가리키는 포인터 변수

m 요소의 1차원 배열을 가리키는 포인터 변수의 형식을 정의합니다.

유형 (*포인터 변수 이름) [m]

포인터 변수 열 수

좋다:

int a[5][7];
int (*p)[7];
p=a;

char b[ 10][80];
char (*r)[80];
r=b+5;

위의 의사 코드 구문 분석 코드는 다음과 같습니다.

/*
int a[5][7];
int (*p)[7];
p=a;
 */

#include<stdio.h>
int main() {
    
    
	int a[4][4];  //定义一个二维数组
	int (*p)[4];  //定义一个一维数组的指针变量,也就是说该数组是指向某一行第四列的一维数组
	int *c;       //普通的指针变量
	p=a;          //将二维数组的首地址赋值给p,也就是说此时的p是指向的a的首行,且(*p)[4]等价于p[0][4]
	printf("%p\n%p\n",a,p);   //打印数组a的首地址和p的首地址
	printf("%d ",sizeof(a));  //打印数组a所占的空间,也就是二维数组a[4][4]所占的空间
	printf("%d ",sizeof(*p)); //打印数组p所占的空间,也就是一维数组p[0][4]所占的空间
	printf("%d ",sizeof(c));  //打印指针变量(地址变量)c所占的空间,
	printf("\n\n");
 	return 0;
}

인쇄 결과는 다음과 같습니다.

여기에 이미지 설명 삽입

/*
char b[ 10][80];
char (*r)[80];
r=b+5;
*/

#include<stdio.h>
#include<string.h>
int main() {
    
    
	char b[10][80];  //定义一个二维数组
	char (*r)[80];   //定义一个一维数组的指针变量,也就是说该数组是指向某一行第八十列的一维数组
	r=b+5;			//将b[0][0]向下移动五行再赋值给r,也就是将a[5][0]的地址赋值给r。
	printf("%p\n%p\n",r,b[5]); //打印地址
	printf("%d ",sizeof(*r));  //查看空间
	printf("%d ",sizeof(b[5]));//查看空间
	return 0;
}

인쇄 결과는 다음과 같습니다.
여기에 이미지 설명 삽입

예 1:

다음 코드가 실행되면 어떤 결과가 출력되고, for 루프의 또 다른 출력 방법을 작성하고, p=a+1;이라는 코드를 작성하면 무엇이 출력될까요?

#include<stdio.h>
int main() {
    
    
	int a[3][4]= {
    
    1,2,3,4,5,6,7,8,9,10,11,12};
	int (*p)[4];
	p=a;
	int *q;
	for(int i=0; i<3; i++) {
    
    
		for(int j=0; j<4; j++) {
    
    
			printf("%d\t",p[i][j]);
		}
		printf("\n");
	}
	return 0;
}

답변 및 분석:

#include<stdio.h>
int main() {
    
    

	int a[3][4]= {
    
    1,2,3,4,5,6,7,8,9,10,11,12};
	int (*p)[4];
	p=a;
	int *q;
	for(int i=0; i<3; i++) {
    
    
		for(int j=0; j<4; j++) {
    
    
			printf("%d\t",p[i][j]);
		}
		printf("\n");
	}
	printf("\n\n");
	
	//一层for循环打印二维数组 
	for(q=a[0];q<a[0]+12;q++){
    
    
		printf("%d  ",*q);
	}
	printf("\n\n");
	
	
	//打印p=a+1,回打印出什么 
	p=a+1;
	for(int i=0; i<2; i++) {
    
    
		for(int j=0; j<4; j++) {
    
    
			printf("%d\t",p[i][j]);
		}
		printf("\n");
	}
	return 0;
}

실행 결과(자체 분석을 위해 위의 지식 포인트와 결합):

여기에 이미지 설명 삽입

예 2:

다음 코드를 실행하면 무엇이 출력됩니까?

#include<stdio.h>
main() {
    
    
	int a[2][3]= {
    
    {
    
    1,2,3},{
    
    4,5,0} },(*pa)[3];
	int i;
	pa=a;
	for(int i=0;i<3;i++){
    
    
		if(i<2){
    
    	
			pa[1][i]=pa[1][i]-1;
		}
		else {
    
    
			pa[1][i]=1;
		}
	}
	printf("%d\n",a[0][1]+a[1][1]+a[1][2]);
}

답변 및 분석:

여기에 이미지 설명 삽입

넷째, 문자열을 가리키는 포인터 변수

문자열 상수: C 언어는 첫 번째 주소에 따라 문자열 상수를 처리합니다.

포인터이기 때문에 포인터 변수의 원리를 따라야 하며 동시에 문자열 상수도 상수라는 것을 알기 때문에 할당번호 왼쪽에 쓸 수 없다.

문자열 char *p="abc"

①첫 번째 주소

② "abc" 주소 상수

③ 첫 번째 문자의 주소는 p에 저장됩니다.

예:

다음 중 맞는 코드와 잘못된 코드를 지적하고 그 이유를 설명하십시오.

char str[]="China";

char *p="China";     ✔   因为字符串是地址常量,所以正确

str = "Chinese";     ❌    str也是地址常量,不能放在赋值号的左边    

p="Chinese";         ✔    p是地址变量,字符串是地址常量,也是"C"的地址

char *q ={
    
    "China"};  ❌    加大括号是初始化,此时就不是地址常量了,所以错误

char s[]={
    
    "China"};  ✔    初始化,大括号可加可不加。所以✔

char *p;*p="china";*p是内容值,但是字符串是地址值,所以❌

5. 함수를 가리키는 포인터 변수

함수 이름은 배열 이름과 동일하며 시작 주소이며 주소 상수입니다.

함수 포인터 변수를 정의하는 방법:

typename(*포인터 변수명)();

예:

다음 코드를 실행한 결과는?

#include<stdio.h>
int min(int a,int b) {
    
    
	return a>b?b:a;
}
int max(int a,int b) {
    
    
	return a>b?a:b;
}
int main() {
    
    
	int x= 6,y=10;
	int (*p)(int a,int b);  //定义指向函数的指针变量
	p=max; 				   //将max函数的地址赋值给指向函数的指针变量
	printf("%d\n",max(x,y));
	printf("%d\n",p(x,y));
	p=min;				   //将min函数的地址赋值给指向函数的指针变量
	printf("%d\n",min(x,y));
	printf( "%d\n",p(x,y)); 
}

작업 결과:
여기에 이미지 설명 삽입

메모:

(1) 함수를 가리키는 포인터 변수를 정의할 때 두 개의 괄호가 있어야 하며 형식 매개변수를 정의할 필요가 없다는 점에 유의해야 합니다. 그러나 devc++와 같은 일부 컴파일러의 경우 형식 매개변수를 정의해야 할 수 있습니다.

(2) 단일 함수 이름은 함수의 첫 번째 주소(함수의 진입 주소)를 나타냅니다.

(3) 함수의 포인터 변수는 함수의 진입점(함수의 첫 번째 주소)만 가리킬 수 있으며 함수의 특정 명령을 가리킬 수 없습니다. (또한 함수를 가리키는 포인터 변수에 1을 더하는 것은 의미가 없습니다.)

(4) 함수를 가리키는 포인터 변수에 값을 할당할 때 함수 이름만 쓰고 매개변수는 쓸 필요가 없다.

6. 포인터를 반환하는 함수

포인터를 반환하는 함수는 다음과 같이 정의됩니다.

유형 이름 * 함수 이름(파라미터 목록) {

}

예:

#include<stdio.h>
int *fun(int *x,int *y) {
    
    
	if(*x<*y)
		return x;
	else
		return y;
}
int main() {
    
    
	int a=7,b=8,*p,*q,*r;
	p=&a;
	q=&b;
	r=fun(p,q);
	printf("%d,%d,%d\n",*p,*q,*r);
	return 0; 
}



7,8,7

--------------------------------
Process exited after 0.1331 seconds with return value 0
请按任意键继续. . .

7. 포인터를 가리키는 포인터 배열과 포인터 변수

포인터 배열

배열의 모든 요소가 포인터 유형(주소)인 경우 포인터 배열이라고 합니다.

체재:

类型名 *数组名[常量表达式];

int *a[5];

메모:

(1) m 요소로 구성된 1차원 배열을 가리키는 포인터 변수를 정의하는 것과의 차이점에 주의하십시오.

类型名 *数组名[常量表达式];본질적으로 1차원 배열이며 주소 상수가 배열에 저장됩니다.

类型名 (*指针名)[常量表达式m];본질적으로 1차원 배열을 가리키는 포인터 변수인 2차원 배열이다.

(2) 각 요소는 포인터 유형(주소)입니다. 즉, 각 요소는 포인터 변수와 동일합니다.

예:

#include<stdio.h>
int main() {
    
    
	char ch[3][4]= {
    
    "123","456","78"},*p[3];
	int i;
	for(i=0; i<3; i++)
		p[i]=ch[i];
	for(i=0; i<3; i++){
    
    
		printf("p = %p \n" ,p[i]);
		printf("ch =%p\n" ,&ch[i][0]);
		printf("p = %s \n" ,p[i]);
		printf("ch =%s \n" ,ch[i]);
		printf("\n");
	}	
	return 0; 
}

실행 결과 및 분석:

여기에 이미지 설명 삽입

포인터에 대한 포인터 변수

포인터 변수의 주소를 저장하는 데 사용되는 포인터 변수를 포인터에 대한 포인터 변수라고 합니다.

정의 형식:

유형 이름**포인터 변수 이름;

정수 a=3;

정수 *p=&a;

정수 **k=&p;

그런 다음: *k는 변수 p(변수 a의 주소)를 가져옵니다. **k는 변수 a의 값을 가져옵니다(a의 데이터 3).

8. 널 포인터

포인터 변수는 null 값을 가질 수 있습니다. 즉, 포인터 변수는 변수를 가리키지 않으며 유용한 저장 단위를 참조하지 않습니다.

NULL은 시스템에서 0으로 정의되어 있습니다. 즉, NULL의 값은 0입니다.

정수 a,b, C, *p=NULL;

이때 p의 값은 null 포인터, 즉 p는 유용한 저장 단위를 가리키지 않습니다. NU LL의 값은 0이지만 p가 주소가 0인 메모리 유닛을 가리킨다고 생각할 수 없다.

메모:

(1) 포인터 변수의 값이 널 포인터일 때 그것이 가리키는 저장 단위를 참조할 수 없다.

(2) 포인터(주소)의 기본 타입이 void 타입인 경우 참조가 있을 때 해당하는 필수 타입 교체를 수행해야 합니다.

9. 요약

포인터 변수에 대해 주의해야 할 몇 가지 사항

  1. 에서 int *a;변수 이름은 *a변수 이름이 변수 이름 명명 규칙, 즉 영숫자 밑줄을 따르기 때문이 아니며 숫자는 시작할 수 없으므로 포인터 변수의 변수 이름은 유형 이름 입니다 . 포인터 타입이라고 합니다.*aint *

  2. int 에서 *a;a 는 8바이트를 차지하는데 당연히 *a4바이트를 차지하는데 *aint 형이니까 4바이트이고 그 char *b안의 b도 8바이트를 차지하지만 *b1바이트를 차지한다. 따라서 어떤 종류의 기본 유형 포인터 변수이든 상관없이 8바이트를 차지하며 *指针变量이 유형의 바이트를 차지합니다. (다른 운영 체제의 결과는 동일하지 않지만 한 가지는 동일합니다. 즉, 기본 유형에 관계없이 포인터 변수가 차지하는 바이트 수가 동일합니다.)

  3. 포인터 *및 에서 &이들은 역 연산 &이며 []상호적입니다. 즉, 다음과 같이 서로를 상쇄할 수 있습니다.

    int a[3]; 
    int b;
    int *a;
    int *p;
    a=&b;
    p=&a[0]; <=> p=a;
    p=&a[3]; <=> 
    p=a+3;
    
    &* 互逆
    
    *[] 等价
    
    &[] 互逆
    
  4. 포인터에 대한 5가지 공식이 있습니다.

    ① 주소 변수의 주소를 얻고 주소를 얻은 사람은 누구를 가리 킵니다.

    ② 내용값으로 *가 있고 읽기나 쓰기 모두 할당번호 왼쪽에 붙여서 쓰고 나머지는 읽음

    ③ 주소에 *가 없고, 주소를 할당한다는 것은

    ④ 포인터 변수는 정의 및 초기화 후에만 사용할 수 있습니다.

    ⑤ address 변수는 주소를 저장하고, content 변수는 내용을 저장합니다.

  5. 중요한 동등성

    int fun(int a[10]) <=> int fun(int *a) <=> int fun(int a[])

  6. 문자열에 대한 포인터 변수에서

    char *p="qweqweqweqw";
    char a[]="qweqwewqeq";
    char *q;
    q=a; a是数组的地址,是一个地址常量,同时也是数组的首地址,即'q'的地址
    p="asdasd"; 虽说p是个地址变量,但是,由于对于字符串来说,"asdasd"也就相当于一个地址常量,也就是‘a’的地址。
    
  7. 구별하다

    (1) m 요소로 구성된 1차원 배열을 가리키는 포인터 변수를 정의하는 것과의 차이점에 주의하십시오.

    类型名 *数组名[常量表达式];본질적으로 1차원 배열이며 주소 상수가 배열에 저장됩니다.

    类型名 (*指针名)[常量表达式m];본질적으로 1차원 배열을 가리키는 포인터 변수인 2차원 배열이다.

  8. 널 포인터

    문자 *q =NULL;

  9. 포인터에 대한 5가지 공식이 있습니다.

    ① 주소 변수의 주소를 얻고 주소를 얻은 사람은 누구를 가리 킵니다.

    ② 내용값으로 *가 있고 읽기나 쓰기 모두 할당번호 왼쪽에 붙여서 쓰고 나머지는 읽음

    ③ 주소에 *가 없고, 주소를 할당한다는 것은

    ④ 포인터 변수는 정의 및 초기화 후에만 사용할 수 있습니다.

    ⑤ address 변수는 주소를 저장하고, content 변수는 내용을 저장합니다.

  10. 중요한 동등성

    int fun(int a[10]) <=> int fun(int *a) <=> int fun(int a[])

  11. 문자열에 대한 포인터 변수에서

    char *p="qweqweqweqw";
    char a[]="qweqwewqeq";
    char *q;
    q=a; a是数组的地址,是一个地址常量,同时也是数组的首地址,即'q'的地址
    p="asdasd"; 虽说p是个地址变量,但是,由于对于字符串来说,"asdasd"也就相当于一个地址常量,也就是‘a’的地址。
    
  12. 구별하다

    (1) m 요소로 구성된 1차원 배열을 가리키는 포인터 변수를 정의하는 것과의 차이점에 주의하십시오.

    类型名 *数组名[常量表达式];본질적으로 1차원 배열이며 주소 상수가 배열에 저장됩니다.

    类型名 (*指针名)[常量表达式m];본질적으로 1차원 배열을 가리키는 포인터 변수인 2차원 배열이다.

Supongo que te gusta

Origin blog.csdn.net/LOL_toulan/article/details/109356397
Recomendado
Clasificación