C语言学习日记七

函数

一、函数检述

  • 函数是完成特定任务的独立程序代码单元。语法规则定义了函数的结构和使用方式。
  • 函数原型告诉编译器函数的类型;函数调用表明在此处执行函数;函数定义明确指定了函数要做什么。
  • 函数和变量一样,有多种类型。任何程序在使用函数之前都要声明该函数的类型。
  • 一般而言,函数原型指明了函数的返回值类型和函数接受的参数类型。这些信息称为该函数的签名。例如 int sum(int n1,int n2);
  • 和定义在函数中的变量一样,形参也是局部变量,属于该函数私有。
  • ANSI C要求在每个变量前都声明其类型。例如void (int x,y,z)//错误写法
  • 用于测试函数的程序有时被称为驱动程序
  • 使用return时,返回的值不一定是变量的值,也可以是任意表达式的值return (n < m) ? n : m;
  • 可以在函数中使用多个return,但是一个return更容易理解函数。
  • 还可以使用return :或return;这样的语句会终止函数,并把控制返回给主调函数。
  • 函数类型是指函数的返回值类型。
  • 函数原型都应声明在使用函数之前。

二、递归

  • C允许函数调用它自己,这种调用过程称为递归。
  • 可以使用循环的地方都可以使用递归。递归方案更简洁,但是效率没有循环高。
  • 每一级递归的变量都属于本级递归私有

1.递归的基本原理

示例:

/* recur.c -- recursion illustration */
#include <stdio.h>
void up_and_down(int);

int main(void)
{
    up_and_down(1);
    return 0;
}

void up_and_down(int n)
{
    printf("Level %d: n location %p\n", n, &n); // #1
    if (n < 4)
        up_and_down(n+1);
    printf("LEVEL %d: n location %p\n", n, &n); // #2
    
}
  1. 每级函数调用都有自己的变量
  2. 每次函数调用都会返回一次。当函数执行完毕后(即“递”这一部分完成时,该“归”了),控制权将被传回上一级递归。程序必须按顺序逐级返回递归。
  3. 递归函数中位于递归调用之前的语句,均按被调函数的顺序执行。#1的顺序 :第1级、第2级、第3级、第4级。总共执行4次。
  4. 递归函数中位于递归调用之后的语句,均按被调函数相反的顺序进行。#2的顺序:第4级、第3级、第2级、第1级。总共执行4次。
  5. 递归函数必须包含能让递归调用停止的语句。

2、尾递归

  • 最简单的递归形式是把递归调用置于函数的末尾,即正好在return 语句之前。
  • 递归会花费更多的内存。因为递归调用在底层其实是对线程栈的压栈和出栈操作,每调用一次都会压栈一次,并记录相关的局部变量信息,线程栈的内存是非常有限的,而递归调用如果是无限的,那么很快就会消耗完所有的内存资源,最终导致内存溢出,这一点与空的while死循环是不一样的,单纯的死循环会大量的消耗cpu资源,但不会占用内存资源,所以不会导致程序异常。
  • 示例
long rfact(int n)    // 使用递归的函数
{
    long ans;
    
    if (n > 0)
        ans= n * rfact(n-1);
    else
        ans = 1;
    
    return ans;
}

3、递归和倒序计算

  • 递归非常适合处理倒序问题,比循环简单
  • 示例
/* binary.c -- 以二进制形式打印整数 */
#include <stdio.h>
void to_binary(unsigned long n);

int main(void)
{
    unsigned long number;
    printf("Enter an integer (q to quit):\n");
    while (scanf("%lu", &number) == 1)
    {
        printf("Binary equivalent: ");
        to_binary(number);
        putchar('\n');
        printf("Enter an integer (q to quit):\n");
    }
    printf("Done.\n");
    
    return 0;
}

void to_binary(unsigned long n)   /* 递归函数 */
{
    int r;
    
    r = n % 2;
    if (n >= 2)
        to_binary(n / 2);
     putchar(r == 0 ? '0' : '1');
    
    return;
}

三、查找地址:&运算符

  • 指针是C语言最重要的概念之一,用于存储变量的地址。
  • 主调函数不使用return 返回的值,则必须通过地址才能修改主调函数中的值。
  • 主调函数与背调函数是成对出现的,是主动和被动的关系,现在有A、B两个函数,A函数调用了B函数,那么A函数就是主调函数,B函数就是被调函数。
  • 一元&运算符给出变量的存储位置。如果pooh是变量名,那么&pooh是变量的位置。可以把地址看作是变量在内存中的位置。
  • %p格式控制符(pointer指针)用来以十六进制整数方式输出指针的值,附加前缀0x。
  • %p是打印地址的, %x是以十六进制形式打印, 完全不同!

四、更改主调函数中的变量

temp = x;//交换x与y的值
x = y;
y = temp;

五、指针简介

  • 从根本上看,指针是一个值为内存地址的变量(或数据对象)
  • ptr = &pooh;//把pooh的地址赋给ptr,因此ptr“指向”pooh。ptr 和 &pooh的区别是ptr是变量,而&pooh是常量。
  • 要创建指针变量,先要声明指针变量的类型。

1.间接运算符:*

  • ptr = &pooh;然后可以使用间接运算符* 找出存储在pooh中的值,因此该运算符有时也被称为解引用运算符。例如:val = *ptr;//找出ptr指向的值。
  • 语句ptr = &pooh;val = *ptr;等同于val = pooh
  • 地址运算符:&,后面跟一个变量名时,&给出该变量的地址。
  • 间接运算符:*,后更一个指针名或地址时,*给出存储在指针指向地址上的值。

2.声明指针

 int * pi;//pi是指向int类型变量的指针
 char * pc;//pc是指向char类型变量的指针,pc的值是一个地址
 float * pf,* pg;//pf、pg都是指向float类型变量的指针
  • *表明声明的变量是一个指针。int * pi;表明pi是一个指针,*pi是int类型。
  • *和指针名之间的空格可有可无,一般声明时用空格,在解引用变量时省略空格。
  • 指针实际上是一个新类型,不是整数类型。
  • void interchange (&x,&y);//交换的是x和y的地址。
  • 实参用于把值从主调函数传递给被调函数。
  • 如果返回值的类型与声明的返回类型不匹配,返回值将会被转换成函数声明的返回类型。
  • 函数签名指定了传入函数的值的类型和函数返回值的类型。

五、一些补充

  • 错误导致无法编译,警告仍然可以编译。

  • 程序中每个C函数与其他函数都是平等的。

  • &&和||有短路求值的特点(最小化求值)。这是因为C语言是从左往右对逻辑表达式求值

     &&是逻辑与运算符,同真则真。倘若左边计算为假,那么不用计算右边,这个逻辑表达式就为假。
     ||是逻辑或运算符,有真则真,倘若左边计算为真,那么也不用计算右边,这个逻辑表达式就为真。
     一般而言,与 != 这个运算符联系密切。
    
  • PC地址通常用十六进制形式表示。

  • 通过指针,可以在被调函数中改变多个主调函数的值,而不必通过返回值的形式,示例:

void interchange( int * u,int * v)//交换u,v所指向的值
{
	int temp;
	temp = *u;
	*u = *v;
	*v =tem;
}
  • 普通变量把值作为基本量,把地址作为通过&运算符获得的派生量,而指针变量把地址作为基本量,把值作为通过*运算符获得的派生量。
  • 编写程序时,可以认为变量有两个属性:名词和值
  • 编译和加载程序时,计算机认为 变量有两个属性:地址 和 值。地址是变量在计算机内部的名称。对程序员隐藏。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值