C语言基础知识(一)————各类符号的含义与输入输出库(stdio)

前言

在编写 C 语言程序之前,我们需要先导入程序运行所需的库,这些库也被称为头文件。本篇基础知识将以 C 语言标准输入输出库 stdio.h 为例进行讲解。

一、占位符:

与 Java 不同,在 C 语言中,占位符用于 printf、scanf 这类格式化输入输出函数,用来标记数据的位置与数据类型。在 printf 输出时,占位符所在的位置会被替换为变量的值;在 scanf 输入时,占位符则代表需要从控制台读取对应类型的数据并存入变量。

C++ 中存在两套 IO 体系:如果沿用 C 风格的 printf/scanf,占位符的用法和规则与 C 语言完全一致;如果使用 C++ 原生的 cout 与 cin 流输入输出,则无需占位符,系统会自动识别变量的数据类型。

在 C 语言中,变量必须先声明后使用,声明时需要指定其数据类型。数据类型决定了变量在内存中占用的字节数、取值范围以及可进行的运算。下面列出 C 语言中常见的变量类型:

数据类型 关键字 占用字节数(32位系统) 取值范围(大致)
短整型 short 2 字节 -32768 ~ 32767
整型 int 4 字节 -2147483648 ~ 2147483647
长整型 long 4 字节(32位)/ 8 字节(64位) 取决于系统位数
长长整型 long long 8 字节 -9223372036854775808 ~ 9223372036854775807
无符号整型 unsigned int 4 字节 0 ~ 4294967295
单精度浮点型 float 4 字节 约 3.4e-38 ~ 3.4e38
双精度浮点型 double 8 字节 约 1.7e-308 ~ 1.7e308
字符型 char 1 字节 -128 ~ 127(或 0 ~ 255)
字符串 char[] 取决于长度 由字符数组存储
指针 void* / 类型* 4 字节(32位)/ 8 字节(64位) 内存地址

注意:上表中的字节数基于常见的 32 位系统,实际大小可能因编译器和操作系统而异。可以使用 sizeof(类型) 运算符在程序中获取某个类型实际占用的字节数。

总而言之,在 C 和 C++ 语言中,占位符就是变量位置的替代品。不同变量对应的占位符如下表所示:

数据类型 占位符 说明
int %d 输出/输入十进制整数
long %ld 输出/输入长整型整数
long long %lld 输出/输入长长整型整数
unsigned int %u 输出/输入无符号十进制整数
float %f 输出/输入单精度浮点数
double %lf 输出/输入双精度浮点数(scanf 中必须用 %lf)
char %c 输出/输入单个字符
char[](字符串) %s 输出/输入字符串
void*(指针) %p 输出指针地址
short %hd 输出/输入短整型整数
unsigned long %lu 输出/输入无符号长整型整数
unsigned long long %llu 输出/输入无符号长长整型整数
double(printf 输出) %e / %E 以科学计数法输出浮点数
double(printf 输出) %g / %G 根据数值大小自动选择 %f 或 %e 输出
int(八进制) %o 以八进制形式输出整数
int(十六进制) %x / %X 以十六进制形式输出整数(小写/大写字母)

二、转义符:

在 C 语言中,转义字符以反斜杠 \ 开头,其核心作用是改变紧跟在反斜杠后面的字符原本的含义。有些字符无法直接写在字符串中,或者本身在 C 语言中具有特殊语法作用,此时就需要借助转义符来表示。

举个例子:双引号 " 是字符串的边界标记,如果直接写在字符串内部,编译器会误认为字符串提前结束,从而引发编译错误;此时使用 \",反斜杠会告诉编译器,这个双引号只是普通字符,并非字符串结束符,最终就能正常输出双引号。再比如换行操作,我们无法直接在双引号包裹的字符串中敲回车换行,使用 \n 就可以实现换行功能。

除了 \" 和 \n 之外,还有很多常用转义字符:\r 代表回车,将光标移到当前行的开头;\t 是水平制表符,相当于按下 Tab 键,用来做文本对齐;\\ 用来输出反斜杠本身;\0 是空字符,作为 C 语言字符串的结束标记,是字符串必不可少的终止符号。

简单来说,转义字符解决了两类问题:一是表示无法直接输入、不可见的控制字符(如换行、制表、字符串结束符等);二是转义 C 语言中自带特殊含义的符号(如双引号、反斜杠等),让它们不再承担语法功能,而是单纯作为普通字符输出。

转义符 含义 说明
\n 换行 将光标移到下一行开头
\t 水平制表符 将光标移到下一个制表位(相当于按 Tab 键)
\\ 反斜杠 输出一个反斜杠 \ 本身
\" 双引号 在字符串中输出双引号 "
\' 单引号 在字符中输出单引号 '
\r 回车 将光标移到当前行开头
\b 退格 将光标向左移动一格
\f 换页 将光标移到下一页开头(常用于打印机)
\a 响铃 发出提示音(部分终端有效)
\v 垂直制表符 将光标移到下一个垂直制表位
\0 空字符 字符串结束标志(ASCII 码为 0)
\xhh 十六进制转义 输出 ASCII 码为十六进制 hh 的字符,如 \x41 输出 A
\ooo 八进制转义 输出 ASCII 码为八进制 ooo 的字符,如 \101 输出 A

注意:转义符必须写在双引号或单引号内才会生效。例如 printf("第一行\n第二行"); 会在输出时换行。

三、头文件:<stdio.h> 标准输入输出库

该库包含的函数有:printf、scanf、fgets、fputs 等。

  1. printf

printf 是输出打印语句,一般写法为 printf("想输出的内容");。如果涉及到变量,则写为 printf("内容+变量所对应的占位符", 变量);。

下面给出几个 printf 的代码示例:

c 复制代码
#include <stdio.h>

int main() {
    int age = 18;
    double score = 92.5;
    char grade = 'A';
    char name[] = "小明";

    // 1. 输出纯文本
    printf("Hello, World!\n");

    // 2. 输出变量(占位符对应变量)
    printf("年龄:%d\n", age);

    // 3. 多个占位符,按顺序对应多个变量
    printf("姓名:%s,成绩:%.1f,等级:%c\n", name, score, grade);

    // 4. 占位符也可以直接放常量或表达式
    printf("两数之和:%d\n", 10 + 5);

    return 0;
}

运行结果:

text 复制代码
Hello, World!
年龄:18
姓名:小明,成绩:92.5,等级:A
两数之和:15

注意:%.1f 表示保留一位小数;\n 是换行符。占位符的数量、顺序必须与后面的变量一一对应,否则输出结果会错乱。

  1. scanf

scanf 用来从键盘读取用户输入的数据并存储在变量中,格式为 scanf("变量对应的占位符", &变量);。

但是,使用 scanf 存储内容时存在一个问题:如果存储的是字符串,且输入中包含空格,则无法存储空格后面的内容。例如:

c 复制代码
#include <stdio.h>
int main(){
	char a[10];
	scanf("%s",&a);
	printf("%s",a); 
} 

结果:

text 复制代码
hello world
hello

这时候,我们就可以使用一个新的函数来解决这个问题。

  1. fgets

fgets 用来从输入流中读取一行字符串,并存储到指定的字符数组中。与 scanf 不同,fgets 可以读取包含空格的整行内容,因此更适合处理带空格的字符串输入。

fgets 的格式为 fgets(字符数组, 最大读取字符数, 输入流);。其中,第三个参数 stdin 表示从键盘标准输入读取数据。

下面给出一个使用 fgets 读取带空格字符串的代码示例:

c 复制代码
#include <stdio.h>

int main() {
    char name[50];

    printf("请输入姓名(可包含空格):");
    fgets(name, sizeof(name), stdin);

    printf("你输入的姓名是:%s", name);

    return 0;
}

运行结果:

text 复制代码
请输入姓名(可包含空格):张三 李四
你输入的姓名是:张三 李四

注意:fgets 会把换行符一并读入字符串,因此输出时会在末尾多出一个换行。如果想去掉末尾的换行符,可以手动将其替换为字符串结束符 \0。此外,fgets 最多读取 最大读取字符数 - 1 个字符,剩余空间会自动补上 \0,从而避免缓冲区溢出。

  1. fputs

fputs 用于将字符串写入指定的输出流,其基本格式为 fputs(字符串, 输出流);。其中,第二个参数 stdout 表示输出到屏幕的标准输出。与 printf 不同,fputs 既不会自动添加换行符,也不会解析字符串中的占位符,而是将字符串内容原样输出。因此,fputs 更适合用于输出无需格式化的纯文本。

具体来说,fputs 的返回值是 int 类型:当写入成功时返回非负值(通常是 0),当发生错误时返回 EOF(即 -1)。这一特性使得 fputs 在需要判断写入是否成功的场景下非常实用,例如在文件写入或网络传输中,可以通过检查返回值来确认数据是否完整送达。

此外,fputs 的第二个参数不仅可以是 stdout,还可以是文件指针(如 FILE *fp),这意味着它同样适用于向文件写入字符串。与 fprintf 相比,fputs 不会对字符串中的 % 等字符做任何特殊处理,因此当字符串内容本身包含大量 % 符号(如格式化文本、日志模板)时,使用 fputs 可以避免意外的格式解析,保证内容原样输出。

从底层实现来看,fputs 会逐个字符地将字符串写入输出流,直到遇到字符串结束符 \0 为止,但并不会把 \0 本身写入。这意味着它非常适合处理以 \0 结尾的 C 风格字符串,而不需要额外指定写入长度。相比之下,fwrite 则需要显式指定每次写入的元素大小和数量,使用起来相对繁琐。因此,在需要输出一整行以 \0 结尾的字符串时,fputs 是更简洁、更直观的选择。

具体来说,fputs 的返回值是 int 类型:当写入成功时返回非负值(通常是 0),当发生错误时返回 EOF(即 -1)。这一特性使得 fputs 在需要判断写入是否成功的场景下非常实用,例如在文件写入或网络传输中,可以通过检查返回值来确认数据是否完整送达。

此外,fputs 的第二个参数不仅可以是 stdout,还可以是文件指针(如 FILE *fp),这意味着它同样适用于向文件写入字符串。与 fprintf 相比,fputs 不会对字符串中的 % 等字符做任何特殊处理,因此当字符串内容本身包含大量 % 符号(如格式化文本、日志模板)时,使用 fputs 可以避免意外的格式解析,保证内容原样输出。

c 复制代码
#include <stdio.h>

int main() {
    char message[] = "Hello, fputs!";

    // 输出到标准输出(屏幕)
    fputs(message, stdout);
    fputs("\n", stdout);  // 手动添加换行

    // 也可以直接输出字符串常量
    fputs("这是第二行内容。\n", stdout);

    return 0;
}

运行结果:

text 复制代码
Hello, fputs!
这是第二行内容。

注意:fputs 不会自动换行,需要手动添加 \n;同时它也不会解析 %d 这类占位符,因此不适合用于输出变量值。若需要格式化输出变量,应改用 printf。此外,fputs 与 fgets 是一对互补函数:fgets 负责从输入流读取数据,fputs 负责向输出流写入数据。

在实际开发中,fputs 常用于以下场景:一是输出日志信息,因为日志通常不需要格式化,直接原样写入即可;二是向文件追加内容,配合文件指针可以轻松实现;三是与 fgets 配合完成文件的逐行复制。需要注意的是,fputs 写入文件时不会自动添加换行符,因此如果希望每条记录独占一行,需要在字符串末尾手动加上 \n。

另外,fputs 与 puts 也有明显区别:puts 只能向标准输出 stdout 写入,并且会在字符串末尾自动追加一个换行符;而 fputs 可以指定任意输出流,且不会自动换行。因此,当需要向文件或其他输出流写入内容、或希望完全控制换行行为时,应优先选择 fputs。

练习

1.定义不同类型的变量并输出他们的值和所占字节数

2.输入圆的半径,计算并输出圆的周长和面积

3.输入一个三位数,将其百位十位个位分别输出

1.定义不同类型的变量并输出他们的值和所占字节数

在 C 语言中,变量必须先声明后使用,声明时需要指定其数据类型。数据类型决定了变量在内存中占用的字节数、取值范围以及可进行的运算。下面列出 C 语言中常见的变量类型:

数据类型 关键字 占用字节数(32位系统) 取值范围(大致)
短整型 short 2 字节 -32768 ~ 32767
整型 int 4 字节 -2147483648 ~ 2147483647
长整型 long 4 字节(32位)/ 8 字节(64位) 取决于系统位数
长长整型 long long 8 字节 -9223372036854775808 ~ 9223372036854775807
无符号整型 unsigned int 4 字节 0 ~ 4294967295
单精度浮点型 float 4 字节 约 3.4e-38 ~ 3.4e38
双精度浮点型 double 8 字节 约 1.7e-308 ~ 1.7e308
字符型 char 1 字节 -128 ~ 127(或 0 ~ 255)
字符串 char[] 取决于长度 由字符数组存储
指针 void* / 类型* 4 字节(32位)/ 8 字节(64位) 内存地址

注意:上表中的字节数基于常见的 32 位系统,实际大小可能因编译器和操作系统而异。可以使用 sizeof(类型) 运算符在程序中获取某个类型实际占用的字节数。

下面给出一个完整的代码示例,演示如何定义不同类型的变量,并使用 sizeof 运算符输出它们的值和所占字节数:

c 复制代码
#include <stdio.h>

int main() {
    // 定义不同类型的变量
    short s = 10;
    int i = 100;
    long l = 100000L;
    long long ll = 10000000000LL;
    unsigned int ui = 3000000000U;
    float f = 3.14f;
    double d = 3.14159265358979;
    char c = 'A';
    char str[] = "Hello";
    int *p = &i;

    // 输出变量的值
    printf("short 变量 s 的值:%hd\n", s);
    printf("int 变量 i 的值:%d\n", i);
    printf("long 变量 l 的值:%ld\n", l);
    printf("long long 变量 ll 的值:%lld\n", ll);
    printf("unsigned int 变量 ui 的值:%u\n", ui);
    printf("float 变量 f 的值:%f\n", f);
    printf("double 变量 d 的值:%lf\n", d);
    printf("char 变量 c 的值:%c\n", c);
    printf("字符串 str 的值:%s\n", str);
    printf("指针 p 指向的地址:%p\n", (void*)p);

    // 输出各变量所占的字节数
    printf("\n各变量所占字节数:\n");
    printf("short 占 %zu 字节\n", sizeof(s));
    printf("int 占 %zu 字节\n", sizeof(i));
    printf("long 占 %zu 字节\n", sizeof(l));
    printf("long long 占 %zu 字节\n", sizeof(ll));
    printf("unsigned int 占 %zu 字节\n", sizeof(ui));
    printf("float 占 %zu 字节\n", sizeof(f));
    printf("double 占 %zu 字节\n", sizeof(d));
    printf("char 占 %zu 字节\n", sizeof(c));
    printf("字符串 str 占 %zu 字节\n", sizeof(str));
    printf("指针 p 占 %zu 字节\n", sizeof(p));

    return 0;
}

运行结果(在 64 位系统上):

text 复制代码
short 变量 s 的值:10
int 变量 i 的值:100
long 变量 l 的值:100000
long long 变量 ll 的值:10000000000
unsigned int 变量 ui 的值:3000000000
float 变量 f 的值:3.140000
double 变量 d 的值:3.141593
char 变量 c 的值:A
字符串 str 的值:Hello
指针 p 指向的地址:0x7ffd12345678

各变量所占字节数:
short 占 2 字节
int 占 4 字节
long 占 8 字节
long long 占 8 字节
unsigned int 占 4 字节
float 占 4 字节
double 占 8 字节
char 占 1 字节
字符串 str 占 6 字节
指针 p 占 8 字节

注意:sizeof 返回的是 size_t 类型,因此使用 %zu 作为占位符输出。字符串 str 占 6 字节,是因为它包含 5 个字符加上末尾的字符串结束符 \0。指针的大小取决于系统位数,在 64 位系统上为 8 字节,在 32 位系统上为 4 字节。

2.输入圆的半径,计算并输出圆的周长和面积

输入值并以这个值进行运算,这时候我们需要用到scanf。输出周长和面积则需要我们printf和数学公式

结果为:

3.输入一个三位数,将其百位十位个位分别输出

这时候我们有两种思路。

第一种,用数字运算,采用取余整除的方式:

第二种,用数组的方式,我们可以将输入的三位数看作是一个数组,然后读取即可

可能有人会问了,我们为什么要减去这个'0'呢?

我们先记住:'0' 是字符0,不是数字0。计算机内存里所有字符存的都是ASCII码。

字符'0'的ASCII码是 48

字符'1'的ASCII码是 49

字符'2'的ASCII码是 50

......

字符'9'的ASCII码是 57

当我们用%s读取输入123到字符数组里:

num0里面存的并不是整数1,而是字符'1',它对应的ASCII码是49。

如果你直接printf("%d", num0),输出的会是49,而不是我们想要的1。

'1' - '0' 等价于 49 - 48 = 1

用字符减去'0',本质就是用ASCII码相减,把数字字符转换成真正的整型数字。

下面是不写减去'0'的代码结果:

总结

这篇文章讲解了 C 语言标准输入输出库 <stdio.h> 的基础知识,核心内容可总结为三部分:

一、占位符:用于 printf/scanf 等格式化函数,标记数据位置与类型。文中给出了完整对照表,覆盖 int(%d)、long(%ld)、float(%f)、double(%lf)、char(%c)、字符串(%s)、指针(%p)等常用类型,并说明 C++ 沿用 C 风格时规则一致。

二、转义符:以反斜杠 \ 开头,用于表示无法直接输入的字符或转义特殊符号。表格列出了 \n(换行)、\t(制表符)、\(反斜杠)、"(双引号)、\0(字符串结束符)等常用转义符及其含义。

三、头文件 <stdio.h> 的四个核心函数:

printf:格式化输出,支持占位符与变量一一对应,附有完整代码示例;

scanf:从键盘读取输入,但无法读取含空格的字符串;

fgets:可读取包含空格的整行字符串,更适合处理带空格的输入;

fputs:向输出流原样写入字符串,不解析占位符、不自动换行,适合输出纯文本或写文件。

相关推荐
程序猿编码2 小时前
工业视觉多任务方案:可编程梯度信息视觉框架,训练评估 + C++ 部署完整实战
开发语言·c++·视觉·推理引擎
水饺编程2 小时前
第1章,了解乌班图环境,使用浏览器和邮箱
c语言·汇编·ubuntu
言乐62 小时前
Python实现语音审核模型
开发语言·python·django·virtualenv·pygame
朝朝辞暮i3 小时前
C++ 第 21 课:struct —— 把一组相关数据打包在一起
开发语言·c++·算法
SHARK_pssm4 小时前
【C++——类和对象(下)】
开发语言·c++·经验分享·笔记
凯哥Java4 小时前
写代码怎么避免逻辑漏洞?
java·开发语言·人工智能·自动化
Escalating_xu4 小时前
【C 语言】操作符详解(下):逗号、下标、结构体、类型转换与表达式求值
c语言
Ai-_Man4 小时前
您您这可以把Dola的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。用AI导出鸭,答案是可以的
开发语言·前端·人工智能·小程序
Java后端的Ai之路4 小时前
Python进阶探索23 - Python中的Time与Datetime模块
开发语言·数据库·python·datetime·time