一、Define指令
(1)define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。
define和#include一样,均以"#“开头。凡是以”#"开头的均为预处理命令,其后边不加分号。为了讲标识符和变量名区分开来,习惯上标识符全部用大写字母。
(2)预处理命令以“#”号开头,如包含命令#include,宏定义命令#define等。一般都放在源文件的前面,它们称为预处理部分。
所谓预处理是指在进行编译之前所作的工作。预处理是C语言的一个重要功能,它由预处理程序负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。
(3)宏的定义:
在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。
Define的用法
1、用于定义常量
//一般用法:
include <stdio.h>
define PI 3.14
int main()
{
double R = 2.0; //定义圆的半径并初始化为2.0
double Area = 0.0;//定义圆的面积并初始化为0.0
Area = PIRR; //圆的面积等于πR的平方
printf("%.2lf",Area);//保留2位小数输出Area的值
return 0;
}
上述例子中,π在main函数中并未赋值也为定义,但是确能够准确输出圆的面积,正是因为在开头使用了#define 定义了PI为3.14,经过宏定义后,在程序中只要出现PI这个字符串,系统都会默认将其用3.14替换掉,这便是宏定义最简单的应用。
2、用于定义一种方法
include <stdio.h>
define fun(A) AA
int main()
{
int a = 10; //定义一个临时变量a并初始化为10
int result = 0; //定义一个临时变量resul用于储存结果
result = fun(a); //将宏定义计算后的结果存储于resul中
printf("%d",result);//输出result的结果
return 0;
}
看出上述例子输出的结果为100,将fun(A)这个字符串用A*A替换了,这便是宏定义
总结:#define [想替换的字符串] [目标字符串]
字符串的宏定义方法就是将想替换的字符串在程序中用目标字符串来替换掉,实现更好的代码可读性与可重写性。
(在宏定义方法时,要注意括号的添加与否,是否会修改源程序的优先顺序。)
3、define的单行定义,举例说明之,属于少见用法
#define A(x) ##x
#define B(x) #@x
#define C(x) #x
如果我们假设x=1,那么A(1)就是1,B(1)就是‘1’,C(1)就是”1“
4、define的多行定义
#define可以进行多行定义,虽然看起来有点蛋疼,但是确实是一个灰常经典而且在设备驱动代码中经常要用到的一个方法,格式如下:
#define MACRO(arg1,arg2) do {
test1;
test2;
}while(0)
TIP:在每一行的末尾要加上\,切记!
5、 定义宏和取消宏定义的方法
定义一个宏使用#define,取消一个宏定义使用#undef
6、使用宏进行条件编译
格式如下:#ifdef ... (#else) ... #endif
如:
#ifdef HELLO
#define WORLD 1
#else
#define WORLD 0
#endif
7、用define来处理头文件被头文件或者源文件包含的情况
由于头文件包含可以嵌套,那么c文件有可能包含多次同一个头文件,就会出现重复定义的问题的,那么可以就通过条件编译开关来避免重复包含,如下:
#ifndef HELLO_H
#define HELLO_H
二、const限定符
1、什么是const?
常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。
2、cons的主要的作用
(1)可以定义const常量,具有不可变性。
(2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。例如: void f(const int i) { …} 编译器就会知道i是一个常量,不允许修改;
(3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。
(4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。如果在函数体内修改了i,编译器就会报错;例如:
void f(const int i) { i=10;//error! }
(5)为函数重载提供了一个参考。
class A { …
void f(int i) {…} //一个函数
void f(int i) const {…} //上一个函数的重载
…
};
(6)可以节省空间,避免不必要的内存分配。
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
(7)提高了效率。编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
3、如何使用const?
(1)修饰一般常量一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。例如:
int const x=2; 或 const int x=2;
(2)修饰常数组定义或说明一个常数组可采用如下格式:
int const a[5]={1, 2, 3, 4, 5};
const int a[5]={1, 2, 3, 4, 5};
(3)修饰常对象常对象是指对象常量,定义格式如下:
class A; const A a;
A const a; 定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。
(4)修饰常指针
const int *A; //const修饰指向的对象,A可变,A指向的对象不可变
int const *A; //const修饰指向的对象,A可变,A指向的对象不可变
int *const A; //const修饰指针A, A不可变,A指向的对象可变
const int *const A;//指针A和A指向的对象都不可变
(5)修饰常引用使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下:
const double & v;
(6)修饰函数的常参数 const修饰符也可以修饰函数的传递参数,格式如下:
void Fun(const int Var); 告诉编译器Var在函数体中的无法改变,从而防止了使用者的一些无意的或错误的修改。
(7)修饰函数的返回值: const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下:
const int Fun1(); const MyClass Fun2();
(8)修饰类的成员函数: const修饰符也可以修饰类的成员函数,格式如下:
class ClassName {
public:
int Fun() const; …
};这样,在调用函数Fun时就不能修改类里面的数据
(9)在另一连接文件中引用const常量
extern const int i;//正确的引用
extern const int j=10;//错误!常量不可以被再次赋值另外,还要注意,常量必须初始化!例如: const int i=5;
三、printf函数
printf 的格式
printf 的格式有四种:
(1) printf("字符串\n");
int main(void)
{
printf("Hello World!\n"); // \n
(2) printf("输出控制符",输出参数);
int main(void)
{
int i = 10;
printf("%d\n", i); /%d是输出控制符,d 表示十进制,后面的 i 是输出参数/
return 0;
}
这句话的意思是将变量 i 以十进制输出。
(3) printf("输出控制符1 输出控制符2…", 输出参数1, 输出参数2, …);
int main(void)
{
int i = 10;
int j = 3;
printf("%d %d\n", i, j);
return 0;
}
输出控制符 1 对应的是输出参数 1,输出控制符 2 对应的是输出参数 2……编译、链接、执行后我们看一下输出结果:
10 3
上面 %d 和 %d之间有空格,所以10 3之间有空格。printf 中双引号内除了输出控制符和转义字符\n外,所有其余的普通字符全部都原样输出。比如:
int main(void)
{
int i = 10;
int j = 3;
printf("i = %d, j = %d\n", i, j);
return 0;
}
这时我们再编译、链接、执行一下:
i = 10, j = 3
i=、,、空格和j=全都原样输出了。此外需要注意的是:“输出控制符”和“输出参数”无论在“顺序上”还是在“个数上”一定要一一对应。
(4) printf("输出控制符 非输出控制符",输出参数);
四、scanf函数
1.scanf函数输出格式
(1) scanf("输入控制符", 输入参数);
功能:将从键盘输入的字符转化为“输入控制符”所规定格式的数据,然后存入以输入参数的值为地址的变量中。
例如
include <stdio.h>
int main(void)
{
int i;
i = 10;
printf("i = %d\n", i);
return 0;
}
(2) scanf("输入控制符非输入控制符", 输入参数);
这种用法几乎是不用的。那为什么 printf 中可以有“非输出控制符”,而 scanf 中就不可以有“非输入控制符”。事实上不是不可以有,而是没有必要!例如:
int main(void)
{
int i;
scanf("i = %d", &i);
printf("i = %d\n", i);
return 0;
}
2、注意点
在 printf 中,所有的“非输出控制符”都要原样输出。同样,在 scanf 中,所有的“非输入控制符”都要原样输入。所以在输入的时候i=必须要原样输入。比如要从键盘给变量 i 赋值 123,那么必须要输入i=123才正确,少一个都不行,否则就是错误。所以 scanf 中%d后面也没有必要加\n,因为在 scanf 中\n不起换行的作用。它不但什么作用都没有,你还要原样将它输入一遍。所以在 scanf 的使用中一定要记住:双引号内永远都不要加“非输入控制符”。除了“输入控制符”之外,什么都不要加,否则就是自找麻烦。而且对于用户而言,肯定是输入越简单越好。
要想将程序中的 scanf 行弄明白,首先要清楚的是:我们从键盘输入的全部都是字符。比如从键盘输入 123,它表示的并不是数字 123,而是字符 '1'、字符 '2' 和字符 '3'。
操作系统内核就是这样运作的。操作系统在接收键盘数据时都将它当成字符来接收的。这时就需要用“输入控制符”将它转化一下。%d的含义就是要将从键盘输入的这些合法的字符转化成一个十进制数字。经过 %d 转化完之后,字符 123 就是数字 123 了。
3、取地址运算符&
&是一个取地址运算符,&后面加变量名表示“该变量的地址”,所以&i就表示变量 i 的地址。&i又称为“取地址i”,就相当于将数据存入以变量 i 的地址为地址的变量中。
那么以变量 i 的地址为地址的变量是哪个变量呢?就是变量 i。所以程序中 scanf 的结果就把值 123 放到变量i中。
综上所述,scanf 语句的意思就是:从键盘上输入字符 123,然后%d将这三个字符转化成十进制数 123,最后通过“取地址 i”找到变量 i 的地址,再将数字 123 放到以变量 i 的地址为地址的变量中,即变量 i 中,所以最终的输出结果就是i=123。