一张图看懂指针(传说中最难理解的)
一张图看懂指针(传说中最难理解的)(2) “&”单目运算符,从右往左,后面只能接内容变量(变量)(1) “&”取地址运算符,取出普通变量的地址。b = 2000;p = 4000; //错误指针变量的引用
一.指针变量
C语言的两种变量:普通变量存储内容值;指针变量存储地址值
- 定义的格式: 类型名 * 指针变量名;(变量名不包含* 星号只是一个标志)
- 注:
- (1). 指针变量专门来存储地址,禁止将一个整型值直接赋值给一个指针变量
int a b *p;
a = 1000;
b = 2000;
p = 4000; //错误
指针变量的引用
(1) “&”取地址运算符,取出普通变量的地址。
(2) “&”单目运算符,从右往左,后面只能接内容变量(变量)
(3) “*”指针运算符,取出指针遍历所指向的普通变量的内容值
(4) 指针变量需【定义】且【初始化】后再使用:
int *p; 此时指针变量p虽然定义了,但是所指向的地址是随记的
*p = 200; 危险! * p只有放在赋值号的左边是为 写,其它为读
(5) 所有的指针变量在内存中分配的字节数相同。sizeof()。都为 2
(6) &与 * 互逆; * 与[ ]等价;&与[ ]互逆
(7) 若数组作为形参,则将数组名做指针变量来处理,int fun(int *a) 等价于 int fun(int a[ ])
二. 指向数组的指针变量
1、指向数组元素的指针变量
由于数组元素和普通元素一样,所以定义指向数组元素的指针变量与定义指向普通变量的指针变量完全一样。如:
int s[10] a b;
int b[3][6];
int *p;
p = &a;
p = &s[2];
p= &b[2][4]; //p最后指向b[2][4]
2、指向一维数组的指针常量(列地址)
(1) 在C中规定:数组名代表数组的首地址,而且是一个地址常量。如:
int a[10];
int *p;
p = a; //等价于 p = &a[0];
(2) 当指针变量指向数组中某一个元素时,指针变量加1后指向数组的下一个元素,指针变量减1时指向数组中前一个元素。如:
float a[10];
float *p;
p = &a[4]; // 则 p-3 指向 a[1]; ==p-3仍然是地址==;
(3) int a[N] *p = a;
p i a i &a[i] 三者完全等价 (地址三等价)
星号 (p i) * (a i) a[i] 三者等价于p[i],[ ] 是下标运算符(元素四等价)
如:
int b[5] = {10 30 20 15 40};
int *q = b 2;
*q 先算q ;表达式值为20,同时q指向了b[3]
* q 表达式值为15,同时q指向了b[3]
(*q) 表达式值为20,同时q指向了b[2]
(*q) 表达式值为21,同时q指向了b[2]
举例说明指针在数组中的使用:
int main(){
int *p a[3] i;
p = a;
for(i = 0; i < 3; i )
scanf("%d" p );
printf("\n\n");
for(p = &a[0]; p < a 3; )
printf("%d " *p );
等价于
for(i = ; i < 3; i )
scanf("%d" &a[i]);
for(i = 0; i < 3;i )
printf("%d " a[i]);
(4) 若两个指针变量指向同一个数组,则这两个指针变量可以进行大小比较:
char s[10];
char *p1 = s 3 p2 = &s[7];
则 p1 > p2 =>0 p1 < p2 =>1
p1 - p2 => -4 p2 - p1 => 4
(5) 在形参中的数组实际上是一个指针变量,并不是真正的数组,因为该数组名的值是可以改变的,而真正的数组名的值是不可以改变的。
(6) 若形参是数组或指针变量,则在函数中可以通过该形参改变实参的
三、指向多维数组的指针变量
1、如:int a[3][4];
(1). a i 是行指针,即指向的是一整行,若对它加1则指向下一行(4个元素)。
(2). *(a i)和a[i]一样,都是一个列指针,即指向的是一个元素
(3). *(a i) j和a[i] j一样,都是元素a[i][j]的地址,即&a[i][j]
(4). * ( * (a i) j) 和 * (a[i] j)、( * (a i))[i]和a[i][j] 一样都是代表元素。
2、指向由m个元素组成的一维数组的指针变量(行指针变量)
格式: 类型 ( * 指针变量名 ) [m];
如:int a[5][7];
int ( * p ) [7];
p = a;
四:指向字符串的指针常量
字符串常量:C语言中对字符串常量是按首地址处理字符串常量
1,首地址 2. 地址常量 3. 第一个字符地址
(1) char str[] = “China”;
(2) str = “Chinese”; 不合法 地址常量不能放在等号左边
(3) char *p = “China”;
(4) p = “Chinese”;
(5) char *p = {“China”}; 不合法 不能加花括号
(6) char str[] = {“China”}; 合法,字符串数组在定义同时可初始化,花括号可加可不加
(7) char *p; *p = “china”; 不合法,"china"代表字符串首地址,*p代表内容值
main()
{ char s[20]="abcdefGHI"; //字符数组可以存字符串
char *p="1234567";
printf("%s\n" s 2); // 输出‘cdefGHI’
printf("%s\n" p 5); // 输出‘67’
pri tf("%s\n" strcat(s 3 p 4)); //strcat 输出结果为 defGHI567
printf("%d\n" strlen(p 2)); // 输出结果为5
printf("%s\n" strcpy(p 3 s 9)); //拷贝
printf("%s\n" s);
scanf("%s" s 3); /* 输入: ABC DEF<回车>*/
printf("%s" s);
}
五、指向函数的指针变量
函数名与数组名一样,是起始地址,而且是一个地址
常量。
定义指向函数的指针变量的方式:
类型名 (*指针变量名)() ;
注:
(1) 在定义指向函数的指针变量时,要注意有两个小括
号必须要有 不需要定义形参。
(2) 单独的函数名代表该函数的首地址(函数的入口地
址)。
(3) 函数的指针变量只能指向函数的入口处(函数的首
地址),不能指向函数中的某条指令。(另对指向
函数的指针变量加1是没有意义的)。
(4) 给指向函数的指针变量赋值时,只写函数名即可, 不必写参数
六、返回指针的函数
类型名 函数名(形参)
{ }
返回指针的函数的定义方式为:
类型名 *函数名(形参列表)
{ return 地址}
int *fun(int *x int *y)
{ if(*x<*y)
return x;
else
return y;
}
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); // 7 ,8, 7
}
七、指针数组和指向指针的指针变量
1、若一个数组的所有元素均为指针类型(地址),则称为
指针数组。
格式:
类型名 * 数组名[常量表达式];
int *s[10];
2、指向指针的指针变量
用来存放指针变量地址的指针变量称为指向指针的指针变量。
定义格式:
基类型名 **指针变量名;
如:
int a=3;
int *p=&a;
int **k=&p;
则:*k得到变量p(变量a的地址)。
**k 得到变量a的值(a的数据3)
八、空指针
指针变量可以有空值,即指针变量不指向任何变量,不指向任何有用的存储单元。
在系统中已将NULL定义为0,即NULL的值为0。
int a b c *p=NULL;
此时p 的值为空指针,即p不指向任何有用的存储单元。尽管NULL的值为0,
但我们不能认为p指向了地址为0的存储单元。
注:
(1)当一个指针变量的值为空指针时,我们不能引用它所指向的存储单元。
(2)若某指针(地址)的基类型为void型,则有引用时应进行相应的强制类型置
换。
#include<stdio.h>
main()
{ int a[]={1 2 3 4 5 6 7 8 9 10 11 12};
int *p=a 5 q=NULL;
q=(p 5); // 当一个指针变量得到空指针时,他所指的房子实际上不存在,也就不能进行写和读操作
printf("%d %d\n" *p *q);
}
好啦,今天的分享就到这里了,想一起学习的小白可以回复“资料”即可领取新手大礼包跟开发工具一份哦