[C语言]快速上手
温馨提示:这篇文章已超过397天没有更新,请注意相关的内容是否还可用!
初识C语言
- 什么是C语言
- 什么是计算机语言
- 什么是底层开发
- 计算机语言的发展
- C语言概述和标准
- 第一个C语言程序
- 打印程序
- 主函数的其他写法
- 数据类型
- C语言提供的数据类型
- 每一个类型的大小
- 类型的使用
- 变量
- 创建变量的方法
- 变量的命名
- 变量的分类
- 变量的使用
- 占位符
- 变量的作用域和生命周期
- 跨文件全局变量使用
- 常量
- 字面常量
- const修饰的常变量
- #define定义的标识符常量
- 枚举常量
- 字符串/转义字符/注释
- 字符串
- 转义字符表
- ASCII码表
- 注释
- 分支和循环
- if...else语句
- while语句
- 多组输入
- 函数
- 函数作用
- 函数样例
- 输入带空格的字符串
- 数组
- 什么是数组
- 数组的创建和访问
- 操作符
- 算数操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用, 函数调用和结构体成员访问操作符
- 表达式求值
- 表达式求值的要素
- 隐式类型转换 (整型提升)
- 整型提升是怎么进行的
- 算数转换
- 表达式求值顺序的影响因素
- 操作符的优先级和结合性表 (由高到低)
- 关键字
- typedef
- static
- register
- const
- 宏和指针
- #define定义的宏
- 内存
- 指针变量的创建和使用
- 指针变量的大小
- 结构体
- 结构体的创建和使用
- 结构体的成员访问
什么是C语言
什么是计算机语言
1. 人和人交流的语言是: 汉语/英语...... 2. 人和计算机交流的语言是: C语言/C++语言...... 3. 计算机语言就是人和计算机交流的语言
什么是底层开发
计算机语言的发展
C语言概述和标准
C语言是一门通用计算机编程语言, 广泛应用于底层开发. C语言的设计目标是提供一种能以简易的方式编译/处理低级存储器/产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言.
二十世纪八十年代, 为了避免各开发厂商用的C语言语法产生差异, 由美国国家标准局为C语言制定了一套完整的美国国家标准语法, 称为ANSIC, 作为C语言最初的标准. 目前2011年12月8日, 国际标准化组织 (ISO) 和国际电工委员会 (IEC) 发布的C11标准是C语言的第三个官方标准, 也是C语言的最新标准, 该标准更好的支持了汉字函数名和汉字标识符, 一定程度上实现了汉字编程.
第一个C语言程序
打印程序
#include //包含输入输出标准头文件 int main() { printf("Hello Bit");//printf是一个库函数,功能就是在屏幕上打印数据 //这里会在屏幕上打印Hello Bit return 0; } //C语言中main函数是程序的入口,一个工程中有且只有一个main函数 //库函数 -- C语言编译器中提供的现成的函数 //.c - 源文件 .h - 头文件主函数的其他写法
//第一种 void main() { //非常古老的写法 -- 不推荐 } //第二种 int main(void) { //void表示main函数不接受任何参数 return 0; } //第三种 int main(int argc, char* argv[]) { //以后了解 return 0; }数据类型
C语言提供的数据类型
char//字符数据类型 short//短整型 int//整型 long//长整型 long long//更长的整型 float//单精度浮点数 double//双精度浮点数 _Bool//布尔类型 -- C99 long double//更长的双精度浮点型 -- C99 //char是字符类型, 字符的本质是字符的ASCII码值, ASCII码值是整型, //所以字符类型在归类的时候, 是可以划分到整型家族的
每一个类型的大小
#include int main() { printf("%d\n",sizeof(char));//1 printf("%d\n",sizeof(short));//2 printf("%d\n",sizeof(int));//4 printf("%d\n",sizeof(long));//4 printf("%d\n",sizeof(long long));//8 printf("%d\n",sizeof(float));//4 printf("%d\n",sizeof(double));//8 printf("%d\n",sizeof(_Bool));//1 printf("%d\n",sizeof(long double));//8 return 0; } //sizeof的作用是求大小, 单位是字节 //计算机中的单位: bit -- byte -- kb -- mb -- gb -- tb -- pb //C语言标准规定: sizeof(long) >= sizeof(int) // sizeof(long double) >= sizeof(double) //%d -- 是一个占位符, 作用是以十进制的形式打印 //\n -- 是一个转义字符, 作用是换行类型的使用
int main() { char ch = 'w'; int weight = 120; //类型的作用就是用来创建变量 //变量创建的本质是向内存中申请一块空间 weight = 20;//其实是把20放在weight这块空间里, 这里使用的是weight的空间 int a = weight;//其实是使用了weight中存放的值, 把weight中的20存放到a中 // 左值 右值 //其实就是左值代表空间, 右值代表空间的内容 return 0; } //机器去看内存的时候都是通过地址去访问的,变量名只是给程序员看的(方便程序员操作)变量
创建变量的方法
int main() { //第一种 //类型 变量名; int a; //第二种 //类型 变量名 = 初始值; float b = 20.12f; return 0; } //小数直接写出来, 编译器默认其是double类型的值 //小数后加f, 这时就是float类型的值变量的命名
变量的命名要遵守以下规则: 1. 只能由字母 (包括大写和小写) / 数字和下划线 (_) 组成 2. 不能以数字开头 3. 长度不能超过63个字符 4. 变量名中区分大小写的 5. 变量名不能使用关键字
变量的分类
#include int a = 10;//全局变量 int main() { int a = 20;//局部变量 printf("%d\n", a); return 0; } //全局变量和局部变量使用时, 局部优先 //原则上变量名不要冲突 //静态变量和全局变量如果不初始化默认是0变量的使用
#include //求两个整数的和 int main() { int num1 = 0; int num2 = 0; //输入两个整数的值 scanf("%d%d",&num1,&num2);//scanf的作用是输入数据 sum1 = num1 + num2; printf("%d\n", sum1); return 0; }以上代码有的编译器(VS2022)可能会报错, 解决方法:
1. 在源文件的第一行添加: #define _CRT_SECURE_NO_WARNINGS 1
2. 替换scanf函数为: scanf_s
VS的一劳永逸解决方法:
1. 找到VS安装路径下的newc++file.cpp的文件
2. 在这个文件中添加: #define _CRT_SECURE_NO_WARNINGS 1
占位符
%c//字符 %d//整型(有符号) - %02d打印两位整数,不够在前面补0 %-2d打印两位整数,不够在后面补空格 %u//整型(无符号) %ld//长整型 %lld//更长的整型 %s//字符串 %f//单精度浮点数 - %.2f保留两位小数打印 %lf//双精度浮点数 - %.2lf保留两位小数打印 %p//地址 %zd//size_t的值
变量的作用域和生命周期
作用域:
1. 概念: 作用域 (scope) 是程序设计概念, 通常来说, 一段程序代码中所用到的名字并不总是有效/可用的而限定这个名字的可用性的代码范围就是这个名字的作用域.
2. 局部变量的作用域是变量所在的局部范围.
3. 全局变量的作用域是整个工程.
生命周期:
1. 概念: 变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段.
2. 局部变量的生命周期是:进入作用域生命周期开始, 出作用域生命周期结束.
3. 全局变量的生命周期是:整个程序的生命周期.
跨文件全局变量使用
extern int g_val;//声明外部符号 int main() { printf("%d\n",g_val); return 0; } //在同项目内全局变量跨文件使用需要声明外部符号 //全局变量具有外部链接属性, 所以在其他源文件内部依然可以使用 //在代码中尽量少的使用全局变量,因为全局变量在任何地方都可以使用,就变得不可控了常量
字面常量
3;//整型字面常量 3.14;//浮点数字面常量 'a';//字符字面常量 "xwwxw";//字符串字面常量
const修饰的常变量
int main() { const int a = 10; a = 20;//const修饰的a具有了常属性不可以直接修改 int arr[a];//这样创建数组可能会报错, 因为数组创建要求[ ]中是一个常量 return 0; } //const修饰的变量, 本质上还是变量#define定义的标识符常量
#define SIZE 10 int main() { int a = SIZE; int arr[SIZE] = {0}; return 0; }枚举常量
#include enum SEX { //列出了枚举常量enum SEX的可能取值 MALE, FEMALE, SECRET=6 }; int main() { enum SEX s = SECRET; printf("%d\n",MALE); return 0; }字符串/转义字符/注释
字符串
#include #include int main() { "x2xcrcr";//字符串以双引号引起 'a';//字符以单引号引起 char a = 'a';//存储字符 char ch1[] = {'1','2','3','a','s'}; char ch2[] = "verbwetw"; printf("%s\n",ch1); printf("%s\n",ch2); printf("%d\n",strlen(ch1)); printf("%d\n",strlen(ch2)); return 0; } //以双引号引起就有字符串的结束标志\0 //求字符串长度时\0不统计在内 //%%会被printf函数解析成%转义字符表
ASCII码表
注释
//C++的注释风格 /* C语言的注释风格 */
分支和循环
if…else语句
#include int main() { int a = 0; printf("认真学习吗?(0/1)"); scanf("%d",&a); if(a) { printf("好offer\n"); } else if(a==0) { printf("烤地瓜\n"); } else { printf("输入不合法\n"); } return 0; } //如果好好学习 a=1 好offer //如果不好好学习 a=0 烤地瓜 //如果输入其他数值 a=%d 输入不合法while语句
#include int main() { int a = 0; scanf("%d",&a); while(a) { printf("%d\n",a); } return 0; } //while后条件为真, 重复执行while语句代码块直到条件为假 //while后条件为假, 不执行while语句代码块多组输入
#include //写一个代码实现多组判断, iq大于等于140输出Genius int main() { int iq = 0; while(scanf("%d",&iq)!=EOF)//实现多组输入 { if(iq >= 140)//如果iq大于等于140输出Genius { printf("Genius\n"); } } return 0; } //scanf函数返回的是读取到的数据的个数 //如果scanf函数读取失败则会返回EOF //#define EOF (-1) //EOF - end of file 文件结束标志 //在一些函数读取失败的时候返回EOF //VS编译器上面按 ctrl+z 会读取失败函数
函数作用
函数是一段可重用的代码, 用于执行特定任务. 函数可以使代码更易于维护和阅读, 因为它们可以使代码更短, 更易于理解, 函数还可以使代码更易于重用, 因为它们可以在多个地方使用.
函数样例
#include int ADD(int x,int y)//函数 - 封装代码逻辑(简化代码, 完成代码复用) {//这里参数是形式参数 return x+y; } int main() { int a = 0; int b = 0; scanf("%d%d",&a,&b); //相当于写成int c = a + b; int c = ADD(a,b);//这里参数是实际参数 printf("%d\n",c); return 0; }输入带空格的字符串
#include int main() { char arr[100] = {'0'}; scanf("%[^\n]s",arr);//读取字符串直到读到'\n' printf("%s\n",arr); gets(arr);//读取一个带空格的字符串,存入arr printf("%s\n",arr); fgets(arr, 100, stdin);//读取一个字符串,存入arr,最大长度为100,从stdin(标准输入输出:键盘)读取 printf("%s\n",arr);//字符串打印还可以写成printf(arr); - 这里传递的是指针 return 0; } //内置函数scanf,gets,fgets扩展数组
什么是数组
1. 定义: 一组相同类型元素的集合 2. 下标: 数组的每个元素都有一个下标, 下标是从零开始的 3. 访问: 数组是可以通过下标来访问的数组的创建和访问
#include int main() { int arr[10] = {0,1,2,3,4,5,6,7,8,9};//数组的创建和初始化 //数组如果初始化可以不指定大小, 会根据初始化内容确定数组大小 //C99标准支持变长数组 int n = 10; int arr[n];//变长数组的创建不支持初始化 int i = 0; while(i操作符
算数操作符
+ - * / % 1. 除了 % 操作符之外, 其他的几个操作符可以作用于整数和浮点数. 2. 对于 / 操作符如果两个操作数都为整数, 执行整数除法. 而只要有浮点数执行的就是浮点数除法. 3. 对于 % 操作符的两个操作数必须为整数, 返回的是整除之后的余数. 4. 除数不能为零, 除数为零编译器会报错.移位操作符
#include int main() { int a = 15; //00000000000000000000000000001111 - 原反补 //根据数值直接写出的二进制序列叫做原码 //正整数的原反补码相同 //int - 4byte - 32bit int b = -15; //10000000000000000000000000001111 - 原 //11111111111111111111111111110000 - 反(符号位不变其它位按位取反) //11111111111111111111111111110001 - 补(反码加一) //>> - 右移 a = 15;//正 //00000000000000000000000000001111 - 原反补 b = a >> 1; printf("%d\n",a);//15 - a是不会发生变化的 printf("%d\n",b);//7 //算数右移(右边丢弃,左边补原符号位) //逻辑右移(右边丢弃,左边直接补0) //00000000000000000000000000000111 - 补反原 - 7 //一般编译器上采用的是算数右移(C语言没有明确规定) //正数的右移可以理解为有除二的效果 a = -15;//负 //10000000000000000000000000001111 - 原 //11111111111111111111111111110000 - 反 //11111111111111111111111111110001 - 补 b = a >> 1; printf("%d\n",a);//-15 printf("%d\n",b);//-8 //VS编译器使用的是算数右移 //11111111111111111111111111111000 - 补 //11111111111111111111111111110111 - 反 //10000000000000000000000000001000 - 原 - -8 // -2 标准未定义行为(有些编译器会报错) - 建议以后不要写这样子的(不要移动负数位)位操作符
#include int main() { //& - 按位与 int a = 3; //00000000000000000000000000000011 - 原反补 int b = -5; //10000000000000000000000000000101 - 原 //11111111111111111111111111111010 - 反 //11111111111111111111111111111011 - 补 int c = a & b; printf("%d\n",c);//3 //按位与 - 有0为0,无0为1 //00000000000000000000000000000011 - 补反原 - 3 //| - 按位或 a = 3; //00000000000000000000000000000011 - 原反补 b = -5; //10000000000000000000000000000101 - 原 //11111111111111111111111111111010 - 反 //11111111111111111111111111111011 - 补 c = a | b; printf("%d\n",c);//-5 //按位或 - 有1为1,无1为0 //11111111111111111111111111111011 - 补 //11111111111111111111111111111010 - 反 //10000000000000000000000000000101 - 原 - -5 //^ - 按位异或 a = 3; //00000000000000000000000000000011 - 原反补 b = -5; //10000000000000000000000000000101 - 原 //11111111111111111111111111111010 - 反 //11111111111111111111111111111011 - 补 c = a ^ b; printf("%d\n",c);//-8 //按位异或 - 相同为0,相异为1 //11111111111111111111111111111000 - 补 //11111111111111111111111111110111 - 反 //10000000000000000000000000001000 - 原 - -8 return 0; } //位操作符操作的是补码的二进制位 //两个相同的数异或,得到的结果是零,任何数字异或零都得到它自己,异或操作是支持交换律的赋值操作符
#include int main() { //= int a = 12; int b = 34; b = a; a = b = 23;//连续赋值 //+= -= *= /= %= &= |= ^= >>= //! - 逻辑反 int falg = 0; printf("%d\n", (!falg));//1 //- + - 负号和正号 //& * - 取地址和解引用 //sizeof - 计算大小(单位是字节) printf("%d\n",sizeof falg);//4 计算变量大小时可以省略括号 - 它是操作符不是函数 int arr[10]; printf("%d\n",sizeof(int [10]));//40 计算arr数组类型的大小 //~ - 按位取反 - 对补码的二进制位操作 int z = 0; //00000000000000000000000000000000 - 原反补 printf("%d\n",~z);//-1 //11111111111111111111111111111111 - 补 //11111111111111111111111111111110 - 反 //10000000000000000000000000000001 - 原 - -1 //后置++ int a = 0; int b = 0; b = a++;//先使用再加加 printf("%d %d\n",a,b); //前置++ a = 0;b =0; b = a++;//先加加再使用 printf("%d %d\n",a,b); //(类型) double a1 = 3.134; int b1 = 0; b1 = (int)a1;//强制类型转换 return 0; } //单目操作符只有一个操作数 //sizeof 不是函数,是一个操作符(计算大小,单位是字节)hr / h3关系操作符/h3 pre class="brush:python;toolbar:false"== != = 1. 下标引用操作符是用于访问数组内的元素的: 数组名[下标] 2. 函数调用操作符是用于进行函数的使用的: 函数名(参数) 3. 函数的参数是可变的. 像 printf, scanf ... 具有可变参数列表的库函数, 它们的参数个数是不确定的 4. 结构体成员访问操作符是用于结构体访问的: 结构体变量.成员名 结构体指针->成员名表达式求值
表达式求值的要素
1. 表达式求值的顺序一般是由操作符的优先级和结合性决定. 2. 有些表达式的操作数在求值的过程中可能需要转换为其他类型.隐式类型转换 (整型提升)
1. C语言的整型算术运算总是至少以缺省整型类型的精度来进行的. 为了获得这个精度, 表达式中的字符和短整型操作数在使用之前被转换为普通整型, 这种转换称为整型提升. 2. 表达式的整型运算要在CPU的相应运算器件内执行, CPU内整型运算器的操作数的字节长度一般就是 int 的字节长度, 同时也是CPU的通用寄存器的长度. 所以, 即使是两个 char 类型的相加, 在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度. 3. 通用CPu是难以直接实现两个八比特字节直接相加运算的 (虽然机器指令中可能有这种字节相加指令) . 因此, 表达式中各种长度可能小于 int 长度的整型值, 都必须先转换为 int 或 unsigned int, 然后才能送入CPU去执行运算.整型提升是怎么进行的
#include int main() { char c1 = 5; //00000000000000000000000000000101 - 原反补(整型的实际长度) //00000101 - c1里面真实存放的长度(二进制的补码发生了截断) char c2 = 127; //01111111 - c2里面真实存放的长度 char c3 = c1 + c2; //计算时要进行整型提升 //c1提升: 00000000000000000000000000000101 - 补(补码整型提升还是补码) //c2提升: 00000000000000000000000001111111 //相加: 00000000000000000000000010000100 //c3存放: 10000100 printf("%d\n", c3);//-124 //%d - 十进制的形式打印有符号的整数 //打印时发生整型提升 - 打印的是原码 //11111111111111111111111110000100 - 补 //11111111111111111111111110000011 - 反 //10000000000000000000000001111100 - 原 - -124 char a = 0xb6; short b = 0xb600; int c = 0xb6000000; if(a==0xb6) printf("a"); if(b==0xb600) printf("b"); if(c==0xb6000000) printf("c");//只打印c char z = 1; printf("%u\n",sizeof(z));//1 printf("%u\n",sizeof(+z));//4 - 发生了整型提升 //%u - 十进制的形式打印无符号的整数 return 0; } //整形提升是按照变量的数据类型的符号位来提升的 //有符号的类型整型提升,补原符号位(最高位就是符号位) //无符号的类型整型提升,补0(每一位都是有效位) //整型提升只适用于比int小的类型 //表达式运算时不关心有无符号 (只使用补码运算), 使用时才关心有无符号算数转换
1. 如果某个操作符的各个操作数属于不同的类型, 那么除非其中一个操作数的转换为另一个操作数的类型, 否则操作就无法进行. 下面的层次体系称为寻常算术转换. long double double float unsigned long int long int unsigned int int 2. 如果某个操作数的类型在上面这个列表中排名较低, 那么首先要转换为另外一个操作数的类型后执行运算. 3. 警告: 算术转换要合理, 要不然会有一些潜在的问题.表达式求值顺序的影响因素
1. 操作符的优先级 2. 操作符的结合性 3. 是否控制求值顺序 4. 可以加上括号控制求值顺序 5. 两个相邻的操作符的执行顺序, 取决于他们的优先级. 如果两者的优先级相同, 取决于他们的结合性. 6. 通过以上规则, 对于一些无法确定唯一的计算路径的问题表达式, 在不同的编译器上结果可能不同. 7. 我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径, 那这个表达式就是存在问题的.操作符的优先级和结合性表 (由高到低)
关键字
typedef
typedef unsigned int u_int;//将无符号的整型重命名为u_int //创建一个名为 dstruct Node 的结构体类型 //并将 dstruct Node 重命名为 Node typedef struct Node { int data; struct Node* next; }Node; int main() { u_int num1 = 0; unsigned int num2 = 0; //num1 和 num2 创建的效果相同 return 0; }static
#include extern int g_val; //声明一下另一个.C文件中定义的g_val全局变量 extern int ADD(int , int); //声明一下另一个.C文件中定义的ADD函数 void test() { static int a = 5;//使a在程序彻底结束之后才销毁 //static修饰的变量就是静态变量 a++; printf("%d ",a); } int main() { int i = 0; while(i test(); i++; } printf("%d\n",g_val);//如果g_val在另一个.C文件中是static修饰的, 这里使用会报错 printf("%d\n",ADD(1,2));//如果ADD在另一个.C文件中是static修饰的, 这里使用会报错 return 0; } //static 修饰局部变量 //static 修饰局部变量改变了变量的存储类型(位置由栈区变为静态区) //由此使得这个静态变量的生命周期变长了, 直到程序结束才结束 //它的作用域仍是该局部变量所在的局部范围 //static 修饰全局变量 //static 修饰全局变量, 使得全局变量的外部链接属性消失 //使得该全局变量只具有内部链接属性 //这个静态变量只能在自己所在的源文件内部使用, 不能在其他源文件内部使用了 //感觉像是作用域变小了, 但是不影响其存储位置 //static 修饰函数 //static 修饰函数和其修饰全局变量是一样的 //一个解决方案可以创建多个项目, 一个项目可以创建多个文件 register int num = 10; //建议将该数据存储入寄存器 //register 仅仅是建议的作用 //到底是不是真的放在寄存器中, 取决于编译器的判断 //其实不用register关键字, 该把变量放到寄存器的时候编译器会自动放进去 return 0; } int n = 10; int m = 20; int *p = &n; *p = 20;//可以 p = &m;//可以 } void test2() { int n = 10; int m = 20; const int* p = &n; //*p = 20; - 不行 p = &m;//可以 } void test3() { int n = 10; int m = 20; int *const p = &n; *p = 20;//可以 //p = &m; - 不行 } int main() { //测试无cosnt的 test1(); //测试const放在*的左边 test2(); //测试const放在*的右边 test3(); return 0; } //const如果放在*的左边 //修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可变 //const如果放在*的右边 //修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变 //const还可以同时放在左右两边 int a =10; int b = 20; int c = ADD(a,b); printf("%d\n",c); return 0; } //#define 和#include 都是预处理指令 int a = 15; int* pa = &a;//指针变量的创建 //&a 取出的是第一个字节地址 //存放指针的变量叫指针变量 //int* int表示pa指向的是int类型的变量 //int* *表示pa是指针变量 printf("%p\n",pa);//打印出的地址是十六进制的 *pa = 30;//将该地址对应的值改成30 printf("%d\n",a); return 0; } //十进制: 15 //二进制: 00000000 00000000 00000000 00001111 //十六进制: f //计算机表现出来的十六进制是: 0x00 00 00 0f //指针 - 编号 - 地址 //指针变量 - 存放指针的变量 - 变量 //一般口头语上说的指针就是指针变量 //变量对应的地址一旦确定就无法改变 int a =10; int* p = &a; printf("%zd\n",sizeof(p)); printf("%zd\n",sizeof(*int)); //8/4 return 0; } //32位机器上: //地址是32个二进制位, 这个地址要存储的话要四个字节, 所以在32位机器上, 指针变量的大小是四个字节 //64位机器上: //地址是64个二进制位, 这个地址要存储的话要八个字节, 所以在64位机器上, 指针变量的大小是八个字节 //学生的相关属性 char name[20];//一个汉字是两个字符 int age; char sex[5]; };//结构体的创建 int main() { struct Stu s = {"张三", 20, "男"};//结构体的初始化 printf("%s %d %s\n",s.name,s.age,s.sex);//结构体成员访问 return 0; } //结构体是自定义的复杂类型 char name[50]; char author[20]; float price; }; //第一种访问方式 void print1(struct Book a) { printf("%s %s %f",a.name,a.author,a.price); } //第二种访问方式 void print2(struct Book* a) { printf("%s %s %f",(*a).name,(*a).author,(*a).price); printf("%s %s %f",a-name,a->author,a->price); } int main() { struct Book a = {"《鹏哥C语言》","鹏哥",66.6f}; print1(a); print2(a); return 0; }

![[C语言]快速上手](https://img-blog.csdnimg.cn/direct/1537b4a801d2494eb78642a059fcf1df.png)
![[C语言]快速上手](https://img-blog.csdnimg.cn/direct/ea0fe03d2795448b91a3be63a6dac353.png)
![[C语言]快速上手](https://img-blog.csdnimg.cn/direct/c6ee8bc514cf426fb5a84baed9e23b48.png)
![[C语言]快速上手](https://img-blog.csdnimg.cn/direct/da546cdcf37e4928a46a04ba57c0bf51.png)