ThinkNotes

Simple is not easy | 化繁为简,知易行难

0%

环境

阿里云ECS, CentOS7, RAM 4G

安装Gitlab

1.安装ssh并配置

#安装
sudo yum install -y curl policycoreutils-python openssh-server
#配置开机启动
sudo systemctl enable sshd
#启动服务
sudo systemctl start sshd

2.配置防火墙

#启动防火墙
service firewalld start
#添加http服务到firewalld,pemmanent表示永久生效
sudo firewall-cmd --permanent --add-service=http
#重启防火墙
sudo systemctl reload firewalld

3.安装gitlab

#下载安装脚本
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.rpm.sh | sudo bash
#安装
yum install -y gitlab-ee

4.配置gitlab

阅读全文 »

1. 连接操作符:##

#define Conn(x,y) x##y

## 表示连接 , x##y 表示x连接y

示例:

int n = Conn(123,456);
     ==> int n=123456;
char* str = Conn("asdf", "adf");
     ==> char* str = "asdfadf";

## 的左右符号必须能够组成一个有意义的符号,否则预处理器会报错

2.字符串化和字符化: #, #@

(1) # 把任意类型的宏入参转化成字符串:

#define ToString(x) #x

符号 # 表示字符串化操作符(stringification)。
其作用是:将宏定义中的传入参数名转换成用一对双引号括起来参数名字符串。
其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。

阅读全文 »

1. 函数指针基本概念

C语言调用函数的本质是什么?

  1. CPU PC指针(program counter)跳转到函数的入口地址,传入参数,传入返回位置
  2. 在函数栈内生成临时变量并执行函数内容指令,执行完毕后返回参数
  3. CPU返回原调用处执行

这里,函数的入口地址实际上就存储在函数名中,也就是说,C代码中的函数名就是函数的入口地址。
既然是地址,就可以用来初始化一个指针,使指针指向该地址。
函数指针,就是存放函数首地址的指针。

1.2 函数指针变量

首先声明普通函数是如下格式:
void Func(int);
定义一个同类型函数的函数指针变量,只需要用*p表示函数名即可:
void (*p)(int);
注意,上面是定义了函数指针变量,而不是声明函数指针类型。

函数指针变量的定义,和普通变量格式不一样。

  • 普通变量: <类型> <变量名>
  • 函数指针:<函数类型 变量名>,按函数声明的格式定义,变量是包含在类型内部

那么此函数指针的类型是什么:
void (*)(int);

怎么使用此函数指针:

阅读全文 »

0.概述

C++除了支持面向对象,也支持函数的扩展和重用。继承类和多态充分支持了扩展,即基类进行概括抽象的设计,派生类实现具体的设计。那么重用呢,如何写一个函数,能在多种情况不加修改的套用?
考虑以下问题:

交换两个整型变量的值的Swap函数:
void Swap(int & x,int & y)
{
    int tmp = x;
    x = y;
    y = tmp;
}
交换两个double型变量的值的Swap函数:
void Swap(double & x,double & y)
{
    double tmp = x;
    x = y;
    y = tmp;
}

这两个函数除了入参类型不同,函数名,参数个数,返回类型都相同。函数体的处理流程也完全一样。能否只写一个Swap,就能交换各种类型的变量?
模板(template)将解决这种问题。

函数模板

函数模板的概念

用函数模板,设计仅数据类型不同的一组函数的通用模板:

template <class 类型参数1,class 类型参数2,……>
返回值类型 模板名 (形参表)
{
    函数体
};

template <class T> //在函数前声明模板,参数类型(class)是T
void Swap(T & x,T & y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

在普通函数前,先用template< class T >声明参数类型T,就可以在函数体使用T,就像使用普通变量一样。在运行时,T传入的类型不同,函数处理的数据类型也不同。
函数模板是如何实现的?它是一种函数吗?

int main()
{
    int n = 1,m = 2;
    Swap(n,m); //编译器自动生成 void Swap(int & ,int & )函数
    double f = 1.2,g = 2.3;
    Swap(f,g); //编译器自动生成 void Swap(double & ,double & )函数
    return 0;
}
阅读全文 »

0.概述

前文分析了C++类内成员的关系,本文讨论类和类之间的关系。
考虑用C++对现实世界的交通工具进行描述。

  • 汽车可能包含各种类型,小汽车,公交车,但他们能抽象出四个轮子,烧油这些基本属性
  • 飞机也有各种类型,但也能抽象出机翼,机身等基本属性
  • 轮船…

如果自顶向下设计,如何设计这些对象的类?

  • 提炼这些交通工具的共有属性,如材质,耗油量,价格,设计成一个交通工具基础类;然后设计一些操作方法,比如制造,启动,停止。
  • 分别设计汽车、飞机、轮船等更具体的类的属性,比如轮子、排水量等,注意,他们也包含基础类的材质,耗油量,价格等基本属性;然后也设计一些方法,比如制造汽车、开汽车和造飞机、开飞机等
  • 然后再设计更细节的类,作为汽车、飞机、轮船类的细化,比如A品牌的汽车,B品牌汽车,作为两个具体类。

仔细考虑以上步骤,有以下问题:

  • 这些类的属性(成员变量)是相互独立的吗?
  • 这些类的方法(成员函数)是相互独立的吗?

C++用类的“继承”描述层层细化的类及其成员变量的关系,用“多态”描述各层方法的实现关系。

类的继承

继承关系的概念

阅读全文 »

0.概述

C++,加的到底是什么?
除了基础语法的补充和优化,C++另外几个核心特点是:

  • 面向对象设计的支持:

    类和对象对变量和函数的封装
    类和类之间的继承
    继承关系的类之间的函数调用的多态

  • 数据结构和算法的支持
    STL和各种常用数据类型

  • 高可复用、可拓展的支持
    类模板,函数模板
    函数、运算符的重载

本文内容:

  • 面向对象设计的概念
  • 类和对象的概念及使用
  • 类的几种构造函数
  • 类的析构函数
  • 类对象的this指针
  • 类的嵌套:封闭类
  • 成员的属性:友元和常量成员

面向对象设计的概念

面向过程设计的不足

程序 = 数据结构 + 算法
程序由全局变量以及众多相互调用的函数组成,算法以函数的形式实现,用于对数据结构进行操作。
结构化程序设计风格中,变量和函数的关系:
image-20221208164648489
其缺陷在于:

  • 结构化程序设计中,函数和其所操作的数据结构,没有直观的联系
  • 随着程序规模的增加,程序逐渐难以理解:
    某个数据结构到底有哪些函数可以对它进行操作?
    某个函数到底是用来操作哪些数据结构的?
    任何两个函数之间存在怎样的调用关系?
  • 结构化程序设计难以维护:
    由于没有“封装”和“隐藏”的概念,要访问某个数据结构中的某个变量,就可以直接访问,那么当该变量的定义有改动的时候,就要把所有访问该变量的语句找出来修改,不利于程序的维护、扩充。
  • 结构化程序设计难以查错:
    当某个数据结构的值不正确时,难以找出到底是那个函数导致的。
  • 结构化程序设计难以重用:
    在编写某个程序时,发现其需要的某项功能,在现有的某个程序里已经有了相同或类似的实现,那么自然希望能够将那部分代码抽取出来,在新程序中使用。在结构化程序设计中,随着程序规模的增大,由于程序大量函数、变量之间的关系错综复杂,要抽取这部分代码,会变得十分困难。

面向对象的程序设计

阅读全文 »

0.概述

本章介绍C++语言和C语言相近的部分基础用法,包括

  • 引用: &
  • 常关键字: const
  • 动态内存分配: new delete
  • 函数内联: inline
  • 函数重载

引用和指针

引用的概念

下面的写法定义了一个引用,并将其初始化为引用某个变量。

类型名 & 引用名 = 某变量名;

某个变量的引用,等价于这个变量,相当于该变量起了一个别名。别名类似于操作系统的文件链接或快捷方式的概念,访问它变量本身的存储空间。

int n = 4;
int & r = n; // r引用了 n, r的类型是int &
r = 4;
cout << r; //输出 4
cout << n; //输出 4
n = 5;
cout << r; //输出5

注意:
1.定义引用时一定要将其初始化成引用某个变量。
2.初始化后,它就一直引用该变量,不会再引用别
的变量了。
3.引用只能引用变量,不能引用常量和表达式。

阅读全文 »

0.概述

结构体(Struct):存放一组不同类型的数据的数据结构。
数组(Array):存放一组相同类型的数据的数据结构。
结构体和int,char,指针等基础数据类型一样,也是一种数据类型。格式定义如下:

struct 结构体名{
    成员类型1 成员名1;
    成员类型2 成员名2;
}实例1,实例2;

结构体的成员(Member)可以为任意类型,如int,char,指针,甚至结构体类型。
结构体可以配合结构体数组、普通指针、函数指针、以及自身嵌套的使用方法,实现复杂数据结构,以及面向对象的代码风格。

1.结构体声明

声明是告诉编译器某个数据结构的定义。一般在头文件对结构体、函数等类型声明。声明过程不分配内存。
一个结构体类型的声明:

struct stu{
    char *name;     //姓名
    int num;        //学号
    int age;        //年龄
    char group;     //所在小组
    float score;    //成绩
};

注意:
1.结构体声明类似于函数声明,是一个语句,末尾加;
2.结构体声明只声明了类型,不实例化变量,因此不分配内存。
3.结构体成员的变量只在实例结构体才分配内存。

2.结构体实例

2.1基础方法

阅读全文 »

查找包含指定内容的文件

grep -r 字符串 目录

示例:查找当前目录的包含“stream”内容的文件:

1
grep -r "stream" ./

zip/unzip

1
2
zip xxx.zip -r <DIR>  
unzip xxx.zip -d <DIR>

背景

配置x’shell的默认字体以及一些操作设置

会话设置

设置主机
1
设置主机账号密码
2
设置xshell字体
3

操作设置

设置Ctrl+c,Ctrl+v复制粘贴
工具->选项->编辑按键
4
新建按键,按ctrl+c
5
设置功能为复制
6
同理设置ctrl+v为粘贴
注意,原shell的ctrl+c终止程序,被替换成了shift+ctrl+c