指针

句柄的真正理解

浪子不回头ぞ 提交于 2020-01-03 17:36:08
**真理一句话:句柄是引用,而不是指针。只能改变对应对象的内容,但不知道对象在哪。 ** 以下内容摘取网上资源,如有违反作者版权,请通知。 句柄是用来标识项目的。(它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。有一说法是指向指针的指针) 项目包括:模块(module)、任务(task)、实例 (instance)、文件(file)、内存块(block of memory)、菜单(menu)、控制(control)、字体(font)、资源(resource),包括图标(icon),光标 (cursor),字符串(string)等、GDI对象(GDI object),包括位图(bitmap),画刷(brush),元文件(metafile),调色板(palette),画笔(pen),区域 (region),以及设备描述表(device context)。 实质: 在windows中,句柄是和对象一一对应的32位无符号整数值。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。 形象说法:要想控制某一设备,不去直接控制设备,而是控制设备的操作手柄。 使用句柄的好处: windows需要向程序员提供必要地编程接口,在这些接口中,允许程序员访问、创建和销毁对象

c++中为什么可以通过指针或引用实现多态,而不可以通过对象呢?

ぐ巨炮叔叔 提交于 2020-01-03 17:28:41
目录 一、类对象的存储方式: 二、无论通过对象还是指针,能使用的方法只与它们静态类型有关。 三、 不同类型的指针有什么区别? 四、 指针与引用来实现多态 五、对象不能实现多态 引言: 在c++中司空见惯的事情就是:可以通过指针和引用可以实现多态,而对象不可以。 那为什么?让我们来解开这神秘的暗纱!转载自:https://www.cnblogs.com/yinheyi/p/10525543.html 一、类对象的存储方式: 在一个类的实例中,只会存放非静态的成员变量。 如果该类中存在虚函数的话,再多加一个指向虚函数列表指针—vptr。 例如声明如下两个类,并分别实例化两个对象,它们的内存分配大致如下:(vptr具体在什么位置,与编译器有关,大多数都在开始处) class base { public: virtual ~base() {}; virtual string GetName() { return "base"; } GetA(); int a; }; class derived : public base { public: virtual ~derived() {}; virtual string GetName() { return "derived";} GetB(); int b; }; base B1, B2; derived D1, D2; 内存分布大致如下:

17~C++ new和delete运算符重载

戏子无情 提交于 2020-01-03 14:02:26
重载 class A的new/delete 以及 new[]/delete[]运算符: 成功返回非空指针,失败返回空指针 #include < iostream > #include < cstdlib > using namespace std ; class A { public : A ( int var = 0 ) : m_var ( var ) { cout << "A构造:" << this << endl ; } ~ A ( void ) { cout << "A析构:" << this << endl ; } static void * operator new ( size_t size ) { void * pv = malloc ( size ) ; cout << "new:" << size << ' ' << pv << endl ; return pv ; } static void operator delete ( void * pv ) { cout << "delete:" << pv << endl ; free ( pv ) ; } static void * operator new [ ] ( size_t size ) { void * pv = malloc ( size ) ; cout << "new[]:" << size <

Leetcode141. 环形链表

梦想的初衷 提交于 2020-01-03 09:53:31
Leetcode141. 环形链表 题目: 给定一个链表,判断链表中是否有环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 示例 1: 输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。 题解: 方案一:hash表 我们遍历所有结点并在哈希表中存储每个结点的引用(或内存地址)。如果当前结点为空结点 null(即已检测到链表尾部的下一个结点),那么我们已经遍历完整个链表,并且该链表不是环形链表。如果当前结点的引用已经存在于哈希表中,那么返回 true(即该链表为环形链表)。 时间复杂度: O ( n ) O(n) O ( n ) ,对于含有 n n n 个元素的链表,我们访问每个元素最多一次。添加一个结点到哈希表中只需要花费 O ( 1 ) O(1) O ( 1 ) 的时间。 空间复杂度: O ( n ) O(n) O ( n ) ,空间取决于添加到哈希表中的元素数目,最多可以添加 n n n 个元素。 方案二:双指针 通过使用具有不同速度的快、慢两个指针遍历链表,空间复杂度可以被降低至 O ( 1 ) O(1) O ( 1 ) 。慢指针每次移动一步,而快指针每次移动两步。

170. 两数之和 III - 数据结构设计

只谈情不闲聊 提交于 2020-01-03 05:06:11
ID: 170 TITLE: 两数之和 III - 数据结构设计 TAG: Java,Python 方法一: 这是第一题两数之和的后续问题之一,两数之和要求一个返回列表中两个数字的索引,这两个数字的和等于目标值。 我们可以从两数之和中汲取灵感,把所有的输入数字保存在一个列表中。 两数之和的一个解决方法是双指针法,指针从两个方向迭代,互相逼近。 但是,双指针法的前提条件之一是输入列表有序。 现在有几个问题: 函数 add(number) 在列表中插入新数字时,是否应该保证列表有序。 或者在调回 find(value) 时按需进行排序? 我们将在后面的算法部分讨论上述两个问题。 算法: 先给出双指针在有序列表中找到两数之和的算法。 初始化两个指针 low 和 high 分别指向列表的头尾。 从两个方向同时进行迭代,要么找到两数之和的解,要么两个指针相遇。 在每个步骤中,我们将根据不同的条件移动指针: 如果当前指针指向元素的和小于目标值,则应该增加总和来满足目标值,即将 low 指针向前移动获得更大的值。 如果当前指针指向元素的和大于目标值,则应该减少总和来满足目标值,即将 high 向 low 靠近来减少总和。 如果当前指针指向元素的和等于目标值,则直接返回结果。 如果两个指针相交,说明当前列表不存在组合成目标值的两个数。 class TwoSum ( object ) : def _

C ++11出现了更好的两种数据类型,C++11中的空指针与强类型枚举

半城伤御伤魂 提交于 2020-01-03 03:47:49
虽说C++现在17了,但是还是讲下C++11中两个类型吧,C ++从一开始就尝试改进C的类型系统,添加类可以构建更好的类型和枚举的类,这样就不需要预处理器的某些用途(这在类型上并不安全)。C ++还为您执行更少的隐式类型转换(例如不允许从void *进行隐式赋值),让编译器为您找到更多错误。C ++ 11更进一步,即使枚举摆脱了整数#define常量的需要,我们仍然有丑陋的,输入不良的NULL指针。 C ++ 11通过添加一个具有自己类型的显式,清晰的nullptr值来清除这一点。C ++ 11还带来了新的强类型枚举。在本文中,我将介绍这些改进。 为什么我们需要强类型枚举? 好玩,有趣,专业C/C++学习交流,源码下载 群:747821062 1.那么为什么我们还需要强类型的枚举? 旧式C ++枚举基本上是整数; 它们可以与整数或其他不同类型的枚举进行比较。问题是,你通常不想这样做,因为枚举应该是一些固定的枚举值列表。 2.为什么要与其他枚举类型(或整数)进行比较? 这就像说,“请把这种指甲与这种牙刷比较。” 这没有任何意义,你可能并不是故意这样做。但旧式的C ++枚举会很高兴地告诉你,“为什么是,这个指甲不像这个牙刷”,或者更糟糕的是,它们可能比较相同,因为它们碰巧共享相同的基本整数值(“啊是的,这个指甲是电子牙刷“)。现在,使用强类型枚举,编译器会告诉您正在执行此操作

typedef void (*Fun) (void) 的理解——函数指针——typedef函数指针之美

左心房为你撑大大i 提交于 2020-01-02 13:44:54
首先介绍大家比较熟悉的typedef int i;//定义一个整型变量i typedef int myInt; myInt j;//定义一个整型变量j 上面介绍得是我们常用的比较简单的typedef的用法,下面首先介绍一下函数指针。 函数指针的形式: 形式1:返回类型(*函数名)(参数表) #include <iostream> using namespace std; //定义一个函数指针pFUN,它指向一个返回类型为char,有一个整型的参数的函数 char (*pFun)(int); //定义一个返回类型为char,参数为int的函数 //从指针层面上理解该函数,即函数的函数名实际上是一个指针, //该指针指向函数在内存中的首地址 char glFun(int a) { cout << a; //return a; } int main() { //将函数glFun的地址赋值给变量pFun pFun = glFun; //*pFun”显然是取pFun所指向地址的内容,当然也就是取出了函数glFun()的内容,然后给定参数为2。 (*pFun)(2); return 0; } 通过上面的一个小例子,我们知道了函数指针的用法, 而typedef可以让函数指针更直观方便 形式2:typedef 返回类型(*新类型)(参数表) typedef char (*PTRFUN)(int);

链表头结点与头指针

六眼飞鱼酱① 提交于 2020-01-02 10:39:32
链表中第一个结点的存储位置叫做头指针,那么整个链表的存取就必须从头指针开始进行了。之后的每一个结点,其实就是上一个的后继指针指向的位置。 链表中第一个结点的存储位置叫做头指针 。 头指针和头结点不同,头结点即第一个结点,头指针是指向第一个结点的指针。链表中可以没有头结点,但不能没有头指针。 链表中设置头结点的好处: 防止单链表是空的而设的。当链表为空的时候,带头结点的头指针就指向头结点,如果当链表为空的时候,头结点的指针域的数值为NULL。 为了方便单链表的特殊操作,插入在表头或者删除第一个结点。这样就保持了单链表操作的统一性。 单链表加上头结点之后,无论单链表是否为空,头指针始终指向头结点,因此空表和非空表的处理统一,方便了单链表的操作,也减少了程序的复杂性和出现bug的机会。 对单链表的多数操作应明确对哪个结点以及该结点的前驱。不带头结点的链表对首元结点、中间结点分别处理等;而带头结点的链表因为有头结点,首元结点、中间结点的操作相同,从而减少分支,使算法变得简单,流程清晰。 来源: CSDN 作者: Dr_W 链接: https://blog.csdn.net/qq_42363032/article/details/103798926

LeetCode:Linked List Cycle II

元气小坏坏 提交于 2020-01-02 01:11:29
题目:判断单链表是否有环,如果有则找出环的起点。 题目链接 这是 另一道题 的扩展,利用快慢指针判断出是否有环后,还需要找出环的起点,分析如下: 设链表长度为len(链表中非空next指针的个数,下面所说的长度均为非空next指针的个数),链表head到环的起点长度为a,环起点到快慢指针相遇点的长度为b,环的长度为r。 假设到快慢指针相遇时,慢指针移动的长度为s,则快指针移动长度为2s,而快指针移动的长度还等于s加上在环上绕的k圈(k>=1),所以2s=s+kr ,即s = kr。 由s = a + b 和 s = kr 可知 a + b = kr = (k-1)r + r; 而r = len - a,所以a + b = (k-1)r + len - a, 即 a = (k-1)r + len - a - b , len - a - b是相遇点到环的起点的长度, 由此可知,从链表头到环起点长度 = (k-1)环长度+从相遇点到环起点长度,于是我们 从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇点为环起点 。 代码如下: 1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x)

快速排序(双指针扫法)

人走茶凉 提交于 2020-01-01 20:28:24
快速排序(双指针) 快速排序是对冒泡排序的一种优化,而双指针又比基础的方法快。在数组的开头和结尾各定义一个指针i和j,在定义一个哨兵vot用于分区,双指针法是交换两个指针在固定状态下的数据,减少交换次数,从而提高速度。 下面上代码 package sort ; public class quicksort { public static void main ( String [ ] args ) { int a [ ] = { 9 , 5 , 7 , 3 , 8 , 4 , 2 , 6 , 1 } ; quicksort ( a , 0 , a . length - 1 ) ; for ( int i = 0 ; i < a . length ; i ++ ) { System . out . print ( a [ i ] + " " ) ; } } private static void quicksort ( int a [ ] , int begin , int end ) { //排序开始的条件 if ( begin >= 0 && end < a . length && begin < end ) { //定义指针,x开始指针,y末尾指针 int x = begin , y = end ; //定义哨兵 int vot = a [ x ] ; //记录哨兵位置 int