浅析c语言的函数调用

浅析c语言的函数调用

C语言中的函数调用形式差别在形参的不同或是返回类型的不一样,下面来谈一下这些函数。

第一种也是最简单的一种:

请看下面例子:(该函数实现比较两个值的大小)

#include<stdio.h>

#include <stdlib.h>

int compare(int x,int y)

{

int z;

if(x>=y)

z=1;

else

z=0;

return z;

}

 int main(void)

{

  int x,y,z;

  printf("please input the and y!\n");

 scanf("%d %d",&x,&y);

z=compare(x,y);

printf("%d\n",z);

return EXIT_SUCCESS;

}

 这个函数知识简单比较xy的值,将xy传递给compare函数,而后返回z值。这里讲一下函数传递的两个规则:

1、函数之间的调用关系是传值调用的;

2、对于指针或是数组名传递的参数则是传址调用的,但这第一条不矛盾。具体在下面讲。

对于规则1的解释是调用程序传递的是变量或实参的一份拷贝,给被调用程序的是一份复制品,这样被调用的函数才不致于随便改动调用程序的数据(这也有例外)。

下面是例子程序:(该函数原本是打算实现交换两个值的,结果实现不了!)

#include<stdio.h>

#include <stdlib.h>

int swap(int x,int y)

{

int temp;

temp=x;

x=y;

y=temp;

}

 int main(void)

{

  int x,y;

  printf("please input the and y!\n");

 scanf("%d,%d",&x,&y);

swap(x,y);

printf("%d,%d\n",x,y);

return EXIT_SUCCESS;

}

试运行这个程序,你会发现,打印出来的仍是xy的原值,调用函数没有起到任何作用,或是说程序并没有达到你所想的效果。这就印证了刚才所说的传值是实参的一份拷贝而已!

第二种是传递的参数是指针,请看下面例程:(该函数实现两个数交换其值)

#include<stdio.h>

#include <stdlib.h>

int swap(int *x,int *y)

{

int temp;

temp=*x;

*x=*y;

*y=temp;

}

 int main(void)

{

  int x,y;

  int *p=&x,*q=&y;//定义两个指针变量指向xy

 printf("please input the and y!\n");

 scanf("%d,%d",&x,&y);

swap(&x,&y);//注意这里的调用形式,必须加上这个"&"符号

printf("%d,%d\n",x,y);

return EXIT_SUCCESS;

}

这个程序时对上面程序的改进或者说是纠正,这样xy才能交换其值。可是你也许会问这时为什么呢?仅仅改变为指针形式就可以吗?是的,让我慢慢道来:这确实是刚才所说的一份拷贝,但现在拷贝的是一份指针,就是指向xy的指针,但是通过swap函数里的却可以间接访问在主函数里的xy的值,所以也就可以修改主函数的值了,但这时主函数的指针值确实改变不了的,因为主函数仅仅是传递了一份拷贝,任凭swap函数这么修改这份指针,始终改不了主函数的指针。现在明白了吗?

第三种:传递的是数组名,请看下面的例程:(该函数实现将某一字符串中的小写改为大写字母,其余的不变 )

#include <stdio.h>

#include <stdlib.h>

void change(char *string)

{

int i=0;

while(*(string+i)!='\n')//记住这种写法“*string+i)”

{

if(*(string+i)>='a'&&*(string+i)<='z')

*(string+i)-=32;

i+=1;

}

}

int main(void)

{

 char string[1000]={"Hello,my world!"};

change(string);

printf("%s\n",string);

return EXIT_SUCCESS;

}

这种就和上面的第二种情况很类似,传递给change函数的是一个指向字符数组首元素的指针的拷贝,仿佛是通过传址调用的,但实际上和刚才说的,尽管传递的是指针拷贝,但还是能改变主函数的数据。对于被调用函数头还可以用这种表达方式:void changechar string[])。对于被调用函数的调用形式应该是程序所写的那样,而不应该写成change(char string),这样gcc环境下编译会出现这样的“taioshi.c:17: parse error before "char"”提示错误。顺便提一下,在change函数,出现了const关键词,这里有一个细微的表达差别:char const *stringchar const string,前者是指指针指的变量不能修改,后者则是值指针值不能修改。还有就是const char *const A,标识指针stringstring指向的对象都不可变!

第四种:返回类型是指针(或是叫指针函数),看下面例程

#include<stdio.h>

#include <stdlib.h>

#include<string.h>

#define MAX_SIZE 1000

//该子函数实现从某一个字符串中查找一个关键词并返回它的指针

char *find_int(char key_value,char *array,int len)

{

int i;

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

if(array[i]==key_value)

return &array[i];

return NULL;

}

int main(void)

{

char array[MAX_SIZE];

char key_value;

int i;

        int  len=0;
 
        printf("plesse  input  the  value  which  you  want  to  find!\n");

scanf("%c",&key_value);

 

printf("please input the string!\n");

scanf("%s",array);

 

len=strlen(array);//计算该字符串的长度

 

       printf("%c\n",*find_int(key_value,array,len));

return EXIT_SUCCESS;

}

    (对于上面的红色字体的注释是“打印返回的关键字,记住返回的是一个指针,这个指针指向所找得字符,这里若是没加*号,将返回一个地址!”)

通过以上函数可以看到返回类型有很多种,这算是比较复杂的一种了。当返回一个指针时,需要在被调用的函数前加上“*”,同时返回一个地址或是空指针。

有时你会被要求修改一个字符串,然后返回该字符串,这时可能你会用这种方式返回一个修改后的指针,但是请记住刚才提到的规则后你就会用正确的方法来解决这类问题了!

参考书籍:《c与指针》 Kenneth A.Reak

以下附上从百度知道里摘的一篇关于指针函数与函数指针论述不错的帖子:

(网址:http://zhidao.baidu.com/question/264795890.html)

函数指针变量

    在C语言中,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数。我们把这种指向函数的指针变量称为“函数指针变量”。

函数指针变量定义的一般形式为:

类型说明符  (*指针变量名)();

其中“类型说明符”表示被指函数的返回值的类型。“(* 指针变量名)”表示“*”后面的变量是定义的指针变量。最后的空括号表示指针变量所指的是一个函数。

例如:

    int (*pf)();

表示pf是一个指向函数入口的指针变量,该函数的返回值(函数值)是整型。

【例】本例用来说明用指针形式实现对函数调用的方法。

int max(int a,int b){

  if(a>b)return a;

  else return b;

}

main(){

  int max(int a,int b);

  int(*pmax)();

  int x,y,z;

  pmax=max;

  printf("input two numbers:\n");

  scanf("%d%d",&x,&y);

  z=(*pmax)(x,y);

  printf("maxmum=%d",z);

}

从上述程序可以看出用,函数指针变量形式调用函数的步骤如下:

1) 先定义函数指针变量,如后一程序中第9行 int (*pmax)();定义 pmax为函数指针变量。

2) 把被调函数的入口地址(函数名)赋予该函数指针变量,如程序中第11行 pmax=max;

3) 用函数指针变量形式调用函数,如程序第14行 z=(*pmax)(x,y);

4) 调用函数的一般形式为:

    (*指针变量名) (实参表)

使用函数指针变量还应注意以下两点:

a) 函数指针变量不能进行算术运算,这是与数组指针变量不同的。数组指针变量加减一个整数可使指针移动指向后面或前面的数组元素,而函数指针的移动是毫无意义的。

b) 函数调用中"(*指针变量名)"的两边的括号不可少,其中的*不应该理解为求值运算,在此处它只是一种表示符号。

指针型函数

    前面我们介绍过,所谓函数类型是指函数返回值的类型。在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的函数称为指针型函数。

定义指针型函数的一般形式为:

    类型说明符 *函数名(形参表)  

     

        ……          

     

其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。类型说明符表示了返回的指针值所指向的数据类型。

如:

    int *ap(int x,int y)

    {

      ......       

}

表示ap是一个返回指针值的指针型函数,它返回的指针指向一个整型变量。

【例】本程序是通过指针函数,输入一个1~7之间的整数,输出对应的星期名。

main(){

  int i;

  char *day_name(int n);   

  printf("input Day No:\n");

  scanf("%d",&i);

  if(i<0) exit(1);

  printf("Day No:--->%s\n",i,day_name(i));

}

char *day_name(int n){

  static char *name[]={ "Illegal day",

                        "Monday",

                        "Tuesday",

                        "Wednesday",

                        "Thursday",

                        "Friday",

                        "Saturday",

                        "Sunday"};

  return((n<1||n>7) name[0] name[n]);

}

本例中定义了一个指针型函数day_name,它的返回值指向一个字符串。该函数中定义了一个静态指针数组name。name数组初始化赋值为八个字符串,分别表示各个星期名及出错提示。形参n表示与星期名所对应的整数。在主函数中,把输入的整数i作为实参,在printf语句中调用day_name函数并把i值传送给形参n。day_name函数中的return语句包含一个条件表达式,n值若大于7或小于1则把name[0]指针返回主函数输出出错提示字符串“Illegal day”。否则返回主函数输出对应的星期名。主函数中的第7行是个条件语句,其语义是,如输入为负数(i<0)则中止程序运行退出程序。exit是一个库函数,exit(1)表示发生错误后退出程序,exit(0)表示正常退出。

应该特别注意的是函数指针变量和指针型函数这两者在写法和意义上的区别。如int(*p)()和int *p()是两个完全不同的量。

int (*p)()是一个变量说明,说明p是一个指向函数入口的指针变量,该函数的返回值是整型量,(*p)的两边的括号不能少。

int *p()则不是变量说明而是函数说明,说明p是一个指针型函数,其返回值是一个指向整型量的指针,*p两边没有括号。作为函数说明,在括号内最好写入形式参数,这样便于与变量说明区别。

对于指针型函数定义,int *p()只是函数头部分,一般还应该有函数体部分。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值