C 语言基础
C 语言基础
数据类型
- 基本类型
- 整型 int
- 字符型 char
- 实型(浮点型)
- 单精度实型 float
- 双精度实型 double
- 构造类型
- 数组类型[]
- 结构体类型 struct
- 聚合类型 union(考研不考)
- 枚举类型 enum(考研不考)
- 指针类型*
- 空类型(无值类)void
C 语言中的关键字
auto、const、double、float、int、short、struct、unsigned
break、continue、else、for、long、signed、switch、void
case、default、enum、goto、register、sizeof、typeof、volatile
char、do、extern、if、return、static、union、while
变量代表内存中具有特定属性的一个存储单元,它用来存放数据,即变量的值。这些值在程序的执行过程中是可以改变的。
变量名实际上以一个名字代表一个对应的存储单元地址。编译、链接程序时,由编译系统为每个变量名分配对应的内存地址。从变量中取值实际上是通过变量名找到内存中存储单元的地址,并从该存储单元中读取数据。
变量的命名规定如下:C 语言规定标识符只能由字母、数字和下画线三种字符组成,并且第一个字符必须为字母或下画线。例如:
sum, _total, month, Student_name, lotus_1_2_3, BASIC, li_ling
是正确的,而
M.D.John, ¥123, 3D64, a>b
是错误的。
编译系统认为大写字母和小写字母是不同的字符,因此 C 语言要求对所有用到的变量做强制定义,即“先定义,后使用”。同时在选择变量名和其他标识符时,应尽量做到“见名知意”,即选择具有含义的英文单词(或其缩写)作为标识符。注意,变量名不能与关键字同名!
#include <stdio.h> // 引用头文件
#define PI 3 // PI就是符号常量
int main() {
int a = 3; // a 就是一个变量
a = 5;
// PI = 10; 错误的,符号常量不可以赋值
return 0;
}
整型常量的不同进制表示
计算机中只能存储二进制数,即 0 和 1,而在对应的物理硬件上则是高、低电平。为了更方便地观察内存中的二进制数情况,除我们正常使用的十进制数外,计算机还提供了十六进制数和八进制数。
下面介绍不同进制数的对应关系。
首先,在计算机中,1 字节为 8 位,1 位即二进制的 1 位,它存储 0 或 1。int 型常量的大小为 4 字节,即 32 位。
设有二进制数 0100 1100 0011 00010101 0110 1111 1110,其最低位是 2 的零次方,最高位是 2 的 30 次方,最高位为符号位,具体情况需要学习计算机组成原理。
上面的二进制数对应的八进制数是 011414253376,它以 0 开头标示,数位的变化范围是 0~7。二进数转换为八进制数的方式是,对应的二进制数每 3 位转换为 1 位八进制数。首先将上面的二进制数按每 3 位隔开,得到 01 001 100 001 100 010 101 011011 111 110,然后每 3 位对应 0~7 范围内。
scanf 函数
C 语言未提供输入/输出关键字,其输入和输出是通过标准函数库来实现的。C 语言通过 scanf
函数读取键盘输入,键盘输入又被称为标准输入。当 scanf
函数读取标准输入时,如果还没有输入任何内容,那么 scanf
函数会被卡住(专业用语为阻塞)。下面来看一个例子:
int main() {
int a;
scanf("%d", &a); // 一定要在变量前加入取地址符,即&符号
printf("a=%d", a);
return 0;
}
运行之后,输入任意数字再按下回车键,就会打印 “a=你输入的数字”。scanf
函数可以允许有多个参数下面是例子:
int a, b;
scanf("%d%d", &a, &b); // 一定要在变量前加入取地址符,即&符号
printf("a=%d, b=%d\n", a, b);
这时,需要输入两个数字(用空格隔开),按下回车键后就会按printf
的格式输出。
常用进制
int main() {
int i_2 = 0b01111011; // 2进制,以 "0b" 开头
int i_8 = 0173; // 8进制,以数字 "0" 开头
int i_10 = 123; // 10 进制
int i_16 = 0x7b; // 16 进制,以 "0x" 开头
printf("%o, %o, %o, %o\n", i_2, i_8, i_10, i_16); // %o 以八进制方式输出整型数
printf("%d ,%d ,%d ,%d\n", i_2, i_8, i_10, i_16); // %d 以十进制方式输出整型数
printf("%x, %x, %x, %x\n", i_2, i_8, i_10, i_16); // %x 以十六进制方式输出整型数
return 0;
}
浮点数
C 语言中通过 float f
来定义浮点变量,f
占用 4 个字节的空间。
基本使用:
float f = 1.234;
printf("浮点数f = %f", f); // %f 是以浮点数形式输出数据
输出为:
浮点数f = 1.234000
提示
直接使用 1.234
会有类似 Clang-Tidy: Narrowing conversion from 'double' to 'float' 的警告,也就是说把一个双精度浮点数赋值给一个float
型变量会丢失精度,因此建议在数字后加一个字母f
,即1.234f
。
其他形式:
float f2 = 1.234f;
float f3 = 3e2f;
float f4 = 32.56e-4f;
printf("f2 = %f\n", f2);
printf("f3 = %f\n", f3);
printf("f4 = %f\n", f4);
输出
f2 = 1.234000
f3 = 300.000000
f4 = 0.003256
这里3e2f
和 32.56e-4f
都是以IEEE754
标准,类似“科学计数法”,即:
3e2
32.56e-4
注意
字母e
或E
之前必须有数字,且之后的指数必须是整数。
正确示例:1e3
、1.8e-3
、-123e-6
、-.1e-3
错误实例:e3
、2.1e3.5
、.e3
、e
字符型数据
用单引号括起来的一个字符是字符型常量,且只能包含一个字符。例如,'a'
、'A'
、'1'
、' '
是正确的字符型常量,而'abc'
、"a"
、" "
是错误的字符型常量。
以 \
开头的特殊字符称为转义字符,转义字符用来表示回车、退格等功能键。下表中给出了部分转义字符及其作用。
转义字符 | 意义 |
---|---|
\n | 换行(LF),将当前位置移到下一行开头 |
\t | 水平制表符(跳到下一个 TAB 位置) |
\0 | 空字符(NULL) |
\\ | 代表反斜线字符\ |
\' | 代表一个单引号字符 |
\" | 代表一个双引号字符 |
字符型变量使用关键字 char 进行定义,一个字符型变量占用 1 字节大小的空间。一个字符常量存放到一个字符型变量中时,实际上并不是把该字符的字型放到内存中,而是把该字符的 ASCIl 码值放到存储单元中,每个字符的 ASCII 码值详见ASCII 码表。打印字符型变量时,如果以字符形式打印,那么计算机会到 ASCII 码表中查找字符型变最的 ASCII 码值,查到对应的字符后会是示对应的字符。这样,字符型数据和整型数据之间就可以通用。字符型数据既可以以字符形式输出,又可以以整数形式输出,还可以通过运算获取想要的各种字符。例如,小写字母a
的十进制 ASCII 码为97
,可以通过以下代码验证:
int main() {
char c = 'a';
printf("%c, %d\n", c, c);
printf("%c\n", 97);
return 0;
}
输出
a, 97
a
对于字符型变量,无论是赋 ASCII 码值还是赋字符,使用 %c
打印输出时得到的都是字符,使用 %d
打印输出时得到的都是 ASCII 码值。
将小写字母转换为大写字母时,由 ASCII 码表发现小写字母与大写字母的差值为 32,因此将变量 c 减去 32 就可以得到大写字母 A。以下是代码:
int main() {
char c, d; // 声明两个变量
c = 97;
d = 'a';
printf("c = %c, d = %c\n", c, d); // 打印都是字母a
printf("c = %d, d = %d\n", c, d); // 打印都是97
c = c - 32; // 小写字母a,转换成大写字母A
d = d - 32; // 观察 ASCII 码表得知,大小写之间相差 32
printf("c = %c, d = %c\n", c, d); // 打印都是字母A
return 0;
}
字符串型数据
字符串型常量是由一对双引号插起来的字符序列。例如,"How do you do."
、"CHINA"
、"a"
和 "$123.45"
都是合法的字符串型常量,我们可用语句 printf("How do you do.")
输出一个字符串。但要注意的是,'a'
是字符型常量,而 "a"
是字符串型常量,二者是不同的。
例如,如果先用语句 char c
定义字符型变量 c,后令 c="a"
或 c="CHINA"
,那么这样的赋值都是非法的,原因是不可以将字符串型常量赋值给字符型变量。
提示
C 语言中没有定义字符串型变量的关键字,而是用字符数组来存储。
C 语言规定,在每个字符串型常量的结尾加一个字符串结束标志,以便系统据此判断字符串是否结束。C 语言规定以字符 '\0'
作为字符串结束标志。
例如,字符串型常量"CHINA"
在内存中的存储结果如下图所示,它占用的内存单元不是 5 个字符,而是 6 个字符,即大小为 6 字节,最后一个字符为'\0'
。然而,在输出时不会输出'\0'
,因为它无法显示。
强制类型转换
int main() {
int i = 5;
float j = i / 2; // 输出的是2
float k = (float) i / 2; // 输出的是2.5
printf("j = %f, k = %f\n", j, k);
return 0;
}
因为变量 i
和 2 都是 int
类型,i / 2
的类型也是整型,因此将其赋值给j
时就得到;而对 i
强制转化为float
类型时,等号右侧的进行的运算是浮点型的除法,赋值给变量 k
就是 了。
运算符
算术运算符包含 +
、-
、*
、/
和 %
,当一个表达式中同时出现这 5 种运算符时,先进行乘(*
)、除(/
)、取余(%
),取余也称取模,后进行加(+
)、减(-
),也就是乘、除、取余运算符的优先级高于加、减运算符。除了 %
运算符外,其余几种运算符既适用于浮点型数又适用于整型数。当操作符的两个操作数都是整型数时,它执行整除运算,在其他情况下执行浮点型数除法。%
为取模运算符、它接收两个整型操作数,将左操作数除以右操作数,但它的返回值是余数而不是商。
由算术运算符组成的式子称为算术表达式,表达式一定有一个值。以下代码中,变量 s 用于帮助读者理解算术运算符的优先级。
int s = 4 + 5 * 2 - 6 / 3 + 10 % 4;
printf("%d", s); // 14