——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
变量
C语言根据变量作用域的不同,将变量分为局部变量和全局变量。
1.局部变量:
1> 定义:在函数(代码块)内部定义的变量(包括函数的形参);
2> 作用域:从定义变量的那一行开始,一直到代码块结束;
3> 生命周期:从定义变量的那一行开始分配存储空间,代码块结束后,就会被回收;
4> 没有固定的初始值。
2.全局变量
1> 定义:在函数外面定义的变量;
2> 作用域:从定义变量的那一行开始,一直到文件结尾(能被后面的所有函数共享);
3> 生命周期:程序一启动就会分配存储空间,程序退出时才会被销毁;
4> 默认的初始值就是0。
所有的全局变量都是静态变量,被关键字static修饰的局部变量也是静态变量。
#include <stdio.h>
void test()
{
static int a = 0;
a++;
int b = 0;
b++;
printf("a=%d,b=%d\n", a, b);
}
int main()
{
//连续调用3此test函数
for(int i = 0; i<3 ; i++)
{
test();
}
return 0;
}
其中a为静态变量,只运行一次,所以运行的结果:
被关键字register修饰的自动变量都是寄存器变量;只有自动变量才可以是寄存器变量,全局变量和静态局部变量不行;寄存器变量只限于int、char和指针类型变量使用。我们一般会将一些频繁使用的自动变量定义为寄存器变量。
int b;
int main()
{
register int a;
}
结构体
当一个整体由多个数据构成时,我们可以用数组来表示这个整体,但是数组有个特点:内部的每一个元素都必须是相同类型的数据。C语言专门提供了一种构造类型来解决这个问题,这就是结构体,可以由多个不同类型的数据构成。
- 定义结构体类型
struct是关键字,是结构体类型的标志。
struct Person
{ // 里面的3个变量,可以称为是结构体的成员或者属性
int age; // 年龄
double height; // 身高
char *name; // 姓名
};
- 定义结构体变量
定义结构体变量有三种形式:
先定义结构体类型,再定义变量
struct Student {
char *name;
int age;
};
struct Student stu;
定义结构体类型的同时定义变量
struct Student {
char *name;
int age;
} stu;
直接定义结构体类型变量,省略类型名
struct {
char *name;
int age;
} stu;
结构体作用域
1> 定义在函数外面:全局有效(从定义类型的那行开始,一直到文件结尾)
2> 定义在函数(代码块)内部:局部有效(从定义类型的那行开始,一直到代码块结束)- 结构体内存细节
// 1.定义结构体类型(并不会分配存储空间)
struct Date
{
int year;
int month;
int day;
};
// 2.定义结构体变量(真正分配存储空间)
struct Date d1 = {2011, 4, 10};
struct Date d2 = {2012, 8, 9};
结构体变量占用的内存空间是其成员所占内存之和,而且各成员在内存中按定义的顺序依次排列;但是存在补齐算法,即结构体所占用的存储空间必须是最大成员字节数的倍数。
- 结构体初始化
将各成员的初值,按顺序地放在一对大括号{}中,并用逗号分隔,一一对应赋值。需要注意的是只能在定义变量的同时进行初始化赋值,初始化赋值和变量的定义不能分开,下面的做法是错误的:
struct Student stu;
stu = {"MJ", 27};
结构体在使用时需要注意,如果某个成员也是结构体变量,可以连续使用成员运算符”.”访问最低一级成员,如下程序所示:
struct Date {
int year;
int month;
int day;
};
struct Student {
char *name;
struct Date birthday;
};
struct Student stu;
stu.birthday.year = 1986;
stu.birthday.month = 9;
stu.birthday.day = 10;
- 结构体数组
结构体数组定义方式和结构体变量相同。在使用方法上也同普通的数组用法是一样的。
struct
{
char *name;
int age;
} stu[2] = { {"MJ", 27}, {"JJ", 30} };
- 结构体作为函数参数
结构体变量其实和普通变量类型相同,将结构体变量作为函数参数进行传递时,其实传递的是全部成员的值,也就是将实参中成员的值一一赋值给对应的形参成员,只是简简单单的值传递,所以改变形参的值不会影响到实参。 - 指向结构体的指针
两种书写方式:
struct Student stu;
struct Student *p;
访问结构体成员:stu.成员名
利用指针可以访问相应的结构体成员:
p->成员名
(*p).成员名
这个程序中也很好的体现了访问结构体成员的方式:
#include <stdio.h>
int main()
{
//定义一个结构体类型
struct Student
{
char *name;
int age;
float height;
};
//定义一个结构体变量
struct Student stu = {"duo", 26, 1.6};
//定义一个结构体指针
struct Student *p;
//纸箱结构体变量stu
p = &stu;
printf("name = %s, age = %d, height = %f\n", stu.name, stu.age, stu.height);
printf("name = %s, age = %d, height = %f\n",(*p).name, (*p).age, (*p).height);
printf("name = %s, age = %d, height = %f\n",p->name, p->age, p->height);
return 0;
}
枚举
枚举是C语言中的一种基本数据类型,并不是构造类型,它可以用于声明一组常数。当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型。比如,你可以用一个枚举类型的变量来表示季节,因为季节只有4种可能的取值:春天、夏天、秋天、冬天。
一般形式为:enum 枚举名 {枚举元素1,枚举元素2,……};
enum Season {spring, summer, autumn, winter};
枚举变量的定义和结构体变量定义方式相同,也是三种方式,可以先定义类型再定义变量,也可以在定义类型的同时定义变量,或者是省略枚举名称,直接定义枚举变量。
预处理指令
1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译。
2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号”#”开头,并且结尾不用分号。
3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源程序文件。
4.C语言提供的预处理指令主要有:宏定义、文件包含、条件编译。
- 宏定义
一、不带参数的宏定义
#define 宏名 字符串
它的作用是在编译预处理时,将源程序中所有”宏名”替换成右边的”字符串”,常用来定义常量。
#undef 宏名
是结束这个宏定义。
二、带参数的宏定义
#define 宏名(参数列表) 字符串
在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换。
#include <stdio.h>
#define average(a, b) (a+b)/2
int main ()
{
int a = average(10, 4);
printf("平均值:%d", a);
return 0;
}
代码中定义了一个带有2个参数的宏average,下面会被替换成:int a = (10 + 4)/2。
从整个使用过程可以发现,带参数的宏定义,在源程序中出现的形式与函数很像。但是两者是有本质区别的:
1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率
- 条件编译
其实条件编译同流程控制中if得用法相似,不过它是属于预处理。
#if 条件1
...code1...
#elif 条件2
...code2...
#else
...code3...
#endif
有时候我们不仅仅需要判断宏的值,还需要判断是否定义过某个宏,这个功能需要#if defined()和#if !defined()来判断,也可以写成#ifdef和#ifndef。
typedef
在C语言中我们可以使用typedef关键字为各种数据类型定义一个新名字。这个宏定义类似,但是却有本质上的区别。
#include <stdio.h>
#define String2 char *
typedef char * String1;
int main()
{
//str1、str2是指向char类型的指针变量
String1 str1, str2;
//str3是指向char类型的指针变量,str4只是个char类型的变量
String2 str3, str4;
return 0;
}
在这个代码中,只有str1、str2、str3才是指向char类型的指针变量,str4只是个char类型的变量。因为经过typedef处理后,String1也算是一种数据类型,
而宏定义纯粹是字符串替换,用char *代替String2。
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-