自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(34)
  • 收藏
  • 关注

原创 Socket

套接字Socket套接字用于两个进程之间互相通信,与其他所有进程间通信方式不同的是,这两个进程可以分别位于两台不同的用网络连接的计算机。同时,Socket也可以用来连接同一台计算机上的两个进程。套接字使用流程首先,服务器应用会使用Socket()创建一个套接字,它是系统分配给该服务器进程的类似文件描述符的资源,不能与其他进程共享。接下来,服务器进程会给套接字起个名字。本地套接字的名字是Linux文件系统中的文件名,一般放在/tmp或/usr/tmp中。对于网络套接字,它的名字是与客户端连接的特定网络有

2021-03-12 17:40:23 203

原创 IPC

进程之间的通信(System V IPC)在系统运行的过程中,常常需要让多个进程互相通信。实现这样功能的方式有很多种,例如文件锁和管道,这里介绍一组由Linux系统提供的机制,称为System V IPC。这一组机制中包含了三种方式,他们分别是信号量,共享内存和消息队列。信号量信号量用来实现系统资源的互斥访问,这里讲的是进程之间的资源互斥访问,线程之间的互斥访问不能使用这样的方式,关于如何使用线程之间的信号量,可以看[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pZE6

2021-03-05 17:18:15 152

原创 管道通信

管道通信进程之间可以互相交换数据,其工作方式是通过管道来实现。在Linux环境中,很多时候可以使用管道符|来让不同进程之间通过管道通信。例如命令ls | cat。这个命令使命令ls的标准输出内容通过管道传达给cat命令的标准输入。C标准管道操作C语函数库<stdio.h>中提供了比较高级的函数来打开和关闭管道,它们是:#include <stdio.h>FILE * popen(const char * command, const char * open_mode);i

2021-03-03 08:01:47 293

原创 POSIX线程

POSIX线程有时候一个应用程序可能需要同时执行多个任务,但是这几个任务又相互协作,需要共享一些数据。这个时候就适合使用多线程来编写程序。线程是任务粒度划分中比进程更小的单元,两个线程可以属于同一个进程,并且两个线程可以同时执行。因为创建线程的目的只是让程序可以同时做多件事情,所以组成一个线程所需的资源只需要能让他正确执行即可,也就是说一个线程所需的资源是足够自己运行的最少资源。所以创建一个线程所需要的系统开销比创建一个进程小很多,并且由于线程之间共享程序的全局变量,所以线程之间更方便相互协作。基于上面的

2021-01-19 15:22:51 272

原创 处理信号

处理信号信号是在程序运行过程中系统突然发生一些特殊事件时,用来通知正在运行的程序的手段。例如当shell中有一个程序正在运行时,用户突然按下了ctrl + C,系统就会想正在运行的程序发送SIGINT信号,该信号表示一个中断。系统用这种方式告诉正在运行的程序,当前正发生的一些事件,便于程序对这些突发时间进行处理。信号的定义在头文件signal.h中,其中常用的有:信号含义SIGABORT进程异常终止SIGALRM超时警告SIGFPE浮点运算异常SIGHUP

2020-12-31 20:32:38 107

原创 C语言创建子进程

C语言创建子进程程序运行的时候,可以创建与自己关联的子进程,创建了这个子进程之后,可以选择等待这个子进程执行完毕,也可以让子进程与自己并行执行,还可以终止自己转而执行子进程。这些操作都是通过一系列相似而又有细微区别的库函数来实现。下面对这些可以使用的库函数进行介绍。system()它的函数定义如下:#include <stdlib.h>int system(const char * string);这个进程会在系统中另外启动一个shell,并在新的shell中执行参数string

2020-12-29 20:12:16 5373

原创 调试程序

调试程序在Linux环境下编程时,系统提供了调试程序的工具,也可以设置断点,从而查看程序在运行中的状态。Linux下最常用的调试工具就是gdb,此外还有一些另外的调试工具,例如断言和内存调试。用gdb调试程序这里使用一个有问题的排序算法实现来演示用gdb调试程序的过程,其排序算法的代码如下:#include <stdio.h>typedef struct{ //不能使用char * data; char data [4096]; int key;} item;item a

2020-12-28 20:01:04 365

原创 Makefile基础

Makefile基础当一个应用程序有很多源文件的时候,因为源文件之间存在互相依赖,所以在编译的时候必须要按照一定的先后顺序来进行。手动编译这些源文件太过繁琐,且容易出错。所以Makefile就是定义了源文件编译行为的文件,有了Makefile文件,在执行make命令的时候,系统就会自动寻找Makefile文件,并按照文件中定义的行为对源文件进行编译。一个Makefile文件由两个主要组成部分,它们分别是目标和规则。目标表示编译过程中的一个编译步骤,通常会生成一个文件,但也有例外。规则则是达到该目标要进行

2020-12-27 13:58:13 275

原创 文件锁定

文件锁定当多个进程需要同时操作一个文件的时候,为了互相协调,防止出现文件不一致的情况,就需要使用系统提供的文件锁定特性。创建锁文件创建锁文件的方式类似操作系统中的二进制信号量机制。这个锁文件是一个空文件,它的作用仅仅是作为一个标志,表示当前有一个进程正在使用文件。注意这种机制只是一种建议锁,而不是强制锁。一个应用程序在明知道锁文件存在(有一个进程正在访问文件)的时候还是可以强行访问文件,这种行为不会引起程序异常,但是会使文件混乱。这种进程之间的协调需要程序员来完成。因为这个锁文件是用来控制进程之间

2020-12-24 15:21:08 246 1

原创 文件处理

底层文件访问每个进程都会有一些自己的文件描述符,这些文件描述符表示当前进程正在操作的文件。在一个进程打开一个文件的时候,实际上就是在自己的文件表中创建该文件的文件描述符,创建文件描述符之后,可以通过该描述符对文件进行操作。当一个程序开始运行的时候,一般都会有三个默认存在的文件描述符。他们分别是:0:标准输入1:标准输出2:标准错误write系统调用系统调用write的作用是把缓冲区buf的前nbytes个字节写入与文件描述符fildes关联的文件,并返回实际写入的字节数。如果函数返回0,表

2020-12-23 19:39:45 187

原创 选项处理

程序参数当我们用C语言写好一个程序并成功编译出可执行的二进制文件之后,可以通过终端进行调用。并且在调用的时候,通常会传入一些参数,这些传入的参数会被存储到一个字符串数组中,并且该数组会被作为main()函数的参数,以便程序对这些参数进行处理。例如int main(int argc, char *argv[]){ for(int i = 0; i < argc; i++){ printf("%s\n", argv[i]); } return 0;}这个main函数中有两个参数,第一个

2020-12-23 13:27:58 88

原创 ShellProgramming

这个文档用于记录自己在学习shell编程时的一些心得,还有一个示例以及对其的解读,以便日后的查阅。文件基本结构一个完整的shell文件中可能有的部分为:#!/bin/sh,第一行的这个命令告诉系统应该用哪个程序来运行这个shell文件。代码,shell程序将要执行的代码部分注释,注释以#开头,#的后面皆为注释内容shell中的变量在shell中定义变量的格式为:var1="Hello"var2=13代码第一行定义了一个var1变量,并将其赋值为Hello,第二行则定义了一个var2

2020-12-21 20:35:55 150

原创 vim命令

vim命令学习vim的时候找到的一个文档,存一下 Lesson 1 SUMMARY 1. The cursor is moved using either the arrow keys or the hjkl keys. h (left) j (down) k (up) l (right) 2. To start Vim from the shell prompt type: vim FILENAME <ENTER> 3. To

2020-12-17 15:12:16 219

原创 友元

友元对于一个类来说,类外部的对象想要访问类中的private成员只有通过公共访问函数来实现。这在有些时候会很不方便,这个时候就可以使用友元的方式使一些特定的外部对象也能访问类内的private成员。友元分为三种,分别为友元函数,友元类和友元成员函数。友元函数如果一个类将一个函数声明为自己的友元函数,则表示该函数能够直接访问本类中的私有成员。声明函数为友元函数在类的声明中完成,而函数的定义跟普通函数一样,不需要额外修改。并且同一个函数可以同时是多个类的友元函数,例如:class Fractor; //

2020-12-08 09:01:07 226

原创 模板类

模板类跟之前介绍过的模板函数类似,模板类并不是一个类,而是像编译器解释了如何生成一个类。所以,声明一个模板类的时候是不会占用内存的,只有在将模板具体化,形成真正可以使用类时,才会为该类分配内存。基本语法template <typename T>class stack{ private: static int num = 0; int cap; T * st;};注意,当类模板中存在静态变量的时候,并不是所有由该模板初始化出来的类都共享这一个变量。而是所有由相同参数具

2020-12-07 19:08:10 3407

原创 多重继承

多重继承多重继承就是一个派生类同时继承多个基类,同样也分为公有继承,私有继承和保护继承三种,这三种继承可以实现的关系跟单继承一样,但是多重继承会带来很多新的问题,这里以公有继承为例:假设我们要实现下面的继承关系:这会带来一个问题。前面说到,使用单继承的时候,派生类之中会有一个基类,派生类只是在基类的数据上额外增加了一些数据。也就是说每一个从基类派生出来的派生类对象都会维护一个基类对象,这就是问题所在。在上面的继承关系中,Worker和Adult都继承了同一个基类,而Singer同时继承了Worker

2020-12-04 14:39:21 997

原创 多态继承11

多态继承多态继承是C++中实现代码重用的一个重要方法。例如最刚开始的时候定义了一个基础类Base:class Base{ private: string name; public: Base(string n): name(n){} void show(){ cout << "Using base function: " << name << endl; }};这个类只是实现了最基本的功能,但是如果临时想为该类添加一个新的功能,就要在B

2020-12-04 10:29:08 328

原创 多态继承

多态继承多态继承是C++中实现代码重用的一个重要方法。例如最刚开始的时候定义了一个基础类Base:class Base{ private: string name; public: Base(string n): name(n){} void show(){ cout << "Using base function: " << name << endl; }};这个类只是实现了最基本的功能,但是如果临时想为该类添加一个新的功能,就要在B

2020-12-02 21:03:22 416

原创 构造函数初始化列表

构造函数初始化列表与普通构造函数的区别构造函数初始化列表用于在显式初始化类成员。在平常的使用构造函数创建对象时,如果对象中将另一个对象作为成员,那么在调用构造函数之前,编译器会用成员对象的默认构造函数进行初始化。如果不想让编译器用默认的构造函数进行初始化,就要使用构造函数初始化列表来显式规定成员对象的初始化形式。构造函数进行的操作是,将成员先初始化,再用给定值赋值给初始化后的成员,而构造函数初始化列表则是直接对成员进行初始化,两者之间的区别跟下面两种创建变量的方式区别类似://在创建的时候直接初始化

2020-11-27 21:18:51 1282

原创 定位New与对象

定位new与对象当使用定位new运算符为对象分配内存时,注意调用对象的析构函数。因为delete运算符必须跟new配套使用,而不是跟定位new配套使用。所以使用定位new为对象分配空间并初始化对象之后,不能用delete清除对象。这时如果对象的构造函数中使用new申请了内存,就会导致内存泄漏,因为不能使用delete清除对象。例如:class BadString{ private: int len; char * str; public: BadString(); BadString

2020-11-27 10:11:32 103

原创 遇到的问题

遇到的问题这个文章用于记录在学习和使用C++的时候遇到的一些问题,以及解决方法,记载了一些非常零散的知识点,没有主题。用new申请结构体,并初始化结构体中的数组在C++11中,有一种新的方法在用new运算符申请结构体内存的同时对其初始化。其格式为:struct car{ int years; double price;};car * p = new car{3, 23.5};但是如果结构体中包含了字符数组(字符串),就不能使用这种格式,例如:struct car{

2020-11-26 14:16:50 79

原创 复制构造函数

复制构造函数提出背景C++中的new和delete关键字给了用户更大的自由对内存进行管理,但是如果使用不当就很容易造成内存泄漏。在创建和使用类的时候,需要额外小心,因为对类的创建和销毁行为的管理不当是造成内存泄漏的重要原因。下面是一个反面教材:class BadString{ private: static int num; //用于记录当前创建的实例化个数,这个值在每个构造函数中都会被+1 char * str; int len; public: BadString(); B

2020-11-25 21:35:09 146

原创 new运算符的使用

new运算符的使用基本语法C++中使用new运算符来申请内存,其基本格式为:int * p1 = new int; //分配一个未初始化的int内存int * p2 = new int(6); //分配一个int内存,并用括号内的值初始化int * p3 = new int [3] {1,2,3}; //分配一组int内存,并用花括号内的值初始化也可以使用new运算符为一个结构体申请内存,这里有一个坑,详情可以看这里。例如:struct car{

2020-11-25 19:14:13 2175

原创 自定义类的类型转换

自定义类的类型转换C++中,不同类型之间在赋值时可能发生自动类型转换,例如int x = 2.4;这个语句将会把2.4转换成int类型然后再赋值给x,这一过程发生了自动类型转换。原始类型向自定义类的转换(使用构造函数)对于用于自己定义的类,C++也可以进行自动类型转换,下面是一个例子:class Stock{ private: double price; public: Stock(double p){ price = p; }

2020-11-24 19:42:30 1267

原创 运算符重载

运算符重载提出背景C++中的基本类型可以使用+,-等运算符对其直接进行操作,这样非常方便。但是默认情况下不能直接用运算符对对象进行操作。例如:class Stock{ private: double price; public: Stock(double); Stock();};对于这个类的对象,如果我们想将两个对象的price成员的值相加,就只能定义一个sum()函数来实现操作。这样我们在使用的时候也要调用这个函数。注意运算符的左

2020-11-24 08:59:04 433

原创 对象和类

对象和类基本概念和语法根据面向对象的定义,类是一系列数据和针对这些数据的操作的集合。由于C++对结构体进行了扩展,所以在功能上类跟结构体的作用完全一致。但是在实际的使用上,结构体只用来封装数,而类用来表示一个对象的模板。类的声明中分为两个部分,私有和公有,两个部分声明的成员有相应的可访问性。类的声明跟定义分开,如果在声明类的同时定了函数,该函数就会被编译成内联函数。并且在开发的时候一般将类的定义写在头文件中,对应类的定义写在一个单独的代码源文件中,编译的时候将多个文件进行编译即可。在类中定义的函数

2020-11-17 18:46:09 59

原创 new运算符的使用

new运算符的使用基本语法C++中使用new运算符来申请内存,其基本格式为:int * p1 = new int;int * p2 = new int(6);int * p3 = new int [3] {1,2,3};也可以使用new运算符为一个结构体申请内存,这里有一个坑,详情可以看这里。例如:struct car{ int years; double price;};car * p = new car{3, 23.5};一旦使用new申请了内存就要妥善管理,如

2020-11-16 17:39:23 254

原创 遇到的问题

遇到的问题这个文章用于记录在学习和使用C++的时候遇到的一些问题,以及解决方法,记载了一些非常零散的知识点,没有主题。用new申请结构体,并初始化结构体中的数组在C++11中,有一种新的方法在用new运算符申请结构体内存的同时对其初始化。其格式为:struct car{ int years; double price;};car * p = new car{3, 23.5};但是如果结构体中包含了字符数组(字符串),就不能使用这种格式,例如:struct car{

2020-11-13 19:46:58 220

原创 作用域和持续性

作用域和持续性C++中持续性表示变量在程序运行的过程中什么时候被创建和销毁,作用域表示表示变量可以从哪里被访问到。持续性C++中有四种不同持续性的变量:自动存储持续性:例如在代码块中定义的变量,随着初始化语句的执行而创建,随着代码块的结束而销毁。静态存储持续性:在代码块中用static关键字修饰的变量和在代码块外声明的变量。它们在编译的时候被初始化,在程序退出的时候才销毁。线程存储持续性:使用thread_local声明的变量,线程退出的时候销毁。动态存储持续性:使用new运算符创建的变量,

2020-11-12 19:44:17 118

原创 函数模板

函数模板基本语法有时候对于多种数据类型可能需要执行相同的操作,如果没有函数模板,则需要为各个数据类型单独实现相应的函数,这样会导致代码的编写非常繁琐。有了函数模板之后只需要为所有的类型实现一个公用的函数模板即可,编译器会根据该模板为不同的类型生成相应的函数。我们声明一个函数模板的时候不创建函数,只是提供创建函数的模板,当需要使用到函数的时候,编译器才会根据模板创建函数。下面是声明一个函数模板的基本格式:template <class T> //这里class也可以用typename代替,

2020-11-10 21:08:11 105

原创 函数重载

函数重载基本用法当一个函数需要根据不同的情况接收不同的参数时,以前的做法通常是为每一种可能的情况单独建立一个函数名,这样会造成代码非常臃肿。而有了函数重载之后,就可以用同一个函数名进行调用,虽然还是要根据不同的参数类型进行单独的实现,但是在调用的时候使用相同的函数名,并根据情况传入不同的参数即可,这样使得代码更加简洁。例如:void print(const char * str, int width); //#1void print(double d, int width);

2020-11-09 20:23:25 163 1

原创 引用参数

引用参数概念其本质是一个变量的别名,如果对一个变量声明了引用变量,那么该引用变量只能是该变量的别名,任何针对引用变量的操作都会被应用到原变量上。因为其本质是一个变量的别名,所以声明的时候只能对将变量赋值给引用变量,并且引用变量在声明的时候必须初始化,例如:int a;int & ref = a;a = 10;printf("a = %d\n", a);ref++;printf("ref = %d\n", ref);在初始化引用变量之后,该引用变量便与用于初始化的变量绑定了,如果

2020-11-09 18:52:04 3299

原创 函数指针

函数指针基本语法跟数据一样,函数也存储在内存中,有自己的地址,有时候可以将一个函数的地址传入到另一个函数中,从而可以在另一个函数中调用该函数。这样做的好处是,在不同的时候可以根据不同的情况调用不同的函数来达到对应的目的。例如:int cmp1(int x, int y);int cmp2(int x, int y);int max(int x, int y, int (*cmp)(int, int));这里max函数中的int (*cmp)(int, int)定义的就是一个函数指针,其中最左边

2020-11-08 21:13:05 106

原创 函数和二维数组

函数与二维数组如果要将一个二维数组传入一个函数,其函数的形参声明形式应该是:int sum(int (*arr)[4], int size);\\为了提高可读性,也可以写成这样的形式int sum(int arr [][4], int size);这里int (*arr)[4]表示arr是一个数组,数组的元素是指向另一个由四个元素组成的数组。也就规定了二维数组的列数为4,这是C++的语言性质。这里int (*arr)[4]中的括号不能去除,如果去除,就表示声明的是一个由四个指向int类型的指针

2020-11-08 21:12:18 425

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除