------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;
}