作者: ShiYu

  • 一些 C 的细节

    做专业课的题目的时候发现之前虽然写了很多代码但是还有很多细节是比较模糊的,这些细节在考试中还是经常遇到的!

    构成C程序的基本单位是函数

    最小单位:表达式
    基本单位:函数
    编译单位:文件

    字符串和字符数组

    • 对于字符数组,其长度是固定的,其中任何一个数组元素都可以为 null 字符。因此,字符数组不一定是字符串。
    • 对于字符串,它必须以 null 结尾,其后的字符不属于该字符串。字符串一定是字符数组,它是最后一个字符为 null 字符的字符数组。

    函数的声明

    正确: int fun(int, int) 
    在函数声明或定义时,可以不写形参的名字。这是因为编译器在这个阶段主要关心参数的类型和数量,而不是参数的具体名称。例如,int fun(int, int) 是一个 有效 的函数声明,它表明有一个名为 fun 的函数,该函数接受两个 int 类型的参数,并返回一个 int 类型的值。

    错误:int fun(int x, y)
    在C语言中,函数的参数列表中的每个参数都需要声明其类型。在int fun(int x, y)中,y没有声明其类型,这会导致编译错误。

    运算符优先级和结合性

    优先级运算符名称和含义使用型式结合方向种类说明
    1[]数组下标数组名[常量表达式]从左到右特殊运算符
    ()圆括号(表达式)
    函数名(形参表)
    .成员选择(对象)对象.成员
    ->成员选择(指针)对象指针->成员名
    2负号运算符– 表达式从右到左单目运算符
    (类型)强制类型转换(数据类型)表达式
    ++自增运算符++变量名
    变量名++
    算术运算符单目运算符
    自减运算符–变量名
    变量名–
    单目运算符
    *取值运算符*指针变量指针运算符单目运算符
    &取地址运算符&变量名单目运算符
    !逻辑非运算符!表达式逻辑作运算符单目运算符
    ~按位取反运算符~表达式位操作运算符单目运算符
    sizeof长度运算符sizeof(表达式)求字节数运算符
    3/表达式 / 表达式从左到右算术运算符双目运算符
    *表达式*表达式双目运算符
    %余数(取模)整型表达式%整型表达式双目运算符
    4+表达式 + 表达式从左到右双目运算符
    表达式 – 表达式双目运算符
    5<<左移变量<<表达式从左到右位操作运算符双目运算符
    >>右移变量>>表达式双目运算符
    6>大于表达式 > 表达式从左到右关系运算符双目运算符
    >=大于等于表达式 >= 表达式双目运算符
    <小于表达式 < 表达式双目运算符
    <=小于等于表达式 <= 表达式双目运算符
    7==等于表达式 == 表达式双目运算符
    !=不等于表达式 != 表达式双目运算符
    8&按位与表达式 & 表达式从左到右位操作运算符双目运算符
    9^按位异或表达式 ^ 表达式从左到右双目运算符
    10|按位或表达式 | 表达式从左到右双目运算符
    11&&逻辑与表达式 && 表达式从左到右逻辑运算符双目运算符
    12||逻辑或表达式 || 表达式从左到右双目运算符
    13?:条件运算符表达式1? 表达式2: 表达式3从右到左条件运算符三目运算符
    14=赋值运算符变量 = 表达式从右到左赋值运算符
    /=除后赋值变量 /= 表达式
    *=乘后赋值变量 *= 表达式
    %=取模后赋值变量 %= 表达式
    +=加后赋值变量 += 表达式
    -=减后赋值变量 -= 表达式
    <<=左移后赋值变量 <<= 表达式
    >>=右移后赋值变量 >>= 表达式
    &=按位与后赋值变量 &= 表达式
    ^=按位异或后赋值变量 ^= 表达式
    |=按位或后赋值变量 |= 表达式
    15,逗号运算符表达式,表达式,…从左到右逗号运算符

    可变参数

    在C语言中,argcargv是用于命令行参数传递的两个变量。它们通常在main()函数中定义,用于接收从命令行传递给程序的参数。下面是它们的作用和用法:

    • argc(argument count):它表示传递给程序的命令行参数的数量,包括程序名称本身。因此,至少为1。它是一个整数类型的变量。
    • argv(argument vector):它是一个指向字符指针数组的指针,用于存储传递给程序的命令行参数的字符串。每个元素指向一个命令行参数的字符串。数组的最后一个元素后面是一个NULL指针。

    将程序prog.c编译链接后运行:prog -nla hello world则*(*(argv+2))是( )

    A. ‘p’
    B. ‘-‘
    C. ‘h’
    D. ‘w’

    argv+2            //地址加2,相当于argv[2]的地址
    *(argv+2)        //表示字符数组argv[2],同时表示字符串‘hello’的首地址
    *(*(argv+2))    //首地址上的值,也就是‘h’
    
    调试输出:
    PS C:\Users\i\Desktop\Code\cpp> ./test.exe  -nla hello world
    4
    argv[0] = C:\Users\i\Desktop\Code\cpp\test.exe
    argv[1] = -nla
    argv[2] = hello
    argv[3] = world
    *(*(argv+2)) = h

    存储类型 register 和 extem

    在C语言中,registerextern是两个不同的关键字,具有不同的用途。

    1. register关键字:
      • register是C语言中的一个存储类说明符,它建议编译器将某个局部变量存储在寄存器中,而不是在RAM中,从而加快对该变量的访问速度。
      • 使用register关键字的局部变量被称为寄存器变量。
      • 请注意,register只是一个建议,编译器可以选择忽略它。现代编译器通常能够自动选择将哪些变量放入寄存器,因此register关键字在现代C语言编程中不太常用。示例:
    register int counter;
    1. extern关键字:
      • extern用于声明一个变量或函数是在别的文件中定义的,而不是在当前文件中定义的。
      • 通过使用extern,你可以在当前文件中引用在其他文件中定义的变量或函数。
      • extern通常用于多文件编程,以实现变量和函数的跨文件访问。示例:
    // file1.c
    int globalVar = 10;
    
    // file2.c
    extern int globalVar; // 使用extern来引用在file1.c中定义的globalVar

    所有的数据都有两种类型,一是常见的数据类型,如int,float等,一种便是存储类型。总共有四种存储类型的变量,分别为自动变量(auto)、静态变量(static)、外部变量(extern)以及寄存器变量(register)。

    定义:

    1、自动变量:函数中所有的非静态局部变量。
    2、静态变量:在变量前加上static关键字的变量。
    3、外部变量:一般用作全局变量作用域的扩展(还有定义外部函数的时候前面也可以有一个extern关键字,具体外部函数请看下面)。
    4、寄存器变量:一般经常被使用的的变量(如某一变量需要计算几千次)可以设置成寄存器变量,register变量会被存储在寄存器中,计算速度远快于存在内存中的非register变量。

    存储变量关乎着变量的作用域和生存时间

    1、从作用域(空间)的角度来看:

    自动变量:其作用域仅仅局限于其定义的函数中,存储在动态存储区,注意存储在动态存储区的数据,在没有显式初始化的时候,其变量的值是随机的,无用的。

    静态变量:存储在静态存储区,静态变量包括静态全局变量和静态局部变量,静态变量在没有显式初始化的时候会被初始化为0或者null,并且只初始化一次(初始化不等同于赋值)。

    静态全局(外)变量:作用域只是在其定义的源文件中有效,对外部变量起到了“屏蔽”的作用。
    静态局部变量:其作用域是其定义的函数中。

    外部变量:把全局变量在其他源文件中声明成extern变量,可以扩展该全局变量的作用域至声明的那个文件,其本质作用就是对全局变量作用域的扩展。

    寄存器变量:存储在cpu的寄存器中,速度快,一般不需要程序员定义寄存器变量,这是由于一些编译器会把需要参加很多次计算的变量转化成寄存器变量,不允许程序员对寄存器变量的地址进行操作。

    2、从生存时间的角度来看:

    自动变量:随着函数的进栈和出栈而创建和销毁

    静态变量:长期存在静态存储区,直到程序结束

    外部变量:长期存在静态存储区,直到程序结束

    寄存器变量:离开函数值就会消失

    static

    静态存储类型定义变量在未对其初始化时会对其初始化为默认值,其中int 型的默认初始化是0,其他选项的存储类型不能保证。

    修饰符类型

    C++ 允许在 char、int 和 double 数据类型前放置修饰符。

    修饰符是用于改变变量类型的行为的关键字,它更能满足各种情境的需求。

    下面列出了数据类型修饰符:

    • signed:表示变量可以存储负数。对于整型变量来说,signed 可以省略,因为整型变量默认为有符号类型。
    • unsigned:表示变量不能存储负数。对于整型变量来说,unsigned 可以将变量范围扩大一倍。
    • short:表示变量的范围比 int 更小。short int 可以缩写为 short。
    • long:表示变量的范围比 int 更大。long int 可以缩写为 long。
    • long long:表示变量的范围比 long 更大。C++11 中新增的数据类型修饰符。
    • float:表示单精度浮点数。
    • double:表示双精度浮点数。
    • bool:表示布尔类型,只有 true 和 false 两个值。
    • char:表示字符类型。
    • wchar_t:表示宽字符类型,可以存储 Unicode 字符。

    修饰符 signed、unsigned、long 和 short 可应用于整型,signed 和 unsigned 可应用于字符型,long 可应用于双精度型。

    这些修饰符也可以组合使用,修饰符 signed 和 unsigned 也可以作为 long 或 short 修饰符的前缀。例如:unsigned long int

    C++ 允许使用速记符号来声明无符号短整数无符号长整数。您可以不写 int,只写单词 unsigned、short 或 longint 是隐含的。

    常量

    整数常量

    整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。

    整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。

    下面列举几个整数常量的实例:

    212         /* 合法的 */
    215u        /* 合法的 */
    0xFeeL      /* 合法的 */
    078         /* 非法的:8 不是八进制的数字 */
    032UU       /* 非法的:不能重复后缀 */

    以下是各种类型的整数常量的实例:

    85         /* 十进制 */
    0213       /* 八进制 */
    0x4b       /* 十六进制 */
    30         /* 整数 */
    30u        /* 无符号整数 */
    30l        /* 长整数 */
    30ul       /* 无符号长整数 */

    整数常量可以带有一个后缀表示数据类型,例如:

    实例

    int&nbsp;myInt&nbsp;=&nbsp;10;
    long&nbsp;myLong&nbsp;=&nbsp;100000L;
    unsigned&nbsp;int&nbsp;myUnsignedInt&nbsp;=&nbsp;10U;  

    浮点常量

    浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。

    当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。带符号的指数是用 e 或 E 引入的。

    下面列举几个浮点常量的实例:

    3.14159       /* 合法的 */
    314159E-5L    /* 合法的 */
    510E          /* 非法的:不完整的指数 */
    210f          /* 非法的:没有小数或指数 */
    .e55          /* 非法的:缺少整数或分数 */

    浮点数常量可以带有一个后缀表示数据类型,例如:

    实例

    float&nbsp;myFloat&nbsp;=&nbsp;3.14f;
    double&nbsp;myDouble&nbsp;=&nbsp;3.14159;  

    字符常量

    字符常量是括在单引号中,例如,’x’ 可以存储在 char 类型的简单变量中。

    字符常量可以是一个普通的字符(例如 ‘x’)、一个转义序列(例如 ‘\t’),或一个通用的字符(例如 ‘\u02C0’)。

    在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:

    转义序列含义
    \|\ 字符
    \’‘ 字符
    \”” 字符
    \?? 字符
    \a警报铃声
    \b退格键
    \f换页符
    \n换行符
    \r回车
    \t水平制表符
    \v垂直制表符
    \ooo一到三位的八进制数
    \xhh . . .一个或多个数字的十六进制数

    下面的实例显示了一些转义序列字符:

    实例

    #include <stdio.h>
    int main()
    {
        printf("Hello\tWorld\n\n");
        return 0;
    }

    当上面的代码被编译和执行时,它会产生下列结果:

    Hello World

    字符常量的 ASCII 值可以通过强制类型转换转换为整数值。

    实例

    char&nbsp;myChar&nbsp;=&nbsp;'a';
    int&nbsp;myAsciiValue&nbsp;=&nbsp;(int)&nbsp;myChar;&nbsp;// 将 myChar 转换为 ASCII 值 97  

    字符串常量

    字符串字面值或常量是括在双引号 ” ” 中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。

    您可以使用空格做分隔符,把一个很长的字符串常量进行分行。

    下面的实例显示了一些字符串常量。下面这三种形式所显示的字符串是相同的。

    "hello, dear"
    
    "hello, \
    
    dear"
    
    "hello, " "d" "ear"

    字符串常量在内存中以 null 终止符 \0 结尾。例如:

    char myString[] = "Hello, world!"; //系统对字符串常量自动加一个 '\0'
  • 十一月十七

    时隔多日,中午在昨天去济南找女朋友啦,可是现在时间真是太紧张了,见面前刘兰婷还嘱咐我:你要带着书,我们还是要学习

    昨天下午七点多到了济南印象城,刘兰婷突然想吃酸奶麻花,让我来的时候顺路买一些,我在这里转了转就发现教堂下面有一家麻花店,可是已经关门了,就在这里买了一些小吃一会带回去吃

    左图即十一月十六晚的洪家楼教堂

    晚上时间过得太快了,吃完饭学了会习就凌晨2点了,这次我居然还不困,之前在宿舍晚上十一点半之后就想睡觉啦。

    第二天中午去吃了吃胖哥俩,之前就经常听刘兰婷说这家店的牛蛙好吃,要带我去吃,这次终于吃到啦,不过还有刘兰婷还说过济南的好多好多好吃的只能以后再慢慢去吃啦,我从上个学期开始到现在都胖了好多,刘兰婷说我脸圆了一圈,不能这么吃下去了😭😭😭 小猫叠猫猫有点可爱!

    下次见面应该是在12月24日之后啦

  • 中文字体分片

    之前看到 @林木木 的这篇文章时,觉得霞鹜文楷这个字体很好看,于是在本站也启用了,这个字体和我平常见到的网页的字体很不一样,就是感觉加载速度特别快。它不像其他网页一次性加载整个字体,而是分批加载,就像慢慢展开的画面一样。这让我很好奇,于是查了一下,原来是因为一种特殊的CSS属性叫做”unicode-range“。

    这个属性的作用是设置要由所定义的字体中使用的字符的特定范围,这样就可以把整个字体文件切成很多小块,一个很大的字体文件在打开网页时可能只需要加载一小部分文件分块,足够显示页面上的文字。这样极大的加快了字体文件的加载速度。

    后面又发现了一个中文字体分包的项目:✨中文网字计划

    在这里提供了大量已经进行分片的字体的cdn,可以很方便的直接引用,也提供了在线分片工具,可以一键上传分片然后下载下来使用~

    现在本站使用的字体也是在这个项目上进行分包的,加载速度快得很!

  • 落叶惊秋

    九月,就这样匆匆过去了。我原本打算在九月的最后一天,用一篇文章来纪念这个月的点点滴滴,然而,我却咕了。

    九月十七日的夜晚,我和室友都学不进习就一起出去吃了烤串羊排,这个羊排真的不错很香!我们围坐在热闹的路边摊,伴随着烤肉的香气和夜色中的灯火,享受着这个美好的夜晚。

    而九月最重要的事情,当然就是考研的预报名啦。我和很多人一样,在报名之前,对于学校和专业都有着许多的犹豫和选择。那是一段充满了纠结和迷茫的日子,我不断权衡着自己的兴趣和未来的发展前景。直到九月二十四日,报名开始的那天,我才最终决定了我的志愿。原本我选择了软件工程,但考虑到招生人数的问题,我最后选择了招生人数更多的计专。

    番茄ToDo还挺好用的,刘兰婷一直在用,我之前用过一次觉得作用不大,后来刘兰婷让我来下一个监督我学习。看得出来我真的很爱数学(不是

    中秋和国庆的假期,我选择留在学校继续学习。中秋节的晚上,我和室友们一起出去吃了火锅,又去了小青城火锅店。老板还很热情地送了我们月饼

    这样九月份也就结束了,之前制定的九月份的学习计划依旧没有完成,目标和现实总是有些差距,不过不影响,十月份该干啥继续干啥就得了

    今天十月一,第一次模拟做了套数学真题,不到俩小时就做完了,大题空了一半!结果批改的时候出乎意料的选择填空全对了,大题也基本做出来的都对了(可能因为01年的真题确实够简单的)

    最近还发现了俩超级好用的下载器( XDM MediaDownloader

    XDM是一个比较强大的下载器,可以代替IDM使用,下载网页中的资源很方便,但是我用来下载一些加密的m3u8视频时无法播放,不知道是不是我操作有问题🥲

    MediaDownloader 是一个开源的超级方便的网页视频下载器,网页中只要能播放的视频都能下载下来,素材提取页面可以当浏览器去浏览网页,会自动嗅探网页中的视频资源,并且可以下载转码成mp4,支持加密的m3u8视频!简直是我用过最好用的下载器啦!

  • 明信片

    某天逛博客的时候发现了 @关关和六六 正在举办的一个寄送明信片的活动

    身为00后好像对邮政,信件的概念很弱,我从未亲手接过从远方寄来的纸质书信,从未感受过那淡淡的墨香和纸上留下的温度,感觉上似乎少了点什么,而且对于邮票,我只能在图片和故事中欣赏它的存在,从未曾见过它的真实模样,也让我有些许遗憾。

    所以我忍不住想要参与这个活动,想要尝试着去体验这种浪漫。