美文网首页
C语言学习笔记01

C语言学习笔记01

作者: Nefelibatas | 来源:发表于2022-02-05 20:38 被阅读0次

    EOF = end of file

    scanf("xxx"); // 可运行
    

    操作系统中0表示真值,OS调用main函数,并返回return 0

    cat xxx.c  //读取文件内容到终端
    

    练习
    写一个程序,读入一行字符串(可能包含空格)输出这个字符串中字符的数量。

    #include <stdio.h>
    int main(){
        char str [100] = {0}; //初始化字符
        //加入正则表达,除了换行其余都包含空格输出
        while (scanf("%[^\n]s",str) != EOF){ //str既是数组也是地址首字符,所以无需&
            getchar(); //获取字符串
            printf(" has %d chars!\n",printf("%s",str));
        } 
        return 0;
    }
    

    sprintf:s->string,将输出内容打印到字符串里
    fprintf: 输出到文件里
    应用: 字符串拼接

    #include <stdio.h>
    int main(){
        char str[100] = {0};
        int a,b,c,d;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        sprintf(str,"%d.%d.%d.%d",a,b,c,d);
    
        // FILE *fp = fopen(./output,"w"); 打开文件 w+可读可写
        FILE *fp = fopen(./output,"a+");
        fseek(fp,0,SEEK_END);
        fprintf(fp,"str = %s\n",str); //写入文件
        fclose(fp); //关闭文件
        return 0;
    }
    

    sscanf:从字符串中获取输入
    fscanf:可进行格式化的读操作

    ./a.out < input 输入重定向
    
    #include <stdio.h>
    int main(){
        char str[100] = {0};
        int a,b,c,d;
        FILE *fp = fopen("./output","a+");
        fseek(fp,0,0);
        while(fscanf(fp,"%d.%d.%d.%d\n",&a,&b,&c,&d)!= EOF){
            printf("%d %d %d %d\n",a,b,c,d);
        }
        fclose(fp);
        return 0;
    }
    

    基本运算符之位运算

    表达式的逻辑返回值:

    1. 真true

    2. bool
      false
      非0即为真

    !真 = 假 【关系运算取非】
    !0 = 真(1) !(null) = 真(1)
    ~位 【数学运算】

    位运算仅支持整型!
    1.必须二进制表示下进行的一类运算
    2.对应二进制位进行计算(有2进1)

    二进制计算
    1.对应位上的数值(0、1)
    2.对应位的权值(2^0, 2^1,... 2^n)

    进制转换(如二进制到十进制)
    对应位的权值( 2^0 , 2^1 ... 2^n)与对应数值相乘之和

    &按位与(二进制位和运算)
    |: 有1为1,全0为0
    ^ : 抑或,相同为0,不同为1
    2^2 = 0
    0^n = n
    【重要】抑或运算是抑或运算的逆运算
    即a^b = c,则c^a = b,c^b =a
    ~按位取反
    <<左移 >>右移

    其他进制中,A对应11,B对应12....

    i++:先完成运算,再加1
    ++i:先加1,再完成运算

    位是最小单元,32位表示二进制位,2^32个状态
    第32位表符号,0为负数,1为正数[-2^31 , 2^31-1]
    2_(10) = 10_(2),取反为1..(中间都为0)..01(是个负数)

    2(10) << 1
    左移,低位补0
    2(10)=10(2) << 1 = 100(2) = 4(10)

    3(10) >> 1
    右移,高位补符号位,根据原符号位补充0或者1
    3(10) = 11(2)= 0...11(2) >> 1
    = 0..01(2) = 1(10)

    任何一个字符在ASCII编码下都可以映射为整型值,
    'A' = 65
    'a' = 97

    数学函数

    头文件math.h
    pow:指数函数
    原型:double pow(double a,double b); 返回a^b的结果
    double:8个字节,float:4个字节
    
    开平方函数(正值)
    原型:double sqrt(double x);返回sqrt(x)
    
    上取整函数,只要有小数位就能向上取
    原型:double ceil(double x);返回ceil(x)结果
    
    下取整函数,只要有小数位就能向下取
    原型:double floor(double x);返回floor(x)结果
    
    fabs函数,实数绝对值
    原型:double fabs(double x);返回fabs(x)
    
    log函数,以e为底对数函数
    原型:double log(double x);返回log(x)
    
    log10函数,以10为底对数函数
    原型:double log10(double x);返回log10(x)
    
    注意使用换底公式
    
    acos函数,反余弦函数arccos(x)
    原型:double acos(double x);返回acos(x)
    x:角度的弧度值
    
    abs函数,整数绝对值
    头文件:stdlib.h
    原型:int abs(int x);返回abs(x)
    
    
    // x的立方根
    #include <stdio.h>
    #include <math.h>
    int main(){
        double x;
        scanf("%lf",&x);
        printf("%lf",pow(x,1.0/3.0));
        return 0;
    }
    //读入一个角度值,将角度值转为弧度值
    #include <stdio.h>
    #include <math.h>
    // 角度值*Π/180
    
    int main(){
        double x;
        const double pi = acos(-1); // Π
        scanf("%lf",&x);
        printf("%lf\n",x*pi / 180);
        return 0;
    }
    //按位取反实现循环
    int main(){
        int a,b;
        while(~scanf("%d%d",&a,&b)){
            printf("a = %d,b= %d \n",a,b);
    
        }
    }
    

    原码 -1(10) = 10000...01(2)
    反码 11111...10
    补码 = 反码+1(末位对齐) = 11111...11

    位运算速度快!

    //利用异或^交换两个数值
    int main(){
        int a,b;
        while (~scanf("%d%d",&a,&b)){
            printf("a=%d,b=%d\n",a,b);
            a ^= b; // a`= a^b
            b ^= a; // b` = b^a`
            a ^= b; // a`^= b`
            printf("swap : a=%d,b=%d\n",a,b);
        }
        return 0;
    }
    
    
    int b =2,c = 0;
    这是一条语句还是两条? 1条,逗号表达式
    逻辑返回值为还是0? 逻辑返回值为0,假值
    int b =1,c = 2; 逻辑返回值为2,真值
    int b =2,c = 1; 逻辑返回值为1,真值
    总结:逗号表示式最后的部分当作逻辑返回值
    0 为逻辑返回值假值
    1 为逻辑返回值真值
    复合语句表现形式{}
    if(表达式) + 单语句
    if(表达式) + 复合语句表现形式{}
    

    练习

    //输入正整数n,根据分数输出分数档位
    #include <stdio.h>
    int main(){
        int n;
        scanf("%d",&n);
        if(!n){
            printf("FOOLISH \n");
        } else if (n < 60){
            printf("FAIL\n");
        } else if (n < 75){
            printf("MEDIUM\n");
        } else if (n <= 100){
            printf("GOOD\n");
        }
        return 0;
    }
    
    switch(a){ //a一定为整型值
        case 1: ...;
            break; //遇到break退出
        case 2: ...;
        case 3: ...;
    
        default:...//以上皆不是,则输出..
    }
    
    #include <stdio.h>
    int main(){
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%s\n",a%b==0?"YES":"NO");
        return 0;
    }
    
    #include <stdio.h>
    int is_val(int n){
        int a = n%10;  
        int b = n/10 %10; 
        int c = n/100;  
        return (a==9 || b==9 || c==9);
    }
    
    #include <stdio.h>
    int main(){
        int n;
        scanf("%d",&n);
        printf("%s\n",is_val(n)?"YES":"NO");
        return 0;
    }
    
    #include <stdio.h>
    
    int main(){
        double n;
        scanf("%lf",&n);
        printf("%g\n",n<0?-n:n);
        return 0;
    }
    
    #include <stdio.h>
    int is_val(int n){ 
        return ((n%7==0) &&(n & 1) );//等价于n%2
    }
    int main(){
        int n;
        scanf("%d",&n);
        printf("%s\n",is_val(n)?"YES":"NO");
        return 0;
    }
    

    帮助cpu的分支预测

    #define likely(x) __builtin_expect(!!(x),1) //likely代表x经常成立
    #define unlikely(x) __builtin_expect(!!(x),0) //likely代表x不经常成立
    //likely(x)中!!(x)逻辑归一化所有真值映射为1,unlikely(x)同理
    
    

    OS告知CPU当前x是否成立。

    CPU如何执行指令?
    1.早期 串行。外存转内存,内存到CPU
    2.并行 流水线
    CPU分支预测,若预测失误,则从并行转为串行

    不影响代码可读性的情况下,尽量减少分支结构if

    循环结构

    while(表达式){  //表达式为真,代码就会被执行一次
     // 代码;
    }
    
    do{
        //代码块
    } while (表达式); //每当代码段执行1次,就会判断1次表达式是否为真
    
    for(初始化;循环条件;执行后操作){
        //代码块
    }
    
    int main(){
        int i =0;
        for(;;){
            if(i>100) break;//终止所有循环
            // continue跳出单层循环
            printf("%d\n",i);
        }
        return 0;
    }
    
    int main(){
        int a=0,b=0;
        if((a++) && (b++)){  
            //a++:先访问a再a+=1,逻辑&&运算,有0则0,最后输出false
            //若为++a && ++b,则最后输出true
            printf("true\n")
    
        } else{
            printf("false\n")
        }
        printf("a=%d,b=%d\n",a,b);//最后输出a=1,b=0,b++未执行,因为逻辑&&运算遇0 则0
       
        return 0;
    }
    
     // 同理运用于其他逻辑运算符中,常见于格式输出
    

    练习:输入一组随机数字,要求输出每个数之间空格,判断其中有多少个奇数

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    int main(){
        int n,cnt = 0;
        srand(time(0)); //随机数,time(0):linux系统中的系统时间,单位(秒)
        scanf("%d",&n);
         for(int i=0; i<n ;i++){
             int val = rand() % 100;
             cnt += (val & 1);  // %2 等价为 1,%4等价于3,%6不等价于任何操作
             i && printf(" ");
             printf("%d",val);
         }
         printf("\n");
         printf("cnt : %d\n",cnt);
    
         return 0;
    }
    
    
    #include <stdio.h>
    int digit(int n){
        int cnt = 0;
        do {
            n /= 10;
            cnt += 1;
        } while(n);
        return cnt;
    }
    
    int main(){
        int n;
        while(~scanf("%d",&n)){
            printf(" %d has %d digits!\n",n,digit(n));
        }
        return 0;
    }
    

    练习:回文数判断

    int is_val(int n){
        int x = n,sum = 0;
        while(x){
            sum = sum * 10 + x % 10;  // x%10求出最后一位
                                      // x/10 除了最后一位的前n位
                                      // x*10 还原前n位,找出前n位的最后一位
            x /= 10;
        }
        return sum == n;
    }
    
    int main() {
        int n;
        scanf("%d",&n);
        for(int i=1; i<= n; i++){
            if(!is_val(i)) continue;
            printf("%d\n",i);
            }
        }
    }
    
    

    函数

    int is_val(int n){  
        // int 返回值                   
        // is_val 函数名
        // int n 参数声明列表
        ...
        }
        return 1;
    }
    

    练习:实现一个程序,先读入两个整数:k和b,输出y=k*x+b直线方程中x=1到x=100间y的值。

    #include <stdio.h>
    int f(int k,int b,int x){
        return k*x + b;
    }
    
    int main(){
        int k,b;
        scanf("%d%d",&k,&b);
        for( int i =1;i<= 100;++i){
            printf(" f(%d) = %d \n",i,f(k,b,i));
        }
        return 0;
    }
    

    函数调用

    #include <stdio.h>
    void func(){
        printf(" func: 2+3 = %d",2+3);
        return ;
    }
    int main(){
        func();
        return 0;
    }
    

    函数声明

    #include <stdio.h>
    void func(); //函数内容放置主函数下方,需要先声明
    
    int main(){
        func();
        return 0;//在OS中,0表示真值,c语言中0表示假
    }
    
    void func(){
        printf(" func: 2+3 = %d",2+3);
        return ;
    }
    

    如何让其他函数优于主函数去执行

    __attribute__((construcotr))//宏定义与预处理命令
    void func(){
        ...
    }
    
    __attribute__((construcotr))//宏定义与预处理命令
    void func1(){
        ...
    }
    
    int main(){
        return 0;//在OS中,0表示真值,c语言中0表示假
    }
    

    习题: 464.统计闰年

    // 4年1闰,100年1闰,400年再闰
    //输入两个年份x和y,统计并输出公元x年到公元y年之间的所有闰年数(包括x年和y年),1≤x≤y≤3000。
    #include <stdio.h>
    int check_year(int y){
        return !!((y % 4 == 0 && y % 100) || y % 400 == 0);//逻辑归一化
    }
    
    int main(){
        int x,y,cnt = 0;
        scanf("%d%d",&x,&y);
        for(int i = x;i <= y; i++){
            cnt += (check_year(i));
        }
        printf("%d\n",cnt);
        return 0;
    }
    

    练习:定义一函数digit(n,k)分离出整数n从右边数第k个数字。
    如digit(2076,1)等于6,而digit(2076,5)等于0。
    main函数输入n和k,调用digit(n,k)输出答案,n在long long范围内。

    #include <stdio.h>
    int digit(long long n, int k){
        int temp = 0;
        for (int i = 0; i< k; i++){
            temp = n % 10;
            n /= 10;
        }
        return temp;
    }
    
    int main(){
        long long n,k;
        scanf("%lld%lld",&n,&k);
        printf("%d\n",digit(n,k));
        return 0;
    }
    

    练习:输入一个正整数n,求1~n之间的"回文数"的个数。
    回文数是指一个数倒过来和原数一样,如12121、11、1221、1是回文数。

    #include <stdio.h>
    int is_val(int n){
        int x = n,temp = 0;
        while(x){
            temp = temp * 10 + x % 10;
            x /= 10;
        }
        return temp == n;
    
    }
    
    int main(){
        int n,cnt = 0;
        scanf("%d",&n);
        for(int i=1;i <= n;i++){
            cnt += (is_val(i));
        }
        printf("%d\n",cnt);
        return 0;
    }
    

    递归

    程序调用自身的编程技巧
    递归程序的组成部分
    给予相关的语义信息
    1.边界条件处理
    2,针对于问题的【处理过程】和【递归过程】
    3.结果返回:

    • return
    • 传出参数(传地址)
    • 全局变量
    • 引用

    向下递推与回溯

    练习:实现一个数的阶乘

    #include <stdio.h>
    int fac(int n){
        if (n == 1) return 1;
        return n * fac(n-1);
    }
    
    int main(){
        int n;
        while(~scanf("%d",&n)){
            printf("fac(n):%d\n",fac(n));
        }
        return 0;
    }
    

    n阶层 循环与递归实现的区别:
    递归好实现,但会频繁使用栈结构,时间复杂度高

    系统栈内存:linux里8mb、WIN中2mb
    函数内定义的局部变量都是占用系统栈空间
    除了malloc、calloc、realloc动态。
    8mb = 800w字节,在函数内数组定义不得超过200w
    爆栈错误,栈溢出

    函数指针:将函数作为参数进行传递
    变量的作用:存值
    函数指针的作用:存储一个函数

    ** 指针数组:本质是数组**

    int (*f1)(int) f1是函数指针变量名,表示接收的函数
    (int):应接收函数的参数列表的形式

    int g( int (*f1)(int), int (*f2)(int),int (*f3)(int)){
        if(x < 0){
            return f1(x); //f1(x)函数调用
    
        if(x > 0){
            return f2(x);
        }
        return f3(x)
    }
    

    变参函数

    实现可变参数max_int,从若干个传入的参数中返回最大值。
    int max_int(int a, ...);
    如何获得a往后的参数列表? va_list类型的变量
    如何定位a后面第一个参数的位置? va_strat函数
    如何获取下一个可变此参数列表中的参数?va_arg函数
    如何结束整个获取可变参数列表的动作?va_end函数

    #include <stdio.h>
    #include <inttypes.h>
    #include <stdarg.h>
    int max_int(int n,...){
        int ans = INT32_MIN,temp;//INT32_MIN整型符号常量
        va_list arg;
        va_strat(arg,n);
        while (n--){
            temp = va_arg(arg,int); // va_arg预处理命令
            if(temp > ans) ans = temp;
        }
        va_end(arg);
        return ans;
    }
    
    int main(){
        printf("%d",max_int(5,1,2,3,2,14));
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:C语言学习笔记01

          本文链接:https://www.haomeiwen.com/subject/fkdykrtx.html