指针小结

来源:互联网 发布:手机淘宝用银行卡支付 编辑:程序博客网 时间:2024/05/01 05:15

    随着课程的深入,知识点越来越多,不少同学开始迷惑了,尤其是学了指针以后,更加混乱了。指针似乎和谁都能扯上关系: 指向变量的指针、指向函数的指针、指向数组的指针、指向字符串的指针、返回指针值的函数、指针数组等等。我在这里把一些重要的概念进行小结,希望能起到理清思路的作用。重点理解不同指针的主要用途和优势

 

1.指向变量的指针

1.1 定义:

    int *p, a;

    p = &a;    // p存储a的地址,或者说p指向a

1.2 使用:

    利用指针运算符 *来间接访问所指向的变量。

    *p = 13;   //*p等价于a

1.3 优势:

    利用指针间接操作变量a,这种间接操作的优势在“指针做函数参数”时得到体现,最典型的例子就是编写“交换两个变量值的函数”,值传递没法实现实参变量的交换。如果形参改为指针变量,则可以实现地址传递,从而实现实参变量值的交换。

void swap(int * x, int * y)

{

    int  temp;

    temp= *x;

    *x= *y;

    *y= temp;

}

int main()

{

    int a=6,b=7;

    swap(&a,&b);

    printf("a=%d\nb=%d\n",a,b);

}

 

2.指向函数的指针

2.1定义和基本用法:

void fun(int a, int b)

{

    printf("a+b=%d\n",a+b);

}

main()

{

    void (*pfun)(int,int);  //定义函数指针pfun

    pfun= fun;     //存储函数fun的首地址,或者说pfun指向函数fun

    (*pfun)(5,6);    //利用pfun来间接调用函数fun

}

2.2 函数指针的优势:

    和指向变量的指针相似,函数指针的优势在“函数作为参数传递”时得到体现。它为编写通用函数提供了可能性。通用函数内部使用形参定义的函数指针来间接调用函数,而实参可以传递具体的函数名过去,根据需要,多次调用通用函数时,可以传递不同的函数进去。最典型的例子就是编写通用的求定积分的程序,即在区间[a, b]上求函数f(x)的定积分。不管f(x), a, b怎样变化,求解的过程是一样的: 将区间[a, b]等分成若干份,求f(x)和x轴之间的若干小梯形的面积和。因此可以写一个通用函数来求解定积分,在调用的时候,通过参数把不同的a,b和函数f(x)的指针传进去即可。程序如下:

//求定积分的通用函数

void Integral(float (*f)(float), float a, float b)  //形参定义函数指针

{

    float sum;

    float h=(b-a)/100.0;

    int i;

    sum= ((*f)(a)+(*f)(b))/2.0;   //用函数指针间接调用函数

    for(i=1;i<100;i++)

    {

        sum+=(*f)(a+i*h);

    }

    sum *= h;

    printf("The result is: %.2f\n",sum);

}

//定义不同的f(x)

float f1(float x)  

{

    return 1+x*x;

}

float f2(float x)

{

    return x/(1+x*x);

} 

int main()

{

    //调用通用函数,传递不同的函数首地址(函数名)和a、b过去

    Integral(f1,0,1);

    Integral(f2,0,3);

}

    利用函数指针变量编写的通用函数避免了代码的重复编写,提高了效率。

 

3.返回指针值的函数

    也就是说函数返回了一个地址值。这种函数在C语言中很普遍,尤其是一些字符串处理函数。比如strcpy,strcat等都返回第一个参数str1的首地址。因为字符串总是以一个’\0’结尾的,所以只要知道了起始地址,也就能方便的处理整个字符串了。很多字符串处理函数的参数也定义为字符指针,所以可以直接用函数调用作为函数的参数。例如:

    strlen(strcat(str1,str2));

    strcat(strcpy(str1,str2), str3);

    另外,动态内存分配函数malloc等也是返回指针值的函数。如果分配成功,返回被分配内存区域的首地址,它是void型指针,配合强制类型转换,可以转换成需要的指针类型。因为分配的内存区域是连续的,所以本质上可以当作数组一样去使用。利用返回的首地址和指针变量,可以访问每一个元素。

 

4.指针和一维数组

4.1指针指向一维数组:

    int a[10], *pa;

    pa = a;  //指针指向数组头

    pa = &a[3];  //指针指向数组的第3个元素

4.2 指针做++和- -运算

    和数组名a不同,pa的值可以被修改,因此可以++- -运算(跳过4个字节),指向下一个元素或前一个元素。配合指针运算符*,可以写出非常简练的表达式或语句。比如两个字符串(分别存储在字符数组str1和str2中)的拷贝,可以简化成如下的形式:

    char *pstr1 = str1;

    char * pstr2= str2;

    while(*pstr1++ = *pstr2++) ;

4.3指针做关系运算

    因为数组元素是连续存放的,所以指向一维数组的指针变量也可以做关系运算。关系运算主要用在循环语句的条件中,比如:

    for( pa = a; pa<a+5; pa++ ) 

        printf(“%d”, *pa);

 

5.指针和二维数组

    重点是理解行指针列指针的概念:对于二维数组a,数组名a是行指针,a+i则跳过i行,为了访问行上的元素,需要把行指针转换为列指针,方法是加*,即 *(a+i),这个地址在数值上等于a+i,但它是列指针,它加j后在列上跳过j个元素,即*(a+i)+j指向第i行第j列的元素,也就是说*(a+i)+j == &a[i][j];那么为了访问元素a[i][j],还需要再做一次指针运算,即,*(*(a+i)+j),它等价于a[i][j]。因为从一维数组我们知道,*(a+i)等价于a[i],所以*(*(a+i)+j)也可以写作*(a[i]+j)。二维数组的每一行本来就可以看作是一个一维数组,数组名是a[i],所以*(a[i]+j)就是a[i]这个一维数组中的第j个元素。

    数值上,它们是相等的: a  == a[0] == &a[0][0] == *a。

    还有一个需要掌握的是行指针变量  int (*p)[4],它的优势是可以将二维数组的一行传递给某个函数


例:二维数组存储学生的成绩,每行存储一个学生,求指定学号的学生的平均成绩。

# include"stdio.h"

float ave(int(*pi)[3],int n)    //定义行指针变量pi,准备接收行指针

{

    int j;

    float sum=0,aver;

    for(j=0;j<n;j++)

    {

        sum+= *(*pi+j);   // 在该例中*(*pi+j)等于 *(*(score+2)+j)或者 *(score[2]+j)

    }

    aver= sum/n;

    return aver;

}

int main()

{

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

    printf("ave= %.2f\n",ave(score+2,3));  //传递行指针score+2给pi

    return 0;

}

 

6.指针数组

    每个元素都是一个指针值的数组。注意区别指针数组和上面定义的行指针变量(有点像函数指针和返回指针值的函数):

    int * p[4];   int (*p)[4]; (前者是指针数组,后者是行指针变量)

    int *fun( )   int (*p)( )  (前者是返回指针值的函数,后者是函数指针)

    指针数组的每一个元素存储一个地址值,每个元素都可以当作同类型的指针变量一样去使用。使用前必须初始化。

    int * p[4]; int a[4];

    for(i=0;i<4; i++)

        p[i] =&a[i];

   指针数组主要用于字符串的处理。教材上例11.4用字符指针数组指向若干个字符串,在对字符串进行排序的时候,不需要挪动字符串本身,而只需要挪动指针数组元素即可,也就是说改变指向关系即可。这提高了程序的效率。

   指针数组的另一个用途就是带参数的main函数:int main(int argc, char * argv[ ]),用命令行方式运行程序时,可以给main函数传递参数,参数和程序名都是字符串,字符串的个数保存在变量argc中,字符串的首地址保存在argv指针数组中。 


例:从命令行输入两个整数,计算并输出它们的和:

//add.c

#include “stdio.h”

#include “stdlib.h”

int main(int argc, char*argv[])

{

    int a, b;

    a= atoi(argv[1]);

    b= atoi(argv[2]);

    printf("a+b= %d\n",a+b);     

 }

命令行输入:add  45  67

运行结果:a+b = 112


注意:上面的输入中,字符串“add”的地址存入了argv[0],“45”的地址存入了argv[1],“67”的地址存入了argv[2]。

0 0
原创粉丝点击