指针
1.1 指针概念
指针也是一个变量,做为指针变量的值是另一个变量的地址。指针存放的内容是一个地址,该地址指向一块内存空间
1.2 指针变量的定义
可以定义一个指向一个变量的指针变量。
int *p;//表示定义一个指针变量。
*p;//代表指针所指内存的实际数据
切记,指针变量只能存放地址,不能将一个int型变量直接赋值给一个指针。
int *p = 100;// 野指针与1.4节本质一样
1.3 空指针
一个指向NULL的指针,我们称之为空指针,意味着这个指针不指向任何一个变量。
int *p = NULL;
1.4 野指针
定义之后没有初始化的指针。
int *p;
*p = 100;
1.5 &取地址运算符
1.6 无类型指针
定义一个指针变量,但不指定它指向具体哪种数据类型。可以通过强制转化将void *转化为其他类型指针,也可以用(void*)将其他类型指针强制转化为void类型指针。
void *p
在C语言当中,可以将任何一种地址赋值给void *指针。
1.7 指针的兼容性
指针之间赋值比普通数据类型赋值检查更为严格,例如:不可以把一个double *赋值给int
1.8 指针与数组的关系
一个变量有地址,一个数组包含若干个元素,每个元素在内存中都有地址。
int a[10];
int *p = a;
比较p和&a[0]的地址是否相同
在C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址,如下图:
int *p = &a;
p = p + 1;//表示移动sizeof(int)=4个字节的位置。如下图:
1.9 通过指针使用数组元素
int a[10];
int *p = a;// 在C语言里面数组名称是个常量,值是不可改变的
地址 值
p + 1代表&a[1] p[1]表示a[1]
p + 5 代表&a[5] p[5]表示a[5]
1.10 指针数组
即用于存储指针的数组,也就是数组元素都是指针。
int *a[4]; //表示:数组a中的元素都为int型指针
1.11 数组指针
即指向数组的指针。
int (*a)[4] ; // 表示:指向数组a的指针,通常用来指向二维数组,如下:
p++; // 每次移动4*sizeof(int)=16个字节
p[0] = arr首地址
p[1] = arr[1];
1.12 指向指针的指针
指针就是一个变量,既然是变量就也存在内存地址,所以可以定义一个指向指针的指针。
inti=10;
int*p=&i;
int**pp=&p;
printf("%d\n",**pp);
1.13 指针变量作为函数的参数
函数的参数可以是指针类型。,它的作用是将一个变量的地址传送给另一个函数。
void swap (int *a, int *b) {
int i = *a;
*a = *b;
*b = i;
}int main() {
inti1= 10;
int i2 = 20;
swap(&i1, &i2);
return 0;
}
1.14 一维数组名作为函数的参数
当数组名作为函数参数时,C语言将数组名解释为指针
当数组名作为函数参数传递给被调用函数时,被调用函数是不知道数组有多少元素的
int func(int array[10]);//指定形参数组的大小是不起任何作用的,因为C编译器对形参数组大小不做检查,只是将数组的首地址传给形参数组。
int func(int array[], int len); //形参数组也可以不指定大小,定义数组时在数组名后跟一个空的中括号,为了在被调函数中处理数组元素的需要,可以另设一个参数len,传递数组元素的个数。
相当于传递是一个地址,那么就可以通过地址来修改实参的值。
只要传递是数组名,那么形参一定可以通过地址修改实参的值。
1.15 二维数组名作为函数的参数
二维数组做函数参数时可以不指定第一个下标。
int func(int array[][10]);
1.16 指向二维数组的指针
参考1.11节,数组指针。
1.17 指向常量的指针与指针常量
const char *p;//定义一个指向常量的指针
char *const p;//定义一个指针常量,一旦初始化之后其内容不可改变
1.18 const 关键字保护数组内容
如果将一个数组做为函数的形参传递,那么数组内容可以在被调用函数内部修改,有时候不希望这样的事情发生,所以要对形参采用const参数。
func(const int array[]); // 在func方法中,array数组中的内容不能被修改, 只读。
1.19 指针作为函数的返回值
char *func(); //返回值为char *类型的函数
1.20 指向函数的指针
指针可以指向变量,数组,也可以指向一个函数。
一个函数在编译的时候会分配一个入口地址,这个入口地址就是函数的指针,函数名称就代表函数的入口地址。
函数指针的定义方式:int(*p)(int);//定义了一个指向int func(int n)类型函数地址的指针。
1定义函数指针变量的形式为:函数返回类型(*指针变量名称)(参数列表)
2函数可以通过函数指针调用
3 int( * P)()代表指向一个函数,但不是固定哪一个函数。
1.21 指向函数的指针作为函数的参数
将函数指针做为另一个函数的参数称为回调函数,示例如下:
1.22 指针运算
赋值:int *p= &a;
求值:int I =*p;
取指针地址 int**pp = &p;
将一个整数加(减)给指针:p + 3; p – 3;
增加(减少)指针值p++,p--
求差值 ,p1 –p2,通常用于同一个数组内求两个元素之间的距离
比较 p1 == p2,通常用来比较两个指针是否指向同一个位置。
1.23 指针小结
指针类型分析
分析指针,可以从变量名处起,根据运算符优先级结合,一步一步分析.
int p; //这是一个普通的整型变量
int p; //首先从P处开始,先与结合,所以说明P是一个指针,然后再与int结合,说明指针所指向的内容的类型为int 型.所以 P是一个返回整型数据的指针
int p[3]; //首先从P处开始,先与[]结合,说明P 是一个数组,然后与int结合,说明数组里的元素是整型的,所以 P是一个由整型数据组成的数组
int *p[3]; //首先从P处开始,先与[]结合,因为其优先级比高,所以P是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与 int结合,说明指针所指向的内容的类型是整型的,所以是一个由返回整型数据的指针所组成的数组
int (*p)[3]; //首先从P处开始,先与结合,说明P是一个指针然后再与[]结合(与”()”这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P是一个指向由整型数据组成的数组的指针
int **p; //首先从 P开始,先*与结合,说明P是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与 int结合,说明该指针所指向的元素是整型数据. 所以P是一个返回指向整型数据的指针的指针
int p(int); //从P处起,先与()结合,说明P是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数然后再与外面的int 结合,说明函数的返回值是一个整型数据.所以P是一个有整型参数且返回类型为整型的函数
int (*p)(int); //从P处开始,先与指针结合,说明P是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P是一个指向有一个整型参数且返回类型为整型的函数的指针
int (*p(int))[3]; //从 P开始,先与()结合,说明P是一个函数,然后进入()里面,与int结合,说明函数有一个整型变量参数,然后再与外面的结合,说明函数返回的是一个指针,,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P是一个参数为一个整数且返回一个指向由整型指针变量组成的数组的指针变量的函数参考:http://www.oschina.net/question/96003_20998