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\n",PI);
12     printf("%d\n",N);
13     printf("%s\n",PATH);
14     printf("%f\n",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\n",ADD(m,n)); //迷惑初学者,跟函数调用类似(错误理解,宏函数不是真正的函数)
14     printf("m+n is:%d\n",myadd(m,n)); 
15 }

 

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

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

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

多行必须添加续行符

 1 #include <stdio.h>
 2 
 3 #define CMP(a,b) if(a>b) printf("a>b\n");\
 4 else printf("a<=b\n")
 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个整数!\n");
10     ret=scanf("%d",&n1);  //hello\n
11     //判断返回值
12     if(ret!=1)  //你输入的不是整数
13     {
14         //清除掉io缓冲区中错误的字符
15         while(getchar()!='\n');
16         goto label;
17     }
18     else
19         printf("n1 is:%d\n",n1);
20 }

 

2. printf工作原理

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

1 #include <stdio.h>
2 
3 int main()
4 {
5     printf("hello world");  //液晶屏上没有输出
6     //printf("hello world\n");  //输出了
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\n",p->name);
20     printf("p->age is:%d\n",p->age);
21     
22     p++;  //跳到下一个结构体
23     
24     printf("p->name is:%s\n",p->name);
25     printf("p->age is:%d\n",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\n",stu1.name);
17     printf("学生年龄: %d\n",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\n",stu4->name); 
38     printf("学生年龄: %d\n",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\n",sizeof(union yy)); //1
29     printf("sizeof tt is:%lu\n",sizeof(union tt)); //4
30     printf("sizeof uu is:%lu\n",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\n",t1.a,t1.a);
35     printf("y1.a is:%c\n",y1.a);
36     printf("y1.a is:%p\n",&(y1.a));
37     printf("y1.b is:%c\n",y1.b);
38     printf("y1.b is:%p\n",&(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\n",mon);
22     printf("tues is:%d\n",tues);
23     printf("wen is:%d\n",wen);
24     printf("tir is:%d\n",tir);
25     printf("fri is:%d\n",fri);
26     printf("sat is:%d\n",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("请输入整数!\n");

    ret=scanf("%d",&n); //34hhh
    if(ret!=1)
    {
        //清空缓冲区
        while(getchar()!='\n');
        goto label;
    }
    else if(ret==1&&getchar()=='\n')  //正确的整数   34\n
        printf("正确的整数:%d\n",n);
    else if(ret==1&&getchar()!='\n') //数字后面有字符  34yut\n
    {
        printf("你输入的数字后面还有字符!!!!\n");
        //清空缓冲区
        while(getchar()!='\n');
        goto label;
    }
}
View Code

 

posted @ 2020-05-30 15:46  Geek_Jian  阅读(227)  评论(0编辑  收藏  举报