【C语言进阶】二、指针-创新互联

一、指针数组

我们提供的服务有:网站制作、成都网站设计、微信公众号开发、网站优化、网站认证、同安ssl等。为成百上千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的同安网站制作公司

存放指针的数组

int* arr[10];

二、数组指针

指向数组的指针

  int (*p)[10]      其中p是数组指针的名字

  int (*) [10]       这个是类型(&arr 取出的类型)

三、数组参数和指针参数

一维数组传参,直接使用指针接收

void test(int *arr)

二维数组的传参,

void test(int arr[3][5]);

void test(int arr[][5]);//行可以省略,列不可以省略,但是不可以都省略

  void test(int (*p)[5]);//形参写成指针的形式

注:

  当函数的形参是二级指针时,不可以只把二维数组的数组名传入函数,因为二维数组的数组名是第一行的地址,需要用数组指针来接收。

四、函数指针

函数指针存储的是函数的地址,其中,例如,函数名是Add  ,&Add  与  Add  意义一样;

int Add (int x,int y)

{

  return x+y;

}

此函数的地址表达方式是:  int  (*pf)(int , int)=Add;   pf  就是函数指针变量。

注:

  a、int ret = (*pf) (2,3); 和 int ret = Add(2,3); 和 int ret = pf(2,3);  等价,其中第一个表达式中的 * 相当于摆设,无实际作用,但如果加了 * 千万不要忘了加括号,必须加括号!

例题:

下边的两行代码的意思

1 . ( *(void (*) () ) 0 ) ();

a、(void (*) () )是函数指针类型,是强制类型转换的作用;

b、(void (*) () ) 0 对0进行强制类型转换,意思就是认为0地址处放置着(void (*) () )类型的函数;

c、*(void (*) () ) 0 对此函数进行解引用

d、( *(void (*) () ) 0 ) () 调用该函数

2 . void(*signal (int , void ( * ) (int)) ) (int);

  a、signal 先和括号结合,所以signal目前是一个函数

  b、signal (int , void ( * ) (int)) 表示signal的第一个参数是 int ,第二个参数是void ( * ) (int) 是一个函数指针类型;

  c、void(*signal (int , void ( * ) (int)) ) (int)  表示函数的返回类型是void(*) (int) 

五、函数指针数组

例如有四个函数:

int (*pf1) (int ,int) = Add;

int (*pf1) (int ,int) = Sub;

int (*pf1) (int ,int) = Mul;

int (*pf1) (int ,int) = Div;

函数指针数组的表达方式

int (*pf[5]) (int ,int) = {0, Add, Sub, Mul, Div}; pf首先和 [4] 结合

六、指向函数指针数组的指针

函数指针                                        int (*pf) (int ,int ) = &Add;

函数指针数组                                 int (* pfarr[4]) (int , int);

指向函数中指针数组的指针           int (* (*p3)[4]) (int , int) = &pfarr;

七、回调函数

        回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一 个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

void test()
{
    printf("hehe\n");
}

void print_hehe(void (*p) ())
{
    if(1)
    {
        p();
    }
}

int main()
{
    print_hehe(test);
    return 0;
}

以上代码,没有调用函数  test(),将函数指针传给了 print_hehe 由此函数通过  if  条件和函数指针来调用函数,此时  test()  是回调函数。 

用法:

#includevoid menu()
{
    printf("##############################\n");
    printf("#####  1.Add       2.Sub  ####\n");
    printf("#####  3.Mul       4.Div  ####\n");
    printf("#####  0.exit             ####\n");
    printf("##############################\n");
}

int Add(int x, int y)
{
    return x + y;
}

int Sub(int x, int y)
{
    return x - y;
}

int Mul(int x, int y)
{
    return x * y;
}

int Div(int x, int y)
{
    return x / y;
}

void calc(int(*pf)(int, int))
{
    int x = 0;
    int y = 0;
    int ret = 0;

    printf("请输入2个操作数:>");
    scanf("%d%d", &x, &y);
    ret = pf(x, y);
    printf("ret=%d\n", ret);
}

int main()
{
    int input = 0;
    int ret = 0;

    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            calc(Add);
            break;
        case 2:
            calc(Sub);
            break;
        case 3:
            calc(Mul);
            break;
        case 4:
            calc(Div);
            break;
        case 0:
            printf("退出!");
            break;
        default:
            printf("选择错误!");
            break;
        }
    } while (input);

    return 0;
}

上边代码中 calc() 就是回调函数.

下边是 qsort 的使用,qsort是一个库函数,是基于快速排序算法实现的一个排序函数,qsort可以排序任意类型的数据。

void qsort (void* base,                                                        待排序数组的起始位置

size_t num,                                                       数组元素个数

size_t width,                                                      一个元素的字节大小

int (*cmp)(const void*  e1,const void* e2)        函数指针,cmp是比较函数,e1、  e2是待比较两个元素的地址。返回值是当e1e2时,返回>0的数。cmp是自定义的比较函数。

)

#include#includeint cmp_int(const void* e1, const void* e2)
{
    return (*(int*)e1 - *(int*)e2);
}

struct Stu
{
    char name[20];
    int age;
    double score;
};

int cmp_stu_by_age(const void* e1,const void* e2)
{
    return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

void test1()
{
    struct Stu arr[3] = { {"mike",20,55.5},{"lisa",30,88.0},{"kuka",50,90.0} };
    int sz = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}

void test()
{
    int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, sz, sizeof(arr[0]), cmp_int);
}

int main()
{
    test();
    test1();
    return 0;
}

注:

  a、void* 类型的指针可以接收任意类型的指针;

指针与数组相关例题解析

例1、

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

sizeof 计算对象所占内存的大小,单位是字节。

printf("%d\n",sizeof(a))                                        16
  printf("%d\n",sizeof(a+0));                                   4/8  表示数组首元素的地址
  printf("%d\n",sizeof(*a));                                      4     表示第一个元素的大小
  printf("%d\n",sizeof(a+1));                                   4/8   第二个元素的地址的大小
  printf("%d\n",sizeof(a[1]));                                   4      第二个元素的大小
  printf("%d\n",sizeof(&a));                                    4/8    数组的地址的大小
  printf("%d\n",sizeof(*&a));                                  16      计算整个数组的大小
  printf("%d\n",sizeof(&a+1));                                4/8    计算指向数组后边数组处地址的大小
  printf("%d\n",sizeof(&a[0]));                                4/8    第一个元素地址的大小
  printf("%d\n",sizeof(&a[0]+1));                            4/8    第二个元素地址的大小

例2、

int main()
{
    char arr[] = {'a','b','c','d','e','f'};
    printf("%d\n", sizeof(arr));
    printf("%d\n", sizeof(arr+0));
    printf("%d\n", sizeof(*arr));
    printf("%d\n", sizeof(arr[1]));
    printf("%d\n", sizeof(&arr));
    printf("%d\n", sizeof(&arr+1));
    printf("%d\n", sizeof(&arr[0]+1));

    printf("%d\n", strlen(arr));
    printf("%d\n", strlen(arr+0));
    printf("%d\n", strlen(*arr));
    printf("%d\n", strlen(arr[1]));
    printf("%d\n", strlen(&arr));
    printf("%d\n", strlen(&arr+1));
    printf("%d\n", strlen(&arr[0]+1));

    return 0;
}

sizeof 计算对象所占内存的大小,单位是字节。

 printf("%d\n", sizeof(arr));                                6
  printf("%d\n", sizeof(arr+0));                            4/8
  printf("%d\n", sizeof(*arr));                               1
  printf("%d\n", sizeof(arr[1]));                            1
  printf("%d\n", sizeof(&arr));                              4/8
  printf("%d\n", sizeof(&arr+1));                          4/8
  printf("%d\n", sizeof(&arr[0]+1));                      4/8

  printf("%d\n", strlen(arr));                                  随机值
  printf("%d\n", strlen(arr+0));                              随机值
  printf("%d\n", strlen(*arr));                                 err,此时*arr是首元素,首元素的值是97,可能会发生越界
  printf("%d\n", strlen(arr[1]));                               err
  printf("%d\n", strlen(&arr));                                随机值
  printf("%d\n", strlen(&arr+1));                            随机值
  printf("%d\n", strlen(&arr[0]+1));                        随机值

例3、

int main()
{
    char arr[] = "abcdef";
    printf("%d\n", sizeof(arr));
    printf("%d\n", sizeof(arr+0));
    printf("%d\n", sizeof(*arr));
    printf("%d\n", sizeof(arr[1]));
    printf("%d\n", sizeof(&arr));
    printf("%d\n", sizeof(&arr+1));
    printf("%d\n", sizeof(&arr[0]+1));
    printf("%d\n", strlen(arr));
    printf("%d\n", strlen(arr+0));
    printf("%d\n", strlen(*arr));
    printf("%d\n", strlen(arr[1]));
    printf("%d\n", strlen(&arr));
    printf("%d\n", strlen(&arr+1));
    printf("%d\n", strlen(&arr[0]+1));
    return 0;
}

sizeof 计算对象所占内存的大小,单位是字节。

  printf("%d\n", sizeof(arr));                         7
  printf("%d\n", sizeof(arr+0));                     4/8 数组首元素地址
  printf("%d\n", sizeof(*arr));                        1    首元素
  printf("%d\n", sizeof(arr[1]));                     1
  printf("%d\n", sizeof(&arr));                      4/8  
  printf("%d\n", sizeof(&arr+1));                  4/8
  printf("%d\n", sizeof(&arr[0]+1));              4/8

  printf("%d\n", strlen(arr));                          6
  printf("%d\n", strlen(arr+0));                      6
  printf("%d\n", strlen(*arr));                         err
  printf("%d\n", strlen(arr[1]));                      err
  printf("%d\n", strlen(&arr));                        6
  printf("%d\n", strlen(&arr+1));                   随机值
  printf("%d\n", strlen(&arr[0]+1));                5

例4、

int main()
{
    char *p = "abcdef";
    printf("%d\n", sizeof(p));
    printf("%d\n", sizeof(p+1));
    printf("%d\n", sizeof(*p));
    printf("%d\n", sizeof(p[0]));
    printf("%d\n", sizeof(&p));
    printf("%d\n", sizeof(&p+1));
    printf("%d\n", sizeof(&p[0]+1));
    printf("%d\n", strlen(p));
    printf("%d\n", strlen(p+1));
    printf("%d\n", strlen(*p));
    printf("%d\n", strlen(p[0]));
    printf("%d\n", strlen(&p));
    printf("%d\n", strlen(&p+1));
    printf("%d\n", strlen(&p[0]+1));
    return 0;
}

sizeof 计算对象所占内存的大小,单位是字节。

  printf("%d\n", sizeof(p));                        4/8
  printf("%d\n", sizeof(p+1));                    4/8
  printf("%d\n", sizeof(*p));                       1 
  printf("%d\n", sizeof(p[0]));                     1
  printf("%d\n", sizeof(&p));                       4/8
  printf("%d\n", sizeof(&p+1));                   4/8
  printf("%d\n", sizeof(&p[0]+1));               4/8
  printf("%d\n", strlen(p));                          6
  printf("%d\n", strlen(p+1));                      5  
  printf("%d\n", strlen(*p));                         err
  printf("%d\n", strlen(p[0]));                      err
  printf("%d\n", strlen(&p));                        随机值
  printf("%d\n", strlen(&p+1));                    随机值
  printf("%d\n", strlen(&p[0]+1));                5

例5、

int main()
{
    inta[3][4] = {0};
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof(a[0][0]));
    printf("%d\n",sizeof(a[0]));
    printf("%d\n",sizeof(a[0]+1));
    printf("%d\n",sizeof(*(a[0]+1)));
    printf("%d\n",sizeof(a+1));
    printf("%d\n",sizeof(*(a+1)));
    printf("%d\n",sizeof(&a[0]+1));
    printf("%d\n",sizeof(*(&a[0]+1)));
    printf("%d\n",sizeof(*a));
    printf("%d\n",sizeof(a[3]));
    return 0;
}

sizeof 计算对象所占内存的大小,单位是字节。

  printf("%d\n",sizeof(a));                                       48                         
  printf("%d\n",sizeof(a[0][0]));                                4 
  printf("%d\n",sizeof(a[0]));                                    16  第一行的大小
  printf("%d\n",sizeof(a[0]+1));                               4/8  第一行首元素的地址+1是第一行第二个元素的地址
  printf("%d\n",sizeof(*(a[0]+1)));                            4     第一行第二个元素
  printf("%d\n",sizeof(a+1));                                   4/8   a表示二维数组第一行的地址,a+1是第二行的地址
  printf("%d\n",sizeof(*(a+1)));                                16  对第二行的地址解引用
  printf("%d\n",sizeof(&a[0]+1));                              4/8 第二行的地址
  printf("%d\n",sizeof(*(&a[0]+1)));                           16  第二行的大小

printf("%d\n",sizeof(*a));                                        16  第一行的大小
  printf("%d\n",sizeof(a[3]));                                      16  第四行的大小,此时虽然越界,但没有访问,所以可以正常运行。

例6、

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int*ptr= (int*)(&a+1);
    printf( "%d,%d", *(a+1), *(ptr-1));    
    return0;
}

结果是2、5

例7、

struct Test
{
    int Num;
    char*pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;

int main()
{
    p=0x100000;
    printf("%p\n", p+0x1);
    printf("%p\n", (unsignedlong)p+0x1);
    printf("%p\n", (unsignedint*)p+0x1);
    return0;
}

答案是: 

00100014          当结构体指针+1时,加的是结构体的大小,所以加20,又因为是16进制表示

00100001          指针变量p被转换成无符号长整型变量,所以+1是就是数值直接+1

00100004          指针变量p被转换成整形指针,+1 就是加一个整形的大小

例8、

int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int* ptr1= (int*)(&a+1);
    int* ptr2= (int*)((int)a+1);
    printf( "%x,%x", ptr1[-1], *ptr2); 
    return 0;
}

答案    0x4   0x20000000

例9、

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

答案是:1;因为花括号中的小括号相当于逗号表达式,所以数组 a 的初始化相当于,a[3][2]={1,3,5};而 a[0]是第一行的地址,打印时,打印第一行的首元素。

例10、

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

答案: FFFFFFFC,  -4

p[4][2] 等价于 *(*(p+4)+2)  ; p 最初是数组名,也就是数组首元素的地址,p是一个数组指针,p+1相当于,向后跳过四个元素,而指针-指针得到的是指针之间的元素个数。自行画图

例11、

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

答案:10   5

例12、

int main()
{
    char*a[] = {"work","at","alibaba"};
    char**pa=a;
    pa++;
    printf("%s\n", *pa);
    return 0;
}

答案:at

因为 char *a[] 中存的是这三个字符串的首字符的地址;

char** pa 中存的是 a 的地址;

pa 最初是指向 a 数组的第一个元素,即  "work" 中w的地址;

pa++ 后指向了 a 数组中第二个元素,即 "at" 中 a 的地址;

又因为数组中每个字符串最后都有一个  \n  所以最后打印  at。 

例13、

int main()
{
    char*c[] = {"ENTER","NEW","POINT","FIRST"};
    char**cp[] = {c+3,c+2,c+1,c};
    char***cpp=cp;
    printf("%s\n", **++cpp);
    printf("%s\n", *--*++cpp+3);
    printf("%s\n", *cpp[-2]+3);
    printf("%s\n", cpp[-1][-1]+1);
    return0 ;
}

答案: POINT        ER        ST        EW

*cpp[-2]  等价于 **(cpp-2)+3;

cpp[-1][-1]  等价于  *(*(cpp-1)-1)+1`;

C8 39

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


当前文章:【C语言进阶】二、指针-创新互联
地址分享:http://myzitong.com/article/dicjoo.html