指针进阶(数组指针,函数指针,函数指针数组)

指针进阶

1.字符指针

在指针的类型中我们知道有一种指针类型为字符指针 char *

一般使用:

int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'a';
    return 0;
}

还有一种使用方式如下:

int main()
{
    const char* pstr = "hello bit.";//这里是把“hello bit”的首字符地址放到了pstr中
    printf("%s\n", pstr);//打印结果为hello bit
    return 0;
}

这里特别容易让人以为是把字符串 hello bit 放到字符指针 pstr 里,但是本质是把字符串 hello bit 的首字符的地址放到了pstr中。类似于数组与指针的关系。

2.数组指针

数组指针的定义

指向数组的指针为数组指针

下面代码哪个是数组指针

int *p1[10];
int (*p2)[10];//p1, p2分别是什么?

解释:这里要注意:【】的优先级要高于 * 号,所以p1先和【】结合,p1是指针数组,存放了10个整型指针。而p2先和 * 结合,说明p2是一个数组指针,该指针指向的是一个大小为10的整型数组。

&数组名VS数组名

int arr[10];

那么arr和&arr有什么不同呢

其实&arr和arr,虽然值是一样的,但是意义是不一样的。

实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。(细细体会一下)

本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型,数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。

数组指针的使用

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
    int i = 0;
    for(i=0; i<row; i++)
   {
        for(j=0; j<col; j++)
       {
            printf("%d ", arr[i][j]);
       }
          printf("\n");//打印完一行后换行
   }
}
void print_arr2(int (*arr)[5], int row, int col)
{
    int i = 0;
    for(i=0; i<row; i++)
   {
        for(j=0; j<col; j++)
       {
            printf("%d ", arr[i][j]);
       }
        printf("\n");
   }
}
int main()
{
   int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
   print_arr1(arr, 3, 5);
    //数组名arr,表示首元素的地址
    //但是二维数组的首元素是二维数组的第一行
    //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
    //可以数组指针来接收
    print_arr2(arr, 3, 5);
    return 0;
}

函数指针

指向函数的指针

void test()
{
 printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();

答案是pfun1

pfun1先和 * 结合,所以为函数指针,指向一个返回类型是空,参数也是空的函数。

pfun2先和()结合,所以为函数,返回类型是空指针,参数为空。

下面来看一段有意思的代码

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

该代码定义了一个名字为signal,返回类型为void ( * )(int),参数为int和void( * )(int)的函数。

这段代码太复杂而且难以理解,可以简化如下

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

函数指针数组

定义

存放函数指针的数组

int (*parr1[10])();

该代码定义了一个名为parr1的存放了十个指向返回类型为int,参数为空的函数的指针的数组。

用途:转移表

例:计算器

普通实现:

#include <stdio.h>
int add(int a, int b)
{
 return a + b;
}
int sub(int a, int b)
{
 return a - b;
}
int mul(int a, int b)
{
 return a*b;
}
int div(int a, int b)
{
 return a / b;
}
int main()
{
 int x, y;
 int input = 1;
    int ret = 0;
    do
   {
        printf( "*************************\n" );
        printf( " 1:add           2:sub \n" );
        printf( " 3:mul           4:div \n" );
        printf( "*************************\n" );
        printf( "请选择:" );
        scanf( "%d", &input);
        switch (input){
        case 1:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = add(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 2:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = sub(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 3:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = mul(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 4:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = div(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 0:
                printf("退出程序\n");
 breark;
        default:
              printf( "选择错误\n" );
              break;
       }
 } while (input);
    
    return 0;
}

使用函数指针数组实现:

#include <stdio.h>
int add(int a, int b)
{
           return a + b;
}
int sub(int a, int b)
{
           return a - b;
}
int mul(int a, int b)
{
           return a*b;
}
int div(int a, int b)
{
           return a / b;
}
int main()
{
     int x, y;
     int input = 1;
     int ret = 0;
     int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
     while (input)
     {
          printf( "*************************\n" );
          printf( " 1:add           2:sub \n" );
          printf( " 3:mul           4:div \n" );
          printf( "*************************\n" );
          printf( "请选择:" );
      scanf( "%d", &input);
          if ((input <= 4 && input >= 1))
         {
          printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = (*p[input])(x, y);//通过函数指针数组调用函数
         }
          else
               printf( "输入有误\n" );
          printf( "ret = %d\n", ret);
     }
      return 0;
}

回调函数

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

首先演示一下qsort函数的使用:

#include<stdio.h>
#include<stdlib.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{
  return (*( int *)p1 - *(int *) p2);
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;
    
    qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);//qsort函数有三个参数,第一个为需要排序的数组的首元素地址,第二个为每个元素所占的字节数,第三个为排序所需用的函数的指针
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
   {
       printf( "%d ", arr[i]);
   }
    printf("\n");
    return 0;
}

使用回调函数,模拟实现qsort(采用冒泡的方式)。

注意:这里第一次使用 void* 的指针,讲解 void* 的作用。

void * 指针能接受任意类型的数据,但是不能解引用,也不能加减运算。

#include <stdio.h>
int cmp(const void * p1, const void * p2)//比较两个数的大小,p1>p2返回值大于0,p1=p2返回值为0,p1<p2返回值小于0
{
  return (*( int *)p1 - *(int *) p2);
}

void swap(void *p1, void * p2, int size)//交换两个数
{
    int i = 0;
    for (i = 0; i< size; i++)
   {
        char tmp = *((char *)p1 + i);
       *(( char *)p1 + i) = *((char *) p2 + i);
       *(( char *)p2 + i) = tmp;
   }//因为无法对void * 类型数据进行操作,所以将p1 p2强制转化为char * 类型,每次交换一个字节的数据,直到交换了size个字节为止,size是p1 p2本来的字节数。
}

void bubble(void *base, int count , int size, int(*cmp )(const void *,const void *))
{
    int i = 0;
    int j = 0;
    for (i = 0; i< count - 1; i++)
   {
       for (j = 0; j<count-i-1; j++)
       {
            if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0)
           {
               swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);
           }
       }
   }
}

int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;
    bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
   {
       printf( "%d ", arr[i]);
   }
    printf("\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值