int a=20;int *p=a;
指针的三个相关值
(1)p:里面放指针即地址,例如p=&a;
(2)*p:p指向的那个对象,例如*p=a;
(3)&p表示p变量的地址
数组:int arr[10]一维数组中数组名就是首元素的地址,但是有两个例外:1.sizeof(数组名):括号里面的是整个数组;2,&数组名:表示的是整个数组的地址。
例如,
int arr[10]={1,2,3,4,5,6};p=arr;printf(“%d",*p);//*p=arr[0]==1
printf("%d",*(p+1));//*(p+1)==arr[1]==2;
它的绝对值等于指针和指针之间的元素个数,但前提是两个指针都指向同一空间,例如&arr[9]-&arr[0]=9可以用来统计字符串数组的元素个数,例如
产生原因:1.未初始化2.越界访问3.指向空间释放(局部变量出函数后空间消失)
避免的方法:1.初始化: int*pa=NULL;不能对空指针赋值。当指针不在使用时,及时置NULL,指针使用前检查有效性。
2.用assert(断言):头文件在
在指针中const可放在*左右边,但是两边的·性质不同。
放左边:例如:const char *p,char const *p。限制了*p,即不能改变它所指向的内容,但可以通过p改变它的地址。
放右边:例如:char*const p.限制了p,即不可以改变它的地址,但可以通过*p改变它所指向的内容。
传值:例如:swap(a,b)
传址:例如:swap(&a,&b)
如果在函数中要改变实参值的时候要用传址,不能用传值。因为形参只是实参的临时拷贝,它们所在内存空间不同,所以需要传址找到实参的在内存中的位置。例如在交换数的时候需要传址,但在求两个数相加的函数中用传值就可以。
本质:即使形参写成了数组的形式,本质上也是指针变量,例如:void test(int arr[ ])==void test (int *arr)传过去的只有首元素的地址。所以在函数中使用sizeof(arr)/sizeof(arr【0】)是得出的结果是一。
int *pa=&a;int **pa1=&pa;//**pa1==*pa==a,ppa为二级指针
1.整型指针数组
类型 int *pa[],即pa数组中存放的类型为int*;
int*arr[]={arr1,arrr2,arr3};||arr数组中存放arr1,arr2,arr3数组首元素地址。
2.字符串指针数组
(1.区分char arr[]="abcdef";该数组可以被修改,而char *arr="abcdef";实际上是把字符串中的首元素地址赋给了arr,abcdef为常量字符串,不可更改。
注:在内存中,内容相同的常数字符串只需保存一份;而不同字符数组即使内容相同但是保存在内存中的空间不同。
(2.打印%s字符串时只需要提供首字符的地址。
(1.格式:int arr[10];int (*p)[10]=&arr 。(2.数组类型:int (*)[10],p是数组指针,p中存放的是整个数组的地址,所以&arr+1跳过4*10个字节。
(1.首元素为第一行地址,数组名是它的第一行地址。而arr[i]是第i行的数组名,即arr[i][0]的地址
(2.二维数组中的元素在内存中连续存放
(1.格式:类型+(*函数指针)(形参 ,形参),例如int (*p)(int ,int )=&add
(2.指针类型的运用
1.(*(void(* )( ) ) 0 ) ( )中void(*) ( )为函数指针类型,(类型)0为将0转变为函数指针类型,所以该式子相当于一个函数。
2.void(*single(int ,void(* )(int )))(int)该式子为single函数的声明,它的参数类型有int ,函数指针类型,返回类型为函数指针类型。
图片中pf函数实现了函数调用,例如pf(add)即是把add函数作为该函数的实参其中p(x,y)=add(x,y)。
(1.typedef unsigned int uint:把unsigned int用uint替换
(2.数组指针重命名要放在*的旁边,例如,typedef int(*parr_t)[6]即把int(*)[6]用parr_t替换。
函数指针也一样。