C/C++
文章平均质量分 53
UKey_
勿以浮沙筑高台
展开
-
linux memalign、valloc函数
转载出处:http://blog.csdn.net/shisiye15/article/details/7827716在GNU系统中,malloc或realloc返回的内存块地址都是8的倍数(如果是64位系统,则为16的倍数)。如果你需要更大的粒度,请使用memalign或valloc。这些函数在头文件“stdlib.h”中声明。 在GNU库中,可以使用函数free释放memal转载 2018-01-02 10:12:14 · 1226 阅读 · 0 评论 -
string和char*互转以及c_str()的陷阱
string类型和char*、char[]的转换string转const char *: 1. 使用string的成员函数c_str(); 2. 使用string的成员函数data();string转char *:1. 使用string的成员函数copy();char *转string:1. 直接赋值即可cha[]转string:1. 使用string的成员函数copy()原创 2017-03-29 10:02:23 · 6227 阅读 · 0 评论 -
细节----函数返回局部变量
先来看一个例子作为引入:#include <stdio.h>#include <stdlib.h>int *test(){ int num = 3; return #}int main(){ int *p = test(); printf("%d\n", *p); return 0;}这样的一段代码,如果是gcc编译会有提示警告:函数返回局原创 2017-03-29 20:00:03 · 632 阅读 · 0 评论 -
函数模板和友元重载运算符报"无法解析的外部符"的解决方法
解决方法:1. 直接把定义和实现都写在类中 2. 如下: #include <iostream> using namespace std; template <class T> class Complex; template <class T> class Compleax { template <class S> //注原创 2017-03-21 21:43:23 · 1869 阅读 · 1 评论 -
函数模板和普通函数的抉择
当函数模板和普通函数同名时,会发生什么,下面直接测试:#include <iostream>using namespace std;template <typename T>void test(T a, T b){ cout<<"函数模板:"<<a<<" "<<b<<endl;}void test(int a, int b){ cout<<"普通函数:"<<a<<" "<<原创 2017-03-20 21:11:36 · 755 阅读 · 0 评论 -
Unix线程概念、控制原语、属性
线程:线程基础概念:线程在Linux中又称轻量级进程。并且它和进程都有PCB(进程控制块),但是区别是进程的虚拟地址空间是独享的,也就是每个进程都有自己的虚拟地址空间,但是线程的PCB是共享的,在同一个虚拟地址空间里面,每个线程有自己的PCB。虽然每个线程都有自己的PCB,但是从内核的角度来看,进程和线程是一样的,这是因为同一个虚拟地址空间里面的每个线程的PCB指向的内存资源的三级页表是相同的。在L原创 2017-02-15 23:36:11 · 1658 阅读 · 0 评论 -
Unix信号机制(上)
(一).信号基本概念相关概念:信号是软件中断,它提供了一种处理异步事件的方法。当A和B进行通信时,B收到了信号,不管程序执行到了哪,都会暂停去处理信号。并且每个进程收到的所有信号,都是内核负责发送和处理,而我们捕捉到信号编写的处理函数,只是相当于内核处理的时候调用的一个函数。在头文件signal.h中,信号名都被定义为正整数变量(信号编号),在linux下,可以使用kill -l查看。信号产生方法:原创 2017-02-13 22:42:57 · 1158 阅读 · 0 评论 -
Unix信号机制(下)
信号(下)(一)时序竞态在信号(上)里面讲解了信号基础的用法。但是考虑一下这样的场景,比如我用alarm函数定时3秒,但是在定时完成后,cpu调度去执行其它的进程了,过了4秒,才回到之前执行到的地方,但是alarm定时的时间已经过了,那么还没等到执行下一条语句,信号就先被处理了,可能导致程序的逻辑出现问题。这里用一个例子说明。 首先介绍一个函数 函数原型:int pause(void) 返回值原创 2017-02-14 16:14:29 · 673 阅读 · 0 评论 -
进程组、会话、守护进程
(一).进程组进程组,也称为作业,代表一个或多个进程的集合。并且每个进程都属于一个进程组。当我们调用fork()函数创建子进程时,默认子进程与父进程属于同一个进程组,并且进程组ID等于组长进程ID,默认第一个进程是组长ID。进程组组长可以创建一个进程组以及创建该组的进程,只要该进程组中还有进程存在,那这个进程组就存在,不管组长进程有没有终止。相关函数:1.获取当前进程的组ID: 函数原型:pid_原创 2017-02-14 18:08:10 · 901 阅读 · 0 评论 -
进程间通信的方式(二):共享映射区
进程间通信方式(二)共享映射区(一).通信方式:进程间通信又称IPC(Inter Process Communication),它可以通过文件 管道 有名管道 共享内存 消息队列 信号量 套接字这几个方式进行通信,但是文件这种以及消息队列基本已被淘汰。 所以常用的通信方式有: 1.管道 2.信号 3.共享映射区 4.本地套接字(二).共享映射区基本概念:通过mmap系统调用,把普通文件映射原创 2017-01-18 00:28:30 · 957 阅读 · 0 评论 -
unix/linux下几种常见的IO模型
unix/linux下几种常见的I/O模型:(以下图片均引用自UNP一书)阻塞式I/O:顾名思义就是当进行I/O时,数据还没有准备好,就会阻塞在I/O上。 下面配合代码进行讲解:#include <string.h>#include <stdio.h>#include <unistd.h>#include <arpa/inet.h>#define SERV_PORT 8000int ma原创 2017-05-12 17:01:05 · 1345 阅读 · 0 评论 -
解析变长结构体的用法和优点
变长结构体:在接触变长结构体之前,以为会是一个很难理解的东西,但是这其实算是C里面的一种技巧吧,优点是:分配了一段连续的内存,防止内存碎片化以及方便内存的管理。使用变长结构体的格式如下:struct Test{ .... int a; .... char b[0];};重点是结构体的最后一个成员char b[0],是个空数组。在我们不知道结构体内的某个成员大小是多少的时候,我们原创 2017-05-14 10:08:06 · 6167 阅读 · 0 评论 -
指针作为参数传入函数的陷阱
下面以一个例子来引出这种错误:#include <iostream>using namespace std;#include <stdlib.h>#include <string.h>void func(int *p){ p = (int *)malloc(sizeof(int) * 10); memset(p, 0, sizeof(p)); p[0] = 1;}原创 2017-05-14 12:25:16 · 8901 阅读 · 6 评论 -
C/C++基础:const关键字总结
const算是一个比较常用的关键字,这里总结一下它的用法,以备后面复习整理使用。总的来说,const可以修饰变量(基本数据类型、指针、引用、对象)、函数(普通函数、成员函数)这两大类。修饰变量修饰基本数据类型不允许更改变量的值,如const int a = 3,若更改a的值会报错对比宏来说,const可以起到类型检查的作用节省空间提高了程序的效率注意: const修饰的变量其实可以通过指针原创 2017-10-14 15:59:29 · 533 阅读 · 0 评论 -
C++中对象与成员函数的联系
#include <iostream>using namespace std;class Test{ public: void func() { cout << "test" << endl; }};int main(){ Test a; a.func(); return 0;}这样一原创 2017-10-06 19:39:53 · 1815 阅读 · 0 评论 -
如何理解typedef关键字
前言最近准备开始总结一些东西,当遇到C语言中的typedef时,回想起当时学的时候遇到了一些误区,这里分享出来供大家参考。typedef可能导致的误区在我们初学的时候,无非就是类似像下面这样使用typedef关键字。#include <stdio.h>typedef int INT;typedef struct test{ int a; int b;}Test;int main()原创 2017-09-28 20:10:38 · 591 阅读 · 0 评论 -
C/C++中结构体占用内存大小的计算方法
结构体在C语言中虽然经常使用,但是怎么计算一个结构体占用多大的内存,很多C语言的新手都没注意过,其实C语言的语法简单,难就难在它更偏向于与底层,与内存打交道。对于嵌入式方面来说,对C语言的要求更高,因为有些硬件的内存并不像我们使用的电脑的内存那么充裕,所以需要节约内存。结构体中同样的变量个数,却可能导致占用内存的大小不同。例子1:#include int main(){ ty原创 2016-10-04 22:54:42 · 10068 阅读 · 4 评论 -
谨防fork与锁之间的深坑
fork之后应当谨慎使用锁:这是因为fork有一个特点,那就是子进程只会保留调用fork的那个线程,父进程中其他的线程在子进程中都会消失。但是fork之后,除了文件锁以外,其他的锁都会被继承。这就导致了,如果在子进程中,对某个已经在父进程中加了锁的锁继续加锁,就会导致死锁发生。并且我们无法对该锁进行解锁,因为在子进程中,该锁的持有者并不存在。 下面给一个例子:#include <stdio.h>原创 2017-06-21 12:27:29 · 2879 阅读 · 3 评论 -
inline关键字和宏函数的异同
相同点:1.减少了函数调用的开销不同点:1.内联函数在编译时会进行语法检查,检查有没有语法错误之类的,而宏函数直接替换 2.替换发生的时期也不同,内联函数是在编译时展开,而宏函数是在预编译时展开 3.宏在处理时需要注意二意性问题(由大括号引起的语意不同,这是为什么有些宏函数会加do{…}while(0)的原因),而内联函数则不需要(因为语法和普通函数相同) 4.当函数的代码比较复杂时,所声明的原创 2017-06-20 23:20:47 · 495 阅读 · 0 评论 -
static关键字在C/C++中的作用(详解)
static关键字在C/C++的作用:1.将变量声明为静态变量:静态变量会存储在程序的数据段中,也就是说不会在栈中分配,它的生命周期是全局的。 如果是局部静态变量,它的生命周期也是全局的并且只被初始化一次,但是作用域就仅仅是在定义的函数体中。 例子:#include <stdio.h>int count = 100;void func(){ static int count = 10原创 2017-06-20 10:47:10 · 1093 阅读 · 0 评论 -
宏函数为什么使用do{...}while{0}包起来
在我们看内核源码或者库以及一些优秀的源码时,都会发现他们的宏函数是包括在do{…}while(0)内。具体的原因其实想想就能明白。考虑下面一个特殊的例子。 宏函数的定义如下:#define test(x) \ a(x); \ b(x);如果在调用时是这样调用的:if (judge) test(x);那么展开之后就是:if (judge): a(x);b(x);这时产生的效果可能就原创 2017-06-20 09:18:46 · 3228 阅读 · 3 评论 -
C++实现不能被继承的类的两种方法
C++实现不能被继承的类的两种方法:基本的思想就是将构造函数和析构函数都声明为私有成员。但是仅仅这样做是不够的,因为声明为私有成员之后,不仅不能被继承,就连实例化自身的对象也不行了。 这里就有两种方法实现真正的不可被继承的类: 1. 使用static关键字: #include<iostream> using namespace std; class Base { public原创 2017-05-14 14:13:40 · 1262 阅读 · 0 评论 -
线程同步(互斥锁、读写锁、条件变量、信号量)
线程同步:线程同步指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时其它线程为保证数据一致性,不能调用该功能。保证了数据的一致性。举个简单的例子就是,当一个线程将全局变量var=100加上10,另外一个线程时将var乘以2,这样最后得出的结果因为cpu不同的调度策略导致不同的结果,可能是220也可能是210还可能是110或者200,220和210可以理解,无非就是一个先操作一个后操原创 2017-02-16 22:29:25 · 2857 阅读 · 0 评论 -
C++引用和指针的区别
C++引用和指针在间接使用其他对象的各种操作功能上面类似,但是两者的不同之处也很明显:1.指针本身占据内存空间,但是引用只是一个对象的别名,本身不分配内存空间;2.指针定义时可以不初始化,但是定义一个引用必须进行初始化,并且初始化时只能是一个对象; 比如:int &b = 3.14; //这样是错的,要明白"引用只是一个对象的别名而已"3.指针可以重新指向另外一个对象,但是引用无法重新绑定到原创 2017-01-12 11:02:27 · 571 阅读 · 0 评论 -
排序算法-直接插入排序
直接插入排序(Straight Insertion Sort)是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。 大致思路就是:把数组中的元素一个一个遍历一遍,寻找该元素应该插入的位置,使得数组有序。待遍历的元素都会用key值记录下来,方便插入操作。其实就是不断地比较、记录key、移位和插入的过程。这里使用算法导论上的图片 ,数组A[6原创 2016-09-30 17:42:51 · 674 阅读 · 0 评论 -
数据结构与算法学习--邻接表
众所周知,图的存储方式有两种,一种是领接矩阵(即二维数组),还有一种是领接表。 领接矩阵适合于稠密图,领接表适用于稀疏图(点多边少)。 领接表即给图中每个顶点创建一个单链表,第i个单链表中的结点表示依附于顶点Vi的边,每个单链表的头节点形成一个一维数组,以便于顶点的访问。具体代码如下: #include <iostream>using namespace std;#include <mal原创 2016-10-21 11:36:08 · 749 阅读 · 0 评论 -
C++对象数组调用构造/析构函数的方法
C++的对象数组: 顾名思义,即是存储对象的数组。比如有一个对象student,实例化为对象数组有如下两种方式:student stu[3]; //第一种方法,在栈空间中占用内存student *stu = new student[3];//第二种方法,在堆空间中分配空间对象数组调用构造函数:class student //定义一个student类,只有个构造函数当示例用{ pu原创 2016-09-20 23:35:25 · 14289 阅读 · 2 评论 -
栈和队列
一. 栈是一种特殊的线性表,特点是:后进先出(LIFO),先进栈的元素后出栈,后进栈的元素先出。基本操作:栈的初始化、判断栈空、入栈、出栈等。比如,堆放一堆书,取出来的当然是第一本了,一本书放到这个书堆也是放在最上面,当然,你要是抽出来。。。。那我也没办法 栈的存储方式有两种,一个是用数组存储,另外一种是使用链表存储。使用数组存储需要注意判断栈的上溢或者下溢。上溢:超过了数组的大小。下溢:数组中原创 2016-09-24 21:47:04 · 629 阅读 · 0 评论 -
二叉树-求{0,1....n-1}的非空子集
今天有同学问了下我怎么编程实现求集合{0,1….n-1}的非空子集合,我发现这恰好是一棵满二叉树的题,可以用二叉树求解。 代码如下: #include <iostream>using namespace std;#include <stdlib.h>int n ;int flag[20]; typedef struct binary_tree{ int data;原创 2016-10-09 18:13:32 · 780 阅读 · 0 评论 -
数据结构与算法学习-快速幂取模
当我们遇到类似于求a*b%c这样的问题的时候,如果是a^b%c,当a^b这个数特别大的时候,以至于int范围存不下该值,那最后取模得到的值当然也是错的,这个时候就运用到快速幂取模算法,这种算法的时间复杂度是O(logn),效率非常快,也是常用的几种算法之一。 快速幂取模依赖于以下数学公式: 以及a*b%c = ((a%c)*(b%c))%c 用二分的思想把b分为奇数和偶数,再运用公式按步求原创 2016-10-09 11:17:11 · 1224 阅读 · 0 评论 -
C语言如何计算算法运行时间
C/C++中的计时函数是clock(),而与其相关的数据类型是clock_t。在MSDN中,查得对clock函数定义如下: clock_t clock( void ); 这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间(wal-clock)。其中c转载 2016-09-19 23:34:18 · 28268 阅读 · 0 评论 -
数据结构与算法学习-并查集
并查集(Union-Find Set): 用于解决若干的不相交集合的如下几种操作的统称: 1.MAKE-SET(x):初始化操作,建立一个只包含元素x的集合。 2.UNION(x,y):合并操作,将包含x和y的集合合并为一个新的集合。 3.FIND-SET(x):查询操作,计算x所在的集合。 通常使用树这种数据结构来表示集合,树中的每一个结点代表一个元素,每棵树代表一个集合。那么如何判断两原创 2016-10-08 23:27:03 · 682 阅读 · 0 评论 -
排序算法-快速排序
快速排序:快排是对冒泡排序的一种改进,它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 快排的执行思路是遵照分治模式的。有如下三个步骤: (1).分解:将数组依据某个值划分成两个部分; (2).解决:通过递归调用,将每个部分分别进行排序; (3).合并:因为排序就在内部完成,所以不需要原创 2016-09-30 17:19:53 · 733 阅读 · 0 评论 -
数据结构与算法学习-哈希表入门
哈希表:又叫散列表,关键值通过哈希函数生成一个哈希地址映射到数组对应的存储位置上,查找时通过关键值直接访问数组。就好比把一个复杂的事务通过一种方式简化成一个小物件,这个小物件就代表了这个复杂的事物。哈希函数:指的是关键值和存储位置建立的对应关系。一般我们只需要一次查找就能找到目标位置,但有些关键字需要多次比较和查找才能找到。因为哈希表里,可能存在关键值不同但是由于哈希函数的计算方式导致生成原创 2016-10-04 20:55:57 · 760 阅读 · 0 评论 -
数据结构与算法学习-二叉树
二叉树是一种特殊的树型结构,它的每一个结点最多只有两个子结点。二叉树根据子结点的不同可以分为:1.完全二叉树:如果一棵树的高度为h,那么除了第h层外,其它各层的结点数都达到最大值,第h层有叶子结点,并且叶子结点都是从左到右依次排布。2.满二叉树:除了叶节点外每一个节点都有左右子叶且叶子结点都处在最底层的二叉树。3.平衡二叉树:又称AVL树,它是一棵二叉排序树,具有这样的性质:它是一原创 2016-10-04 21:23:27 · 593 阅读 · 0 评论 -
进程间通信的方式(一):管道
管道(一).通信方式:进程间通信又称IPC(Inter Process Communication),它可以通过文件 管道 有名管道 共享内存 消息队列 信号量 套接字这几个方式进行通信,但是文件这种以及消息队列基本已被淘汰。 所以常用的通信方式有: 1.管道 2.信号 3.共享映射区 4.本地套接字(二).管道基本概念:而其中的管道机制,是属于最简单的一种通信方式。它适用于有血缘关系的进原创 2017-01-15 23:31:52 · 742 阅读 · 0 评论 -
字典树hdu1247
题意:如果有个单词是由其它两个单词组成的,就输出。 思路:每个结点加个标志位,判断是不是一个完整的单词。如果进行查找操作,查找成功之后,把查找成功的部分截掉,查找剩下的部分,如果也查找成功,那就输出。比如“a ahat hat”,”ahat”在字典树中查找时,找到’a’是一个单词,截掉’a’的部分,剩下”hat”,继续找,找到了”hat”,就证明是由两个单词组成的了。#include <iostr原创 2016-11-23 21:24:28 · 477 阅读 · 0 评论 -
字典树hdu1251
字典树: 用于统计、排序和保存大量的字符串,它的优点是节约了存储空间,并且查找的效率很高。 题意: Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). 思路:用字典树存储单词表,在建树的过程中就记录该单词出现的次数,然后查询的时候,直接输出对应的单词的次数就行了。比如样例中单原创 2016-11-23 20:32:00 · 422 阅读 · 0 评论 -
线索二叉树
线索二叉树是为了便于访问一个结点的前驱和后继的信息。它在每个结点上新增了两个标志位,用来判断当前结点到底有没有左子树/右子树,如果没有,就把其利用起来存前驱/后继的信息。同时它也新增了一个头节点用来将整个二叉树联系起来。具体实现如下,有大量注释便于理解。#include <iostream>using namespace std;#include <cstdio>#include <cstri原创 2016-11-22 20:14:31 · 486 阅读 · 0 评论 -
C++sort()给结构体数组排序
在对结构体数组排序时,首先确定排序数组的关键字,并且在排序过程中不是交换关键字的顺序,而是交换这个结构的地址,从而使结构体数组有序。 #include <iostream>using namespace std;#include <algorithm>typedef struct Test{ int a; int b;}t;t test[100];bool原创 2016-11-20 17:04:12 · 32992 阅读 · 5 评论