目录
一、数据类型 & signed 和 unsigned & 取值范围
五、单目操作符: ++(自增) --(自减) +(正) -(负)
一、数据类型 & signed 和 unsigned & 取值范围
(一)数据类型
内置类型:C语言本身就有
自定义类型:顾名思义,用户自己定义的
1、字符型
[]中的内容可省略
char
[signed] char
unsigned char
2、整型(整数)
[]中的内容可省略
1 短整型
short [int]
[signed] short [int]
unsigned short [int]
2 整型
int
[signed] int
unsigned int
3 长整型
long [int]
[signed] long [int]
unsigned long [int]
4 更长的整形
long long [int]
[signed] long long [int]
unsigned long long [int]
3、浮点型(小数)
float
double
long double
4、布尔类型(真 or 假)
使用时要包含头文件 stdbool.h
#include<stdbool.h>
bool
5、sizeof 计算数据类型所占的内存大小
使用 sizeof 来计算【某变量】或【某数据类型】所占的内存,返回的是所占用的内存大小,和【该变量或数据类型中】保存的数值内容没有任何关系。(单位:Byte 字节,1 Byte = 8 bit)
(1)sizeof 的使用
sizeof (类型)
sizeof 表达式
注:若为表达式,则表达式不真实参与运算
(2)数据类型的大小
printf("%zd\n",sizeof(类型));
常用类型所占用的内存大小(单位:字节)
表出处:王健伟,《C++新经典》,清华大学出版社,2020年8月出版,表2.1
(二)signed 和 unsigned
字符型 和 整型 才被关键字 signed 和 unsigned 修饰
注:
① signed关键字,表示一个类型带有正负号,有负值
② unsigned关键字,表示该类型不带正负号,只表示零和正整数;正因为不表示负值,负值的取值范围会加到正值上,因此unsigned声明变量,可使该变量的取值范围增大一倍
每种数据类型能够取值的范围(可能不全)
表出处:王健伟,《C++新经典》,清华大学出版社,2020年8月出版,表2.2
③ signed int == int ,unsigned int == unsigned ;
但 char 可能等同于 signed char ,也可能等同于unsigned char ,取决于编译的实现,大部分编译器上char == singned char
④有符号整数使用"%d"打印,无符号使用"%u"(unsigned )打印
(三)取值范围
① limits.h 文件中说明了整型类型的取值范围
② float.h 文件中说明了浮点型类型的取值范围
③ 以下常量可加强代码的可移植性:
- SCHAR_MIN , SCHAR_MAX :signed char 的最小值和最大值;
- SHRT_MIN , SHRT_MAX :short 的最小值和最大值;
- INT_MIN , INT_MAX :int 的最小值和最大值;
- LONG_MIN , LONG_MAX :long 的最小值和最大值;
- LLONG_MIN , LLONG_MAX :long long 的最小值和最大值;
- UCHAR_MAX :unsigned char 的最大值;
- USHRT_MAX :unsigned short 的最大值;
- UINT_MAX :unsigned int 的最大值;
- ULONG_MAX :unsigned long 的最大值;
- ULLONG_MAX :unsigned long long 的最大值;
二、变量
变量:其值可以改变的量
(一)变量创建 & 初始化 & 赋值
出处:王健伟,《C++新经典》,清华大学出版社,2020年8月出版
省略 [ ] 则为创建
不省略 [ ] 则为初始化
在创建变量时给一个初始值是一种好的编程习惯,如果不给变量初始化,有的编译器会报错(局部变量不初始化的时候,他的值是随机的;全局变量不初始化,默认值为0)
int a; 创建(与定义的格式一样)
char b = 3.14; 初始化
a = 10; 赋值
(二)变量的分类
全局变量:在大括号外部定义的变量;整个工程都能使用(共享充电宝)
局部变量:在大括号内部定义的变量;在自己局部范围内使用(自家充电宝)
#include<stdio.h>
int a = 100; //全局变量
int main()
{
int a = 10; //局部变量
printf("%d\n",a);
return 0;
}
上面代码会输出10,当全局变量名和局部变量名同名时,优先使用局部变量
(三)变量的储存
学习C语言时,我们会关注内存的三个区:栈区,堆区,静态区
- 栈区:局部变量、函数参数
- 堆区:动态内存管理
- 静态区:全局变量、静态变量
三、算数操作符: + - * / %
操作符(运算符)两边的数称为操作数,以上算数运算符有两个操作数,这种操作符也称双目操作符
+(加)、-(减)、*(乘)、/(除)、%(取余数)
/(除)操作符要得到小数结果,至少要一个操作数是小数
4.0 / 1 == 4.0
4 / 1.0 == 4.0
%(取余数)操作数只能是整数,结果的正负取决于第一个操作数
四、赋值操作符: = & 复合赋值
(一)赋值操作符
将等号右边的值赋给左边的变量
(二)复合赋值
【赋值 " = " 】之前加其他运算符,构成复合赋值运算符
int a = 3;
a = a + 2;
a += 2; 复合赋值,效果同上句
五、单目操作符: ++(自增) --(自减) +(正) -(负)
++(自增)分为前置++ 和后置++ ,--(自减)同理;
前置:先自增(减),后使用
后置:先使用,后自增(减)
+(正),-(负):改变一个值的正负号
六、强制类型转换
出处:王健伟,《C++新经典》,清华大学出版社,2020年8月出版
int a = (int)3.14;
double x,y;
x = 5.0
y = 2.0
a = (int)(x/y);
强扭的瓜不甜,不在万不得已的情况下一般不会使用强制类型转换
七、细说 printf & 详讲scanf
(一)细说printf
1、基本用法
把双引号中的内容进行输出,使用前引入头文件 stdio.h
注:printf()不会自动换行,善用 "\n" 来换行
2、占位符
在双引号中的输出内容中“占位置”,会和后面的值进行交换;
多个占位符,占位符与后面的值要一一对应
注:占位符的第一个字符一律为百分号%(占位符标志),第二个字符决定输出结果
常用占位符:
%c 字符
%d 十进制 int 类型
%f 小数(包括 %f -- float 类型 和 %lf -- double 类型)
%hd 十进制 short int 类型
%ld 十进制 long int 类型
%lu unsigned long int 类型
%Lf long double 类型
%p 指针(用来打印地址)
%s 字符串
%u unsigned int 类型
%x 十六进制 int 类型
%zd size_t 类型
3、打印显示正负号
printf("%+d",12); 输出:+12
printf("%+d",-12); 输出:-12
上例 "%+d" 可以保证输出的值,总是带有正负
4、打印限定宽度
占位符可以限定最小宽度,默认右对齐,希望左对齐则补负号(-)
小于最小宽度补空格,大于正常输出
作用:输出对齐
int a = 123;
printf("%5d",a);
限定最小为五位数,输出:空格 空格 123
printf("%-5d",a);
输出:123 空格 空格
对于小数,%f 和 %lf 打印是默认小数点后面有六位:
double a = 123.45;
printf("%12lf",a);
输出:空格 空格 123.450000
5、打印限定小数位数
① 希望限定小数位数则可以使用,超过小数限定位数则会四舍五入(默认有六位小数)
printf("%.2f",3.1); 输出:3.10
printf("%.2f",3.145); 输出:3.15
② 可与限定宽度混合使用
printf("%6.2f",2.365);
输出:空格 空格 2.37
③ 最小宽度 和 小数位数 是可以通过 * 来传参
printf("%*.*f", 6, 2, 32.5);
输出:空格 32.50
6、输出部分字符串
printf("%.5s\n", "hello world");
输出 hello
(二)详讲scanf
1、基本用法
用于读取用户的键盘输入
int a;
scanf("%d",&a);
& 为取地址符
用户输入数据、按下回车键后,scanf()会处理用户的输入,将其存入变量
可以传多个值:
scanf("%d %d %f %f", &i, &j, &x, &y);
输入多个值,为了直观和消除每个值之间的空白字符,每个占位符之间可以用空格隔开;
不用空格隔开也可以,因为scanf()运行时,会自动过滤空白字符,包括空格、制表符、换行符等,因此一个或多个空格不影响scanf()解读数据,另外,使用回车键,将输入分成几行,也不影响解读
用户输入要严格匹配格式串,如:
scanf("%d,%d", &i, &j);
用户输入:整数,整数
2、返回值
若读取成功,则返回读取的个数
读取失败(读取错误或读取到文件结尾),则返回 EOF(end of file 文件结束标志)
注:ctrl + z 能提前结束输入
3、scanf()的占位符
如下,与printf()的占位符基本一致
%c 字符
%d 整数
%f float 类型小数
%lf double 类型小数
%Lf long double 类型小数
%s 字符串
%[ ] 在括号中指定匹配的字符(如:%[0-9]),遇到不在集合之中的字符,匹配会停止
4、赋值忽略符
有时,用户的输入可能不符合预定的格式
#include <stdio.h>
int main()
{
int year = 0;
int month = 0;
int day = 0;
scanf("%d-%d-%d", &year, &month, &day);
printf("%d %d %d\n", year, month, day);
return 0;
}
用户不严格按照 【整数 - 整数 - 整数】 的格式输入,可能是 【整数 / 整数 / 整数】
为了避免这种情况,scanf()提供了一个【赋值忽略符 " * " 】,只要加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃
scanf("%d%*c%d%*c%d", &year, &month, &day)
用户不论是按照【整数 整数 整数】,【整数 - 整数 - 整数】还是【整数 / 整数 / 整数】 的格式输入,都会忽略掉整数之间的字符,因为解读后被丢弃了
八、我觉得有意思的点
(一)sizeof 的打印
sizeof 运算符的返回值,C语言只规定是无符号整型,所以可能是 unsigned int 或 unsigned long 或 unsigned long long ,对应的printf占位符是"%u","%lu","%llu",这不利于代码的可移植性,C语言提供了一个解决方法,创造出一个 size_t 类型来统一表示无符号整型的返回值,用"%zd"进行打印。
(二)scanf()的储存原理
用户的输入先放入缓存,等到按下回车键后,按照占位符对缓存进行解读
解读用户输入时,会从上一次解读遗留的第一个字符开始,直到读完缓存,或者遇到第一个不符合条件的字符为止
例:
#include <stdio.h>
int main()
{
int x;
float y;
// ⽤⼾输⼊ " -13.45e12# 0"
scanf("%d", &x);
scanf("%f", &y);
return 0;
}
过程:
"%d" 占位符会忽略起首的空格,从" - " 处开始获取数据,读取到"-13" 停下来,因为后面的" . "不属于整数的有效字符,这就是说占位符"%d"会读到"-13";
第二次调用 scanf() 时,就会从上一次停止解读的地方,继续往下读取,这一次读取的首字符是"."由于对应的占位符是%f,会读取到.45e12,这是采用科学计数法的浮点数格式,后面的# 不属于浮点数的有效字符,所以会停在这里。
(e12 是 10的12次方,【.45e12】为 【0.45 × 10的12次方】)
(三)scanf()占位符注意事项
① 除了%c 以外,都会自动忽略起首的空白字符。%c 不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格。 如果要强制跳过字符前的空白字符,可以写成scanf(" %c", &ch),即%c 前加上一个空格,表示跳过零个或多个空白字符。
② 在C语言的 【scanf 函数】中,【格式控制字符串】中的空格用来【指定跳过输入流中的空白字符(包括空格、制表符和换行符)】;
当你在 " %d " 后加上空格时,会【跳过一个或多个空白字符,然后继续等待输入一个整数】。这意味着,在输入整数前的任何空白字符都会被忽略。所以," %d " 后面的空格可以用来消耗换行符或空格,以便在输入数字后读取到下一个非空白字符。
注:
【格式控制字符串】"%d" 只想输入一个数时在后面加空格,它会在你输入整数后,【跳过若干空白字符,继续让你输入一个整数】,但由于只有一个整数会被读取,后面输入的整数没有用,如下演示:
int a = 0;
scanf("%d ", &a);
这里%d后面有空格,会让你输入两次,第二次输入作废,不要这样写
③ 占位符%s,它其实不能简单地等同于字符串。它的规则是,从当前第一个非空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。因为%s不会包含空白字符,所以无法用来读取多个单词,除非多个%s一起使用。这也意味着, scanf () 不适合读取可能包含空格的字符串,比如书名或歌曲名。另外, scanf() 遇到%s 占位符,会在字符串变量末尾存储一个空字符\0。输入多个字符串可以空格分隔,如下:
char str1[10], str2[20], str3[30];
scanf("%s %s %s", str1, str2, str3);
每个"%s"之间都有空格,消除空白字符
④ scanf()将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时,很可能会超过数组的边界,导致预想不到的结果。为了防止这种情况,使用%s 占位符时,应该指定读入字符串的最长长度,即写成%[m]s ,其中的[m] 是一个整数,表示读取字符串的最大长度,后面的字符将被丢弃,注意多留一位数组元素给系统自动补上的 "\0" 。
(区别:printf()限定字符串长度:% [ . 整数 ] s)
char name[11];
scanf("%10s", name)
以上博客内容仅供分享