指针篇
1.基本指针变量
(1)定义
int i,j;
int *pointer_1,*pointer_2;
pointer_1 = &i;
pointer_2 = &j;
等价于
int *pointer_1 = &i,*pointer_2 = &j;
(指针误区: 大家首先应该知道,指针是地址,是不可变的;指针变量(上述定义的pointer_1为指针变量)是变量,变量是可变的,和通常的变量相比,它存放的量CPU会当地址来处理)
-------------------------------------------------------
(2)简记
*:取该地址空间存放量,*后面的内容CPU当地址处理;
&:取该变量的地址,&后面的内容CPU当变量来处理;
2.一维数组的指针变量
(1)定义
int a[10];
int *p;
p = &a[0];
等价于 p = a;
a[0]和a都表示该数组的首地址;
(2)指向数组的指针变量也可以带下标,如:p[i]、*(p+i);
(3)数组名a代表数组首元素的地址,它是一个指针常量,它的值在程序运行期间是固定不变的,请不要出现类似a++这样的错误。
3.当用数组名做函数参数时传递给函数的是数组的首元素地址,因此要求形参是指针变量;
归纳:
①:形参、实参都用数组名
int a[10];
f(a,10);
.
.
.
viod (int x[ ] , n)
{...}
简解:编译器遇到形参为数组名会当指针变量来处理,故此程序运行期间形参指向数组a[ ]各个元素,或者理解为形参实参在程序运行区间占用同一段内存空间;
②实参数组名,形参指针变量
int a[10];
f(a,10);
.
.
.
viod (int *x, n)
{...}
简解:函数开始执行x指向数组各个元素
③实参形参都是指针变量
int a[10], *p = a;
f(p , 10);
.
.
.
void f(int *x,int n)
{...}
简介:1. p先指向数组a首元素; 2. p值给x; 3. x指向数组a各个元素;
④实参为指针变量,形参为数组名
int a[10],*p = a;
f(p , 10)
void f(int x[],int n)
{...}
简解:1.形参当指针变量处理,后面同③
4.数组a 的性质
int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}}
int 型数据在KEIL编译环境下,占2字节内存
表示形式 |
含义 |
地址 |
a |
二维数组名,指向一位数组a[0],即0行首地址 |
设2000 |
a[0]、*(a+0)、*a |
0行0列元素地址 |
2000 |
a+1,&a[1] |
1行0列元素地址 |
2008 |
a[1]、*(a+1) |
1行0列元素a[1][0]的地址 |
2008 |
a[1]+2、*(a+1)+2、&[1][2] |
1行2列(即a[1][2])元素地址 |
2012 |
*(a[1]+2)、*(*(a+1)+2),a[1][2] |
1行2列(即a[1][2])元素值 |
元素13 |
(1)为什么*(a+1)表示第一行的首地址呢?
答:*(a+x)==a[X]; 两者等价。
(2)那么C语言中是怎么造成*(a+x)与a[X]完全等价呢?
答:在一位数组中,*a就是a[0],a+1指向a[1],a+2指向a[2],a+3指向a[3],也就是说
*(a+1)、*(a+2)、*(a+3)分别是a[1]、a[2]、a[3]。在实际代码生成机械码的关系中,两个效应完全等价。
5.对于 int(*p)[4]的解释
答:int(*p)[4]表示p是一个指针变量,它指向包含4个整形元素的一维数组,此时p只能指向一个包含4个元素的一维数组,p不能指向一维数组中的某一个元素,p的值就是该一维数组的起始地址。
P
(*p)[0] |
(*p)[1] |
(*p)[2] |
(*p)[3] |
→
由此也可得出
指针作为函数参数 |
① 指向变量的指针变量(一般) |
② 指向一维数组的指针变量 |
6.while(*from != ‘\0‘) == while(*from != 0),CPU在处理时,字符与ASCLL码按相同处理。
7.字符数组与字符指针变量
char str[14];
str = "I Love China"; ×(对字符数组只能对各个元素赋值)
数组只可以在定义时整体赋初值,但不能再赋值语句中整体赋值;
BUT(aber)
char *a;
a = "I Love China"; √(注意赋值给a的不是字符,而是字符串第一个元素的地址)
等价于
char *a = "I Love China";
/******典printf******/
char *format;
format = "a=%d,b=%f\n"; 当字符串处理
printf(format,a,b);
等价于
printf("a=%d,b=%f\n",a,b);
8.指向函数的指针
#include<stdio.h>
void main()
{
int max(int,int);
int(*p)(int,int);
int a,b,c;
p = max;
scanf("%d,%d",&a,&b);
c = (*p)(a,b);
printf("a = %d,b = %d,max = %d\n",a,b,c);
}
(1),“int(*p)(int,int);”用来定义p是一个指向函数的指针变量,*p两端的括号绝对不能省略。
(2),"p = max"的作用是将函数max的入口地址赋给指针变量p。和数组名代表数组首元素地址类似,函数名代表该函数的入口地址。(同理:max++是错误的)
(3),指向函数的指针变量的一般定义形式:
数据类型(*指针变量名)(函数参数表列);
9.用指向函数的指针作函数参数
如:
int a = 1;
int b = 2;
int max(int x,int y)
{______________}
void process(int,int,int(*fun)(int,int)); //声明
process(a,b,max); //引用
10.返回指针值的函数
类型名 *函数名(参数列表);
如:
int *a(int x ,int y);
解释:括号的运算优先级大于*号,及是函数a(int x ,int y )的返回值取地址值;
请区别上题8中的int(*p)(int,int);此为指向函数的指针;
int(*p)(int,int); //指向函数的指针
int *a(int,int); //返回指针值的函数
此两者用法顺序相反
用法:
float *p;
float score[][4] = {{1,2,3,4},{5,6,7,8},{11,12,13,14}};
float *search(float (*pointer)[4],int n);
p = search(score, m);
11.指针数组
(1)定义形式
类型名 * 数组名[数组长度];
如:int *p[4];
请不要写成 int (*p)[4]; 这是指向一维数组的指针变量;
指针数组中每一个量都用作指针变量;
为什么用指针数组?
答:它可以比较适合于用来指向若干个字符串,使字符串处理更加方便灵活。
12.指向指针的指针
(1)定义
char **p;
谨记:*p是**p的地址,p是**p的地址,**p是变量。p和*p都是地址;
p前面有两个*号,*运算符的结合性是从右到左,因此**p相当于*(*p),显然*p是指针变量的定义形式。
13.NULL
#define NULL 0 (这句在stdio.h里面已经有了)
p = NULL;
表示p不指向任一有用单元,应该注意p的值为NULL与未对p赋值是两个不同的概念。前者是有值的(0),不指向任何程序变量,后者虽未对p赋值但并不等于P无值,只是它的值是一个无法预料的值,也就是p可能指向一个事先未指定的单元。这种情况很危险的。因此,在引用指针变量之前应对它赋值。
任何指针变量或地址都可以与NULL作相等或不相等的比较,例如:
if(p == NULL)...
14.指向同一个数组中的指针运算
(1)相减、比较
a[0] |
a[1] |
a[2] |
a[3] |
a[4] |
p1指向a[1],p2指向a[3]
那么:
减法:p2 - p1 = 2,但 p1 + p2是无意义的;
比较:指向前面的元素的指针变量“小于”指向后面元素的指针变量。
即:p1 < p2,或者说“p1 < p2”为1(真);
15.void 指针类型
char *p1;
void *p2;
.
.
.
p1 = (char *)p2;
也可:
p2 = (void *)p1;
void用来指向一个抽象的类型数据,将它的值赋给另一个指针变量时要进行强制类型转换使之适合于被赋值的变量的类型。
15.指针类型小结
定义 | 含义 |
int i; | 定义整型变量i |
int*p; | p为指向整型数据的指针变量 |
int a[n]; | 定义整型数组a,它有n个元素 |
int *p[n]; | 定义指针数组p,它有n个指向整型数据的指针元素组成(多) |
int (*p)[n]; | p为指向含n个元素的一维数组的指针变量(一) |
int f(); | f为返为整型函数值的函数 |
int*p(); | p为返回一个指针的函数,该指针指向整型数据 |
int(*p)(); | p为指向函数的指针,该函数返回一个整型值 |
int **p; | p是一个指针变量,它指向一个指向整型数据的指针变量 |
下次更新时间2014.09.26
新的理解和见解可留言相互交流,共同学习