C语言学习总结9——函数定义


1、函数的定义

函数定义的语法如下:
类型
函数名(形式参数)
代码块

int function(int a)
{
    代码块
}

2、return语句

当执行流到达函数定义的末尾时,函数就将返回(return),也就是说,执行流返回到函数被调用的地方 。return语句允许你从函数体的任何位置返回,并不一定要在函数体的末尾。它的语法如下所示:

return expression

表达式expression 是可选的。如果函数无需向调用程序返回一个值,它就被省略。这类函数在绝大多数其他语言中被称为过程(procedure)。这些函数执行到函数体末尾时隐式地返回,它们没有返回值。这种没有返回值的函数在声明时应该把函数的类型声明为void

但是,从表达式内部调用一个过程类型的函数(无返回值)是一个严重的错误,因为这样一来在表达式的求值过程中会使用一个不可预测的值(垃圾)。

3、函数的声明

3.1、原型

函数原型(Function Prototype):也称为函数声明(Function Declaration),它描述了函数的接口,包括返回类型、函数名和参数列表。函数原型不包含函数体,也不需要对形参进行命名(也可以进行命名),只需指明参数的类型即可。例如:int add(int, int);

向编译器提供一些关于函数的特定信息显然更为安全,我们可以通过两种方法来实现:
一、如果同一源文件的前面已经出现了该函数的定义,编译器就会记住它的参数数量和类型,以及函数的返回值类型。接着,编译器便可以检查该函数的所有后续调用(在同一个源文件中),确保它们是正确的。
二、使用函数原型(function prototype);原型总结了函数定义的起始部分的声明,向编译器提供有关该函数应该如何调用的完整信息。使用原型最方便的方法是把原型置于一个单独的文件,当其他源文件需要这个函数的原型时,就使用#include指令包含该文件。
在这里插入图片描述

3.2、函数的缺省认定

当程序调用一个无法见到原型的函数时,编译器便认为该函数返回一个整型值。对于那些并不返回整型值的函数,这种认定可能会引起错误。

所有的函数都应该具有原型,尤其是那些返回值不是整型的函数。记住,值的类型并不是值的内在本质,而是取决于它被使用的方式。如果编译器认定函数返回一个整型值,它将产生整数指令操纵这个值。如果这个值实际上是个非整型值,比如说是个浮点值,其结果通常将是不正确的。
在这里插入图片描述

4、函数的参数

在这里插入图片描述

如果被函数传递的参数是一个数组名,并且在函数中使用下标引用该数组的参数,那么在函数中对数组元素进行修改实际上修改的是调用程序中的数组元素。函数将访问调用程序的数组元素,数组并不会被复制。这个行为被称为“传址调用”

对原始数据的影响:
传值调用:由于函数接收的是实际参数值的副本,因此在函数内部对参数值的修改不会影响原始数据。函数只是在其本地副本中修改该值。
传址调用:由于函数直接访问原始数据的内存地址,因此在函数内部对数据的修改会直接影响原始数据。

数组参数的这种行为似乎与传值调用规则相悖。但是,此处其实并无矛盾之处——数组名的值实际上是一个指针,传递给函数的就是这个指针的一份拷贝。下标引用实际上是间接访问的另一种形式,它可以对指针执行间接访问操作,访问指针指向的内存位置。参数(指针)实际上是一份拷贝,但在这份拷贝上执行间接访问操作所访问的是原先的数组。

bool inteven_parity(int value, int n_bits) {  
    int parity = 0; // 计数器,用于计算1的个数  
      
    // 循环计算value中最低n_bits位中1的个数  
    while (n_bits > 0) {  
        parity += value & 1; // 检查最低位是否为1  
        value >>= 1;         // 将value右移一位,相当于丢弃最低位  
        n_bits -= 1;         // 减少要检查的位数  
    }  
      
    // 如果parity是偶数(即parity对2取余为0),则返回TRUE(或1)  
    // 注意:在C语言中,通常使用0表示FALSE,非0值表示TRUE  
    // 这里我们可以直接返回parity % 2的结果,因为0是偶数,1是奇数  
    return parity % 2 == 0; // 如果是偶数,返回true(在C语言中是非零值)  
    // 或者等价地,可以返回!(parity & 1);  
}  
  
// 示例使用  
int main() {  
    int value = 9;  // 二进制表示为 1001,有两个1  
    int n_bits = 4; // 我们检查最低的4位  
    bool result = inteven_parity(value, n_bits);  
    printf("Parity is even: %s\n", result ? "true" : "false"); // 应该输出 "true"  
    return 0;  

如下函数的目的是交换调用程序所传递的这两个参数的值。但这个程序是无效的,因为它实际交换的是参数的拷贝,原先的参数值并未进行交换。

void swap(int x, int y) {  
    int temp;  
    temp = x;  // 将x所指向的值赋给temp  
    x = y;     // 将y所指向的值赋给x所指向的位置  
    y = temp;   // 将temp的值赋给y所指向的位置  
}  

为了访问调用程序的值,你必须向函数传递指向你希望修改的变量的指针。接着函数必须对指针使用间接访问操作,修改需要修改的变量。如下程序所示:

void swap(int *x, int *y) {  
    int temp;  
    temp = *x;  // 将x所指向的值赋给temp  
    *x = *y;     // 将y所指向的值赋给x所指向的位置  
    *y = temp;   // 将temp的值赋给y所指向的位置  
}  
#include <stdio.h>  
  
/**  
 * 把一个数组的所有元素都设置为零。  
 * 从数组最后一个元素开始,逐个清除数组中的所有元素。  
 * 注意使用递减索引避免了越出数组边界的可能性。  
 */  
void clear_array(int array[], int n_elements) {  
   while(n_elements)
    array[--n_elements] = 0;
}  
  
int main() {  
    int array[] = {1, 2, 3, 4, 5};  
    int n_elements = sizeof(array) / sizeof(array[0]); // 计算数组元素个数  
  
    // 调用clear_array函数  
    clear_array(array, n_elements);  
  
    // 打印清零后的数组以验证  
    for (int i = 0; i < n_elements; ++i) {  
        printf("%d ", array[i]);  
    }  
  
    return 0;  
}

这个例子同时说明了另外一个特性。在声明数组参数时不指定它的长度是合法的,因为函数并不为数组元素分配内存。间接访问操作将访问调用程序中的数组元素。这样,一个单独的函数可以访问任意长度的数组,但是,函数并没有办法判断数组参数的长度,所以函数如果需要这个值,它必须作为参数显式地传递给函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值