您的位置:首页 > 编程语言 > C语言/C++

C语言回顾之结构体、枚举、宏定义、typedef、extern和static的使用

2014-12-11 19:02 816 查看
一、结构体

1、什么是结构体

由多个不同类型的数据构成一个整体

2、定义结构体步骤

(1)定义结构体类型

(2)根据结构体类型,定义结构体变量

例如:

#include <stdio.h>

int main()
{

struct Person
{ // 里面的3个变量,可以称为是结构体的成员或者属性
int age; // 年龄
double height; // 身高
char *name; // 姓名
};

// 2.根据结构体类型,定义结构体变量
struct Person p = {20, 1.55, "jack"};
p.age = 30;
p.name = "rose";

printf("age=%d, name=%s, height=%f\n", p.age, p.name, p.height);

/* 错误写法
struct Person p2;
p2 = {30, 1.67, "jake"};
*/

struct Person p2 = {.height = 1.78, .name="jim", .age=30};
//p2.age = 25;

return 0;
}


3、结构体内存分析
定义结构体类型并不会分配内存,当为结构体类型的变量赋值时才会分配内存

#include <stdio.h>
int main()
{
struct Student
{
int age;// 4个字节

char a;

//char *name; // 8个字节
};

struct Student stu;
//stu.age = 20;
//stu.name = "jack";
// 补齐算法(对齐算法)
// 结构体所占用的存储空间 必须是 最大成员字节数的倍数

int s = sizeof(stu);
printf("%d\n", s);

return 0;
}


4、结构体内存细节
#include <stdio.h>
int main()
{
// 1.定义结构体类型(并不会分配存储空间)
struct Date
{
int year;
int month;
int day;
};

// 2.定义结构体变量(真正分配存储空间)
struct Date d1 = {2011, 4, 10};
struct Date d2 = {2012, 8, 9};

// 会将d1所有成员的值对应地赋值给d2的所有成员
d2 = d1;
d2.year = 2010;

printf("%d - %d - %d\n", d1.year, d1.month, d1.day);

printf("%d - %d - %d\n", d2.year, d2.month, d2.day);
/*
printf("%p - %p - %p\n", &d1.year, &d1.month, &d1.day);

int s = sizeof(d1);
printf("%d\n", s);

*/
}

}


5、定义结构体的3种方式

(1) 先定义类型,再定义变量(分开定义)

struct Student
{
int age;
};
struct Student stu;
(2) 定义类型的同时定义变量

struct Student
{
int age;
} stu;
struct Student stu;


(3) 定义类型的同时定义变量(省略了类型名称)

struct
{
int age;
} stu;


6、结构体类型的作用域

(1) 定义在函数外面:全局有效(从定义类型的那行开始,一直到文件结尾)

(2) 定义在函数(代码块)内部:局部有效(从定义类型的那行开始,一直到代码块结束)

// 从这行开始,一直到文件结尾,都是有效(跟全局变量一样)
struct Date
{
int year;
int month;
int day;
};
void test2()
{
struct Date
{
int year;
};
// 这里使用的是test2函数内部的struct Date类型
struct Date d1 = {2011};

// 结构体类型也是有作用域,从定义类型的那一行开始,一直到代码块结束
struct Person
{
int age;
};
struct Person p;
}

int main()
{
struct Date d1 = {2009, 8, 9};
test2();

// 不能使用test2函数中定义的类型
// struct Person p2;
return 0;
}


7、结构体定义细节
结构体类型不能重复定义
/* 错误写法:结构体类型重复定义*/
struct Student
{
int age;
double height;
char *name;
} stu;

struct Student
{
int age;
double height;
char *name;
} stu2;


8、结构体内部变量所占字节
int main()
{
struct RankRecord
{
int no; // 序号  4个字节
char *name; // 名字8个字节</span>
int score; // 积分 4个字节
};

//一共占用16个字节
struct RankRecord records[3] =
{
{1, "jack", 5000},

{2, "jim", 500},

{3, "jake",300}
};

records[0].no = 4;
// 错误写法
//records[0] = {4, "rose", 9000};

for (int i = 0; i<3; i++)
{
printf("%d\t%s\t%d\n", records[i].no, records[i].name, records[i].score);
}

//printf("%d\n", sizeof(records));

return 0;
}


9、指向结构体的指针
(1)指向结构体的指针的定义

struct Student *p;

(2)利用指针访问结构体的成员

(*p).成员名称

p->成员名称

int main()
{
struct Student
{
int no;
int age;
};
// 结构体变量
struct Student stu = {1, 20};

// 指针变量p将来指向struct Student类型的数据
struct Student *p;

// 指针变量p指向了stu变量
p = &stu;

p->age = 30;

// 第一种方式
printf("age=%d, no=%d\n", stu.age, stu.no);

// 第二种方式
printf("age=%d, no=%d\n", (*p).age, (*p).no);

// 第三种方式
printf("age=%d, no=%d\n", p->age, p->no);

return 0;
}


10、结构体和函数
如果结构体作为函数参数,只是将实参结构体所有成员的值对应地赋值给了形参结构体的所有成员,修改函数内部结构体的成员不会影响外面的实参结构体

#include <stdio.h>
struct Student
{
int age;
int no;
};
void test(struct Student s)
{
s.age = 30;
s.no = 2;
}

// 会影响外面的实参结构体
void test2(struct Student *p)
{
p->age = 15;
p->no = 2;

}

void test3(struct Student *p)
{
struct Student stu2 = {15, 2};
p = &stu2;
p->age = 16;
p->no = 3;
}

int main()
{
struct Student stu = {28, 1};

//test(stu);
//test2(&stu);
test3(&stu);

printf("age=%d, no=%d\n", stu.age, stu.no);

return 0;
}


11、结构体的镶套定义
#include <stdio.h>

int main()
{
struct Date
{
int year;
int month;
int day;
};
// 类型
struct Student
{
int no; // 学号
struct Date birthday; // 生日
struct Date ruxueDate; // 入学日期
// 这种写法是错误的
//struct Student stu;
};

struct Student stu = {1, {2000, 9, 10}, {2012, 9, 10}};
printf("year=%d,month=%d,day=%d\n", stu.birthday.year, stu.birthday.month, stu.birthday.day);
return 0;
}


二、枚举
当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型。比如,你可以用一个枚举类型的变量来表示季节,因为季节只有4种可能的取值:春天、夏天、秋天、冬天。
#include <stdio.h>
int main()
{
、
// 1.定义枚举类型
enum Season
{
spring = 1,
summer,
autumn,
winter
};

// 2.定义枚举变量
enum Season s = 100000;

printf("%d\n", s);

return 0;
}


三、宏定义
1、所有的预处理指令都是以#开头

2、预处理指令分3种,分别为宏定义,条件编译,文件包含

3、预处理指令在代码翻译成0和1之前执行

4、预处理的位置是随便写的

5、预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾,可以用#undef取消宏定义的作用

6、宏名一般用大写或者以k开头,变量名一般用小写

#include <stdio.h>

//#define kCount 4

int main()
{
char *name = "COUNT";
printf("%s\n", name);
#define COUNT 4
int ages[COUNT] = {1, 2, 67, 89};
for ( int i = 0; i<COUNT; i++) {
printf("%d\n", ages[i]);
}
// 从这行开始,COUNT这个宏就失效
#undef COUNT
int a = COUNT;
return 0;
}


7、带参数的宏定义效率比函数高

#include <stdio.h>

#define sum(v1, v2) ((v1)+(v2))

#define pingfang(a) ((a)*(a))

int main()
{
// pingfang(5+5) (10*10)
// pingfang(5+5)
// pingfang(5+5) (35)
// pingfang(5+5)/pingfang(2)
int c = pingfang(5+5)/pingfang(2);

printf("c is %d\n", c);
/*
int c = sum(2, 3) * sum(6, 4);

printf("c is %d\n", c);*/
/*
int a = 10;

int b = 20;

int c = sum(a, b);

printf("c is %d\n", c);
//int c = sum(a, b);*/

return 0;
}


8、条件编译
#include <stdio.h>

// 只要写了#if,在最后面必须加上#endif

//#define A 5

int main()
{
#ifndef A
//#ifdef A
//#if !defined(A)
printf("哈哈\n");
#endif

//int a = 10;
/*
if (a == 10)
{
printf("a是10\n");
}
else if (a == 5)
{
printf("a是5\n");
}
else
{
printf("a其他值\n");
}*/
/*

#if (A == 10)
printf("a是10\n");
#elif (A == 5)
printf("a是5\n");
#else
printf("a其他值\n");
#endif

*/

return 0;
}


四、typedef
1、作用:给已经存在的类型起一个新的名称

2、使用场合:

(1)基本数据类型
typedef int MyInt;
typedef MyInt MyInt2;
// 给指针类型char *起一个新的类型名称String
typedef char * String;
(2) 结构体
有3种定义方法
struct Student
{
int age;
};

typedef struct Student MyStu1;

typedef  struct Student2
{
int age;
} MyStu2;

typedef struct
{
int age;
} MyStu3;
(3)指针
struct Person
{
int age;
};

typedef struct Person * PersonPoint;

typedef struct Person1<span style="white-space:pre">	</span>
{
int age;
} * PersonPoint1;


(4)枚举
有2种定义方法
enum Sex {Man, Woman};
typedef enum Sex MySex1;

typedef enum {
Man,
Woman
} MySex2;


(5) 指向函数的指针
typedef int (*MyPoint)(int, int);
int sum(int a, int b)
{
return a + b;
}


3、使用
int main()
{
// 定义结构体变量
String name = "jack";
printf("%s\n", name);

struct Person p = {20};
PersonPoint p2 = &p;

MySex s = Man;
enum Sex s = Man;
enum Sex s2 = Woman;

struct Student stu3;
MyStu stu = {20};
MyStu stu2= {21};
MyPoint = sum;
sum(10,20);
return 0;
}


五、递归
1、递归的2个条件:

(1)函数自己调用自己
(2)必须有个明确的返回值
2、设计一个函数,用来计算b的n次方
#include <stdio.h>
int pow2(int b, int n);

int main()
{
int c = pow2(3, 2);

printf("%d\n", c);
return 0;
}

/*
分析:
pow2(b, 3) == b*b*b == pow2(b, 2) * b
pow2(b, 2) == b*b == pow2(b, 1) * b
pow2(b, 1) == b == pow2(b, 0) * b
pow2(b, 0) == 1
*/


函数执行完毕,开始返回->1*b*b*bint pow2(int b, int n){ if (n <= 0) return 1; return pow2(b, n-1) * b;}


六、static和extern
1、外部函数定义的函数能被本文件和其他文件访问, 默认情况下所有函数都是外部函数, 不允许有同名的外部函数。2、内部函数
定义的函数只能被本文件访问,其他文件不能访问, 允许不同文件中有同名的内部函数3、static对函数的作用(1) 定义一个内部函数(2) 声明一个内部函数4、extern对函数的作用:(1) 完整地定义一个外部函数(2) 完整地声明一个外部函数(3)extern可以省略,默认情况下声明和定义的函数都是外部函数
// 声明一个test函数
// 完整地声明一个外部函数
// extern可以省略
//extern void test();
void test();

int main()
{
test();

return 0;
}
// 声明一个内部函数
static void test2()
{

}


4、全局变量
(1)外部变量:定义的变量能被本文件和其他文件访问,默认情况下,所有的全局变量都是外部变量,不同文件中的同名外部变量,都代表着同一个变量

(2)内部变量:定义的变量只能被本文件访问,不能被其他文件访问,不同文件中的同名内部变量,互不影响

5、static对变量的作用:

定义一个内部变量

6、extern对变量的作用:

声明一个外部变量

// 定义一个外部变量
int a;
// 定义一个内部变量
static int b;
// 声明一个外部变量
extern int a;


7、static的作用
1、static修饰局部变量的使用场合:

(1)如果某个函数的调用频率特别高

(2)这个函数内部的某个变量值是固定不变的
2、static修饰局部变量的作用

(1) 延长局部变量的生命周期:程序结束的时候,局部变量才会被销毁

(2) 并没有改变局部变量的作用域

(3) 所有的test函数都共享着一个变量b

#include <stdio.h>
void test()
{

int a = 0;
a++;
printf("a的值是%d\n", a); // 1

static int b = 0;
b++;
printf("b的值是%d\n", b); // 3
}

int main()
{
for (int i = 0; i<100; i++) {
test();
}
return 0;
}
该函数执行完b的值为10,调用了10次b++,程序不会在每次调用的时候都把b清0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐