我们知道,通常我们来访问数组元素和指针变量的时候都可以通过下标和偏移两种方式来访问,那么他们有什么不一样的地方呢?

wKioL1ZijAuQEKFXAABLi_GPCH0242.png

我们来看一个小栗子:

int main ( )
{
             int a [5] = { 1, 2 , 3, 4, 5 };
             int *ptr = (int *)(& a + 1 );
             printf( "%d %d\n" ,*(a+ 1),*(ptr -1));
             system("pause" );
             return 0 ;
}

##对指针进行的加一操作实际上加的是指针类型的大小而不是以字节为单位。

&a+1:取出数组的首地址,在该地址上面加上一个sizeof(a)的值,即&a+5*sizeof(int)

 a+1:数组第二个元素的地址

二维数组

int arr[i][j]  访问方式:*(*(arr+i)+j)       

int main ( )
{
             int arr [3][ 2] = { (0 , 1), ( 2, 3 ), (4, 5) };
             int  *p ;
             p = arr [0];
             printf( "%d" , p[ 0] );
             system("pause" );
             return 0 ;
}

结果:1

详解:在数组中我们用括号将元素包含在其中,我们认为它是逗号表达式,在数组初始化的时候之初始化逗号表达式里最后一个元素。所以arr[0][0]=1  

         上述程序中p=a[0]相当于p=&a[0][0]。 

int main ( )
{
             int a [5][ 5];
             int( *p )[4];
             p = (int (*)[4]) a;
             printf( "%p ,%d\n" , &p[ 4][2 ] - &a[ 4][2 ], &p[ 4][2 ] - &a[ 4][2 ] );
             system("pause" );
             return 0 ;
}

结果: FFFFFFFc  -4

详解:我们使用一个大小为4的数组指针来访问了一个大小为5 的数组,在p的眼中默认它的数组大小是4,所以每次它的外层下标加一被默认为越过了4个元素,

          而a的外层下标加一被默认为是越过了5个元素

int main ( )
{
             int aa [2][ 5] = { 1 , 2, 3, 4 , 5, 6, 7 , 8, 9, 0 };
             int *ptr1 = (int *)(& aa + 1 );
             int *ptr2 =/*(int *)*/(*( aa + 1 ));
             printf( "%d%d" , *(ptr1 - 1), *(ptr2 - 1) );
             system("pause" );
             return 0 ;
}

结果:10 5

详解:&aa+1指向0后面的元素,强转成int之后-1则向前偏移一个×××空间

          (aa+1) 其中aa表示一维数组的首址,aa的类型是int(*)[5]加一之后偏移五个×××空间指向6,再解引用相当于&aa[1][0]向前偏移一个字节空间指向5

二级指针:存放以及指针变量的地址

一维数组的传参

函数声明为int fun(int *p)

数组 int arr[10]的传参形式可以为: 1.fun(arr)  2.fun(&arr[])

二维数组传参

1.将其作为一维数组处理将首元素首址传参

int fun ( int * p )
int main( )
{
             int arr [3][ 4];
             fun( &arr [0][ 0] );
}

2.将指针指向整个内层一维数组传参

int fun ( int( * p )[4 ] )
int main( )
{
             int arr [3][ 4];
             fun( arr );
}

##在函数内部不能使用sizeof 来求数组的大小,所以必须传参获得数组的大小

利用二级指针的传参

当利用二级指针传参时,我们要将一级指针的地址传入

函数被声明为:int fun2(int **p){...} 我们在传参时可以这样传:fun2(&p) /*p为一个指针变量 */      fun2(&arr)   /*  arr被声明为char *arr[] ,其是一个指针数组  */

典型错误:内存泄漏 ,str开辟内存失败

原因:形参是实参的临时拷贝,对于指针变量也是同样,我们在平时使用的传址调用的成功实现是因为我们通过解引用访问了指针变量存放的地址的内容,而在这里,我们是直接对指针变量进行操作,我们所分配的空间都给了局部变量st而不是我们所期望的str

void getmemory ( char * st )
{
             st = (char *)malloc( 20 * sizepf( char ) );
             if (st == NULL)
            {
                         printf( "Out of memory!\n" );
                         exit( EXIT_FAILUR )
            }
}
int main ( )
{
             char *str = NULL;
             getmemory( &str );
             return 0 ;
}

改正:传进指针的地址即二级指针

void getmemory ( char ** st )
{
            * st = (char *)malloc( 20 * sizepf( char ) );
             if (*st == NULL)
            {
                         printf( "Out of memory!\n" );
                         exit( EXIT_FAILUR )
            }
}
int main ( )
{
             char *str = NULL;
             getmemory( &str );
             return 0 ;
}

典型错误:返回局部变量地址

char *getmemory ( )
{
             char arr [10];
             return arr ;
}
int main ( )
{
             char *str ;
             str = get memory( );
            strcpy( str, "abc" );
             return 0 ;
}

改正:将临时变量改成静态变量,空间不被销毁可以访问

char *getmemory ( )
{
             static char arr[ 10];
             return arr ;
}
int main ( )
{
             char *str ;
             str = get memory( );
            strcpy( str, "abc" );
             return 0 ;
}

函数指针

测试输出函数的地址:

printf( "&fun = %p\n" , &fun );

printf( "fun = %p\n" , fun );

输出结果相同

##在函数指针中fun和&fun没有任何区别,完全相同

调用函数:

fun( );

(*fun)();

(************fun)();

程序结果相同------*符号在此没有作用,编译器不识别!

函数的地址要保存在一个指针中

函数指针的书写形式:一般来说我们根据函数的类型来书写指针 【类型】【指针名】【函数的参数类型列表】

EG:   通过函数指针来访问函数

int add ( int a, int b ){ ... };
int main ( )
{
             int( *padd )(int, int) = add ;
             int ret = (*padd)( 1, 2 );
             return 0 ;
}

引入函数指针的意义:实现回调函数

int add ( int a, int b )
{
             return a + b;
}
int sub ( int a, int b )
{
             return a - b;
}
int operation ( int( * pfun )(int , int) )
{
             int num1 = 0;
             int num2 = 0;
             scanf( num1 , num2 );
             return pfun ( num1, num2 );
}
int main ( )
{
             int ret operation( add );
             printf( "%d\n" , ret );
             system( "pause" );
             return 0 ;
}

函数指针数组

int( *pfun [4] )( char *, const char *);
pfun[0 ] = fun;
pfun[1 ] = fun1;

调用:pfun[i]("123","123");