Nibbles Blog Nibbles Blog
  • 专题汇总
    • 技术学习
    • 个人成长
    • 运营技能
    • 自媒体
    • Minecraft
  • 推荐
    • 好物推荐
    • APP推荐
  • 关于我
    • Nibbles Studio
  • 友情链接
首页 › 技术学习 › 谈谈printf()和scanf() | C语言基础

谈谈printf()和scanf() | C语言基础

Avatar photo
Nibbles 尼布
20 4 月, 2025

不同于Python,直接就可以使用类似的print()和input(),C语言中这两个库函数都需要引入最基础的表示输入输出的stdio.h头文件
#include <stdio.h>

博主环境使用Windows 11,C语言IDE大多用的是Visual Studio 2022,校内使用CFree5;
按认识顺序撰文,从helloworld认识printf(),而后认识scanf()

1. printf() 打印输出

相比于博主之前学过的Python语言中的print(),C语言中的printf(),从函数名上多了个f字母,代表format(格式),说明可以定制输出⽂本的格式,这文本格式也叫数据类型。

数据类型

Intro

参考文档:https://zh.cppreference.com/w/c/language/arithmetic_types#.E6.95.B0.E6.8D.AE.E6.A8.A1.E5.9E.8B

sizeof() 函数

sizeof()是个用于计算操作符类型长度的函数,输出的单位为字节(Bite)(换算:1Bite=8bit)
虽然输出的单位是字节,看着输出类型好像是整数,但是根据实际的编辑器输出的附加提示可得这是size_t类型。所以printf中的占位符应该是%zd。

#include <stdio.h>
int main()
{
    printf("%zd",sizeof(int));  // 输出:4(表示int类型的长度为四个字节)
    return 0;
}
根据头文件来查数据类型对应的取值范围
  • limits.h ⽂件中说明了整型类型的取值范围。
  • float.h 这个头⽂件中说明浮点型类型的取值范围。(有的编译器下可能没有写)
    取值范围的极限值都是定义在头文件中的一些常量里的,比如INT_MIN、INT_MAX代表int数据类型的最⼩值和最⼤值,这些我们叫宏常量。
// 节选自limits.h

#define INT_MIN &nbsp; &nbsp; (-2147483647 - 1)
#define INT_MAX &nbsp; &nbsp; &nbsp; 2147483647

integer 整型

  • short:长度为2,范围为 -32767~32767
  • int:长度为4,范围为 -2147483647~2147483647
    (初学者目前刷到的题目都是int就能解决的,只要注意题目中有关于2147483647的提示就直接用int,巧记Tips:我们学校的学号正好和此范围都是十位数)
  • long:长度为4,范围为 -2147483647L~2147483647L (注意末尾有L)
  • long long:长度为8,范围为 -9223372036854775807i64~9223372036854775807i64
    (在算法竞赛中,为了不让长度作为判题有误的限制,一般使用long long)
  • unsigned int: 范围为0~4294967295,可以简写为unsigned
关于 signed 或 unsigned

C语⾔使⽤ signed 和 unsigned 关键字修饰字符型和整型的。
signed 关键字,表⽰该类型带有正负号,可以包含负值;
unsigned 关键字,表⽰该类型不带有正负号,只能表⽰零和正整数。
默认不带此关键字的话,省略的前缀为 signed
整数变量声明为 unsigned 的好处是,同样⻓度的内存能够表⽰的最⼤整数值,增⼤了⼀倍。

floating-point 浮点型

ps:到浮点型的话,范围数字很长,所以这里直接用十进制小数点位数来代表范围

  • float:长度为4,单精度,精确到小数点后6位,范围的末尾有f
  • double:长度为8,双精度,精确到小数点后15位。
  • long double:长度为8(msvs)或16(gcc),精确到小数点后15位,但实际范围比double更大。

character 字符型

char 字符类型,长度为1,字符型的常量一般用单引号包围'',这点尤其注意。
如果是转义字符,比如 \n,\0,\t都算作一个字符。
再比如有些看不见的操作也可以算作一个字符,比如空格和换行。

bool 布尔型

C语⾔原来并没有为布尔值单独设置⼀个类型,⽽是使⽤整数 0 表⽰false(假),⾮零值表示true(真)。
在 C99 标准中引⼊了布尔类型来表⽰真假的,需要包含<stdbool.h>头文件 #include <stdio.h>。
(对于老一点的编译器可能需要C99支持,比如CFree)
布尔类型(_Bool)长度为1,其类型的变量取值仅有true和false两个。

#include <stdio.h>
int main()
{
    // 整型
    printf("%hd", 5); //short对应的
    printf("%d", 5);  // int对应的【常用】
    printf("%ld", 5);  // long对应的
    printf("%lld", 5);  // long long对应的

    // 浮点型:根据小数点后面取到的位数不同选择不同的数据类型
    printf("%f", 3.14f);  // float对应的,注意末尾有f
    printf("%lf", 3.1415); // double对应的 【常用】
    printf("%Lf", 3.1415); // long double 对应的,注意大写L

    // 字符型:字符和其对应的ASCII码值是对应的
    printf("%c", 'A');
    printf("%c", 65);

    // 字符串
    printf("%s", "HelloWorld");
}

输出格式

基本格式

printf() 不会在⾏尾⾃动添加换⾏符,运⾏结束后,光标就停留在输出结束的地⽅,不会⾃动换 ⾏。
那么其中有占位符表示输入格式的部分,需要借助双引号参数1外的参数加入这个位置。

谈谈printf()和scanf() | C语言基础-Nibbles Blog

占位符到转换说明

占位符就是写在第一个字符串参数中%开头的,形如%d,%f,在一定位置可表示要填入的参数格式/控制参数输出格式的这类字符。
占位符表格:

数据类型变量声明类型占位符
短整型short%hd
整型int%d
无符号整型unsigned int%u
长整型long%ld
无符号长整型unsigned long int%lu
长长整型long long%lld
单精度浮点型float%f
双精度浮点型double%lf
长双精度浮点型long double%Lf
字符型char%c
字符串型String%s
指针(独立类型)–%p

如果对于上面表格中写的部分,那么只看这种占位符其实也是转换说明,但如果加上下面这些后就算是转换说明,转换说明基本格式如同%m.pX 或 %-m.pX。

限定最小宽度

在占位符中间插入数字(或转化说明基本格式中的小数点前的数字m)即代表输出的最小宽度。
最小宽度的理解:宽度对于整型来说就是数字位数,如果说位数小于最小宽度,会在数字前面自动补空格直到是最小宽度;如果给出的位数已经超过了最小宽度,那么直接输出。
默认在数字前面补空格即右对齐,如果需要左对齐的话,可以再在%后加一个-。

#include <stdio.h>
int main(){
    printf("%d\n", 123);   // Output:"123"
    printf("%5d\n", 123);  // Output:"  123"
    printf("%-5d\n", 123); // Output: "123  "
    return 0;
}
始终显示正负号

在占位符中间插入+就可以了。(和上面的的-的用法要分清哦!)

#include <stdio.h>
int main()
{
    printf("%+d\n", 123);  // Output: "+123"
    printf("%+d\n", -123); // Output: "-123"
    return 0;
}
限定小数点后位数

%和字母之间的小数点后紧接着的数字(或转化说明基本格式中的小数点前的数字p)就代表要保留的位数,会四舍五入到这个指定的位数。

#include <stdio.h>
int main()
{
    printf("%.2f\n", 1.233);  // Output: "1.23"
    printf("%.2f\n", 1.236);  // Output: "1.24"
    return 0;
}

ps:默认不指定保留几位的时候,输出的最多位数取决于数据类型精度。
可以和限定最小宽度的一起使用,小数点算一个宽度。

#include <stdio.h>
int main()
{
    printf("%5.2f\n", 1.236);  // Output: " 1.24"
    return 0;
}
输出部分字符串

如果把上面限定小数点后位数的方法,用到字符串输出用的%s上,那就是可以指定字符串输出的长度了。

#include <stdio.h>
int main()
{
    printf("%.7s\n", "Nibbles is handsome.");  // Output: "Nibbles"
    return 0;
}
限定值以 * 代
#include <stdio.h>
int main()
{
    printf("%*.*f\n", 6, 2, 0.5);  // Output: "  0.50"
    return 0;
}

2. scanf() 输入

除了按照上述的直接输出的程序方式。一个完整的简单程序应该有IO两部分(Process处理后续涉及):Input(输入),Output(输出)。 输出方式就是上面的 printf() 打印到屏幕,输入就是scanf()
先给示例:

谈谈printf()和scanf() | C语言基础-Nibbles Blog
#include <stdio.h>
int main()
{
    int num = 0;
    scanf("%d", &num);
    printf("Number: ", num);
}

变量

定义 = 声明 + 内存分配

int num = 0;

这样是定义了一个变量 num,并将其初始化,初始值设置为0。
变量的定义过程是 int num 部分,此时会在内存中分配一个空间。

extern 单独声明

extern int external_var;

单独只有声明的需要使用 extern 关键字,一般在头文件中声明,但不分配内存。
但是如果在其他文件中已经有定义了变量,在该文件中想要引用其他文件的定义可以使用 extern

变量的生命周期控制

全局变量

在函数的 { } 之外定义的变量,初始化如果不指定是默认为0。
如果是在定义之前使用 extern (如上在头文件中单独声明案例)
在内存的静态存储区。在整个程序中:程序开始执行时创建,在程序结束时销毁。

局部变量

在函数的 { } 之内定义的变量,要是出了花括号的部分就没法再引用。
在整个程序中:进入程序中变量所在函数时创建,在退出该函数时销毁。
通常存储在栈区(auto 变量)。使用 static 关键字把变量变为静态变量,默认初始值才可以是0,否则没有初始值是随机数,此时在内存的静态存储区。

变量的命名规则

  • 可以包含的字符:字母(a-z, A-Z)、数字(0-9)和下划线(_) 。
  • 第一个字符必须是字母或下划线。
  • 变量名区分大小写。
  • 变量名不能是C语言的关键字。
    • 关键字:auto, break, case, char, const, continue, default, do, double, else, enum, extern, float, for, goto, if, int, long, register, return, short, signed, sizeof, static, struct, switch, typedef, union, unsigned, void, volatile, while
  • 应选择具有描述性的变量名,以便于理解变量的用途(不建议学大学里课堂上那样,为了图快而使用abc这样的单字母变量名)。

输入格式

基本格式

如下在程序执行时,会在冒号后面停留光标,等待你输入整数。之后回车即可把刚输入的整数赋给value整型变量。

第一个参数就是格式化字符串,之后的参数的基本格式应该是 <取地址运算符><变量名>
一次可以读入多个变量,但是要注意,有多少个占位符/转换说明,后面其后就要有多少个参数,遵循按顺序对应。如果一次输入多个值,各个值之间常可以用空格换行隔开,函数处理时候会⾃动过滤空⽩字符,包括空格、制表符、换⾏符。(但是如果是%c会把空格作为一个字符,如果要忽略可以写成% c,即在%和字母间加个空格)
scanf()函数中的占位符决定了输入的格式。如果输入的格式不一样的话,会强制把输入的截断到与占位符表示的格式一样的部分。

#include <stdio.h>
int main()
{
    int num_int;
    float num_float;
        // Input: "3.14"
    scanf("%d", &num_int);  
    printf("%d\n", num_int);   // Output: "3"
    scanf("%f", &num_float);
    printf("%f\n", num_float); // Output: "0.140000"
}

还可以简化为:

#include <stdio.h>
int main()
{
    int num_int;
    float num_float;
        // Input: "3.14"
    scanf("%d%f", &num_int, &num_float);  
    printf("INT: %d\nFLOAT: %f\n", num_int, num_float); 
    /**
    Output:
        INT: 3
        FLOAT: 0.140000
    */
}

字符串输入不建议使用该函数,%s 不会包含空⽩字符,所以⽆法⽤来读取多个单词组成的短语/句子。读入时不会检测字符串是否超过数组⻓度。储存字符串时,很可能报错表示超过数组的边界。

函数返回值和EOF文件结束

在刷题时候,碰到题目要求函数式编程,在题目中已经给出了基本的代码结构,如下:

#include <stdio.h>
void print(int m, int n);

int main() {
    int m, n;
    while (scanf("%d%d", &m, &n) != EOF) {
        print(m,n);
        printf("\n");
    }
    return 0;
}

在while的表达式里有关于scanf()函数返回值的条件语句。
scanf()函数的返回值是个整数,且是和函数的占位符数是一致的。如果什么都没读取到就是返回0。如果在成功读取任何数据之前,发⽣了读取错误或者遇到读取到⽂件结尾,则返回常量 EOF (-1)。
那么这个EOF的结束效果如何在我们输入中体现呢?
Ctrl+Z 连按三次(VS2022中的效果),或者其他有的编译器中按一次即可。

赋值忽略说明

这一符号的设计主要是服务用户的。比如你规定了日期的输入格式为2025/4/19,结果输了个2025.4.19。此时就需要赋值忽略符(assignment suppression character)这样的处理了。

#include <stdio.h>
int main()
{
    int year = 0;
    int month = 0;
    int day = 0;
    scanf("%d%*c%d%*c%d", &year, &month, &day);
    printf("%d-%d-%d", year, month, day);
    return 0;
}

这里的 %*c 中间的*就是作为赋值忽略符,这里的 %*c 可以不必和后面参数对应,不必返回,且读取到值也不输出,我们输出格式在 printf()函数里标定了 <year>-<month>-<day> 。

声明:本站原创文章文字版权归本站所有,转载务必注明作者和出处;本站转载文章仅仅代表原作者观点,不代表本站立场,图文版权归原作者所有。如有侵权,请联系我们删除。
C语言
1
0
Avatar photo
Nibbles 尼布
向着终生成长者迈进!
赞赏

评论 (0)

取消
    发表评论

猜你喜欢

  • 运算符 | Java语言基础
  • 变量详解 | Java语言基础
  • 初识 Java 及数据类型 | Java语言基础

公众号同步更新

🔍微信搜一搜“尼布技术志”

文章目录

  • SiteMap
  • Umami
  • CSDN
  • xLog「待开放」
  • Substack「待开放」
Copyright © 2022-2025 Nibbles Blog. Designed by nicetheme. 浙公网安备33038102332481号 浙ICP备2024120131号
旗下产品: 匿补阁 个人工作室主页 Nibbles AI 匿补阁小商城 匿补阁CardShop NavP
  • C语言4
  • Java4
  • python2
  • AI2
  • 公众号2
  • 专题汇总
    • 技术学习
    • 个人成长
    • 运营技能
    • 自媒体
    • Minecraft
  • 推荐
    • 好物推荐
    • APP推荐
  • 关于我
    • Nibbles Studio
  • 友情链接