前言本文对C语言指针和指针使用时的问题做一个概览性的总结,并对一些值得探讨的问题进行讨论。阅读本文,读者能达到统览C语言指针的目的。以下的讨论只针对32/64位机器。指针纲领:什么是指针要知道什么是指针,就要先了解内存的编址方法。内存的编址存储器由一块块的空间(存储单元)组成,为了方便寻找到每一块空间,我们需要对每一个空间进行标识——内存编址。字节(Byte)是讨论内存空间时的基本单位,每个存储单
在Linux下,一切皆文件,而文件无非是被打开的文件与未被打开的文件。冯·诺依曼体系决定了,若要对磁盘上的文件进行读写,必须首先将其加载到内存中,所以被打开与未被打开文件之间最大的区别即为是否在内存中有一块属于自己的内存空间与相关的内存数据结构。在这篇文章中,我们讨论的即是被打开的文件,即是被加载到内存中的文件,即是文件的IO。本文会从之前讨论过的C语言的文件IO函数讲起,然后过渡到Linux有关
进程创建关于进程的创建,在Linux进程状态与进程优先级部分已进行过讨论,为了保证文章的完整性,这里再进行简述。在linux平台下,创建进程有两种方式:运行指令和使用系统调用接口,前者是在指令层面创建进程,后者是在代码层面创建进程。在C/C++代码中,使用 fork(2) 创建子进程,fork(2)的工作有3步:创建进程、填充进程内核数据结构和值返回,fork(2) 在值返回时分别在父、子进程中返
“地址空间”在之前讨论C++内存管理,以及平常写C/C++程序时,有如下的存储空间布局:虽然不是所有的实例都按照上图所示的分区排布,但这是一种最典型的做法,足以说明问题。这个示意图与在C++内存管理中所示的相似,但还是需要说明一下:(方便起见,暂时将这个空间称为程序的“地址空间”)在32位机器下,地址空间的范围是[0, 232),这是由地址总线排列组合的范围决定的。地址空间被大体划分为两个部分:内
C++11概览自从1998年C++第一个标准定档以来,作为C++真正意义上的第二个大标准,C++11带来了数量巨大的变化,其中包含140多个新特性,以及600多个针对 C++98/03 的缺陷修正。C++11能更好地用于系统开发和库开发,语法更加泛化和简单化,更加稳定和安全,在保证功能强大的同时提高开发效率。C++11也有很多不完善的地方,除此之外,还有很多鸡肋的、被人吐槽的新特性和功能。本文只对
概述本文对hash_table进行封装,以模仿SGI STL对unordered系列容器进行简单实现,旨在加深对C++封装与泛型技法的体会与理解。阅读本文之前,建议先对哈希表进行学习。unordered_map与map一样,unordered_map的所有元素类型都是pair,pair的第一个成员为Key,第二个成员为Value。因为Key在任何情况下都不允许被修改,所以Key在pair中其实是被
概述本文模仿SGI STL对红黑树进行封装,以实现简单的 set 和 map。本文的目的不是造一个更好的轮子,而是加深对C++封装与泛型技法的体会与理解。阅读本文之前,建议先对红黑树进行学习。map因为map的实现更具代表性,所以先对map进行讨论。map的所有元素都会根据的元素的键值自动被“排序”,通过对红黑树的了解,这种“排序”其实是通过对二叉搜索树的中序遍历体现的。map的所有元素类型都是p
位图位图概述位图(bit set)中存储位(bit),每个元素只有两个可能值,1/0 或者 true/false。与bool数组相比,位图的空间开销更小,每个元素占据 1bit 空间,是C++最小内置类型char的八分之一。位图是哈希思想衍生出的容器,在完成哈希表判断元素存在功能的同时,极大地节省了所需的内存空间。位图的每个位都可以被单独访问,例如给定一个位图bitSet, 则 bitSet[3]
哈希概述哈希(hash)又称散列,其基本想法是,将存储的值与其存储位置建立某种映射,因此哈希的查找效率非常高,是一种支持常数平均时间查找的结构。与红黑树相比,哈希的效率表现是以统计为基础的,不需要依赖输入数据的随机性。建立值-址映射建立哈希结构的第一步是将“值”(数据)与“址”(存储位置,即下标)联系起来,便于利用“值”快速找到对应的元素。直接定址和除留余数是两种常用的映射方式,为了按索引快速访问
红黑树的性质和定义红黑树的性质红黑树是一种平衡搜索二叉树。红黑树的每个节点存储了一个标记颜色的变量(红色或黑色),通过对任意一条从根到叶子结点的路径中节点着色方式的限制,使树的最长路径不超过最短路径的两倍,因而红黑树处于一种近似平衡的状态。与AVL树相比,红黑的平衡条件更宽松,旋转的次数更少,因此在频繁插入删除的情况下,红黑树的性能比AVL树好。红黑树具有以下性质:根(_root)节点是黑色的;每
AVL树AVL树的定义和性质在输入值不够随机,或者经过某些插入或删除操作时,二叉搜索树会失去平衡,降低搜索效率,极端情况下,当插入数据接近有序时,二叉搜索树会退化为链表,导致搜索效率近似下降为O(N)。为了尽量保证二叉搜索树的平衡,两位俄罗斯的数学家 G.M.Adelson-Velskii 和 E.M.Landis 在1962年发明了AVL树。AVL树是一种平衡搜索二叉树,其具有以下性质:它的左右
Linux进程概念与管理方式Linux下的进程冯·诺依曼计算机体系结构决定了,一个程序只有被加载到内存中才能被 CPU 执行。粗浅来说,一个可执行程序被加载到内存中,即成为一个进程,但这种说法是不完全正确的。在 Linux 中,一个进程包括两部分:可执行程序的代码、数据和与这个可执行程序相对应的 PCB,即进程 = 代码和数据 + PCB。PCB(process ctronl block) 即进程
二叉搜索树概述二叉搜索树是一种具有特殊性质的二叉树。二叉搜索树可以是一棵空树,若不为空树,其:若左子树不为空,则左子树所有的节点值小于根节点值;若右子树不为空,则右子树所有的节点值大于根节点值。与二叉树一样,二叉搜索树也是递归定义的,二叉搜索树的左右子树都是二叉搜索树。二叉搜索树的结构二叉搜索树的结构是一棵二叉树,其左子树的节点值都小于根节点值,右子树的节点值都大于根节点值。二叉搜索树使用链式结构
虚函数被virtual修饰的成员函数被称为虚函数,虚函数的地址会被纳入类的虚函数表(virtual function table)。inline 和 virtual不会同时生效,用virtual修饰内联函数时,编译器会忽视函数的内联属性,此时函数不再是内联。虚函数一定不是内联函数。虚函数的重写子类继承父类,并有一个与父类形式相同(函数名、参数、返回值)的虚函数,称子类重写了父类的虚函数。虚函数被重
继承概述作为面向对象的三大特性之一,继承(inheritance)是面向对象编程中代码复用的一种重要手段。继承是类设计层面的一种复用,它允许在保证原有类性质不变的基础上对其进行扩展新的属性和功能,产生新的类。例如,在类 person 中定义关于 ‘人’ 的基本属性和行为,以 person 为基础扩展出特定人群的特殊属性和行为,即产生了一个新的类,这即是继承的基本思想。被继承的类称为父类(基类),继
迭代器适配器(iterator adapters)迭代器适配器是迭代器应用于迭代器的产物,包括 insert iterator, reverse iterator 和 iostream iterator。迭代器适配器本质是对容器或一般迭代器进行封装,以使其更加符合需求。reverse_iterator概述reverse_iterator 可以将一般迭代器的行进方向进行逆转,使operator++
priority_queue概述priority_queue 即优先级队列,是一个具有权值观念的容器。priority_queue 完全以底部容器为根据,并额外加上了堆的处理规则,以保证 priority_queue 的堆序性质。与 stack 和 queue 一样,priority_queue是一种容器适配器。本文以C++泛型技法对 priority_queue 进行实现,关于优先队列的结构和性
容器适配器(Container adapters)作为 STL 六大组件之一,适配器(adapter) 承担着各个组件间的转换和灵活组合功能。适配器本质上是一种封装,将某些既有组件进行组合封装,以得到新组件或者实现新功能。将适配器应用于容器,则称其为容器适配器(container adapters)。容器适配器是对已有容器的封装,stack 和 queue 是 STL 中的两个容器适配器
结构和定义list 的结构是一种带头双向循环链表,与单向不循环链表相比,双向循环链表找尾节点和进行节点操作时更方便快捷,哨兵位的设置也便于维护整个链表。与单向链表相似,双向链表的物理结构是离散的,可以参考数据结构_单向链表。维护链表时,只需要维护头结点即可,即对于带头链表来说,只需要维护哨兵位节点即可。本文参考SGI STL模拟实现一个功能类似的 list 类,以达到深入学习的目的。链表的节点定义
定义和结构作为一种序列式容器,vector的结构和操作与数组非常相似,不同之处在于vector对内存空间使用的灵活性,由于可以进行容量检测和扩容,vector极大提高了内存的利用率。同时,模板的使用可以使用户便捷地进行各种类型数据的存取和操作。本文参考SGI STL实现一个功能相似的vector容器,以达到深入学习的目的。vector的逻辑结构和物理结构都是连续的,这点在数据结构_顺序表中已做了详
定义和结构对字符串的使用和操作往往非常频繁,在C++中,为了便于对字符串进行管理,引入了string类。string类是basic_string类模板的一个实例:有typedef basic_string<char, char_traits, allocator> string。string类的存储结构其实是一个顺序表,与C语言传统字符串的使用相比,用string类对字符串进行管理,往
什么是makefilemakefile是一个文件。一个工程中的源文件数量不计其数,其按类型、功能、模块分放在不同的目录中,makefile制定了一系列规则指定哪些文件先编译,哪些文件后编译,哪些文件需要重新编译,以及更加复杂的功能操作。make是一个工具,用来解释makefile中的指令。make和makefile带来的好处就是自动化编译,在完成makefile的编写后,只需要一个make命令整个
本文以目标文件的结构为引子,通过探索在Linux环境下,一个具体的目标文件的结构来窥探ELF文件的结构。了解ELF文件的结构,对于加深对链接的理解、认识操作系统背后机理都有很大好处。编译和链接在正式讨论目标文件的结构之前,需要先对一个C/C++程序从源代码到可执行程序的构建过程有所了解。由于这部分不是本文重点,所以只做简要介绍。平常使用IDE进行程序设计时,这些工具往往会将编译和链接的过程一步完成
泛型编程(generic progamming)假设想写一个交换函数,将第一个和第二个对象进行交换,由于不确定要比较数据的类型,所以可以针对不同类型写出所有函数的重载。如果这样做,会发现这些函数除了针对的类型不同,其他地方都相同,一个个实现这些函数未免麻烦并且容易出错。此外,如果希望将函数用于未知类型,这种方式就不起作用了。泛型编程可以完美解决这个问题。泛型编程是一种编程风格,其中算法以尽可能抽象
C/C++内存分配在一个程序的进程地址空间中,其内存分配如下:栈用来存储非静态局部变量、函数参数/返回值等,栈是向下增长的;堆用于程序的动态内存分配,堆是向上增长的;数据段用来存储全局数据和静态数据;代码段用来存储可执行指令,只读常量,字符串常量就存储在代码段中。数据段和代码段在语言层面又分别称为静态区和常量区。C的动态内存管理C语言中用来管理动态内存的函数有:malloc、calloc、real
Linux用户分类root用户和普通用户作为一款多用户的操作系统,Linux可以分为两种用户:root用户和普通用户。root用户即超级用户,几乎可以在Linux系统下做任何事情,不受限制;普通用户往往受到权限限制,可以做有限的事。两种用户的区别也体现在命令行提示符上,root用户的命令行提示符是'#',普通用户的命令行提示符是'$'。用户切换使用 su [用户名] 并输入用户密码可以实现用户切换
初始化列表给类的对象初始化(赋初值)有两种手段:在构造函数的函数体内赋值;初始化列表第一个方式在讨论构造函数时已经进行过说明,在创建对象时,编译器通过调用构造函数给对象中的各个成员变量赋一个合适的初始值。虽然通过调用构造函数,对象的各成员变量有了一个初始值,但严格来说并不能将其称为对象成员的初始化,因为初始化只进行一次,而在构造函数体内可以进行多次赋值。事实上,初始化列表是成员变量被定义和初始化的
面向过程和面向对象顾名思义,面向过程关注的完成一个事件的整个过程,面向对象关注的是事件的参与者及其之间的交互。C语言是面向过程的,分析出求解问题的步骤,通过函数调用逐步解决问题。C++是面向对象的,将一件事拆分成不同对象,靠不同对象的交互完成。在面向对象编程的世界里,一切皆为对象,对象把数据与程序封装起来,提供对外访问的能力,提高了软件的重用性、灵活性和扩展性。类的引入和定义C++中的结构体在C语
C++是在C语言的基础上发展而来的,解决了C语言中存在的一些明显的问题。本文针对C语言存在的问题,引出C++中的解决方案,以对C++的语法进行说明和分析。命名空间域的概念可以将C++中的域理解为作用域。C++标准规定:使得特定名字保持有效的那些可能并不连续的程序文本就是该名字的作用域。作用域限定了名字的可见范围和使用范围。C++中常见的域有:类域、命名空间域、局部域、全局域。什么是命名空间在大型的
什么是引用引用不是新定义一个变量,而是给已存在对象取了一个别名,从语言逻辑角度看,引用不占用内存空间,而与被引用的对象共用同一块内存空间。使用引用时,需要注意以下几点:引用在定义时必须初始化;一个变量可以有多个引用;C++中的引用一旦初始化便不能转移;在语法逻辑角度,引用不占用额外的内存空间,只是某个对象的别名引用的使用场景(意义)做参数输出型参数此时形参是实参的一个别名,形参的改变会影响实参,故
Copyright © 2005-2023 51CTO.COM 版权所有 京ICP证060544号