023.long,long long与CPU架构的那些事儿_哔哩哔哩_bilibili
intel公司在上世纪创的8086型号CPU是第一个32位CPU用x86来表示
后来升级到64位取名“x86-64”替代为x64
024.size_t类型与sizeof的使用_哔哩哔哩_bilibili
x86:
long=int 4位
long long 8位
x64:
long 8位
long long 8位
自我调整
025.实际开发过程中真正的整型:微软与跨平台的int标准_哔哩哔哩_bilibili
主要讲了在企业实际开发中不会使用int char什么的,会使用下节的头文件
补充了long等的使用(实际开发基本不用)
026.★企业实际开发的整型声明:stdint.h的引用_哔哩哔哩_bilibili
按住Ctrl点进stdint.h头文件可以查看图(2)
图(2)
027.历史项目遗留_哔哩哔哩_bilibili
在现在的项目来说基本上是要确定宽度使用uint32_t这些,但对于linux等以前的项目要面向更多的机器比如上世纪的32位16位机器,就会使用int来确保兼容性。
028.隐式与显式类型转换_哔哩哔哩_bilibili
Type Conversion类型转换
如果这样转换的话 uSmallNum会先被转化被32位然后 = 赋值过程中被转化为16位给sSmallNum,做了一次显性的再做了一次隐性的
029.固定宽度整数类型的格式化宏输出inttypes.h_哔哩哔哩_bilibili
030.least和fast整型的企业用途与区别_哔哩哔哩_bilibili
在<inttypes.h>中用可读性更高的代码来代替%d %u &lld等可读性差的代码 --> %"PRId16" %"PRIdFast32"
int_fast32_t中的fast代表最低使用32位,但是为了效率可以使用更高位数的64位
int_least16_t中的least代表最低使用16位
142.企业使用[迭代方法]来替代递归_哔哩哔哩_bilibili------2024.12.8
用这样的迭代方法来代替递归,因为递归会占用大量的内存空间,在企业中不实用,尽量避免。
045.bool类型与实际案例_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdbool.h>
int main()
{
bool is_game_over = false;
bool is_game_won = true;
printf("%d\n", is_game_over);
printf("%d\n", is_game_won);
}
引用stdbool.h头文件
false就是0 true就是1
046.char范围与无符号char_哔哩哔哩_bilibili
一个字节是8位
char占一个字节 2^8=256 范围是 -128~127
uchar是0~255 常用于处理数据
uint8_t是0~255常常用于计算,因为它占空间很小
(目前就先知道有这么个用途,后面再讲)
047.常量const与#define宏_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define PI 3.14 //宏定义
//const int MAX_USERS = 100;
int main()
{
const int MAX_USERS = 100; //普通常量定义
//const也可以放在全局
printf("MAX_USERS: %d\n", MAX_USERS);
printf("PI: %f\n", PI);
}
宏定义(define)是作为全局的常量
const可以全局也可以局部
章节小节:048.第二章结束语_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
int16_t num16 = 848;
uint16_t num16u = 7946;
int8_t num8 = 127;
uint8_t num8u = 255;
int32_t num32 = 4565445;
uint32_t num32u = 4565445 * 2;
float numf = 655.26;
double numd = 454.1655;
printf("%"PRId16"\n", num16);
printf("%"PRIu16"\n", num16u);
printf("%d\n", num16);
printf("float / int :%f\n", numf / num16);
printf("int / float :%f\n", num16 / numf);
}
未看:040.float和double有效精度对比原理与计算_哔哩哔哩_bilibili
随便看的数组一节:
uint32_t num[5] = { 0 }所有的五个元素都为0
uint32_t num[5] = { 1 }第一个元素是1 其他四个元素为0
156.指针_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
int building_floors[5] = { 101,102,103,104,105 };
int* ptr_floor_103 = &building_floors[2];
int* ptr_floor_105 = &building_floors[4];
printf("building_floors[2]的地址是:%p\n", &building_floors[2]);
printf("ptr_floor_103所指向的地址是:%p\n", ptr_floor_103);
printf("ptr_floor_103所指向地址的值是:%d\n", *ptr_floor_103);
}
157.指针与修改_哔哩哔哩_bilibili
可以通过邻居来访问自己家的地址
printf("building_floors[3]的地址是:%p\n", &building_floors[3]);
printf("building_floors[3]的地址是:%p\n", &building_floors[2]+ 1);
指针只需要获取地址并且修改指针的值就可以修改原本的值,这是外挂最基本的原理
找到你的基址就可以修改你
反外挂可以通过指针一层套一层来隐藏基址(多级指针)
int *ptr_floor_106 = ptr_floor_103;
*ptr_floor_106 = 106;
如果要写的比较标准
printf("楼层的地址是:%p,楼层号:%d\n",(void*)ptr_to_floor, *ptr_to_floor);
158.指针星号的企业风格规范以及容易引发的问题_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 999;
int* p, q; //int *p int q
//不推荐一行定义多个变量,容易产生歧义,除非有明确注释
//可以做法:int *p,*q; 也不推荐,建议多行定义
p = &a;
q = &a;
printf("p:%d\n", *p);
printf("q:%d\n", q);
}
这里q不是指针是一个int类型变量,不建议一行多定义。
int* p和 int *p只是风格问题 frank的是后者更强调是个指针。
159.指针的意义与作用究竟是什么:外部服务操作_哔哩哔哩_bilibili
指针作用和意义:通过外部来访问自己本身,不需要自己动手。类似于:代购
指针的应用:windows的快捷方式
160.野指针的初步介绍_哔哩哔哩_bilibili
野指针:指向了一个无效的内存地址或者已经释放的内存地址的指针。
非常危险。
野指针会访问一个不可描述的内存空间,会导致不可预测的行为。
161.空指针的初步介绍_哔哩哔哩_bilibili
空指针:通常指没有指向任何有效内存空间的指针。
162.空指针的初始化_哔哩哔哩_bilibili
左值一定是一个变量名。
一个空指针的小案例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t* ptr_to_floor = NULL;
uint8_t check = 0;
uint32_t number = 100;
printf("输入 0 为空指针,输入 1 不为空指针:\n");
scanf("%"PRId8"", &check);
if (check) {
ptr_to_floor = &number;
}
if (ptr_to_floor == NULL) {
printf("没有指定的楼层的地址!\n");
}
else {
printf("楼层的地址是%p,楼层号是%d\n", (void*)ptr_to_floor, *ptr_to_floor);
}
}
并且诸如此类的错误是 scanf中的%d可能使用不当,比如uint8_t类型应使用%hhd或者%"PRId8"。
163.从代码上尝试认识野指针_哔哩哔哩_bilibili
空指针是一个正常的现象,但野指针是一个问题,它需要处理掉。
代码演示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t floor = 103;
uint32_t* ptr_to_floor = &floor;
printf("当前指向的地址:%p,值:%d\n", (void*)ptr_to_floor, *ptr_to_floor);
{
//创建一个新的作用域
uint32_t temp_floor = 104;
ptr_to_floor = &temp_floor;
printf("当前指向的地址:%p,值:%d\n", (void*)ptr_to_floor, *ptr_to_floor);
}
printf("当前指向的地址:%p,值:%d\n", (void*)ptr_to_floor, *ptr_to_floor);
//在作用域外他仍然是指向的104,这已经严重污染了程序的安全性
//假如这个作用域内是机密数据,通过未及时释放的指针就可以访问到内部的机密数据了
}
运行结果:
当前指向的地址:0000007539D8FA94,值:103
当前指向的地址:0000007539D8FAD4,值:104
当前指向的地址:0000007539D8FAD4,值:104
164.数组的首地址与指针的算数运算_哔哩哔哩_bilibili
int size = sizeof(numbers) / sizeof(number[0]);
sizeof(numbers)这个部分计算整个数组所占用的1内存大小,单位是字节。
sizeof(numbers[0])计算第一个元素的大小,字节。
知识点:
int占四个字节也就是4byte [bait] 1byte = 8bit [bit] bit就是位,也叫比特位
int是32位 = 4字节
%td ptrdiff_t类型: 计算指针之间的距离
int *start_ptr = &number[0];
int *end_ptr = &number[size-1];
printf("数组首尾之间的距离是:%td\n\n",end_ptr - start_ptr);
指针相减返回的类型是ptrdiff_t类型,在64位中是int64的类型,在32位中是int类型(在vs2022上)
#ifdef _WIN64
typedef unsigned __int64 size_t;
typedef __int64 ptrdiff_t; //64位 %td格式化输出
typedef __int64 intptr_t;
#else
typedef unsigned int size_t;
typedef int ptrdiff_t; //32位
typedef int intptr_t; 源自:vcruntime.h
t
:代表 "pointer difference"(指针差异)。它用于指示该格式符是用来打印指针差异类型的数据,通常是ptrdiff_t
类型。t
主要是为了区分它与其他整型格式符(如%d
)而设计的。
d
:表示 "decimal"(十进制)。它表示该值应以十进制形式输出
165.续上集:指针的算数运算与比较运用_哔哩哔哩_bilibili
166.再探size_t与数组与指针的使用_哔哩哔哩_bilibili
以上两集悲惨丢失笔记,下面简写一点
以上两集悲惨丢失笔记,下面简写一点
以上两集悲惨丢失笔记,下面简写一点
for循环中++i 理论上比 i++ 性能更好
因为i++是先存储i的值然后再加1并返回
++i 是先把i+1并返回但
在迭代器和对象复杂的情况下可能会明显一些 推荐使用++i
目前的编译器会自动优化掉两者的区别
ptr += 1;不会使得指针移动
ptr = ptr +1;和ptr++;才会使指针永久移动
size_t是用来表示大小、长度和索引
64位:u64
32位:u32
%zu专门用来输出size_t
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
int main(void)
{
int32_t array[] = { 10, 20 ,30, 40, 50, 60, 70, 80, 90, 100 };
size_t array_size = sizeof(array) / sizeof(array[0]);
int32_t* ptr = array;
printf("数组的原始数据:\n array[] = {");
for (size_t i = 0; i < array_size; i++)
{
printf(" %d ", array[i]);
}
printf("}\n\n");
//通过指针对数组每个值进行操作
printf("数组的修改数据:\n array[] = {");
size_t i = 0;
for (i; i < array_size; ++i)
{
*(ptr + i) += 5;
printf(" %d ", *(ptr + i));
}
printf("}\n\n");
printf("永久移动指针来遍历->数组的修改数据:\n array[] = {");
int32_t *start_ptr = array;
int32_t *end_ptr = &array[array_size - 1];
for (ptr; ptr <= end_ptr; ptr++)
{
printf(" %d ", *ptr);
}
ptr--;
printf("}\n\n");
//移动后的指针指向
printf("目前指针指向的是: %d\n", *ptr);
}
167.案例:指针查找特定元素的索引并返回_哔哩哔哩_bilibili
不使用函数来完成案例
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <stdint.h> #include <stdbool.h> int main(void) { int32_t value[] = { 10,20,30,40,50,60,70,80,90,100 }; size_t value_size = sizeof(value) / sizeof(value[0]); int32_t* ptr = value; int32_t target_value = 90; int32_t target_ptr = NULL; size_t index = 0; bool found = false; for (size_t i= 0; i < value_size; ++i) { if (*(ptr + i) == target_value) { target_ptr = ptr; index = i; found = true; } } if (found) { printf("元素 %d 的index: %zu\n", target_value, index); } else { printf("元素 %d 未找到index !", target_value); } }
使用函数来完成案例
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <stdint.h> #include <stdbool.h> bool found_index_of_value(const int32_t* array, size_t size, int32_t target_value, size_t* index); int main(void) { int32_t value[] = { 10,20,30,40,50,60,70,80,90,100 }; size_t value_size = sizeof(value) / sizeof(value[0]); int32_t* ptr = value; int32_t target_value = 90; int32_t target_ptr = NULL; size_t index = 0; bool found = false; if (found_index_of_value(ptr, value_size, target_value, &index)) { printf("元素 %d 的index: %zu\n", target_value, index); } else { printf("元素 %d 未找到index !", target_value); } } bool found_index_of_value(const int32_t* array, size_t size, int32_t target_value, size_t* index) { for (size_t i = 0; i < size; ++i) { if (*(array + i) == target_value) { *index = i; return true; } } return false; }
知识点: 妙用&与指针
bool found_index_of_value(const int32_t* array, size_t size, int32_t target_value, size_t* index)
该函数定义中使用的是size_t *index 在main里是size_t index,通过在函数中*index=i来使得main中的index的值发生改变,且不需要return
详细案例:170-1节↓
170-1.函数的值传递与地址引用传递_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
void add_ten_by_value(int32_t* value);
int main(void)
{
int32_t my_value = 10;
printf("原本的值:%d\n", my_value);
add_ten_by_value(&my_value);
printf("经过add_ten_by_value调用后的值: %d\n", my_value);
}
void add_ten_by_value(int32_t* value)
{
*value += 5;
}
知识点:
通过地址传递(pass by reference引用传递)来实现了在外部函数中对main内的变量进行修改值
171.案例:员工薪资系统:指针作为函数返回值_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#define EMPLOYEES_COUNT 5
void view_all_employees_salaries(uint32_t* salaries);
void increase_salaries(uint32_t* salaries);
uint32_t calculate_bonus(uint32_t salary);
uint32_t* find_highest_salaries(uint32_t* salaries);
int main(void)
{
/*
* 员工薪资管理系统
* -查看所有员工的薪资
* -批量加工资
* -计算员工的年终奖
* -查找最高薪资的员工(获取他的地址)
*/
uint32_t salaries[EMPLOYEES_COUNT] = { 5000,5600,7000,7700,10000 };
view_all_employees_salaries(salaries);
increase_salaries(salaries);
view_all_employees_salaries(salaries);
uint32_t *highest = find_highest_salaries(salaries);
printf("员工中最高薪资是: %" PRIu32 "\n", *highest);
printf("最高薪资的年终奖是: %" PRIu32 "\n", calculate_bonus(*highest));
}
void view_all_employees_salaries(uint32_t* salaries)
{
/*
int32_t salaries[] 和 int32_t *salaries 在 C 语言中没有本质的区别,二者都被当作指针处理。
选择使用哪种写法通常是个人偏好或代码风格的问题。int32_t salaries[] 语法上更像是数组的感觉,而 int32_t *salaries 明确地表明它是一个指针。
在大多数情况下,它们是可以互换的。
*/
printf("所有员工的薪资: ");
for (size_t i = 0; i < EMPLOYEES_COUNT; ++i)
{
printf("%" PRIu32 " ", salaries[i]);
}
printf("\n");
}
void increase_salaries(uint32_t* salaries)
{
for (size_t i = 0; i < EMPLOYEES_COUNT; ++i)
{
salaries[i] += 10000;
}
}
uint32_t calculate_bonus(uint32_t salary)
{
return salary / 10;
}
uint32_t* find_highest_salaries(uint32_t* salaries)
{
uint32_t* highest = salaries;
for (size_t i = 1; i < EMPLOYEES_COUNT; ++i)
{
if (salaries[i] > *highest) {
highest = &salaries[i];
}
}
return (uint32_t*)highest;
}
172.游戏案例:指针的练习_哔哩哔哩_bilibili
环境可以泯灭人才
在 C 语言中,
std
并不是一个语言关键字,而是通常指代 标准库(Standard Library)的简称
关于c语言中的static:
- 局部变量:
static
使得局部变量的生命周期持续整个程序运行,而不仅仅是函数的执行周期,且该变量仅初始化一次。- 全局变量/函数:
static
限制了全局变量和函数的作用域,使它们只在定义它们的文件内部可见,外部无法访问。使用
static
可以帮助你控制变量和函数的可见性和生命周期,进而实现更好的模块化和封装。#include <stdio.h> void counter() { static int count = 0; // static局部变量 count++; printf("Counter: %d\n", count); } int main() { counter(); // 输出 Counter: 1 counter(); // 输出 Counter: 2 counter(); // 输出 Counter: 3 return 0; }
在这个例子中,
count
是一个static
局部变量,它在多次调用counter()
函数时保持其状态,并且每次调用时都会继续从上一次调用结束的地方开始,而不是重新初始化为 0。
案例:升级寻找宝藏的小游戏
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <stdint.h> #include <stdbool.h> #define EXP_PER_LEVEL 100 #define MAX_LEVEL 10 const char* get_treasure_hints(uint32_t* level); void increase_exp(uint32_t* exp, uint32_t exp_increment); bool check_level_up(uint32_t* level, uint32_t* exp); int main(void) { uint32_t player_exp = 0; uint32_t player_level = 0; printf("%s\n\n", get_treasure_hints(&player_level)); increase_exp(&player_exp, 50); if (check_level_up(&player_level, &player_exp)) { printf("%s\n\n", get_treasure_hints(&player_level)); } increase_exp(&player_exp, 50); if (check_level_up(&player_level, &player_exp)) { printf("%s\n\n", get_treasure_hints(&player_level)); //0->1 } increase_exp(&player_exp, 75); if (check_level_up(&player_level, &player_exp)) { printf("%s\n\n", get_treasure_hints(&player_level)); } increase_exp(&player_exp, 120); //1->2 if (check_level_up(&player_level, &player_exp)) { printf("%s\n\n", get_treasure_hints(&player_level)); } increase_exp(&player_exp, 120); //2->3 if (check_level_up(&player_level, &player_exp)) { printf("%s\n\n", get_treasure_hints(&player_level)); } } void increase_exp(uint32_t* exp, uint32_t exp_increment) { *exp += exp_increment; } bool check_level_up(uint32_t* level, uint32_t* exp) { if (*exp >= EXP_PER_LEVEL && *level <= MAX_LEVEL) { *exp -= EXP_PER_LEVEL; (*level)++; printf("恭喜你升级,当前等级: %" PRIu32 "\n", *level); return true; } return false; } const char* get_treasure_hints(uint32_t* level) { static const char* treasure_hints[MAX_LEVEL] = { "提示 1: 欢迎新玩家加入游戏,请沿标记路线前往村长的家!", "提示 2: 前往村庄郊外猎杀皮皮鸡,并将皮皮鸡的肉带回村落!", "提示 3: 古老的诅咒逐渐松动,你感觉到了一丝不安,于是决定动身前往古龙密山前去一探究竟!", "提示 4: 在古龙密山的一处洞穴中,一柄沾染了古龙精血的锈剑向你发出了呼唤!" }; return treasure_hints[*level]; }
缺陷1:increase的经验超过1级(如:200)就会导致提示失误,但在我这个案例中,必须寻找到一个宝藏才可能升级,直接升两级及以上有些不合乎常理。
173.练习:更新分数_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
void update_score(uint32_t* player_score, uint32_t score)
{
*player_score += score;
}
void double_score(uint32_t* player_score)
{
*player_score *= 2;
}
uint32_t* compare_score(uint32_t* player1_score, uint32_t* player2_score)
{
return (*player1_score > *player2_score) ? player1_score : player2_score;
}
void view_score(uint32_t player_score)
{
printf("当前玩家的分数是: %" PRIu32 "\n",player_score);
}
int main(void)
{
uint32_t player1_score = 600;
uint32_t player2_score = 1100;
update_score(&player1_score, 100);
view_score(player1_score);
double_score(&player2_score);
view_score(player2_score);
printf("分数更高的是: %" PRIu32 "\n", *(compare_score(&player1_score, &player2_score)));
}
174.游戏案例:收藏奖杯_哔哩哔哩_bilibili
知识点:
const char* add_achievement(const char* achievement)
在这个语句中,第一个const表示返回的一个字符串不可以被修改。例如: char* new = add_achievement("第一名"),假如return的是"恭喜你获得第一名",这个"恭喜你获得第一名"就不可以被修改,但是new可以被修改。只是确保了return值不可修改。
第二个const就是在函数内部不可以修改achievement字符串
游戏案例:黑神话悟空成就
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <stdint.h> #include <stdbool.h> #define MAX_ACHIEVEMENTS_COUNT 10 const char* achievements[MAX_ACHIEVEMENTS_COUNT]; size_t achievements_count = 0; void add_achievement(const char* new_achievement); void print_achievements(); void view_achievement_details(size_t index); void print_achievements_details(); int main(void) { add_achievement("下降凡尘第一难"); add_achievement("敲敲打打第二难"); add_achievement("山中斗狼第三难"); add_achievement("吸存运用第四难"); add_achievement("真个壮怀第五难"); add_achievement("长蛇隐迹第六难"); add_achievement("得心应手第七难"); add_achievement("余韵远传第八难"); print_achievements(); print_achievements_details(); } void add_achievement(const char* new_achievement) { if (achievements_count < MAX_ACHIEVEMENTS_COUNT) { achievements[achievements_count++] = new_achievement; } else { printf("Error!玩家当前成就已超出最大成就数量,请仔细检查!\n"); } } void print_achievements() { printf("\n\n=====================================================\n"); puts("玩家成就列表:"); for (size_t i = 0; i < achievements_count; ++i) { printf("%zu: %s\n", i + 1, achievements[i]); } printf("=====================================================\n"); } void print_achievements_details() { printf("\n\n=====================================================\n"); puts("玩家成就详细列表:"); for (size_t i = 0; i < achievements_count; ++i) { view_achievement_details(i + 1); } printf("=====================================================\n"); } void view_achievement_details(size_t index) { static const char* achievements_details[MAX_ACHIEVEMENTS_COUNT] = { "听罢老猴子的故事,该起程了。", "配好披挂,狼虫不怕。", "名是假的,不必留情。", "生前吃人,死后人吃。", "旧酿泡新物,死后奔前途!", "秀士述了隐情,且先饶他一命。", "好对手,配得好兵器。", "三钟响,幽魂藏。" }; printf("%zu: %s", index, achievements[index - 1]); printf("\t\t\t\t\t\t"); printf("%s\n", achievements_details[index - 1]); }
176.初识结构体C语言大师:编得狂,骂得响[后篇]_哔哩哔哩_bilibili
struct Person {
char name[50];
size_t age;
float height;
float weight;
};
struct Person zjne = { "周江鸟恩", 20, 180, 80 };
printf("%s\n", zjne.name);
177.创建结构体变量与访问方式_哔哩哔哩_bilibili
typedef struct Person {
char name[50];
size_t age;
float height;
float weight;
} Person;
Person zjne = { "zjne", 1000, 1.0, 999 };
printf("%s is %zu years old , %.2f height and %.2f weight\n",
zjne.name, zjne.age, zjne.height, zjne.weight);
Person *ptr_zjne = &zjne;
printf("%s is %zu years old , %.2f height and %.2f weight\n",
ptr_zjne->name, ptr_zjne->age, ptr_zjne->height, ptr_zjne->weight);
两种方式 普通的和指针的
178.匿名结构体、函数参数为结构体_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct Student {
char name[50];
uint32_t id;
float score;
} Student;
void print_stu(Student stu);
void update_score_by_reference(Student* stu, float new_score);
void update_score_by_value(Student stu, float new_score);
int main(void)
{
Student stu = { "SlasherMan", 10001, 64.0 };
puts("Before update: ");
print_stu(stu);
puts("After update by value: ");
update_score_by_value(stu, 100);
print_stu(stu);
puts("After update by reference: ");
update_score_by_reference(&stu, 100);
print_stu(stu);
}
void print_stu(Student stu) {
printf("Student Name: %s\n", stu.name);
printf("Student ID: %" PRIu32 "\n", stu.id);
printf("Student Name: %.2f\n\n", stu.score);
}
void update_score_by_value(Student stu, float new_score)
{
stu.score = new_score;
}
void update_score_by_reference(Student* stu, float new_score)
{
stu->score = new_score;
}
输出结果:
Before update:
Student Name: SlasherMan
Student ID: 10001
Student Name: 64.00After update by value:
Student Name: SlasherMan
Student ID: 10001
Student Name: 64.00After update by reference:
Student Name: SlasherMan
Student ID: 10001
Student Name: 100.00
// 通过指针传递结构体,可以改变结构体的值
而通过值传递只可以在函数中生成一个局部变量stu,并不是main函数里的stu
179.值语义初始化结构体变量_哔哩哔哩_bilibili
知识点:
“值语义”(Value Semantics)是指一个变量或对象的值被传递或赋值时,会复制该值,而不是引用它。也就是说,当你将一个变量的值赋给另一个变量时,新的变量会得到原值的副本,修改副本不会影响原始值。
这与“引用语义”(Reference Semantics)相对,引用语义中赋值的是引用或地址,改变其中一个对象会影响到另一个
值语义:安全,降低意外改数据的风险
get_point执行后立即销毁,想去修改函数中10,20是很难的,反外挂的一层
typedef struct Point {
int32_t x;
int32_t y;
} Point;
Point get_point();
int main(void)
{
Point my_point = get_point();
printf("my_point:( %d, %d )\n", my_point.x, my_point.y);
}
Point get_point()
{
Point p;
p.x = 10;
p.y = 20;
return p; //return 一个结构体副本
}
在这个案例中,通过值语义将get_point中的p return给my_point实现值语义初始化结构体变量
180.结构体数组_哔哩哔哩_bilibili
typedef struct Point {
int32_t x;
int32_t y;
} Point;
int main(void)
{
Point my_point[2] = {
{1,2},
{3,4}
};
for (size_t i = 0; i < 2; i++)
{
printf("my_point %zu:( %d, %d )\n", i, my_point[i].x, my_point[i].y);
}
}
181.嵌套结构体_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct Address {
char street[50];
char city[50];
char country[50];
} Address;
typedef struct Person {
char name[50];
uint32_t age;
Address address;
} Person;
int main(void)
{
Person SlasherMan = {
"SlasherMan",
19,
{"XXXXXXXX", "YYYYYYYYYYYYYY", "ZZZZZZZZZZZZZZZ"}
};
printf("Name: %s\n", SlasherMan.name);
printf("Age: %" PRIu32 "\n", SlasherMan.age);
printf("Address:\n");
printf("Street: %s, city: %s, country: %s\n", SlasherMan.address.street, SlasherMan.address.city, SlasherMan.address.country);
Person* ptr = &SlasherMan;
printf("Name: %s\n", ptr->name);
printf("Age: %" PRIu32 "\n", ptr->age);
printf("Address:\n");
printf("Street: %s, city: %s, country: %s\n", ptr->address.street, ptr->address.city, ptr->address.country);
}
182.Enumeration枚举_哔哩哔哩_bilibili
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
typedef enum {
MONDAY, // 0
TUESDAY,
WEDNESDAY,
THURESDAY,
FRIDAY,
SATURDAY,
SUNDAY = 1000000
} Weekday;
const char* get_weekday_name(Weekday day);
int main()
{
Weekday day = SUNDAY;
printf("SUNDAY: %d\n", day);
printf("FRIDAY: %d\n", FRIDAY);
printf("The first one is %s\n", get_weekday_name(MONDAY));
}
const char* get_weekday_name(Weekday day)
{
switch (day)
{
case MONDAY: return "MONDAY";
default:
break;
}
}
知识点:
枚举( Enumeration)是一个数据类型,当你想define多个连续的变量时可以使用
可以自定义设置值 默认从0依次+1下面一个是上面的值+1
如果这里的SATURDAY是10000则 SUNDAY就是10001
183.Union联合_哔哩哔哩_bilibili
知识点:
联合Union
它允许在相同的内存位置存储不同的数据类型。
联合体的所有成员共享一块内存空间,大小等于其最大成员的大小。
这就意味着在任一时刻,联合体只能存储一个成员的值。
一个变量可能存储多种类型的数据,但是在一个给定时刻里,只使用其中一中的数据类型,这样可以节省内存。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
typedef union{
int int_value;
float float_value;
char* string_value;
} Data;
typedef enum {
INT,
FLOAT,
STRING
}DataType;
typedef struct TypedData {
DataType type;
Data data;
} TypedData;
void print_data(TypedData data);
int main(void)
{
TypedData data1 = { INT, {.int_value = 10} };
TypedData data2 = { FLOAT, {.float_value = 2.75} };
TypedData data3 = { STRING, {.string_value = "Hello! Union."} };
print_data(data1);
print_data(data2);
print_data(data3);
}
void print_data(TypedData data)
{
switch (data.type)
{
case INT:
printf("Integer: %d\n", data.data.int_value);
break;
case FLOAT:
printf("Float: %.2f\n", data.data.float_value);
break;
case STRING:
printf("String: %s\n", data.data.string_value);
break;
}
}
难点:
联合体,枚举,结构体的连用
难点:架构
知识点:
表驱动法 通过预计算和存储结果,避免了重复的计算。这样,程序可以通过查找表中的预存值来快速返回结果。
比如提前计算好1-9的平方值并存储在一个数组中,想查找谁的平方值就可以直接返回不需要重复计算。
在我们的这个案例中可以是class是0就输出是"Warrior"战士 , 这个意思
修改后的案例:失落城堡2简单案例:
- 头文件部分
game_types.h
#ifndef GAME_TYPES_H #define GAME_TYPES_H typedef enum { Dual_Blades, //双刀 Staff, //法杖 Bow, //弓箭 Musket, //火枪 } ItemType; typedef enum { Goblin, //哥布林种类 Stone, //石怪种类 Dragon, //魔龙种类 } EnemyType; #endif // !GAME_TYPES_H
game_ablities.h
#ifndef GAME_ABILITIES_H #define GAME_ABILITIES_H #include <inttypes.h> #include <stdbool.h> typedef union { int32_t strength; //力量 float mana; //魔法值 float power; //弓箭力量 float fire_power; //火力值 } Ability; #endif // !GAME_ABILITIES_H
game_structs.h
#ifndef GAME_STRUCTS_H #define GAME_STRUCTS_H #include "game_types.h" #include "game_abilities.h" typedef struct { char name[50]; ItemType item; Ability ability; uint32_t exp; uint32_t level; uint32_t health; } Player; typedef struct { char name[50]; Ability ability; EnemyType enemy; size_t difficulty; } Enemy; #endif // !GAME_STRUCTS_H
game_functions.h
#ifndef GAME_FUNCITONS_H #define GAME_FUNCITONS_H #include "game_structs.h" void create_player(Player* player, char* name, ItemType item); Enemy generate_enemy(char* name, EnemyType enemy_type, size_t difficulty); void battle(Player* player, Enemy* enemy); void print_player_info(const Player player); void print_enemy_info(const Enemy enemy); #endif // !GAME_FUNCITONS_H
- 源文件部分
game_functions.c
#define _CRT_SECURE_NO_WARNINGS #include "game_functions.h" #include <stdio.h> #include <string.h> void create_player(Player* player, char* name, ItemType item) { strcpy(player->name, name); player->exp = 0; player->health = 100; player->level = 1; player->item = item; switch (item) { case Dual_Blades: player->ability.strength = 1; break; case Staff: player->ability.mana = 1; break; case Musket: player->ability.fire_power = 1; break; case Bow: player->ability.power = 1; break; } } Enemy generate_enemy(char* name, EnemyType enemy_type, size_t difficulty) { Enemy enemy; strcpy(enemy.name, name); switch (enemy_type) { case Goblin: enemy.ability.strength = difficulty * 10; break; case Stone: enemy.ability.strength = difficulty * 20; break; case Dragon: enemy.ability.mana = difficulty * 100; break; } return enemy; } void battle(Player* player, Enemy* enemy) { printf("%s encounter a %s, then they begin to battle!\n", player->name, enemy->name); //假设每次玩家获胜 player->exp += 50; printf("%s has defeated the %s and gains 50 exp!\n", player->name, enemy->name); } void print_player_info(const Player player) { printf("玩家 %s 数据如下:\n", player.name); printf("所持武器: "); switch (player.item) { case Dual_Blades: puts("双刀"); break; case Staff: puts("法杖"); break; case Musket: puts("火枪"); break; case Bow: puts("弓箭"); break; } printf("生命值: %" PRIu32 ", 经验值: %" PRIu32 ", 等级: %" PRIu32 "\n", player.health, player.exp, player.level); } void print_enemy_info(const Enemy enemy) { printf("怪物信息.......\n"); }
run_app.c
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <stdint.h> #include <stdbool.h> #include "game_functions.h" #include "game_structs.h" int main(void) { Player player1; create_player(&player1, " 无敌至尊我的世界大王", Musket); Enemy Goblin_scout = generate_enemy("哥布林战士", Goblin, 4); battle(&player1, &Goblin_scout); print_enemy_info(Goblin_scout); print_player_info(player1); }
- 简单的输出
代码输出:
185.第09章节结束语_哔哩哔哩_bilibili
黑客帝国:若有完美,必有谎言
世界上没有完美的东西,c语言的东西也不可能完全讲完
理解 消化 训练 必不可少
186.字符串_哔哩哔哩_bilibili
char string[5] = "Hello"; printf("%s\n", string);
这里应该是6个长度,因为还有 '\0'
建议:不定义长度arr[],或者长度非常长
数组类型的可以被修改 如果加了const就不可以修改
指针类型默认就不可以被修改
char* ptr = "Hello"; ptr[0] = 'A';
这样编译器不会报错但是会输出卡住
187.strcpy_s的用法_哔哩哔哩_bilibili
char str[100] = "hello";
// H e l l o \0 \0 \0 \0 \0 \0 \0
数组的会默认是0 ,字符串默认是 \0
指针定义字符串前面加const 规范
const char* ptr = "Hello";
strcpy_s的用法
#include <stdio.h> #include <string.h> #define SIZE 50 int main(void) { const char src[] = "Hello"; char dest[SIZE]; strcpy_s(dest, SIZE, src); printf("src = %s\n", src); printf("dest = %s\n",dest); }
strcpy_s需要传入三个参数,与strcpy不同,strcpy如果目标字符串小于源字符串则会出现溢出,而加入了_s之后,在二者中间需传入目标数组的大小size。
188.选修(难、非入门):VS编译器捕获字符串异常_哔哩哔哩_bilibili
strcpy_s(dest, sizeof(dest), src); printf("sizeof(dest) = %zu\n", sizeof(dest)); printf("sizeof(dest)/ sizeof(dest[0]) = %zu\n",
输出:
sizeof(dest) = 50
sizeof(dest)/ sizeof(dest[0]) = 50在字符串中,sizeof(string)是字符串长度,因为是按字节来的,char类型就只占一个字节而已所以和sizeof(dest)/sizeof(dest[0])大小一样
在实际开发过程中是有着异常捕捉,通过图中的一些操作,并调整Debug模式到Release模式来捕捉
189.strlen_哔哩哔哩_bilibili
strlen计算字符串长度,不包含 \0
char dest[50] = {}; //或者 { 0 }
strcpy_s(dest, sizeof(dest), "Hello")
这样初始化字符串很安全
190.strcat_s_哔哩哔哩_bilibili
字符串拼接
#include <stdio.h>
#include <string.h>
#define SIZE 50
int main(void)
{
char dest[50] = { 0 };
strcpy_s(dest, sizeof(dest), "Hello");
printf("Before: %s\n", dest);
char* src = ", World!\n";
rsize_t dest_size = sizeof(dest) - strlen(dest) - 1;
strcat_s(dest, dest_size, src);
printf("After: %s", dest);
}
191.sprintf_s_哔哩哔哩_bilibili
C语言标准 —— C89(C90)、C99、C11、C17、C2X_c2x标准-CSDN博客
c99就是1999年修订的 c11就是2011年修订的
在c11中将微软写的strcat_s sprintf_s等_s的添加到了标准中,也有没添加的,比如strtok_s
#include <stdio.h>
#include <string.h>
int main(void)
{
char dest[50] = { 0 };
int number = 10;
double pi = 3.141592653589793238f;
int ret = sprintf_s(dest, sizeof(dest), "Integer: %d, Double: %.2f", number, pi);
if (ret >= 0)
{
printf("%s\n", dest);
}
}
sprintf_s将格式化的字符串复制到dest中,有一个返回值ret,如果ret >=0则success
192.strncpy_s_哔哩哔哩_bilibili
strncpy_s和strcpy_s类似只不过多了一个最大可复制数
#include <stdio.h> #include <string.h> int main(void) { char dest[50] = { 0 }; const char* src = "Hello, World!\n"; int max_copiable_number = 11; errno_t result = strncpy_s(dest, sizeof(dest), src, max_copiable_number); if (result == 0) { printf("%s", dest); } return 0; }
193.strncat_s_哔哩哔哩_bilibili
#include <stdio.h>
#include <string.h>
int main(void)
{
char dest[20];
strcpy_s(dest, sizeof(dest), "Slasher");
char* src = ",World!\n";
size_t max_append = 6;
int result = strncat_s(dest, sizeof(dest), src, max_append);
if (result == 0)
{
printf("Concatenated string: %s", dest);
}
else {
printf("Error concatenating string!\n");
}
}
strncat_s :追加字符串,有字数限制
194.gets_s_哔哩哔哩_bilibili
gets没有字符长度限制,在c11删除,增加gets_s
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[100];
printf("Please enter your string: ");
if (gets_s(str, sizeof(str)) == NULL) {
printf("Error input!");
}
else {
printf("Your entered string: %s\n", str);
}
}
195.strtok_s_哔哩哔哩_bilibili
在编程中,"token"(标记)通常指的是代码中最小的语法单元,它是源代码在编译或解释过程中被识别并处理的基本元素。
strtok_s用于将字符串按要求delimit(分隔符)来分割。
#include <stdio.h> #include <string.h> int main(void) { char str[] = "Minecraft is a sandbox game"; char* delim = " "; char* context = NULL; char* token = strtok_s(str, delim, &context); while (token != NULL) { printf("Token: %s\n", token); token = strtok_s(NULL, delim, &context); } }
strtok_s中的context 是保存strtok_s函数在其内部的上下文指针,用于指向下一个小字符串
它是一个二级指针,并且规定是要有具体的指向,在这里我们定义一个一级指针context,在传值时传入context的地址作为二级指针,这样这个二级指针就指向了一级指针就有了明确的指向。
196.strcmp_哔哩哔哩_bilibili
但凡具有字符串修改的基本都有_s
strlen strcmp这种不修改的没有
strcmp是两个字符串相减
apple<banana
hello<hey
按照ASCII一个字符一个字符对比
#include <stdio.h>
#include <string.h>
int main(void)
{
const char str1[] = "Minecraft is a sandbox game"; //a97 = A65 +32
const char str2[] = "Minecraft is a sandbox game";
const char str3[] = "Minecraft is A sandbox game";
const char str4[] = "Minedraft is a sandbox game";
const char *arr[] = { str1,str2,str3,str4 };
char** ptr = arr;
for(ptr; *ptr<=str4; ptr++)
{
if (strcmp(str1, *ptr) == 0)
{
printf("There are equal!\n");
}
if (strcmp(str1, *ptr) > 0)
{
printf("The value of the first is greater than the second.\n");
}
if (strcmp(str1, *ptr) < 0)
{
printf("The value of the first is less than the second.\n");
}
}
ptr--;
}
这里是一个不严谨的指针二级字符串指针
char**
是指向指针的指针,而{ str1, str2, str3, str4 }
是一个初始化列表,它是用于初始化数组或结构体的。然而,char**
不能直接这样初始化,它需要指向一个指针数组(即char*
数组)。所以,char**
不能直接用来存储多个指向char
的指针
197.strncmp_哔哩哔哩_bilibili
#include <stdio.h>
#include <string.h>
int main(void)
{
const char str1[] = "Minecraft is a sandbox game"; //a97 = A65 +32
const char str2[] = "Minecraft is a sandbox game";
const char str3[] = "Minecraft is A sandbox game";
const char str4[] = "Minedraft is a sandbox game";
const char *arr[] = { str1,str2,str3,str4 };
char** ptr = arr;
size_t num = 5;
for(ptr; *ptr<=str4; ptr++)
{
if (strncmp(str1, *ptr, num) == 0)
{
printf("There are equal!\n");
}
if (strncmp(str1, *ptr, num) > 0)
{
printf("The value of the first is greater than the second.\n");
}
if (strncmp(str1, *ptr, num) < 0)
{
printf("The value of the first is less than the second.\n");
}
}
ptr--;
}
strncmp可以比较前maxCount个字符
198.strchr与strrchr_哔哩哔哩_bilibili
#include <stdio.h> #include <string.h> int main(void) { //strchr //strrchr //str_reverse_char reverse:逆转 const char str[] = "SlasherMan"; char to_find = 'a'; char* ptr_str = strchr(str, to_find); printf("ptr_str: %s\n", ptr_str); printf("Finding it! '%c'of index: %td\n", to_find, ptr_str - str); char* ptr_strr = strrchr(str, to_find); printf("ptr_strr: %s\n", ptr_strr); printf("Finding it! reverse'%c'of index: %td\n", to_find, ptr_strr - str); }
strchr找到字符并返回字符及其后面的字符串
strrchr从后面找
199.strstr_哔哩哔哩_bilibili
strstr:
//strstr查找子字符串在不在父字符串之中
//如果在返回在父字符串中指向子字符串位置的指针#include <stdio.h> #include <string.h> int main(void) { //strstr查找子字符串在不在父字符串之中 //如果在返回在父字符串中指向子字符串位置的指针 const char text[] = "SlasherMan is a handsome boy"; const char sub[] = "handsome"; //Subprogram子程序 char* result = strstr(text, sub); if (result != NULL) { printf("\"%s\" is in \"%s\"\n", sub, text); } else { printf("Not Found!\n"); } }
200.strspn与strcspn_哔哩哔哩_bilibili
//strspn strcspn
//strspn(str1, str2) 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标
//strcspn(str1, str2) 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符#include <stdio.h> #include <string.h> int main(void) { //strspn strcspn //strspn(str1, str2) 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标 //strcspn(str1, str2) 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符 const char* str1 = "Hello, World! SlasherMan"; const char* str2 = "Hello,World"; size_t len = strspn(str1, str2); printf("len: %zu\n", len); const char* name = "filenam???e.md"; const char* invaild_name = "/\\<>? \"':*"; len = strcspn(name, invaild_name); if (len < strlen(name)) { printf("invaild name!"); } else { printf("This name is vaild"); } }
201.再次废话_哔哩哔哩_bilibili2025/1/18
关于字符串指针和指针指向字符串数组
#include <stdio.h> #include <string.h> int main(void) { //推荐使用const char str[] char str[] = "Hello"; char* ptr = str; ptr[2] = 'S'; printf("指针指向字符串: %s\n", ptr); printf("指针指向字符串: %s\n\n", str); const char const_str[] = "Hello"; char* ptr_const_str = const_str; ptr[2] = 'S'; printf("指针指向const字符串: %s\n", ptr_const_str); printf("指针指向const字符串: %s\n\n", ptr_const_str); char* ptr_str = "World"; printf("字符串指针:%s\n", ptr_str); ptr_str[0] = "A"; printf("字符串指针:%s\n", ptr_str); }
总结:
使用指针指向变量字符串数组时可以通过指针修改字符串
使用字符串指针时不可以修改(默认const)
使用指针指向const字符串数组时修改无效
202.案例(略难):关于string.h_哔哩哔哩_bilibili 2025/1/19
写一个案例实现四个功能
- 给一句话替换里面的某个单词
- 统计字符
- 单词计数,一句话到底有多少个单词
- 独特的单词提取
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TEXT_SIZE 100
#define WORD_SIZE 50
#define DELIMS " /.,?!\n"
//给一句话替换里面的某个单词
//统计字数
//单词计数,一句话到底有多少个单词
//独特的单词提取
void replaceText(const char* text, const char* oldWord, const char* newWord, const char* result);
int countChar(const char* text, char Target);
int countWords(const char* text);
void extractUniqueWords(const char* text, char uniqueWords[][WORD_SIZE], int* uniqueCounts);
int main(void)
{
char text[TEXT_SIZE] = "This is a simple text, the text is for testing.";
char replacedText[TEXT_SIZE] = { 0 };
char* oldWord = "text";
char* newWord = "example";
char countCharTarget = 's';
char uniqueWords[TEXT_SIZE][WORD_SIZE] = { 0 };
int uniqueCounts = 0;
replaceText(text, oldWord, newWord, replacedText);
printf("replacedText: %s\n", replacedText);
int charCount = countChar(text, countCharTarget);
printf("'%c' appears %d times\n", countCharTarget, charCount);
int wordsCount = countWords(text);
printf("This text has %d words\n", wordsCount);
extractUniqueWords(replacedText, uniqueWords, &uniqueCounts);
puts("Total words:");
for (size_t i = 0; i < uniqueCounts; ++i)
{
printf("%s\n", uniqueWords[i]);
}
return 0;
}
void replaceText(const char* text, const char* oldWord, const char* newWord, char* result)
{
char buffer[TEXT_SIZE] = {0};
const char* pos = text;
const char* temp = text;
size_t oldLen = strlen(oldWord);
while ((temp = strstr(pos, oldWord)) != NULL)
{
strncat_s(buffer, TEXT_SIZE, pos, temp - pos);
strcat_s(buffer, TEXT_SIZE, newWord);
pos = temp + oldLen;
}
strcat_s(buffer, TEXT_SIZE, pos);
strcpy_s(result, TEXT_SIZE, buffer);
}
int countChar(const char* text, char target)
{
int count = 0;
while (*text)
{
if (*text == target)
{
count++;
}
text++;
}
return count;
}
int countWords(const char* text)
{
int count = 0;
char buffer[TEXT_SIZE] = { 0 };
strcpy_s(buffer, TEXT_SIZE, text);
char* context = NULL;
char* token = strtok_s(buffer, DELIMS, &context);
while (token != NULL)
{
count++;
token = strtok_s(NULL, DELIMS, &context);
}
return count;
}
void extractUniqueWords(const char* text, char uniqueWords[][WORD_SIZE], int* uniqueCounts)
{
char buffer[TEXT_SIZE] = { 0 };
char* context = NULL;
strcpy_s(buffer, TEXT_SIZE, text);
char* token = strtok_s(buffer, DELIMS, &context);
while (token != NULL)
{
int found = 0;
for (int j = 0; j < *uniqueCounts; ++j)
{
if (strcmp(token, uniqueWords[j]) == 0)
{
found = 1;
break;
}
}
if (!found)
{
strcpy_s(uniqueWords[*uniqueCounts], WORD_SIZE, token);
(*uniqueCounts)++;
}
token = strtok_s(NULL, DELIMS, &context);
}
}
203.第10章结束语_哔哩哔哩_bilibili
204.输入输出初步认识_哔哩哔哩_bilibili
- 输入流的数据首先被暂存到一个叫做缓冲区的内存区域。
- 缓冲区作用:提高数据的存储效率。它是批量读取而不是一个字节一个字节读取,设定一个缓冲区,一下子交给下一级(比如:内存 等)
- 缓冲区类似快递打包站
stdin:
当通过从键盘上输入数据的时候,数据首先被操作系统接收,然后存储在标准输入的缓冲区当中等待被程序读取。
stdout:
将输入发送到外部,发送到显示屏,文件等。