指针数组、数组指针、指针的指针及函数指针详解与用法

先来介绍一下指针: 

指针一种类型,理论上来说它包含其他变量的地址,因此有的书上也叫它:地址变量。
是类型就有大小且都是4字节大小,里边只是存储了一个变量的地址而已。
大小为4字节是因为寻址空间为(32位)0x00000000~~0xffffffff,最大只需要4字节,所以就设定指针类型大小为四字节
不管什么类型的指针,char * 、int * 、int (*)[] 、string * 、float *、long  long *、 double * 、
int (*)()(函数指针)等等。
都是说明了本指针所指向的地址空间是什么类型而已,了解了这个基本上所有的问题都好象都变的合理了。

下面我们再来看一下指针数组和数组指针:

//如果你想了解指针最好理解以下的公式 : 
int*ptr;         //指针所指向的类型是int 
char*ptr;        //指针所指向的的类型是char 
int**ptr;        //指针所指向的的类型是int* (也就是一个int * 型指针) 
int(*ptr)[3];    //指针所指向的的类型是int()[3] //二维指针的声明 

指针数组:一个数组里存放的都是同一个类型的指针,通常我们把他叫做指针数组。 比如 int * a[10];它里边放了10个int * 型变量,由于它是一个数组,已经在栈区分配了10个(int * )的空间,也就是32位机上是40个字节,每个空间都可以存放一个int型变量的地址,这个时候你可以做个循环去初始化它。

例子:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    int *ptr[2];
    ptr[0] = (int *)malloc(4);
    ptr[1] = (int *)malloc(4);
    int i = 0;
    for(i; i < 2; i++)
    {
        *ptr[i] = (i + 1) * 10;
    }
    printf("sizeof(ptr)=%d\n",sizeof(ptr));
    i = 0;
    for(i; i < 2; i++)
    {
        printf("sizeof(ptr[%d])=%d\n", i, sizeof(ptr[1]));
        printf("sizeof(*ptr[%d])=%d:*ptr[%d]=%d\n", i, sizeof(*ptr[1]), i, *ptr[i]);
    }

    int *qtr[2];
    int arr[] = {1, 2, 3};
    int brr[] = {10, 20, 30};
    qtr[1] = arr;
    qtr[2] = brr;
    i = 0;
    for(i; i < 3; i++)
    {
        printf("qtr[1][%d] = %d\n", i, qtr[1][i]);
    }
    i = 0;
    for(i; i < 3; i++)
    {
        printf("qtr[1][%d] = %d\n", i, qtr[2][i]);
    }

    char *str[5] = {"hello","world","welcome"};
    printf("sizeof(str)=%d\n",sizeof(str));
    i = 0;
    for(i; i < 3; i++)
    {
        printf("str[%d]=%s\n", i, str[i]);
        printf("sizeof(str[%d])=%d\n", i, sizeof(str[i]));
        printf("strlen(str[%d])=%d\n", i, strlen(str[i]));
    }
    free(ptr);
    return 0;
}
//注:动态分配的内存块要手动释放,然会造成内存泄漏

运行结果为:
这里写图片描述

数组指针: 一个指向一维或者多维数组的指针;

int main()
{
   int * b = int arr[10];//指向一维数组的指针b    
   int (*b2)[10] = int brr[10][10]; //注意,这里的b2指向了一个二维int型数组的首地址. 注意:在这里,b2等效于二维数组名,但没有指出其边界,即最高维的元素数量,但是它的最低维数的元素数量必须要指定!就像指向字符的指针,即等效一个字符串,不要把指向字符的指针说成指向字符串的指针。这与数组的嵌套定义相一致。 
   int(*b3) [30] [20];   //三级指针――>指向三维数组的指针; 
   int (*b4) [20];       //二级指针; 
   b3 = int crr[1] [20] [30]; 
   b4 = int drr[30] [20];//两个数组都是由600个整数组成,前者是只有一个元素的三维数组,每个元素为30行20列的二维数组,而另一个是有30个元素的二维数组,每个元素为20个元素的一维数组。
                         //再次重申:这里的b2的类型是int (*) ,这样表示一个指向二维数组的指针。 b3表示一个指向(指向二维数组的指针)的指针,也就是三级指针.
   return 0;
}
  • 补充: 不管是一维数组还是多维数组存储地址空间都是连续的。

指针的指针:

  • 顾名思义,就是保存指针的地址,指向指针的指针。一级指针可以获取到两个值,一个是保存的地址,另一个是所指向地址空间里面的值。指针的指针可以获取到三个值,第一个是保存的指针的地址,第二个是保存指针所指向的地址,第三个是保存指针所指向的地址空间里面的值。一级指针有一次解引用,二级指针有两次解引用,以此类推。每次解引用得到的是指向所保存的值。
int main()
{
   int a = 10;
   int *ptr = &a;
   int **pptr = &ptr;
   printf("ptr=%x\n",ptr); 
   printf("*ptr=%d\n",*ptr);
   printf("pptr=%x\n",pptr);
   printf("*ptr=%x\n",*pptr);
   printf("**ptr=%d\n",**pptr); 
   return 0;
}

这里写图片描述

函数指针:

  • 函数指针就是指向函数首地址的指针,函数也有地址空间,首地址即为函数名又为函数的入口,通过函数指针就能够调用该指针所指向的函数。

例子:

int sum(int a, int b)
{
    return a + b;
}
int main()
{
    int a = 10;
    int b = 20;
    int (*p)() = &sum;
    int m = (*p)(a, b);
    printf("m=%d\n",m);
    return 0;
}

这里写图片描述

关于数组指针和函数指针,使用场景也不多,接触比较少,总结的也不多,欢迎大家前来补充。

猜你喜欢

转载自blog.csdn.net/magic_world_wow/article/details/80502256