多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

邂逅C语言——重要知识点第二章(个人整理版)

邂逅C语言——重要知识点第二章(个人整理版) 二.C语言数据类型和变量1.数据类型介绍• C 语言原来并没有为布尔值单独设置一个类型而是使用整数 0表示假非零值表示真。在C99中也引入了布尔类型 是专门表示真假的。• 布尔类型的使用得包含头文件 stdbool.h• 布尔类型变量的取值是true或者false#include stdbool.h #include stdio.h int main() { bool flag true; if (flag) printf(i like C\n); return 0; }• sizeof操作符①sizeof 是⼀个关键字也是操作符专门是用来计算 sizeof 的操作符数的类型长度的单位是字节。 sizeof 操作符的操作数可以是类型也可是变量或者表达式。②sizeof 的操作数如果不是类型是表达式或变量的时候可以省略掉后边的括号的。int a 10; sizeof a;//合法计算变量a的大小 sizeof(int);//合法计算int类型的大小 sizeof int;//错误类型必须加括号③sizeof 后边的表达式是不真实参与运算的根据表达式的类型来得出大小。int a 10; sizeof(a); // 计算int类型大小4字节a不会执行 printf(%d, a); // 输出10a的值未变④sizeof 的返回值类型是size_t。注sizeof运算符的返回值C 语言只规定是无符号整数并没有规定具体的类型而是留给系统自己去决定 sizeof到底返回什么类型。不同的系统中返回值的类型有可能是 unsigned int 也有可能是unsigned long甚至是unsigned long long对应的 printf()占位符分别是%u、%lu和%llu。这样不利于程序的可移植性。C 语言提供了⼀个解决方法创造了⼀个类型别名 size_t用来统一表示sizeof的返回值类型。对应当前系统的 sizeof的返回值类型可能是unsigned int也可能是unsigned long long。#include stdio.h int main() { int a 10; printf(%zd\n, sizeof(a)); printf(%zd\n, sizeof a);//a是变量的名字可以省略掉sizeof后边的() printf(%zd\n, sizeof(int)); printf(%zd\n, sizeof(3 3.5)); return 0; }在C语言中%zd是用于格式化输出ssize_t 类型的格式符%zu格式化输出size_t 类型的格式符ssize_t 是有符号整数可负 size_t 是无符号整数非负2.signed 和 unsigned• C 语言使用 signed和unsigned关键字修饰字符型和整型类型的。signed 关键字表示一个类型带有正负号包含负值unsigned 关键字表示该类型不带有正负号只能表示零和正整数。对于 int类型默认是带有正负号的也就是说int等同于signed int。由于这是默认情况关键字 signed 一般都省略不写但是写了也不算错。int 类型也可以不带正负号只表示非负整数。这时就必须使用关键字unsigned声明变量。• 整数变量声明为 unsigned的好处是同样长度的内存能够表示的最大整数值增大了⼀倍。比如16位的 signed short int的取值范围是-32768~32767最大是32767而unsigned short int 的取值范围是0~65535最大值增大到了65,535。32位的signed int 的取值范围可以参看limits.h 定义了基本数据类型的取值范围中给出的定义。•字符类型 char 也可以设置 signed 和 unsigned 。signed char c; // 范围为 -128 到 127 unsigned char c; // 范围为 0 到 255• 注意C 语言规定 char 类型默认是否带有正负号由当前系统决定。这就是说char 不等同于signed char它有可能是signed char也有可能是 unsigned char。这一点与 int不同int就是等同于signed int。3.变量• 变量的分类•全局变量在大括号外部定义的变量就是全局变量全局变量的使用范围更广整个工程中想使用都是有办法使用的。•局部变量在大括号内部定义的变量就是局部变量局部变量的使用范围是比较局限只能在自己所在的局部范围内使用的。#include stdio.h int global 2023;//全局变量 int main() { int local 2018;//局部变量 printf(%d\n, local); printf(%d\n, global); return 0; }• 如果全局变量和局部变量名字相同呢#include stdio.h int n 1000; int main() { int n 10; printf(%d\n n);//打印的结果是多少呢 return 0; }其实当局部变量和全局变量同名的时候局部变量优先使用。• 全局变量和局部变量在内存中存储在哪里呢一般我们在学习C/C语言的时候我们会关注内存中的三个区域栈区、堆区、静态区。①.局部变量是放在内存的栈区②.全局变量是放在内存的静态区③.堆区是用来动态内存管理的4.算术操作符• C语言中为了方便运算提供了⼀系列操作符其中有⼀组操作符叫算术操作符。分别是 - * / % 这些操作符都是双目操作符。注操作符也被叫做运算符是不同的翻译意思是⼀样的。• 重点介绍一下 / 和 %①.运算符 / 用来完成除法除号的两端如果是整数执行的是整数除法得到的结果也是整数。#include stdio.h int main() { float x 6 / 4; int y 6 / 4; printf(%f\n, x); // 输出 1.000000 printf(%d\n, y); // 输出 1 return 0; }上面示例中尽管变量x的类型是float浮点数但是6 / 4得到的结果是1.0而不是1.5 原因就在于 C 语言里面的整数除法是整除只会返回整数部分丢弃小数部分。• 要想得到浮点数的结果两个运算数必须至少有⼀个浮点数这时 C 语言就会进行浮点数除法。#include stdio.h int main() { float x 6.0 / 4; // 或者写成 6 / 4.0 printf(%f\n, x); // 输出 1.500000 return 0; }上面示例中6.0 / 4表示进行浮点数除法得到的结果就是1.5。• 再看一个例子#include stdio.h int main() { int score 5; score (score / 20) * 100; return 0; }上面代码你可能觉得经过运算score会等于25但是实际上score等于0。这是因为 score / 20 是整除会得到⼀个整数值0所以乘以100后得到的也是0 。为了得到预想的结果可以将除数 20改成20.0让整除变成浮点数除法。#include stdio.h int main() { int score 5; score (score / 20.0) * 100; return 0; }②.运算符 %表示求模(余)运算即返回两个整数相除的余值。这个运算符只能用于整数不能用于浮点数。#include stdio.h int main() { int x 6 % 4; // 2 return 0; }• 负数求模的规则是结果的正负号由第⼀个运算数的正负号决定#include stdio.h int main() { printf(%d\n, 11 % -5); // 1 printf(%d\n,-11 % -5); // -1 printf(%d\n,-11 % 5); // -1 return 0; }上面示例中第⼀个运算数的正负号11或-11决定了结果的正负号。5.赋值操作符• 在变量创建的时候给⼀个初始值叫初始化在变量创建好后再给⼀个值这叫赋值。• 赋值操作符 是⼀个随时可以给变量赋值的操作符。• 赋值操作符也可以连续赋值如int a 3; int b 5; int c 0; c b a3;//连续赋值从右向左依次赋值的。• C语言虽然支持这种连续赋值但是写出的代码不容易理解建议还是拆开来写这样方便观察代码的执行细节。• 重点区分前置自增后置自增前置自减后置自减int a 10; int b a;//的操作数是a是放在a的前⾯的就是前置 printf(a%d b%d\n,a , b); int a 10; int b a;//的操作数是a是放在a的后⾯的就是后置 printf(a%d b%d\n,a , b); int a 10; int b --a;//--的操作数是a是放在a的前⾯的就是前置-- printf(a%d b%d\n,a , b);//输出的结果是9 9 int a 10; int b a--;//--的操作数是a是放在a的后⾯的就是后置-- printf(a%d b%d\n,a , b);//输出的结果是9 10• 强制类型转换inta (int)3.14;//意思是将3.14强制类型转换为int类型这种强制类型转换只取整数部分6.printf 介绍• printf() 的作用是将参数文本输出到屏幕。它名字里面的f代表format格式化表示可以定制输出文本的格式。• printf() 不会在行尾自动添加换行符运行结束后光标就停留在输出结束的地方不会自动换行。为了让光标移到下一行的开头可以在输出文本的结尾添加⼀个换行符 \n。• 占位符列举printf()的占位符有许多种类与 C 语言的数据类型相对应。下面按照字母顺序列出常用的占位符方便查找具体含义在后面章节介绍。•%a 十六进制浮点数字母输出为小写。•%A 十六进制浮点数字母输出为大写。• %c 字符。• %d 十进制整数。// int•%e 使用科学计数法的浮点数指数部分的e为小写。•%E 使用科学计数法的浮点数指数部分的E为大写。•%i 整数基本等同于%d。• %f 小数包含 float 类型和 double 类型。//float %f double - %lf•%g 6个有效数字的浮点数。整数部分一旦超过6位就会自动转为科学计数法指数部分的e为小写。•%G 等同于%g唯⼀的区别是指数部分的E为大写。• %hd 十进制 short int 类型。•%ho 八进制 short int 类型。•%hx 十六进制 short int 类型。• %hu unsigned short int 类型。• %ld 十进制 long int 类型。•%lo 八进制 long int 类型。•%lx 十六进制 long int 类型。• %lu unsigned long int 类型。•%lld 十进制 long long int 类型。•%llo 八进制 long long int 类型。•%llx 十六进制 long long int 类型。•%llu unsigned long long int 类型。•%Le 科学计数法表示的 long double 类型浮点数。• %Lf long double 类型浮点数。•%n 已输出的字符串数量。该占位符本身不输出只将值存储在指定变量之中。•%o 八进制整数。• %p 指针用来打印地址。• %s 字符串。• %u 无符号整数unsigned int。• %x 十六进制整数。• %zd size_t 类型。•%% 输出⼀个百分号。注%*d为赋值忽略符只用于scanf函数读取输入但不保存变量直接丢弃。• 限定宽度printf() 允许限定占位符的最小宽度。#include stdio.h int main() { printf(%5d\n, 123); // 输出为 123 return 0; }上面示例中%5d表示这个占位符的宽度至少为5位。如果不满5位对应的值的前面会添加格。输出的值默认是右对齐即输出内容前面会有空格如果希望改成左对齐在输出内容后面添加空格可以在占位符的 %的后面插入一个 -号。#include stdio.h int main() { printf(%-5d\n, 123); // 输出为 123 return 0; }上面示例中输出内容123的后面添加了空格。• 对于小数这个限定符会限制所有数字的最小显示宽度。#include stdio.h int main() { printf(%12f\n, 123.45);// 输出 123.450000 return 0; }上面示例中%12f表示输出的浮点数最少要占据12位。由于小数的默认显示精度是小数点后6位所以 123.45输出结果的头部会添加2个空格。• 限定小数位数输出小数时有时希望限定小数的位数。举例来说希望小数点后面只保留两位占位符可以写成 %.2f。// 输出 Number is 0.50 #include stdio.h int main() { printf(Number is %.2f\n, 0.5); return 0; }上面示例中如果希望小数点后面输出3位0.500占位符就要写成%.3f。• 这种写法可以与限定宽度占位符结合使用。// 输出为 0.50 #include stdio.h int main() { printf(%6.2f\n, 0.5); return 0; }上面示例中%6.2f 表示输出字符串最小宽度为6小数位数为2。所以输出字符串的头部有两个空格。• 最小宽度和小数位数这两个限定值都可以用 *代替通过printf()的参数传入。#include stdio.h int main() { printf(%*.*f\n, 6, 2, 0.5); return 0; } // 等同于printf(%6.2f\n, 0.5);上面示例中% * . * f的两个星号通过printf()的两个参数6和2传入。• 输出部分字符串%s 占位符用来输出字符串默认是全部输出。如果只想输出开头的部分可以用 %.[m]s指定输出的长度其中 [m]代表⼀个数字表示所要输出的长度。// 输出 hello #include stdio.h int main() { printf(%.5s\n, hello world); return 0; }上面示例中占位符%.5s表示只输出字符串“hello world”的前5个字符即“hello”。7.scanf介绍• 基本用法scanf()函数用于读取用户的键盘输入。程序运行到这个语句时会停下来等待用户从键盘输入。用户输入数据、按下回车键后scanf()就会处理用户的输入将其存入变量。它的原型定义在头文件stdio.h。scanf()的语法跟printf()类似。• scanf() 处理数值占位符时会自动过滤空白字符包括空格、制表符、换行符等。所以用户输入的数据之间有一个或多个空格不影响 scanf()解读数据。另外用户使用回车键将输入分成几行也不影响解读。1 -20 3.4 -4.0e3上面示例中用户分成四行输入得到的结果与一行输入是完全一样的。每次按下回车键以后scanf() 就会开始解读如果第一行匹配第一个占位符那么下次按下回车键时就会从第二个占位符开始解读。scanf() 处理用户输入的原理是用户的输入先放入缓存等到按下回车键后按照占位符对缓存进行解读。• 解读用户输入时会从上一次解读遗留的第一个字符开始直到读完缓存或者遇到第一个不符合条件的字符为止。#include stdio.h int main() { int x; float y; // ⽤⼾输⼊ -13.45e12# 0 scanf(%d, x); printf(%d\n, x); scanf(%f, y); printf(%f\n, y); return 0; }上面示例中scanf()读取用户输入时%d占位符会忽略起首的空格从-处开始获取数据读取到 -13停下来因为后面的.不属于整数的有效字符。这就是说占位符%d会读到-13 。第二次调用 scanf()时就会从上一次停止解读的地方继续往下读取。这一次读取的首字符是 .由于对应的占位符是%f会读取到.45e12这是采用科学计数法的浮点数格式。后面的# 不属于浮点数的有效字符所以会停在这里。• 由于 scanf()可以连续处理多个占位符所以上卖你的例子也可以写成下面这样。#include stdio.h int main() { int x; float y; // ⽤⼾输⼊ -13.45e12# 0 scanf(%d%f, x, y); return 0; }• scanf的返回值scanf()的返回值是⼀个整数表示成功读取的变量个数。如果没有读取任何项或者匹配失败则返回0。如果在成功读取任何数据之前发⽣了读取错误或者遇到读取到⽂件结尾则返回常量 EOF(-1)。EOF - end of file 文件结束标志。#include stdio.h int main() { int a 0; int b 0; float f 0.0f; int r scanf(%d %d %f, a, b, f); printf(a%d b%d f%f\n, a, b, f); printf(r %d\n, r); return 0; }输入输出测试• 如果输入2个数后按 ctrlz 输入结束符提前结束输入在VS环境中按3次ctrlz才结束了输入我们可以看到r是2表示正确读取了2个数值。• 如果一个数字都不输入直接按3次 ctrlz,输出的r是-1也就是EOF• scanf() 常用的占位符如下与printf()的占位符基本一致。• %c 字符。• %d 整数。• %f float 类型浮点数。• %lf double 类型浮点数。• %Lf long double 类型浮点数。• %s 字符串。• %[ ] 在方括号中指定一组匹配的字符比如 %[0-9] 遇到不在集合之中的字符匹配将会停止。上面所有占位符之中除了%c以外都会自动忽略起首的空白字符。%c不忽略空白字符总是返回当前第一个字符无论该字符是否为空格。如果要强制跳过字符前的空白字符可以写成scanf( %c, ch)即%c前加上一个空格表示跳过零个或多个空白字符。下面要特别说一下占位符%s它其实不能简单地等同于字符串。它的规则是从当前第一个非空白字符开始读起直到遇到空白字符即空格、换行符、制表符等为止。因为 %s不会包含空白字符所以无法用来读取多个单词除非多个%s⼀起使用。这也意味着scanf() 不适合读取可能包含空格的字串比如书名或歌曲名。另外scanf()遇到%s占位符会在字符串变量末尾存储一个空字符\0 。scanf() 将字符串读入字符数组时不会检测字符串是否超过了数组长度。所以储存字符串时很可能会超过数组的边界导致预想不到的结果。为了防止这种情况使用 %s占位符时应该指定读入字符串的最长长度即写成 %[m]s其中的[m]是⼀个整数表示读取字符串的最大长度后面的字符将被丢弃。#include stdio.h int main() { char name[11]; scanf(%10s, name); return 0; }上面示例中name是一个长度为11的字符数组scanf()的占位符%10s表示最多读取用户输入的10个字符后面的字符将被丢弃这样就不会有数组溢出的风险了。• 赋值忽略符有时用户的输入可能不符合预定的格式#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; }上面示例中如果用户输入2020-01-01就会正确解读出年、月、日。问题是用户可能输入其他格式比如 2020/01/01这种情况下scanf()解析数据就会失败。• 为了避免这种情况 scanf()提供了一个赋值忽略符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); return 0; }上面示例中%*c就是在占位符的百分号后面加入了赋值忽略符*表示这个占位符没有对应的变量解读后不必返回。
返回列表