Jialong's Blog

Do things I love, and seek happiness.

0%

0.前言

第一次使用Tex语言完整地完成了一篇实验报告的构建排版,这过程中遇到了各种各样的问题,有些问题虽然解决了,但在原理方面还是一知半解,之后再遇到还希望能多看文档。这篇博客是来记录第一次编写过程中遇到的一些问题。

这是第一次实验报告导出的pdf文档封面展示:

这是tex源代码

阅读全文 »

1.3 指数信号与正弦信号

1.3.1 连续时间复指数信号与正弦信号

连续时间复指数信号有如下形式: \[ x(t)=Ce^{at} \]

实指数信号

上式中的\(C\)\(a\)都为实数的信号。

周期复指数信号和正弦信号

第二种重要的信号为将上式\(a\)限制为纯虚数的信号(复指数信号): \[ x(t)=e^{jw_0t} \] 当基波周期\(T_0 = \left| \frac {2\pi} {w_0} \right|\)时,该信号是周期信号。

阅读全文 »

理解本文的基础是公钥密码加密,即非对称加密,比如其中一种非对称加密算法RSA。

非对称加密使用一对密钥,一个为公钥Pub,另一个为私钥Priv

明文P经过公钥Pub使用RSA加密算法混淆后变成了密文M,密文M无法用公钥Pub解开,只能用私钥Priv解开

同样的,明文P经过私钥Priv使用RSA加密算法混淆后变成了密文N,密文N只能用公钥Pub解开

阅读全文 »

转眼间2019年就要结束了,依稀记得2019年的刚开始我还在发空间动态说自己又买了一本日历,然而...明年就不买了吧,我并没有记得经常去看日历,更别说去每天一张一张地撕它。这一年里经历了非常多的事情,从学习、生活、关于未来的各方各面,我都发生了极大的改变,这源于我不断变化的想法,目标总是飘忽不定,我思考过,也经常迷茫,现在也是。

在写下这些话的时间里,我其实是非常难过和害怕的,这一个周末似乎没干什么事情就又要浑浑噩噩地结束了,直到现在还有一个DDL等着我,明早截止,我还没做完,间歇性拖延症晚期这件事情,一直发生在我身上,毫不夸张地说,我可以不间歇地拖延整整24小时,这过程中总想着做些什么、改变些什么,但除了睡觉,大部分时间眼睛都盯在手机屏幕上,尽管我知道这样做一点儿也不好,但结果还是发生了。我知道学习的重要性,也会去为了一个想要实现的东西不断地思考并找到解决方法,就比如搭建网站这件事情,前前后后花了很多的时间也学习了很多相关知识,基本掌握了中间的原理,结果在我预想的时间之前很久就做出来了,结果还是超乎预期的好。说实话,完成一件能看的到结果的事情能给人的心理带来很大的快感的愉悦,但愉悦过后,又只剩下了迷茫和拖延,并且在为了找到下一个实践目标而苦苦挣扎着。有时候大脑盯着手机屏幕看一些信息的时候,知道这是自己不想接收和浪费时间的,但就是控制不住自己去点开看,这样的人性的弱点也造就了很多的商机,造就了很多企业和公司的成功。

说点儿别的。在关于情感和人际交往方面,我可能是一个与绝大多数人都不一样的人,在情感上,我很少与他人或者是在公开场合表露(包括我的社交媒体,我发现,自己现在很少在社交媒体上表露自己的情感,更多的是分享一些自己的兴趣爱好,比如我热爱的摄影,因而,我也就把自己的空间对所有人开放了,微信这个东西另当别论,说实话,我挺讨厌这个软件的),但我还是知道自己想要的是什么,纵然我在过去的一年里总是带着一些自卑的情感,很久没有与他人进行深入内心的交谈,KY的与陌生人打电话活动也错过了很多次,每次都是在想和别人深入交流的时候才想起来,结果肯定是已经结束了,今后还是要多多关注,想想能与一同关注KY的人打电话是一件挺幸福的事情,也希望自己能早日找到灵魂伴侣。在人际交往方面,我尝试过学校的很多社团和活动,最终无一例外全都放弃了,我觉得也挺好,这也证明了我确实不喜欢过多的浮于表面和拉帮结派建造复杂人际关系的事情,做好自己就最好了,能认识几个朋友还是随缘了,人也并不需要那么多看上去像是朋友的朋友。

扯了这么多,还是回到最重要的学习和事业上吧。12月希望自己能好好学习学校的课程知识,好好地应对一下考试。明年下半年就要大三了,这学期结束以后要为成为一个前端工程师立一些目标,毕竟就快要毕业了,还是希望自己能去做自己喜欢的工作,上研究生这件事就暂时不考虑了,我在经历了一些事情以后对于读研这件事一点儿也不感兴趣了,做好自己就好了。

以上。

GitBook作为一个非常好用的基于Node.js的命令行工具,可以输出HTML、PDF、eBook等多种格式的电子书,这里就不再详细讲述GitBook的构建以及发布到Github托管的过程,网络上有非常多的教程,可以自行Google查看。

刚开始在每次更新内容的时候都需要一系列的git命令将原始内容仓库和构建的网页仓库同步到Github上,大概需要10条命令,如果你的更新频率很高的话,发布内容将会是有个痛苦的过程,但这里我们可以通过一个shell脚本只使用$ sh deploy.sh一条命令完成同步内容和构建网页的所有过程。

首先,在你的GitBook内容根目录下建一个deploy.sh文件,使用文本编辑器打开,然后输入以下内容:

#!bin/sh
git checkout master
# 切换到master分支,及内容所在的仓库
git add .
git commit -m "Update"
git push -u origin master
# 添加、提交到Git仓库,然后push到Github上
gitbook build
# 构建Gitbook
git checkout gh-pages
# 切换到gh-pages分支,即生成的HTML网页的仓库
cp -r _book/* . 
# 复制前面构建的内容
git add .
git commit -m "Update"
git push -u origin gh-pages
# 添加、提交到Git仓库,然后push到Github上
git checkout master
# 返回master主分支

然后打开命令行,为这个脚本授权:

$ chmod +x deploy.sh

至此就完成了,以后在更新的时候只需要输入一条命令$ sh deploy.sh就可以完成所有操作了。

一、储存类别

  • 对象:具有一定大小空间的一块内存。
  • 标识符:用来指定特定对象的内容。
  1. 作用域
    • 描述了程序中可访问标识符的区域。
    • 分类:
      • 块作用域
      • 函数作用域
      • 文件作用域
      • 函数原型作用域:从形参定义处到原型声明结束。
    • 全局变量:也称为文件作用域变量。
  2. 链接
    • C变量的三种链接属性:
      • 外部链接:该类型变量可以在多文件程序中使用
      • 内部链接:该类型变量只能在一个翻译单元中使用
      • 无链接:具有块作用域、函数作用域或函数原型作用域的变量
    • 储存类别说明符static
  3. 存储期:
    • C对象有4种
      • 静态存储期:在程序的执行期间一直存在,文件作用域变量都具有静态存储期。
      • 线性存储期:用于并发程序设计。
      • 自动存储期:所有局部变量都有该性质,在函数调用时被创建,离开函数时被销毁。
      • 动态分配存储期:
  4. 自动变量
    • 属于自动存储类别,有自动存储期、块作用域、无链接。
    • 可显式使用关键词auto
    • 块作用域和无链接意味着只有在变量定义的块中才能通过变量名访问该变量。
  5. 寄存器变量
    • 特殊的自动变量。也是自动存储期、块作用域、无链接。
    • 可以显式使用关键词register,是一种请求,编译器可能会拒绝你的请求,此时就变成了普通变量,但仍然无法访问该变量的内存。
    • 作用是储存在最快的可用内存中,能够以更快的速度访问。
    • 存储在寄存器中而非内存中,所以无法获取寄存器变量的地址。
  6. 块作用域的静态变量
    • 静态指的是在内存中原地不动,但它的值可以改变。
    • 具有块作用域、无链接、有静态存储期。
    • 在块中static(提供静态存储期)声明这种变量。
    • 如果未显式地初始化静态变量,它们会被初始化为0
  7. 外部链接的静态变量
    • 具有文件作用域、外部链接、静态存储期。
    • 有时又称为外部存储类型、该类别地变量被称为外部变量
    • 创建过程:在所有函数外面(定义性声明)创建这个外部变量。
    • 函数使用该变量时,为了指出使用的是外部变量,可以用关键字extern再次声明。
    • 如果一个源文件使用的外部变量定义在其他文件中,则必须用extern在该文件中声明该变量。
    • 定义式声明、引用式声明。
  8. 内部链接的静态变量
    • 具有静态存储期、文件作用域、内部链接。
    • 所有函数外部,用存储类别说明符static定义该类变量。
    • 该类型变量只能用于同一个文件中的函数
    • 可以在函数中使用类别说明符extern重复声明该类型变量,这并不会改变其链接属性。
  9. 多文件(多翻译单元)
    • 程序在多个翻译单元中才能体现区别内部和外部变量的重要性。
  10. 存储类别的选择
    • 正常情况下多使用自动存储类别,使用外部变量可能在不经意中修改变量的值,count类型变量除外。

二、

1.建立结构变量

struct book {
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
}
  • 该结构描述了由两个字符数组和一个float类型变量组成的结构。

2.定义结构变量

struct book library;

  • 把library声明为一个使用book结构类型的结构变量。

  • 所以struct book 相当于过去的int、double等类型。

    struct book {
        char title[MAXTITL];
        char author[MAXAUTL];
        float value;
    } library;

    该程序为上面声明的完整版。

    struct { //无结构标记
        char title[MAXTITL];
        char author[MAXAUTL];
        float value;
    } library;

    声明结构和定义结构可以一步完成,如上所示。

3.初始化结构

4.访问结构成员(点运算符)

5.结构初始化器

6.结构数组

struct book library[MAXBKS];

7.指向结构的指针

struct guy * him;

  • 指针可以指向任何现有的guy类型如barney、fellow[0](一个结构数组的一项即为一个结构变量)。

him = &barney or him = &fellow[0];

8.用指针访问成员

him == &barney,那么him->income即是barney.income.

同时,*him即为指针指向的结构类型。所以,

barney.income == (*him).income == him->income

9.向函数传递结构的成员、地址、结构本身

10.其他特性:

  • 使用指针传递信息(作为函数参数):是使用原始结构进行计算的。
  • 使用结构作为函数参数:是使用副本进行计算。

一、字符串输入

1.gets()函数

  • 使用方法:读取整行输入,直到遇到换行符,然后丢弃换行符,储存其余的字符,并在字符末尾添加一个空字符使之成为一个C字符串。
  • 使用中存在的问题:gets(words)(char words[STLEN])的唯一参数为words,该函数无法检查数组是否装得下输入行。数组名会被转化成该数组首元素的地址,该函数只知道数组的开始处,并不知道数组在何处结束。
  • 如果输入过长,会导致缓存区溢出,详情见书上内容。

2.gets()的替代品:fgets()函数

  • fgets()函数通过第二个参数来限制读入的字符数来解决溢出问题。
  • 相较于gets()的区别:
    • 第二个参数指明了读入字符的最大数量,若该值为n,那么将读入n-1个字符,或遇到第一个换行符为止。
    • 第三个参数指明了要读入的文件,如果要从键盘输入,则参数设置为stdin标识符。
    • 如果读到一个换行符,fgets()会将其储存在数组中,而不是将其丢弃。

3.gets_s()函数

  • fgets()的区别

    • 该函数只从标准输入中读取,所以无需第三个参数。

    • 读到换行符会将其丢弃

    • 如果读到最大字符数都没有读到换行符,会进行以下操作:

      首先设置目标数组的首字符为空字符

      读取并丢弃随后的输入直至读到换行符或文件结尾

      返回空指针

      然后调用依赖实现的“处理函数”

4.s_gets()函数

  • 读取整行输入并用空字符替代换行符,或者(在字符串未结束就遇到了空字符)读取一部分输入,并丢弃其余的部分。

该函数的代码:

char * s_gets(char * st, int n)
{
    char *ret_val;
    int i = 0;
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        while (st[i] != '\n' && st[i] != '\0')
            i++;
        if (st[i] == '\n')
            st[i] = '\0';
        else 
            while (getchar() != '\n')
                continue;
    }
    return ret_val;
}

5.scanf()函数

  • 以第一个非空白字符座位读取的开始,以第一个空白字符(空行、空格、制表符、换行符)座位字符串的结束。
  • 其他内容略。

二、字符串输出

1.puts()函数

  • 该函数显示字符串时会在末尾添加一个换行符
  • 该函数的参数为地址,且用双引号括起来的字符串常量作为参数时,参数被视为该字符串的地址。
  • 当参数为数组中某个项的地址时,如str[5],会从这个位置开始依次输出。
  • 结束条件为空字符

2.fputs()函数

  • 第二个参数要指明写入数据的文件,若要打印在显示器上,则用stdout作为参数。
  • 该函数不会在字符串末尾添加换行符

3.printf()

  • 省略

三、字符串函数

0.这里只写出书上详细介绍的5组字符串函数:strlen() | strcat()/strncat() | strcmp()/strncmp() | strcpy()/strncpy() | sprintf()

1.strlen函数

  • 该函数用于统计字符串的长度,函数返回值为字符串的长度。

2.strcat()函数

  • 基本定义
    • 该函数用于拼接字符串
    • 接受两个字符串作为参数
    • 把第二个字符串的备份附在第一个字符串的末尾,并把拼接后形成的新字符串作为第一个字符串,第二个字符串不变。
    • 该函数的函数类型是char *,即指向char的指针。
    • 所以该函数返回第一个参数,即拼接第二个字符串后的第一个字符串的地址
  • 存在的问题
    • 无法检查第一个数组是否能容纳第二个字符串。

3.strncat()函数

  • 该函数的第三个参数指定了最大添加字符数
  • 例如strncat(bugs, addon, 13)会把addon字符串的聂荣附加给bugs,加到第13个字符或者遇到空字符的时候停止
  • 所以,算上空字符(必须要添加空字符,否则就不是字符串了),bugs数组应该足够大,以容纳原始字符串(不包含空字符)、添加在后面的13个字符、末尾的空字符。

4.strcmp()函数

  • 用来把用户的响应于已储存的字符串作比较(比较两个字符串的内容)
  • 比较的是字符串的内容而不是字符串的地址,例如
    • 定义:
      • #define ANSWER "Grant"
      • #define SIZE 40
      • char try[SIZE]
      • s_gets(try, SIZE)\
      • 如果使用while (try == ANSWER),则永远得不到两者相等的结果,因为while比较的是指针,即地址,二者的地址肯定不相同
      • 但使用strcmp(try, ANSWER)则能够得到两者内容相等的结果。
    • 注:该函数只会比较try中第一个空字符前面的部分,所以该函数可以比较储存在不同大小数组中的字符串。
  • 该函数的返回值:
    • 返回实例:
      • 比较“A"和本身,返回0
      • 比较”A"和"B",返回-1
      • 比较“B"和”A“,返回1
    • 结论:
      • 二者相等返回0
      • 第一个的ASCII码比第二个大就返回负数,比第二个大就返回整数
      • 返回的整数和负数即为二者的ASCII码之差
    • 注:
      • 返回值的具体数值并不重要,重要的是它是0还是非0
      • 该函数比较的是字符串而不是字符
  • 局限:
    • 该函数比较字符串中的字符,直到发现不同的字符为止,这个过程可能会持续到字符串末尾。

5.strncmp()函数

  • 该函数可以比较字符不同的地方,也可以只比较第三个参数指定的字符数

  • 例如书中的实例:可以限定函数只查找这几个字符。


6.strcpy()函数

  • 该函数是用来拷贝整个字符串的内容,即相当于字符串赋值运算符
    • 例如:
      • str1和str2都是指向字符串的指针
      • str2 = str1;这个语句拷贝的指针的地址而不是具体内容
      • 所以要想拷贝整个字符串就要用到该函数
    • 注意:
      • 接受两个字符串指针作为参数,可以把第二个指针声明为指针、数组或者字符串常量
      • 第一个指针应该指向一个数据对象如数组,且该字符串有足够的空间存储源字符串的副本。
    • 其他属性:
      • 该函数的返回类型是char *,返回的是第一个参数的值,即一个字符的地址。
      • 第一个参数不必指向数组的开始,该属性可用于拷贝数组的一部分,详情见书上的程序。
  • 局限:
    • strcat()一样,不能检查目标空间是否能容纳的下源字符串的副本。

7.strncpy()函数

  • 该函数的第三个参数指明了可拷贝的最大字符数
    • 如果要拷贝的字符超过了指定的参数n,当拷贝了n个字符后就会停止,并且也不会在后面添加空字符,容易出现错误,所以要非常注意。

8.sprintf()函数

  • 该函数与printf()函数类似,但这个是把数据写入字符串,而不是打印在显示器上。

  • 该函数的第一个参数是目标字符串的地址,其余的与printf()类似。

    • 示例:
    char first[MAX];
    char last[MAX];
    char formal[2 * MAX + 10];
    //给以上前面两个数组赋值后就可以进行如下的操作
    sprintf(formal, "%s, %-19s\n", last, first);

一、抽象数据类型的实现

//数据类型的实现
public class Counter
{
    //实例变量
    private final String name;
    private int count;
    
    //构造函数
    public void Counter(String id)
    { name = id; }
    
    //实例方法
    public void increment()
    { count++; }
    public int tally()
    { return count; }
    public String toString()
    { return count + " " + name; }
}
//测试该数据类型的用例
public static void main(String[] args)
{
    //创建并初始化对象
    Counter heads = new Counter("heads");
    Counter tails = new Counter("tails");
    
    //调用实例方法
    heads.incerment();
    heads.increment();
    tails.increment();
    
    StdOut.println(heads + " " + tails);
    StdOut.println(heads.tally + tails.tally() ;)
}

相关概念

  • 实例变量:
    • 一个实例变量对应了无数的值,因为数据类型的每个实例对象都有有个。
  • 构造函数:
    • 构造函数是用来创建一个对象的表示,即来初始化实例变量。
    • 它由可见性修饰符、构造函数名称(即数据类型的名称)、参数变量以及初始化实例变量的代码构成。
    • 上一条加粗的三个组成了签名,例如public Counter (String id)即为一个签名。
  • 实例方法:
    • 是每个对象的具体行为,即实现数据类型的实例方法。
    • 与静态方法的唯一区别是它能够访问并操作实力变量。
  • 作用域
    • 参数变量:作用域为整个方法。
    • 局部变量:定义后的所有语句(一个花括号内)。
    • 实例变量:整个类。