一、变量
变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C 是大小写敏感的。
1、变量的声明和定义
-
变量声明向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。extern关键字表示声明。
-
变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,多个变量之间用逗号分隔。
例:
extern int a; // 声明一个全局变量 a
int a; // 定义一个全局变量 a
extern int a =0; // 定义一个全局变量 a 并给初值。一旦给予赋值,一定是定义,定义才会分配存储空间
int a =0; //定义一个全局变量 a,并给初值
声明变量后不能直接使用这个变量,需要定义之后才能使用。
- 如果需要在一个源文件中引用另外一个源文件中定义的变量,我们只需在引用的文件中将变量加上 extern 关键字的声明即可。
addtwonum.c 文件代码:
#include <stdio.h>
/*外部变量声明*/
extern int x ;
extern int y ;
int addtwonum()
{
return x+y;
}//addtwonum.c
test.c 文件代码:
#include <stdio.h>
/*定义两个全局变量*/
int x=1;
int y=2;
int addtwonum();
int main(void)
{
int result;
result = addtwonum();
printf("result 为: %d\n",result);
return 0;
}//test.c
结果
result 为:3
2、布尔类型变量
在 C 语言标准(C89)没有定义布尔类型,所以 C 语言判断真假时以 0 为假,非 0 为真。所以我们通常使用逻辑变量的做法:
//定义一个int类型变量,当变量值为0时表示false,值为1时表示true
int flag;
flag = 0;
//......
flag = 1;
if( flag )
{
//......
}
但这种做法不直观,而且没有明确 flag 一定是布尔值。所以我们又借助 C 语言的宏定义:
//宏定义布尔类型
#define BOOL int
#define TRUE 1
#define FALSE 0
//定义一个布尔变量
BOOL flag = FALSE;
这种方法虽然直观,但依然是换汤不换药,变量 flag 在编译器看来依然是 int 类型。
新版本总会改进一些不好的地方,所以在最新的 C 语言标准(C99)解决了布尔类型的问题。C99 提供了 _Bool 型,所以布尔类型可以声明为 _Bool flag。
_Bool 依然仍是整数类型,但与一般整型不同的是,_Bool 变量只能赋值为 0 或 1,非 0 的值都会被存储为 1。
C99还提供了一个头文件 <stdbool.h> 定义了 bool 代表 _Bool,true 代表 1,false 代表 0。只要导入 stdbool.h ,就能非常方便的操作布尔类型了。
//导入 stdbool.h 来使用布尔类型
#include <stdbool.h>
#include <stdio.h>
//计算n!,n的值在main中定义
int main(void)
{
int n = 10; //计算叠乘数
int sum = 1; //用来存放叠乘的结果
bool flag = false; //叠乘标记
int num = n; //循环次数
while( !flag )
{
sum = sum * (num--);
//当num=1时结束循环
if( num == 1)
{
flag = true;
}
}
printf ("%d的叠乘值为 %d \n", n, sum);
return 0;
}
二、常量
常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。
常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。
1、整数常量
整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。
整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。
例:
85 /* 十进制 */
0213 /* 八进制 */
0x4b /* 十六进制 */
30u /* 无符号整数 */
30l /* 长整数 */
30ul /* 无符号长整数 */
2、浮点常量
浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。带符号的指数是用 e 或 E 引入的。
例:
3.14159 /* 合法的 */
314159E-5L /* 合法的 */
3、字符常量
字符常量是括在单引号中,例如,‘x’ 可以存储在 char 类型的简单变量中。
字符常量可以是一个普通的字符(例如 ‘x’)、一个转义序列(例如 ‘\t’),或一个通用的字符(例如 ‘\u02C0’)。
转义序列表:
转义序列 | 含义 |
---|---|
\ | \ 字符 |
’ | ’ 字符 |
" | " 字符 |
? | ? 字符 |
\a | 警报铃声 |
\b | 退格键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ooo | 一到三位的八进制数 |
\xhh | 一个或多个数字的十六进制数 |
\ooo 是对用三位八进制数转义表示任意字符的形象化描述。
比如 char ch = ‘\101’; 等价于 char ch = 0101; (以0开头的表示八进制)。
\xhh 里面是 x 是固定的,表示十六进制(hexadecimal),h 也表示十六进制。
比如 char ch = ‘\x41’; 就是用十六进制来表示,它与前面的 \101 是等价的。
4、字符串常量
字符串字面值或常量是括在双引号 “” 中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
可以使用空格做分隔符,把一个很长的字符串常量进行分行。
注意:
在 C 语言中,单引号与双引号是有很大区别的。
在 C 语言中没有专门的字符串类型,因此双引号内的字符串会被存储到一个数组中,这个字符串代表指向这个数组起始字符的指针;
而单引号中的内容是一个 char 类型,是一个字符,这个字符对应的是 ASCII 表中的序列值。
5、常量定义
有两种方式可以用来定义常量。
- const 定义的是变量不是常量,而是去改变一个变量的存储类,把该变量所占的内存变为只读。带有类型。编译运行的时候起作用,存在类型检查。
定义const常量时不会分配内存,只在首次使用const常量定义变量时会在内存中分配,const 定义常量从汇编的角度来看,只是给出了对应的内存地址。
const doulbe Num = 3.14159; //此时并未将Pi放入ROM中 ......
double i = Num; //此时为Pi分配内存,以后不再分配!
double j = Num; //没有内存分配
- #define 是宏定义,它不能定义常量,但宏定义可以实现在字面意义上和定义常量相同的功能,本质的区别就在于 #define 不为宏名分配内存。在预编译的时候起作用,不存在类型检查。
- #deifine需要注意“边缘效应”
例:
#include <stdio.h>
#define N 2+3
//正确写法 #define N (2+3)
int main(){
double a ;
a = (float)N/(float)2;
printf("a 的值为 : %.2f", a);
return 0;
}
按照预想结果应为 a的值为:2.5
实际结果却是 a的值为:3.5
因在预处理阶段,编译器将 a=N/2 处理成 a=2+3/2,这就是 #define 宏的边缘效应,所以我们应该写成 #define N (2+3)。