바늘
목차
1. 포인터 변수의 정의
C 언어에는 일반 변수(콘텐츠 변수)와 주소 변수(포인터 변수)를 포함하여 두 종류의 변수가 있습니다. 일반 변수(콘텐츠 변수)는 콘텐츠를 저장하고 주소 변수(포인터 변수)는 주소를 저장합니다.
- 정의된 형식
格式
: type * 포인터 변수 이름
//普通变量
int a;
//地址变量
int *a;
메모:
① 정의변수(일반변수, 포인터변수)는 앞에 타입명이 있어야 한다.
② 포인터 변수를 정의할 때 포인터 변수 이름 앞의 기호는
"*"
포인터 타입의 변수가 현재 정의되어 있음을 나타냅니다.“*”
~ 아니다포인터 변수 이름의 일부는 플래그일 뿐입니다.③ 포인터 변수는 주소를 저장하기 위해 특별히 사용되며 포인터 변수에 직접 정수를 할당하는 것은 금지되어 있습니다.
- 포인터 변수에 대한 참조
“&”
주소 연산자를 사용하면&
일반 변수의 주소를 연산자를 통해 꺼낼 수 있습니다
.
*
포인터 연산자,*
포인터 변수가 가리키는 일반 변수의 값을 꺼낼 수 있습니다
. (일반 변수를 간접적으로 참조)
예:
#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)+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]
동일은 모두 요소 를 나타냅니다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. 요약
포인터 변수에 대해 주의해야 할 몇 가지 사항
-
에서
int *a;
변수 이름은*a
변수 이름이 변수 이름 명명 규칙, 즉 영숫자 밑줄을 따르기 때문이 아니며 숫자는 시작할 수 없으므로 포인터 변수의 변수 이름은 유형 이름 입니다 . 포인터 타입이라고 합니다.*a
int *
-
int 에서
*a;
a 는 8바이트를 차지하는데 당연히*a
4바이트를 차지하는데*a
int 형이니까 4바이트이고 그char *b
안의 b도 8바이트를 차지하지만*b
1바이트를 차지한다. 따라서 어떤 종류의 기본 유형 포인터 변수이든 상관없이 8바이트를 차지하며*指针变量
이 유형의 바이트를 차지합니다. (다른 운영 체제의 결과는 동일하지 않지만 한 가지는 동일합니다. 즉, 기본 유형에 관계없이 포인터 변수가 차지하는 바이트 수가 동일합니다.) -
포인터
*
및 에서&
이들은 역 연산&
이며[]
상호적입니다. 즉, 다음과 같이 서로를 상쇄할 수 있습니다.int a[3]; int b; int *a; int *p; a=&b; p=&a[0]; <=> p=a; p=&a[3]; <=> p=a+3; & 和 * 互逆 *和 [] 等价 & 和 [] 互逆
-
포인터에 대한 5가지 공식이 있습니다.
① 주소 변수의 주소를 얻고 주소를 얻은 사람은 누구를 가리 킵니다.
② 내용값으로 *가 있고 읽기나 쓰기 모두 할당번호 왼쪽에 붙여서 쓰고 나머지는 읽음
③ 주소에 *가 없고, 주소를 할당한다는 것은
④ 포인터 변수는 정의 및 초기화 후에만 사용할 수 있습니다.
⑤ address 변수는 주소를 저장하고, content 변수는 내용을 저장합니다.
-
중요한 동등성
int fun(int a[10]) <=> int fun(int *a) <=> int fun(int a[])
-
문자열에 대한 포인터 변수에서
char *p="qweqweqweqw"; char a[]="qweqwewqeq"; char *q; q=a; a是数组的地址,是一个地址常量,同时也是数组的首地址,即'q'的地址 p="asdasd"; 虽说p是个地址变量,但是,由于对于字符串来说,"asdasd"也就相当于一个地址常量,也就是‘a’的地址。
-
구별하다
(1) m 요소로 구성된 1차원 배열을 가리키는 포인터 변수를 정의하는 것과의 차이점에 주의하십시오.
类型名 *数组名[常量表达式];
본질적으로 1차원 배열이며 주소 상수가 배열에 저장됩니다.类型名 (*指针名)[常量表达式m];
본질적으로 1차원 배열을 가리키는 포인터 변수인 2차원 배열이다. -
널 포인터
문자 *q =NULL;
-
포인터에 대한 5가지 공식이 있습니다.
① 주소 변수의 주소를 얻고 주소를 얻은 사람은 누구를 가리 킵니다.
② 내용값으로 *가 있고 읽기나 쓰기 모두 할당번호 왼쪽에 붙여서 쓰고 나머지는 읽음
③ 주소에 *가 없고, 주소를 할당한다는 것은
④ 포인터 변수는 정의 및 초기화 후에만 사용할 수 있습니다.
⑤ address 변수는 주소를 저장하고, content 변수는 내용을 저장합니다.
-
중요한 동등성
int fun(int a[10]) <=> int fun(int *a) <=> int fun(int a[])
-
문자열에 대한 포인터 변수에서
char *p="qweqweqweqw"; char a[]="qweqwewqeq"; char *q; q=a; a是数组的地址,是一个地址常量,同时也是数组的首地址,即'q'的地址 p="asdasd"; 虽说p是个地址变量,但是,由于对于字符串来说,"asdasd"也就相当于一个地址常量,也就是‘a’的地址。
-
구별하다
(1) m 요소로 구성된 1차원 배열을 가리키는 포인터 변수를 정의하는 것과의 차이점에 주의하십시오.
类型名 *数组名[常量表达式];
본질적으로 1차원 배열이며 주소 상수가 배열에 저장됩니다.类型名 (*指针名)[常量表达式m];
본질적으로 1차원 배열을 가리키는 포인터 변수인 2차원 배열이다.