C语言入门第十六篇,再议指针

前面我们介绍了指针的基本性质,今天我们再深入的研究指针的内容。
我们之前了解了指针就是指向变量,那些只是皮毛,想要真正掌握指针就看下面的内容理解的怎么样了。
指针和数组
之前介绍了指针可以通过自己地址的加和减去访问其他地址里面的变量内容,其中一种场景就是指针指向了数组(指针并不能随意的去访问内存地址中的内容,这设计到了操作系统的知识,这里不再赘述),下面我们来看看实际的例子:

#include<stdio.h>
int main()
{
    int a[5]={1,2,3,4,5};
    int i;
    int *p;
    p=a;
    for(i=0;i<5;i++){
        printf("%d\n",*p);
        p++;
    }
    return 0;
} 

上面的代码可以看出,指针指向数组的情况,指针会指向数组的头部,如下图所示
指针指向数组
上图应该很清楚的表达了这个程序的过程,指针p指向了数组头部,通过循环将指针自家,指针不断的指向下一个元素,并输出。
这时你也可以通过下标引用的方式,来访问指针所指向的元素。上面的循环也可以写成下面的样子。

for(i=0;i<5;i++){
        printf("%d\n",p[i]);
    }

这时指针就类似数组,但是这样用也有点危险,因为如果指针越界的话,会带来未知的错误,所以在用指针的时候,一定要在自己的可控范围内。

指针和函数
个人理解的指针和函数分为两种,函数指针和指针函数。
函数指针
函数指针的意思是指向函数的指针,这个在实际的应用中最常见的就是回调函数和转换表。
我们先来讲讲回调函数。有时候我们在编写程序的时候需要传入是一个函数作为参数。具体我以例子来说明:

#include<stdio.h>
int main()
{
    int max(int ,int );
    int min(int ,int );
    int sum(int ,int );
    int process(int ,int ,int(*fun)(int ,int ) );
    int a,b;
    printf("please enter two number:");
    scanf("%d%d",&a,&b);
    printf("max is ");
    process(a,b,max);
    printf("min is ");
    process(a,b,min);
    printf("sum is ");
    process(a,b,sum);
}
int max(int x,int y)
{
    int z;
    if(x<y)
    {
        z=y;
    }
    else
    {
        z=x;    
    }
    return z;
}
int min(int x,int y)
{
    int z;
    if(x<y)
    {
        z=x;
    }
    else
    {
        z=y;
    }
    return z; 
}
int sum(int x,int y)
{
    int z;
    z=x+y;
    return z;
}
int process(int x,int y,int (*fun)(int x,int y))
{
    int z;
    z=(*fun)(x,y);
    printf("%d\n",z);   
}

大家运行一下这个程序,其实很容易明白,我们通过传入不同的函数的指针,让process函数实现求最大值,最小值,求和这些操作,为什么叫做回调函数呢?因为process去回调了,我自己写的max,min,sum函数。这里需要注意,传入process的时候直接写的就是函数名,因为函数名就代表该函数的开头指针。
指针函数
指针函数的概念相对于函数指针来说要简单一些,指针函数表示函数返回一个指针,写法如下:

int *f(int);

这个函数返回一个指向整形变量的指针。下面我们来看看具体例子:

#include<stdio.h>
int main()
{
    int a[][4]={{40,50,60,70},{41,50,60,70},{42,50,60,70},{43,50,60,70}};
    int *search(int (*p)[4],int m);
    int *q;
    int b,i;
    printf("please enter number you want search:");
    scanf("%d",&b);
    q=search(a,b);
    for(i=0;i<4;i++)
    {
        printf("%d\t",*(q+i));
    }
    return 0;
} 
int *search(int (*p)[4],int m)
{
    int *temp;
    temp=*(p+m);
    return temp;
}

我们来看看这个例子,这个例子其实很简单。这个程序输出二维数组中用户输入的值所在那一行的所有数。

  1. 首先程序定义了一个二维数组,声明一个指针函数传入二维数组和一个用户输入的值,定义一些变量
  2. 然后用户输入值,指针q接受指针函数返回的指针值
  3. 接着输出指针q所指向的那一行。
  4. 最后我们看看这个指针函数的定义,首先明白这个函数只是返回一个指向整形变量指针的函数。
  5. 函数用temp接受了p+m的地址值,然后返回了temp;
    看起其实很简单,这里面还是有一些小细节,可能很多人不懂,例如int (*p)[4]这个刚刚我说了是二维数组,要结合我们刚刚讲的来看这个式子,我说过指针和数组在一定情况下可以互换,所以这里把二维数组行方向的数组换成了指针。原理和上面差不多,相当于我的指针指向了行,如下图:
    指针指向二维数组
    当p指针自加的时候,就会指向下一行。多多运行上一个程序就好。
    指针和数组的区别
    我们本章从指针和数组开始,讲到这里我们还是要讲讲他们的区别。有人看到刚刚的例子就会问,二维数组是不是可以用指针的指针来表示?如果你能提出这样的问题,那证明你已经很厉害了,对c语言有自己的见解。回答这个问题我们先来看看指针和数组的区别。
    1.数组在创建的时候就已经分配好了内存。
    这一点很重要,为了我们后续更好的使用数组和指针必须理解这一点。我们必须明白,int a[10];这时候编译器申请了10个整型字节的内存大小的空间(至于1个整数是多少个字节,请看前面的基础数据类型)。数组是连续的一片存储
    然而在指针的声明的时候,他仅仅简简单单的是一个指向整型变量的一个地址
    2.指针如果无法存取,则需要申请空间。
    请看下面的代码
#include<stdio.h>

int main()
{
    int *q;
    *q=9;
    printf("%d\n",*q);
    return 0;
} 

这样操作是错误的,编译器在运行的时候会报错,然后下面的这种方法就可以通过编译。

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int *q;
    q=(int *)malloc(sizeof(int));
    *q=9;
    printf("%d\n",*q);
    return 0;
} 

这里我们使用了后面会使用很多的,malloc申请内存。其实你不要觉得他有多高级,只是简单的把那一行看成申请内存就好了。然后因为没有,所以要申请,就这么简单。
有了申请内存我们就可以用指针的指针来表示二维数组了(当然还有其他不用申请内存的方法,用指针的指针表示二维数组就留给大家来实现啦)。其实二维数组本身就可以看成一个指针的指针。可以看看下面的代码

#include<stdio.h>

int main()
{
    int a[][4]={{40,50,60,70},{41,50,60,70},{42,50,60,70},{43,50,60,70}};
    int i,j;
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("%d ",*(*(a+i)+j));
        }
        printf("\n");
    }
} 

这里举这么多例子就是为了让大家明白数组和指针的转化。如果不是很清楚就先多看看例子,然后去练习写一下。
指针和函数参数
指针在作为函数的参数的时候依然是传值(C语言都是传值并非传址),所以可以先看看这篇文章C语言利用指针在函数中交换两个数的思考
通过上面那篇文章我可以了解如果传入指针的话,需要间接访问才能去修改变量的值,所以指针作为函数参数的时候一定要注意,不然你会发现你传入函数的值没有变。
总结
本篇内容有点杂,甚至我写到后面都不知道该怎么写了,然后又重新整理思路。这篇相当于给大家讲一些比入门要深一点的东西,相信大家一定会用到,如果现在看的有点晕的话,可以后面再来看这章。我尽量让每一篇都相对独立一些,这样什么不懂就可以再回头看什么。
本篇主要围绕指针和数组,指针和函数结合的情况,讨论了大家可能会遇到的情况。
1.指针和数组主要是指针和数组之间的互换,以及互相之间的应用。
2指针和函数,主要是指针函数和函数指针,以及指针作为函数参数的时候的一些情况。

练习
1.试着用指针的指针表示一个二维数组。
2.编写一个回调函数,这个回调函数可以实现两个数加减乘除。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章