一、字符类型 char 与字符串
1. 知识点
- char 类型:用于存放单个字符,在内存中占 1 个字节(在Windows/Linux/macOS等常见环境下均如此,可用 sizeof(char) 验证)。
- 字符常量:用单引号括起来,如 '1'、'A'、'.'。它们实际存储的是该字符对应的 ASCII 码值(整数)。
- 输出:用 %c 格式占位符打印单个字符。
- 中文字符:一个中文字符在C语言中通常占用 2~4 个字节(取决于编码,如GBK占2字节,UTF-8占3~4字节),而 char 只有1字节,因此 char 变量不能存放一个完整的中文字符,强行赋值会截断,导致编译错误或乱码。
- 字符串:C语言中没有独立的字符串类型,而是用 char 数组 来存储一串字符,并以 \0(空字符) 作为结束标志。例如:char name[100]; 声明了一个能存放 99 个有效字符的字符数组(最后一位留给 \0)。
- 字符串占用内存:每个英文/数字/符号占1字节。每个中文通常占2~3字节(与编码有关)。结尾的 \0 占1字节。所以 char no[6] = "aaa你"; 如果环境使用GBK编码,“你”占2字节,"aaa你" 总长 5 字节 + \0 = 6 字节,刚好塞满数组;如果编码是UTF-8,“你”占3字节,会导致溢出,非常危险。
2. 注意事项与小细节
- 单引号与双引号的区别:'A' 是字符(char),"A" 是字符串(char 数组,实际包含 'A' 和 '\0'),两者类型不同,不能混用。
- 字符输出占位符:%c,切勿误用 %s 输出单个字符,否则会从该地址一直读到 \0,可能越界。
- 中文字符处理:若确实需要存储中文,应使用宽字符 wchar_t 或直接使用字符串数组,并配合对应的头文件和函数(、wprintf 等)。初学阶段先记住 char 不能存中文即可。
- 字符串数组的初始化大小:建议声明时比实际需要多预留至少1字节给 \0。例如已知要存最多99个字符的字符串,数组至少声明 [100]。
- sizeof 返回值:sizeof(char) 固定为1,sizeof 返回 size_t 类型,用 %zu 输出。
注明:
3. 中文为什么“一个字节装不下”?
常用汉字有 几千个,而一个字节最多只能区分 256 种不同的东西,
这就像你有 1000 件衣服,但衣柜只有 256 个格子,完全不够放。
因此想存一个中文字,必须用 多个字节 来共同表示同一个字。
比如最常见的两种编码:
- GBK 编码:一个汉字占 2 个字节
- UTF-8 编码:一个汉字通常占 3 个字节
所以“你”这个字,在内存里其实是 2 个或 3 个连续的字节共同描述的一个整体。
二、scanf 键盘录入
1. 知识点
- 基本用法:scanf("格式控制字符串", 地址列表);将键盘输入的数据按指定格式转换,并存入对应变量的地址中。
- 整数:
scanf("%d", &a); - 浮点数:
scanf("%lf", &x); - 字符:
scanf(" %c", &ch); (注意空格的作用,跳过前面的空白符) - 字符串:scanf("%s", 数组名); (数组名本身就是地址,不加 &)
为什么 scanf("%s", 数组名) 不用加 &?
举个例子:
char name[100];
scanf("%s", name); // 正确,name 自动变成地址
- 多个数据录入:➤ scanf("%d %d", &a, &b); 用户在输入时可以用空格、回车或Tab隔开数据,并不强制用空格,只要求格式与占位符之间的分隔符一致。
- ➤ 占位符之间若不加任何字符(如 "%d%d"),输入时也必须连续无分隔,容易出错,通常建议留空格。
- 占位符对应关系:%d → int%ld → long int%lld → long long int%f → float%lf → double%Lf → long double%s → char数组(字符串)%c → char
- 地址传递:普通变量(如 int age)必须加 & 取地址,数组名(如 name)则代表首地址,不需要加 &。
- 输入分隔符:格式串中若写入普通字符(如 scanf("%d,%d",&a,&b);),则用户输入时也必须原样键入这些字符(例如 12,34),否则匹配失败。
2. 代码中的典型错误及纠正
错误一:long int 使用 %d
long int num1, num2;
scanf("%d %d", &num1, &num2);
- 问题:%d 对应 int,而这里变量是 long int,类型不匹配,可能导致数据截断或错误。
- 改正:应改为 %ld,即 scanf("%ld %ld", &num1, &num2);。
错误二:double 用 %Lf
double sg;
scanf("%s %d %Lf", &name, &ages, &sg);
- 问题:%Lf 是 long double 的格式,sg 为 double,应使用 %lf。
- 改正:scanf("%s %d %lf", name, &ages, &sg);同时注意前面 name 不要加 &(见错误三)。
错误三:字符串数组取地址
scanf("%s", &name) 虽然在一些编译器下能工作,但类型上 &name 是 char (*)[100](指向数组的指针),而 %s 期望 char *。虽然它们的值相同,但不符合规范,且可能引发警告或未定义行为。
错误四:输入多个数据时分隔符不严谨
scanf("%s %d %Lf", &name, &ages, &sg);
- 由于用户输入可能包含空格(如姓名),而 %s 遇到空白就会停止,若姓名包含空格则只能读入前半部分。练习点在于用“空格”分隔三个数据,但姓名内不能有空格,这是 %s 的天然局限。需要更复杂输入时可使用 fgets,初学时了解即可。
错误五:长浮点型输出
printf("%.2Lf米", sg);
%Lf 用于输出 long double,而 sg 是 double,应使用 %lf(或直接用 %f,printf 中 %f 和 %lf 都适用于 double)。一般输出 double 用 %f 或 %lf 均可,%Lf 留给 long double。
总结正确的输入语句范例:
int age;
double height;
char name[100];
scanf("%s %d %lf", name, &age, &height); // name 不加 &
printf("姓名:%s,年龄:%d,身高:%.2lf\n", name, age, height);
三、变量定义、计算与输出
1. 知识点
- 变量先声明再使用:C语言要求变量在函数开头(C89)或使用前(C99)声明,并指定数据类型。
- 算术运算:直接用 + - * / 对变量的值进行计算,结果可赋值给另一个变量或直接作为表达式输出。
- 格式化输出:printf 中占位符与变量的顺序、类型必须严格对应。例如:%d 输出整数%lf 或 %f 输出双精度/单精度浮点数%.2lf 表示保留两位小数
- 综合实例:长方形面积、体积计算类题目,考查多变量输入、公式计算、输出格式化,是很好的基础训练。
//使用键盘录入输入长方形的长,宽,高
// 通过scanf分别计算长方形的A,B,C的面积,以及计算整体的体积
double length;
double width;
double height;
//键盘录入,通过用户输入的数值进行计算
printf("输入三个数表长方形的长,宽,高:");
scanf("%lf %lf %lf", &length, &width, &height);
//分别计算A,B,C的面积
//A面
double sumA = length * width;
//B面
double sumB = height * width;
//C面
double sumC = height * length;
//输出长方形的A,B,C的面积
printf("长方形A面面积:%.2lf\n长方形B面面积:%.2lf\n长方形C面面积:%.2lf\n",sumA,sumB,sumC);
//计算长方形的体积
double sum = width * height * length;
printf("长方形的体积为:%.2lf", sum);
2. 细节与注意事项
- 变量命名:见名知意,如 length、width、height,避免随意使用 a, b, c,增强代码可读性。
- 类型选择:整数一般用 int,若数值很大超出 int 范围(-2^31 ~ 2^31-1)则换 long long。涉及小数(如身高、面积可能带小数)必须用浮点类型 float / double,否则整数除法会截断小数。
- 输入前给出明确提示:printf("请输入…:"); 是良好习惯,用户才知道该做什么。
- 计算结果最好存入变量:先算 sumA = length * width;,再统一用 printf 输出,这样逻辑清晰,也便于调试。
- 输出格式:➤ %.2lf 保留两位小数,四舍五入。➤ \n 换行,使输出更整齐。➤ 多个变量输出时,注意占位符顺序与后面参数一一对应,否则产生混乱。
- 长浮点型占位符:long double 类型用 %Lf 输入输出,普通 double 绝不能用大写的 L。
四、完整代码修正示例(根据当天知识点)
假设我们要做练习四的正确版本:
#include
int main() {
char name[100];
int age;
double height;
printf("请输入你的姓名、年龄、身高(用空格隔开):");
scanf("%s %d %lf", name, &age, &height); // 改正占位符,数组不加 &
printf("你的姓名为:%s\n年龄:%d岁\n身高:%.2lf米\n", name, age, height);
return 0;
}
五、本次学习的核心要点速查表
| 主题 | 关键规则 |
|---|
char | 1字节,不能存中文,单引号,%c 输出 |
| 字符串 | char 数组 + \0 结尾,数组名即地址,%s 输入/输出不加 & |
scanf | 普通变量前面加 &,数组不加;占位符必须与变量类型严格匹配 |
printf | 占位符顺序和类型要与参数一致;%lf 输出 double,%.2lf 保留两位 |
| 类型匹配 | int-%d,long-%ld,double-%lf,long double-%Lf |
| 输入分隔 | 默认用空格/Tab/回车分隔;如格式串中有普通字符,输入时也要原样写出 |
| 运算与输出 | 先算后输出,公式写清楚,变量命名有意义 |