• C语言学习(12)


    宏定义

    1.  宏定义:  理解为字符的替换

      语法:  #define   PI   3.14   //定义了一个宏,名字叫做PI,代表3.14这个小数

     1 #include <stdio.h>
     2 
     3 //定义一个宏
     4 #define PI 3.14
     5 #define N  88
     6 #define PATH  "/mnt/hgfs/share"
     7 
     8 int main()
     9 {
    10     int r=5;
    11     printf("%f
    ",PI);
    12     printf("%d
    ",N);
    13     printf("%s
    ",PATH);
    14     printf("%f
    ",PI*r*r);
    15 }

    注意:宏定义的名字一般都写成大写

    优点: 宏定义的执行效率很高(宏定义在预处理的时候就已经被替换了,而变量等到程序运行的时候才会加载到内存种参与运算),宏定义不是变量

    宏定义总共两种表现形式:

      形式1:  普通的宏定义      #define   PI   3.14      不要理解为变量了

      形式2:  宏函数                #define   ADD(a,b)    (a)+(b) 

     1 #include <stdio.h>
     2 
     3 //定义一个宏函数
     4 #define ADD(a,b) a+b
     5 int myadd(int a,int b)
     6 {
     7     return a+b;
     8 }
     9 int main()
    10 {
    11     int m=12;
    12     int n=13;
    13     printf("m+n is:%d
    ",ADD(m,n)); //迷惑初学者,跟函数调用类似(错误理解,宏函数不是真正的函数)
    14     printf("m+n is:%d
    ",myadd(m,n)); 
    15 }

      注意:    宏函数不是真正意义上的函数

        宏函数一定加上圆括号(为了防止出现优先级的问题) 

        宏定义如果有多行(一行写不下),必须加上续行符

    多行必须添加续行符

     1 #include <stdio.h>
     2 
     3 #define CMP(a,b) if(a>b) printf("a>b
    ");
     4 else printf("a<=b
    ")
     5     
     6 int main()
     7 {
     8     int m=78;
     9     int n=76;
    10     CMP(m,n);
    11 }

    C语言中printf和scanf的工作原理

    1.  scanf工作原理

      返回值:表示输入的符合要求的数据个数

      scanf和printf在系统中有个IO缓冲区,键盘输入的内容先进入到缓冲区,然后scanf从缓冲区里面读取符合要求的数据

      int getchar(void)      一次从缓冲区中读取一个字符(并把字符从缓冲区里面剔除

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int n1,n2;
     6     int ret;
     7     int ret1;
     8 label:
     9     printf("请输入1个整数!
    ");
    10     ret=scanf("%d",&n1);  //hello
    
    11     //判断返回值
    12     if(ret!=1)  //你输入的不是整数
    13     {
    14         //清除掉io缓冲区中错误的字符
    15         while(getchar()!='
    ');
    16         goto label;
    17     }
    18     else
    19         printf("n1 is:%d
    ",n1);
    20 }

    2. printf工作原理

      先将输出的内容存放到IO缓冲区里面,遇到 或者return  0 主函数退出会自动刷新缓冲区(把缓冲区里面的内容显示在液晶屏上面)

    1 #include <stdio.h>
    2 
    3 int main()
    4 {
    5     printf("hello world");  //液晶屏上没有输出
    6     //printf("hello world
    ");  //输出了
    7     
    8     while(1);  //不让程序退出
    9 }

    C语言中的结构体,共用体,枚举

    1.  结构体:

    定义:   struct   结构体的名字

         {

        结构体成员;

          };

    比如:  struct  student   //把不同类型的数据打包成一个整体,程序员自定义了一种新的数据类型

           {

        char name[10];

        int age; 

            };

     1 #include <stdio.h>
     2 #include <string.h>
     3 struct student
     4 {
     5     char name[10];
     6     int age;
     7 };
     8 int main()
     9 {
    10     //一个班级10个学生
    11     struct student array[10];
    12     strcpy(array[0].name,"张三");;
    13     array[0].age=18;
    14     
    15     strcpy(array[1].name,"李四");;
    16     array[1].age=18;
    17     
    18     struct student *p=array;  //&array[0]
    19     printf("p->name is:%s
    ",p->name);
    20     printf("p->age is:%d
    ",p->age);
    21     
    22     p++;  //跳到下一个结构体
    23     
    24     printf("p->name is:%s
    ",p->name);
    25     printf("p->age is:%d
    ",p->age);
    26     
    27     
    28 }

    简化书写   typedef  struct  student

                       {

                                 char name[10];

                                  int age; 

                         }stu,*pstu;   

    stu就是 struct  student 类型名      stu  stu1; //stu1是个普通结构体变量 

    pstu就是struct  student  *类型名  pstu  stu4;  //stu4是个结构体指针变量

    结构体的初始化和使用:

    struct  student  stu1={“张三”,18};

    struct  student  stu1;

    stu1.name="张三";

    stu1.age=18;

    struct  student  stu1={.name="张三";.age=18;}

    struct  student  *stu1;

    stu1->name="张三";

    stu1->age=18;

    struct  student  *stu1;

    (*stu1).name="张三";

    (*stu1).age=18; 

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 //定义一个结构体
     5 struct student
     6 {
     7     char name[10];
     8     int age;  
     9 };
    10 
    11 int main()
    12 {
    13     //写法一:定义结构体变量并初始化
    14     struct student stu1={"张三",18};  //int a;
    15     //普通结构体采用小数点引用成员
    16     printf("学生姓名:%s
    ",stu1.name);
    17     printf("学生年龄: %d
    ",stu1.age);
    18     
    19     //写法二:定义结构体变量没有立马初始化,后面才赋值
    20     struct student stu2;
    21     //stu2.name="张三";  //数组赋值只能用strcpy()
    22     strcpy(stu2.name,"李四");
    23     stu2.age=18;
    24   
    25     //写法三:linux内核代码中很常见
    26     //优点:可以不按照结构体定义的顺序赋值
    27     struct student stu3={
    28          .age=19,
    29          .name="王五" //小数点一定要写上
    30     };
    31     
    32     
    33     //写法四:定义结构体指针
    34     struct student *stu4=malloc(sizeof(struct student)); //野指针  Segmentation fault (core dumped)
    35     strcpy(stu4->name,"赵六");
    36     stu4->age=18;
    37     printf("学生姓名:%s
    ",stu4->name); 
    38     printf("学生年龄: %d
    ",stu4->age);
    39     
    40     //写法五:定义结构体指针
    41     struct student *stu5=malloc(sizeof(struct student));
    42     strcpy((*stu5).name,"赵七");
    43     (*stu5).age=18;  
    44    
    45    free(stu4);
    46    free(stu5);
    47 }

    普通结构体变量使用小数点引用成员:struct  student stu1      stu1.age;

     结构体指针使用->引用成员:    struct  student  *p;     p->age;‘

    2. 结构体大小规则

    32位系统

    第一步:找到结构体成员中数据类型最大的成员

    第二步:如果数据类型最大成员>=4字节,那么整个结构体按照4字节对齐

                   如果数据类型最大成员<4字节,那么整个结构体按照最大数据成员的大小对齐

    第三步:如果char和short连续挨在一起,需要合并

    64位系统

    第一步:找到结构体成员中数据类型最大的成员

    第二步:如果数据类型最大成员>=8字节,那么整个结构体按照8字节对齐

                   如果数据类型最大成员<8字节,那么整个结构体按照最大数据成员的大小对齐

    第三步:如果char和short连续挨在一起,需要合并(小心这一步跟32位系统的区别)

    3. 联合体(共用体)

    定义:  union  联合体的名字   //跟结构体写法类似

              {

              };

      union  sex

           {

               char  a;

               char  b;

            };

    普通联合体变量:  union  sex   sex1;    sex1.a='M';

    联合体指针:         union  sex   *p=&sex1;      p->b='W';

    联合体数组:         union  sex   array[10];

    跟结构体的区别,特点:

      联合体中所有的成员变量占用同一块内存区域(成员变量是互斥)

      联合体大小由最大成员的大小决定,也要满足字节对齐

     1 #include <stdio.h>
     2 union yy  //1<8    1字节对齐
     3 {
     4     char a;  //1
     5     char b;  //1
     6 };
     7 
     8 union tt  
     9 {
    10     char a;  
    11     int b;  
    12 };
    13 
    14 union uu  //  16字节
    15 {
    16     char a[11];  //11
    17     double b;  //8
    18     int c;
    19 };
    20 
    21 int main()
    22 {
    23     //定义联合体变量
    24     union yy y1;
    25     y1.a='@';  //只给a赋值了,b没有赋值
    26     y1.b='#'; //由于a和b共用同一块内存,b覆盖掉前面a的值
    27     
    28     printf("sizeof yy is:%lu
    ",sizeof(union yy)); //1
    29     printf("sizeof tt is:%lu
    ",sizeof(union tt)); //4
    30     printf("sizeof uu is:%lu
    ",sizeof(union uu)); //16
    31     union tt t1;
    32     t1.b=567;
    33     //请问t1.a是多少????  %d打印
    34     printf("t1.a is:%c   ASCII is:%d
    ",t1.a,t1.a);
    35     printf("y1.a is:%c
    ",y1.a);
    36     printf("y1.a is:%p
    ",&(y1.a));
    37     printf("y1.b is:%c
    ",y1.b);
    38     printf("y1.b is:%p
    ",&(y1.b));
    39 }

    实际用途:

    用来表示互斥的概念--》用联合体

    union  sex 

     {

         char  man;   //   'M'  --》男     'W' --》女

         char  woman;

     }

    4. 枚举:

    定义:  enum   枚举的名字  {枚举数据}

    enum  day {mon,tues,wen};

    enum  color  {red, green  blue};

     1 #include <stdio.h>
     2 
     3 //enum day {mon,tues,wen};  //默认情况下三个枚举变量值:分别是 0  1  2
     4 
     5 //enum day {mon,tues=7,wen}; // 0  7  8
     6 enum color {red,green,blue,yellow,black};
     7    //0  1  2 3 4 5 6 一个星期的七天 可读性差
     8 enum day {mon,tues=7,wen,tir,fri=2,sat}; // 0 7 8 9 2 3
     9 
    10 struct car  //小汽车
    11 {
    12     char name[10]; //品牌
    13     enum color carcolor; //车的颜色
    14     float price;
    15 };
    16 int main()
    17 {
    18     //定义一台车
    19     struct car car1={"奔驰s600",black,2000000.0};
    20     
    21     printf("mon is:%d
    ",mon);
    22     printf("tues is:%d
    ",tues);
    23     printf("wen is:%d
    ",wen);
    24     printf("tir is:%d
    ",tir);
    25     printf("fri is:%d
    ",fri);
    26     printf("sat is:%d
    ",sat);
    27 }

    C语言中的头文件

    作用: 包含其它头文件

    结构体,联合体,枚举的定义

    全局变量,函数的声明

    内联函数定义

     宏定义

    头文件的标准写法:

    参考系统中标准头文件:  
    #ifndef   _XXXX_H     目的为了防止重复包含同一个头文件

    #define   _XXXX_H

    #endif

    头文件<>和“”区别:

    <>  --》多用于系统自带的头文件,编译器会自动去系统的环境变量中寻找这个头文件

    环境变量:系统的一个默认路径/usr/include

    “”   --》多用于自定义的头文件,编译器会自动从当前路径下寻找这个头文件,如果当前路径下面没有,就去环境变量中找

    C语言程序编译的四个过程

    hello.c源文件  --->hello 可执行程序  经历四个过程: 预处理--》编译--》汇编--》链接生成可执行程序

    C语言的条件编译(跟宏定义配合使用)

    1. 作用: 满足条件就会帮你编译代码,不满足,就不编译(代码写了跟没写一样,被注释掉了)

    2. 写法一:

      #if  宏定义  //判断宏定义的值是真还是假

        代码;

      #else

        代码;

      #endif

    变形形式:  #if    #elif    #else   #endif

    写法二:

      #ifdef  宏定义    //宏定义定义了就执行,不是判断真假

        代码;

      #else     //没有定义

        代码;

      #endif

    写法三:

      #ifndef  宏定义   //  宏定义没有定义就执行

        代码;

      #else   //定义了就执行

        代码;

      #endif

    注意:以上都是完整的标准写法,  #else可以写也可以不写的

    作业:

    1.   scanf("%d",&n);   //   34hhh   不正确的整数

    #include <stdio.h>
    
    int main()
    {
        int n;
        int ret;
    label:
        printf("请输入整数!
    ");
    
        ret=scanf("%d",&n); //34hhh
        if(ret!=1)
        {
            //清空缓冲区
            while(getchar()!='
    ');
            goto label;
        }
        else if(ret==1&&getchar()=='
    ')  //正确的整数   34
    
            printf("正确的整数:%d
    ",n);
        else if(ret==1&&getchar()!='
    ') //数字后面有字符  34yut
    
        {
            printf("你输入的数字后面还有字符!!!!
    ");
            //清空缓冲区
            while(getchar()!='
    ');
            goto label;
        }
    }
    View Code
  • 相关阅读:
    痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(2.2)- 在串行NOR Flash XIP调试原理
    痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(2.1)- 玩转板载OpenSDA,Freelink调试器
    痞子衡嵌入式:史上最强i.MX RT学习资源汇总(持续更新中...)
    痞子衡嵌入式:终于可以放开聊一聊i.MXRT1170这颗划时代MCU了
    痞子衡嵌入式:MCUBootUtility v2.0来袭,i.MXRT1010哪里跑
    痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(1)- 官方EVK简介
    3万字总结,Mysql优化之精髓
    不停机替换线上代码? 你没听错,Arthas它能做到
    Springboot 2.x 如何解决重复提交 (本地锁的实践)
    MYSQL插入千万数据的工具类
  • 原文地址:https://www.cnblogs.com/xiaojian98/p/12993016.html
Copyright © 2020-2023  润新知