数组指针,函数指针

回顾:

字符串在字符串常量区,若两个指针中存的都是helloworld!,那么就没必要在内存中存两份,那么puts的输出结果为yes

Printf中不一定只能传“”,也可以传数组的首元素


指向数组的指针

数组指针:能够指向整个数组。与之前学过的指针不同,他们只能指向数组中的一个元素。

int  a[10] = {1,2,3,4,5,6,7,8,9,0};

对于数组a而言,数组的数组名a就是首元素的地址。

&a,那么a是一个指针,a的类型就是一个长度为10的一位整形数组,那么&a就是一个指向长度为10的一维数组的指针。

a的类型:int[10];

所以在编写程序过程中,不能写一个int *p;p = &a;二者的类型不匹配

p是一个int 型的指针,而&a是一个长度为10的一维整形数组的指针

如何定义地址变量p:int(*p)[10];

其中,*是一个类型说明符,说明p是一个指针,剩下的int[10]即为指针的基类型。

()是不可省略的,若省略(int*p[10]),则为指针数组,其含义为:定义了一个叫p的数组,其中装有10个int*,p为数组名。


由前面的内容可知,a<=>&a[0],指向数组的指针。a[0]此时是一个长度为4的一维整形数组,a作为数组名,就是该数组首元素的地址。那么a就是一个地址值,但是在编译器中int *p = a编译会报警。

在二维数组中,(a + i)得到的是第i行的地址,*(a + i)得到的是第i行首元素的值,*(*(a + i)+ j)就是第i行第j列元素的值。

数组指针应用:

二维数组求和:

int sumArray(int (*a)[4],int len)
{
    int i,j,sum = 0;
    for(i = 0;i < len;++i)
    {
        for(j = 0;j < 4;++j)
        {
            sum += *(*(a + i) + j);
        }

    }
    return sum;
}

求二维数组每一行的平均值

void advArray(int (*a)[4],int rows,int * result)
{
    int i,j;
    for(i = 0;i < rows;++i)
    {
        int sum = 0;
        for(j = 0;j < 4;++j)
        {
            sum += *(*(a + i) + j);
        }
        result[i] = sum / 4;
    }
}

函数指针

形如int (*pfn)(int,int) 的指针就是函数指针,*pfn就是这个函数指针的名字

函数的函数名即为入口地址

函数指针的作用

运用函数指针也还是为了实现间接访问

在函数的入口地址后面加一个(),就表示调用函数

目的:降低程序的耦合性(利用回调函数)

举个例子:打印能被3整除的数

void printArray(int *a,int len,int (*pfn)(int))
{
    int i;
    for(i = 0;i < len;++i)
    {
        if(pfn(a[i]) != 0)
        {
            printf("%d\n",*(a + i));
        }
    }
}
int div2(int n)
{
    return n % 2 == 0;
}
int div3(int n)
{
    return n % 3 == 0;
}
int main(void)
{
    int a[] = {1,2,3,4,5,6,7,8,9,10,11,12};
    int len = sizeof(a) / sizeof(a[0]);
    printArray(a,len,div3);
    return 0;
}

指针的指针

注意:要实现在被调函数中修改主调函数的值,要传递给被调函数的一定是主调函数的地址

图中,q即为指向指针的指针

当一个指针数组作为实参传递时,形参的类型是指针的指针

练习:

利用二分法查找字符串中的值

void swap(char *a,char *b)
{
    char *t;
    t = *a;
    *a = *b;
    *b = t;
}
void reverse(char **s,int len)
{
    int i;
    for(i = 0;i < len / 2;++i)
    {
        swap(s+i,s+len + i - 1);
    }
}

void sortString(char **s,int len)
{
    int i,j;
    for(i = 0;i < len - 1;++i)
    {
        for(j = i + 1;j < len;++j)
        {
            if(strcmp(s[i],s[j]) > 0)
            {
                swap(&s[i],&s[j]);
            }
        }
    }
}
char *binaryFind(char **s,int len,char *ss)
{
    int begin = 0;
    int end = len - 1;
    while(begin <= end)
    {
        int mid = (begin + end) / 2;
        if(strcmp(ss,s[mid]) > 0)
        {
            begin = mid + 1;
        }
        else if(strcmp(ss,s[mid]) < 0)
        {
            end = mid - 1;
        }
        else
        {
            return s[mid];
        }
        
    }
    return NULL;
}
int main(void)
{
    char *s[] = {"hello","world","china"};
    char *ss = "hello";
    int len = sizeof(s) / sizeof(s[0]);
    sortString(s,len);
    int *ret = binaryFind(s,len,ss);
    printf("%p\n",ret);
 }

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值