Day05

函数

  • 函数的声明
    /*
     * C语言规定:
     * 如果将函数的敌营写在了函数调用之后,那么必须要在调用之前编写函数的声明
     *
     * 什么是函数的定义:
     * 函数的定义就是函数具体实现的代码,真正实现了函数功能的代码
     *
     * 什么是函数的声明:
     * 函数的声明就是在调用之前告诉编译器,有一个名字叫什么,接收什么参数,返回值是什么类型的一个函数
     * 只需要将函数定义{前面的代码拷贝即可
     *
     */
  • 注意点
/*
     * 注意点:
     * 1. 如果不按照C语言的规定在函数调用之前编写函数的声明,那么在不同编译器下会有不同的运行结果
     * GCC编译器可以编译通过,但是在其他编译器可能就会报错
     * 2. 由于函数的声明仅仅是为了告诉编译器,我们有一个什么函数,所以函数的声明可以声明多次,但是函数的
     * 实现只能一次
     * 3. 由于函数的声明仅仅是为了告诉编译器,我们有一个什么函数,所以函数的声明只要写在调用之前即可
     * 4. 由于函数的声明仅仅是为了告诉编译器,我们有一个什么函数,所以声明时候不用指定参数的名称
     * 5. 如果函数的返回值类型是int类型,那么可以不用编写函数的声明,但是还是按规矩写上
     *
     * 总结: 函数定义编写在调用之后,在main函数外面编写函数声明,只要写上参数类型,参数名称可以不写
     *
     */
test(int);//不需要写参数的名称

int main()
{
    int a = 3;
    test(a);
    return 0;
}
test(int num){
    return 0;
}

  • main函数(了解)
#include <stdio.h>
/*
 * 1. main函数是系统自动调用的函数,我们不能手动调用
 * 2. 系统在调用main函数的时候,默认会传递两个参数
 * argc: argv数组保存数据的个数
 * argv: 默认保存了一个数据,这个数据就是当前文件的地址(数组)
 * 3.argv中保存的元素是可以动态添加的
 * 4. main函数的return 0的含义
 *  告诉系统当前的程序是正常结束,如果return返回的不是0,就代表告诉系统程序不是正常结束的
 *
 */

int main(int argc, const char *argv[])
{   
    argv数组保存数据的个数
    printf("%i\n", argc); //1
    //该文件的地址
    printf("%s\n", argv[0]);

    return 0;
}

  • 函数的分类
test(int);
int test2();
int main()
{
    /*
     * 函数的分类:
     * 没有返回值, 没有形参的函数
     * 没有返回值, 有形参的函数
     * 有返回值, 没有形参的函数
     * 有返回值, 有形参的函数
     *
     *
     * 注意点:
     * 1. 如果没有写函数的返回值类型,默认就是int类型
     * 2. 如果函数的返回值类型和实际返回的类型不同,那么会自动转换为返回值类型
     */

//    int a = 10;
//    int res = test(a);
//    printf("%i\n", res);

    int res = test2();
    printf("%i\n", res); //返回类型是double自动转换为int类型
    return 0;
}

test(int num){
    return num;
}
int test2(){
    return 3.15;
}

递归

递归就是自己调用自己,但是递归的性能与循环比较差,容易内存溢出

  • 练习1

    -内存分析


#include <stdio.h>
int pow(int, int);
int main()
{
    /*
     * 编写一个函数实现求b的n次方
     * b(0) = 1
     * b(1) = b
     * b(2) = b * b
     * b(3) = b(2) * b
     * .
     * .
     * .
     * b(n) = b(n-1) * b
     *
     */

    int res =  pow(3, 3);
    printf("%i\n", res);
    return 0;
}

int pow(int num, int n){
    if(0 == n){
        return 1;
    }else {
        return pow(num, n-1) * num;
    }
}
  • 练习2

    • 内存分析


#include <stdio.h>
int test(int);
int main()
{
    /*
     * 实现n!
     * 1! = 1
     * 2! = 1 * 2
     * 3! = 1 * 2 * 3
     * 4! = 3! * 4
     * .
     * .
     * .
     * n! = (n-1)! * n
     *
     */

    int a = 3;
    int res = test(3);
    printf("%i\n", res);


    return 0;
}

int test(int n){
    if(1 == n){
        return 1;
    }else {
        return test(n-1) * n;
    }
}

C语言的进制

  • 基本概念
    注意点: 0x和0X代表十进制, 0b和0B代表二进制,没有区别
int main()
{
    /*
     * 在C语言中,如果想要用十六进制的表示某个数,前面需要加上0x
     * 在C语言中,如果如果想要用八进制的表示某个数,前面需要加上0
     * 在C语言中,如果如果想要用二进制的表示某个数,前面需要加上0b
     *
     */

    //注意点:%i %d代表以十进制输出整数
    int num1 = 12;
    printf("%i\n", num1);

    int num2 = 0xc;
    printf("%i\n", num2);

    int num3 = 014;
    printf("%i\n", num3);

    int num4 = 0b1111;
    printf("%i\n", num4);
    return 0;
}
  • 进制输出方式
    %o代表以八进制输出,%x代表以十六进制输出,以二进制输出需要自己实现
int main()
{
    int num = 12;
    //以八进制输出
    printf("%o\n", num);
    //以十六进制输出
    printf("%x\n", num);
    return 0;
}
  • 其他进制的转换为十进制的简易方法
 /*
     * 二进制 -->十进制
     * 规则: 系数 * 基数(索引次幂)
     * 
     * 系数: 每一位对应的值就是系数
     * 基数: 从二转换到十进制,那么二就是基数
     *      从八进制转换到十进制, 八就是基数
     * 索引: 从最低位以0开始,依次递增
     * 
     * 1*2(3)+ 1*2(2)+ 0*2(1)+ 0*2(0)
     * 1        1       0       0
     * 
     */
  • 十进制转换为其他进制
/*
     * 
     * 十进制转换二进制
     * 规则: 除2取余数,余数倒叙 
     * 
     * 24
     * 2
     * ---
     * 12  0
     * 2
     * ---
     * 6   0
     * 2
     * ---
     * 3   0
     * 2
     * ---
     * 1   1
     * 2
     * ---
     * 0   1
     * 十进制转换八进制
     * 规则: 除8取余,余数倒叙
     * 
     * 十进制转换十六进制
     * 规则:除16取余,余数倒叙
     */
  • 二进制转八进制
    注意点: 在八进制中最大的数字是7,三个二进制位最大能表示的数字就是7,把三位二进制数看最一个八进制

  • 二进制转换为十进制
    注意点: 在十进制中最大的数字是15,四个二进制位最大能表示的数字就是15,把四位二进制数看最一个八进制
    在C语言中,不看数据怎么存,只看数据怎么取


源码反码补码

注意点: 在计算机当中无论是正整数还是负整数都是以补码的方式参与计算

  • 正数的源码反码补码
    /*
     * 在计算机中,正数和负数的源码,补码,反码是有区别的
     * 在计算机中所有存储的数据都是以0和1的方式存储的
     *
     */


    /*
     * 正数的源码,补码,反码都是它的二进制
     * 12---> 1100
     *
     * 1100 就是12的源码
     * 1100 就是12的反码
     * 1100 就是12的补码
     *
     * 注意点:
     * 1. int类型在计算机中占4个字节,1个字节等于8位,所以int总共占32位
     * 2. 在存储整数的时候,第一个(最高位)是符号位,0代表正数,1代表负数
     *
     * 12 --> 0000 0000 0000 0000 0000 0000 0000 1100
     */
  • 负数的源码反码补码
    /*
     * 负数的源码,反码,补码
     * -12
     * 源码: 二进制,将最高位变为1
     * 1000 0000 0000 0000 0000 0000 0000 1100
     * 
     * 反码: 除了符号位以外, 0变为1, 1变为0
     * 1111 1111 1111 1111 1111 1111 1111 0011
     * 
     * 补码: 补码 = 反码+1
     * 
     * 1111 1111 1111 1111 1111 1111 1111 0100
     */
  • 练习
    注意点: 参与运算的都是补码,所以计算出来的正确结果的是补码,要想知道正确结果是多少,需要将补码转换为源码
/*
     * 注意点: 计算出来的正确结果的是补码,要想知道正确结果是多少,需要将补码转换为源码
     * 
     * 4 - 6 = ?
     * 
     * 0000 0000 0000 0000 0000 0000 0000 0100  4的补码
     * 
     * 1000 0000 0000 0000 0000 0000 0000 0110  6的源码
     * 1111 1111 1111 1111 1111 1111 1111 1001  6的反码
     * 1111 1111 1111 1111 1111 1111 1111 1010  6的补码
     * 
     * 
     * 运算:
     * 
     * 0000 0000 0000 0000 0000 0000 0000 0100  4的补码
     * 1111 1111 1111 1111 1111 1111 1111 1010  6的补码
     * --------------------------------------------------
     * 1111 1111 1111 1111 1111 1111 1111 1110  计算结果补码
     * 
     * 1111 1111 1111 1111 1111 1111 1111 1101  计算结果反码
     * 
     * 1000 0000 0000 0000 0000 0000 0000 0010  -2
     */

位运算

  • 位运算符号
    /*
     * & 按位与
     * | 按位或
     * ~ 按位取反
     * ^ 按位异或
     */
  • 按位与
    技巧: 任何一位和1相与,结果还是原来那一位
    /*
     * & 按位与
     * 规则: 一假则假
     * 4 & 3
     *
     * 0000 0000 0000 0000 0000 0000 0000 0100  4的补码 &
     * 0000 0000 0000 0000 0000 0000 0000 0011  3的补码
     * ---------------------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 0000  结果是0
     */

  • 按位或
 /*
     *
     * | 按位或
     * 规则: 一真则真
     *
     * 4|3 = ?
     *
     * 0000 0000 0000 0000 0000 0000 0000 0100  4的补码
     * 0000 0000 0000 0000 0000 0000 0000 0011  3的补码
     * ---------------------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 0111  结果是7
     *
     */
  • 按位取反
    注意点; 取反的时候符号位也一并取反
/*
     * ~ 按位取反
     * ~ 9 = ?
     * 0000 0000 0000 0000 0000 0000 0000 1001  9的补码
     * 1111 1111 1111 1111 1111 1111 1111 0110  取反后的补码
     * -----------------------------------------------------
     * 1111 1111 1111 1111 1111 1111 1111 0101  取反后的反码
     * 1000 0000 0000 0000 0000 0000 0000 1010  -10
     *
     */
  • 按位异或
    1. 任何两个相同的值异或,结果都是0
    2. 任何一个数和0异或,结果还是那个数
    3. 任何一个数异或另外一个数两次后,结果还是那个数本身
     printf("%i\n", 4 ^ 4); // 0
     printf("%i\n", 4 ^ 0); // 4
     printf("%i\n", 5 ^ 4 ^ 4); // 5
/*
     * ^ 按位异或
     * 规则: 相同位0,不同为1
     * 9 ^ 3 = ?
     * 
     * 0000 0000 0000 0000 0000 0000 0000 1001  9的补码
     * 0000 0000 0000 0000 0000 0000 0000 0011  3的补码
     * ----------------------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 1010  10
     */
  • 面试题
    判断奇偶数
int main()
{
    /* 奇数按位与1,结果永远都是1,偶数按位与1,结果都是0
     * 0000 0000 0000 0000 0000 0000 0000 0010
     * 0000 0000 0000 0000 0000 0000 0000 0001
     * -------------------------------------------
     * 0000 0000 0000 0000 0000 0000 0000 0001
     *
     */

    /*
     * 判断奇偶数的案例
     *
     */
    int num = -1;
    if(1 == (num & 1)){
        printf("奇数");
    }else {
        printf("偶数");
    }
    return 0;
}

将两个数的值相互交换的另一种方法

int main()
{
    /*
     * 交换两个数的值
     * 
     *
     */
    int a = 10;
    int b = 20;
    // 原理:就是利用一个数异或另一个数两次后,会得到它本身
    a = a ^ b; 
    b = a ^ b; // b = (a ^ b) ^ b = a = 10
    a = a ^ b; // a = a ^ a ^ b = b = 20
    printf("a = %i, b = %i\n", a, b);
    return 0;
}
  • 左移和右移位(<< >>)
int main()
{
    /*
     * 左移 <<
     * 规则: 一个数左移几位,就是这个数乘以2多少次幂
     *
     * 右移 >>
     * 规则: 一个数左移几位,就是这个数除以2多少次幂
     * 移动规则: 除符号位以外整体右移动,多出来的砍掉,缺少的用符号位填充
     *
     */
    printf("%i\n", 8 << 1); //左移1位
    printf("%i\n", 8 >> 1); //右移1位
    return 0;
}
  • 练习
#include <stdio.h>


void printBinary(int);
int main()
{
    /*
     * 要求用户输入的整数,以二进制的形式输出
     * 利用&1的特点:
     * 每一位与1都能得到它本身,利用此特点可以输出
     * 思路: 让该整数右移31位然后每次再往左走一位
     *
     *
     */


//    int num = 10;

//    for(int i = 0; i < 32; i++){
//        int temp = (num >> 31 - i) & 1;
//        printf("%i", temp);
//    }



    printBinary(10);
    return 0;
}
// 封装方法让这个函数可以传其他基本数据类型的参数
void printBinary(int value){
    //1. 判断字节数计算出所占位数
    int len = sizeof(value) * 8;
    //2. 让该值的二进制右移len -1然后每次再往左走一位
    for(int i = 0; i < len; i++){
        int temp = (value >> len - 1 - i) & 1;
        printf("%i", temp);
    }
}


内存存储

  • 变量内存存储分析
int main()
{
    /*
     * 变量存储方式内存分析
     * 1. 计算机分配内存的规则: 从大到小的分配
     * 2. 变量名称对应的是变量占用内存最小的那个字节
     *
     * 由于计算机只能识别0和1,所以会把十进制的9转换为二进制的9
     *
     * 0000 0000 0000 0000 0000 0000 0000 1001
     *
     * 给变量分配内存的时候是从内存地址比较大的开始分配
     * 所以计算机在存储数据的时候也会从内存地址比较大的开始存储
     * 会从转换好的二进制高位开始依次从内存地址最大的字节开始存储
     *
     */
    
    // %p是专门用于输出变量地址的
    // &是专门用于取出变量地址
    int num1 = 9;
    int num2 = 4;
    printf("%p\n", &num1); //0028FEBC
    printf("%p\n", &num2); //0028FEB8

    return 0;
}
  • 字符存储
int main()
{
    /*
     * 字符char存储分析:
     * char = 'a';
     * 1.由于计算机只能识别0和1所以不能直接将'a'存储到内存中
     * 字符在计算机存储的其实是它对应的ASCII码值
     * 2. ASCII码表是什么?
     * ASCII码表是一套字符对应的数值表
     *
     * 注意点: C语言中不看怎么存,只看怎么取数据
     * char类型只占用1个字符,所以只有8位可以存储数据
     * ASCII码表中字符对应的ASCII码值是从0~127之间
     * 
     */
    
    
    /*
     *总结: 字符存储的顺序
     * 1. 根据字符在 ASCII码表中找到对应的十进制数
     * 2. 将找到的十进制数转换位二进制
     * 3. 将转换好的二进制存储到内存中
     * 
     */

    char ch = 'a';
    printf("%i\n", ch); //97
    return 0;
}

  • 练习
    在企业开发中,尽量不要把数据写死,这样便于后于修改
#include <stdio.h>
char upperCase(char);
int main()
{
    /*
     * 定义一个函数实现用户传入小写字母,将其转换为大写字母
     * a~z 对应的是97~122 A~Z对应65~90
     * 规律 小写字符减去大写字符 相差32
     */


    char ch = 'r';
    char res = upperCase(ch);
    printf("%c\n", res);
    return 0;
}

char upperCase(char ch){
    // 限定输入的条件
    // 在企业开发中尽量不要写数字,这种写法便于以后维护
    if(ch < 'a' || ch > 'z'){
        printf("请输入正确范围内的字母\n");
    }else {
        char res = ch - ('a' - 'A');
        return res;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容