黑马程序员--C语言自学笔记---13结构体、预编译、宏、条件编译

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

 

1.   结构体数组

1)        概念:数组的元素也可以是结构类型的。因此可以构成结构数组。结构数组的每一个元素都是具有相同结构类型的下标结构变量。

2)        定义格式:

①  定义结构体的同时定义结构体数组

struct 结构名{

成员列表

}数组名[数组长度];

struct Student{

int age;

char *name;

}stu[3];

②  先定义结构体后定义结构体数组

struct Student{

int age;

char *name;

};

struct Student stu[3];

3)         结构数组的初始化

以上面的Student结构体为例:

①  定义结构数组的时候初始化

struct Student{

int age;

char *name;

}stu[3]={{14,”小明”},{17,”小哥”},{20,”老大”}};

②  先定义结构体后定义数组的同时初始化

struct Student boys[2]={{23,”mimi”},{22,”dfdf”}};

③  先定义结构体数组,在单个初始化,整体赋值

struct Student boys[2];

boys[0]={32,”zbz”};

boys[1]={40,”lzl”};

④  先定义结构体数组,后初始化数组的每个元素的每个成员

struct Student boys[2];

boys[0].age=32;

boys[0].name=”cjk”;

4)        结构数组的遍历

for(int i=0;i<2;i++){

  printf(“%d,%s\n”,boys[i].age,boys[i].name);

}

5)        结构数组实现简易通讯录

#include <stdio.h>
//定义一个结构体
struct Person{
   char name[20];
   char num[15];
};
int main(int argc, const char * argv[]){
   //定义结构体
   //定义结构体数组
   struct Person p[2];
   //提示输入信息
   printf("输入要保存的联系人信息,格式为:姓名电话\n");
   //输入要保存的联系人信息
   for (int i=0; i<2; i++) {
       scanf("%s %s",p[i].name,p[i].num);
   }
   //查看保存的信息
   for (int i=0; i<2; i++) {
       printf("姓名:%s 电话:%s\n",p[i].name,p[i].num);
   }
   return 0;
}


2.   结构体指针

1)        概念:一个指针变量当用来指向一个结构变量时,称之为结构指针变量。结构指针变量中的值是所指向的结构变量的首地址。通过结构指针即可访问该结构变量。这与数组指针和函数指针的情况是相同的。

2)        定义格式为

struct   结构名  *结构指针变量名

struct Student *stu; stu就是一个结构体指针

3)        结构体指针变量访问结构体成员

struct Student{char name[20];

              intage;

}stu1={“cjk”,32};

struct Student *p=&stu1;

①     (*p).结构体成员

(*p).name访问姓名

(*p).age    访问年龄

②     p->结构体成员

p->name访问姓名

  p->age  访问年龄

3.   结构体嵌套

1)        结构体定义中,结构体的成员又是另外一个结构体变量。

①          构体定义中可以嵌套其他结构体类型的变量,不可以嵌套自己这个类型的变量,但是可以嵌套自己类型的指针

struct Date{
          Intyear;
          Intmonth;
          Intday;
};
struct Student{
          char*name;
          intage;
          structDate birthday; //嵌套Date结构体类型变量
          structStudent stu;    //错误
          structStudent *stu;  //正确
};


②          嵌套结构体的初始化

struct Student stu1={“cjk”,23,{1980,01,01}};

③          嵌套结构体的访问

stu1.birthday.year; //访问嵌套的结构体成员year

stu1.birthday.month;    //访问嵌套的结构体成员month

stu1.birthday.day; //访问嵌套的结构体成员day

④          嵌套自身类型的结构体指针

struct Person{

          char*name;

          int  age;

          structPerson *son;

};

struct Person son={“儿子”,6,NULL};        //先定义一个内层的结构体变量

struct Person father={“父亲”,40,&son};//定义一个外层的结构体变量

father.son->age;或者(*father.son).age;//访问嵌套的结构体成员

4.   结构体和函数

1)        用结构体变量和结构体成员做为函数的形参,都是值传递。

2)        结构体指针做函数的形参

#include <stdio.h>
struct Car{
    int lunzi;
    int speed;
};
void xiuche(structCar *c){
    c->lunzi = 2;
}
int main(int argc, const char* argv[]) {
    //定义一个结构体变量
    structCar c1={4,200};
    //用结构体变量的地址传给函数
    //也就是用结构体指针作为函数的形参
    xiuche(&c1);
    printf("lunzi=%d\n",c1.lunzi);
    return0;
}


5.   枚举类型

1)        C语言中提供了一种类型,这种类型的变量的取值被限定在了一定的范围之内了

2)        定义格式: enum 枚举类型名{枚举值1,枚举值2,…};

enumweekday{zhouyi,zhouer,zhousan,zhousi,zhouwu,zhouliu,zhouri};

weekday就是一个枚举类型

3)        枚举类型变量的定义

enum iColor{white,black,gold};

①  先定义枚举类型,再定义枚举变量

enum 枚举类型名  枚举变量列表;

enum iColor iPhoneColor;//取值应为三个中的一个

iPhoneColor = white;

②  定义枚举类型的同时,定义变量

enum Sex(man,woman)isex;

isex = man;

③  枚举变量的值

枚举类型定义完成后,系统会自动给枚举类型的每个元素都会赋一个整型的初值。

默认初值:从第一个元素开始值为0,以后每个元素的值为前一个元素的值+1.

white的值为0,black为1,gold为2.

④  给枚举类型变量进行不正常的赋值:

IPhoneColor = 1;//尽量不要这样去赋值,虽然不会报错

6.   typedef关键字

1)        给已存在的数据类型定义一个新的名称

使用↓↓↓

2)        基本数据类型

typedef int  WODE;WODE  a=1;

3)        用在数组,给数组起别名

typedef int ARRAY[4];//定义一个长度为4的数组类型

ARRAY a={1,2,3,4}

4)        给结构体起别名

①  对结构体Person

Typedef struct Person P;//P就等同于struct Person

P p1={…};

②  对匿名结构体

Typedef struct{int a;int b;}MYNAME;

5)        给枚举类型起别名

typedef enum Sex S;

6)        给函数指针起别名

int (*p)(int,int);//函数指针

typedef int (*FUN)(int,int);//FUN为这个函数指针的别名

7.   预处理指令

以“#”开头的为预处理指令。在源程序中这些命令都放在函数之外,而

一般都放在源文件的前面,称为预处理部分。

所谓预处理是指在进行编译的第一遍扫描(此法扫描和语法分析)之前

所做的工作。预处理是C语言的一个重要功能,它由预处理程序负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。

C语言提供了多种预处理功能,如宏定义、文件包含、条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。

8.   宏

1)        定义:#define 宏名 宏字符串(可以是常量、变量、表达式)

注意:预处理指令,经常写在函数之前。

2)        宏替换:源程序在编译之前,由与处理程序对我们写的源代码进行处理,会把源代码中所有出现宏名的地方一律使用宏的字符串去替换。

宏替换时直接把宏的字符串拿过去,不加括号

3)        无参宏的使用注意事项:

①  习惯上宏名用大写字母表示,以便于与变量区别,但也允许使用小写字母。

②  宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以包含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如果有错误,只能在编译已经被宏展开后的源程序时发现。

③  宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。

④  宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。

⑤  宏可以嵌套。意思是一个宏可以使用另一个宏。

#define R 3

#define T R*R

⑥  使用宏起别名

#define INT  int

INT a;

⑦   

4)        有参宏

#define 宏名(形参表) 字符串

替换时用实参替换掉形参

注意事项:

①  宏的形参之间可以出现空格,但是宏名和形参之间不能出现空格

②   

③  使用有参宏求两个数的最大值

#define MAX(a,b) a>b?a:b

9.   #define和typedef的区别

1)        宏定义只是简单地字符串代换,是在预处理完成的,而typedef是在编译时处理的,他不是简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。

#define  PINT1 int*   //只是替换

typedef  int * PINT2; //起别名

PINT1 a,b;//只有a是int *类型的,而b只是一个普通int类型变量

PINT2 a,b;//两个都是int *类型的

10. 条件编译

1)        按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。有利于程序的移植和调试。

2)        条件编译当然也可以用条件语句来实现。但是用条件语句将会对整个源程序进行编译,生成的目标代码程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2,生成的目标程序较短。

3)        发生在预处理阶段,在编译之前做的事情。

4)        #if(表达式1)

程序段1

#elif(表达式2)

  程序段2

#else

  程序段3

#endif

表达式1为真则编译程序段1,否则表达式2为真编译程序段2,否则编译程序段3

5)        #ifdef  标识符

程序段1

           #else

           程序段2

           #endif

      判断标识符是否进行宏定义,定义则编译程序段1,否则编译程序段2

6)#ifndef  标识符

程序段1

          #else

           程序段2

          #endif

      如果标识符没有进行宏定义,则编译程序段1,否则编译程序段2.

11. 使用条件编译指令来调试bug

#include <stdio.h>
#define DEBUG1 0
#if DEBUG1 == 1
     #defineLog(format,...) printf(format,##__VA_ARGS__)
//format是格式控制,##表示可以没有参数__VA_ARGS__表示变量
#else
#define Log(format,...)
#endif
void test(){
    int a=10;
    Log("a=%d\n",a);
}
void test1(){
    int b=12;
    Log("b=%d\n",b);
}
int main(int argc, const char* argv[]) {
   
    test();
    test1();
    return0;
}
 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bright1st

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值