指针变量

语言中结构体变量和结构体类型的定义

让人想犯罪 __ 提交于 2020-03-06 13:43:49
1. 结构体类型定义 定义方式1 : Typedef struct LNode { int data; // 数据域 struct LNode *next; // 指针域 } *LinkList; 定义方式2 : struct LNode { int data; // 数据域 struct LNode *next; // 指针域 } ; Typedef struct LNode *LinkList; 以上两个定义方式是等价的,是将*LinkList 定义为struct LNode 类型,即LinkList 被定义为一个类型名。这样就可以用LinkList 来定义说明新的变量了,如: LinkList L ; 即将L 定义为struct LNode 类型的指针变量 2. 结构体类型变量定义 定义方式1 : struct LNode { int data; // 数据域 struct LNode *next; // 指针域 }LnodeA ; 定义方式2 : struct LNode { int data; // 数据域 struct LNode *next; // 指针域 } ; struct LNode LnodeA ; 以上两个定义方式也是等价的,这样就将LnodeA 定义为一个truct LNode 类型的变量,即LnodeA 为一个truct LNode 类型的变量名。

C语言之指针

社会主义新天地 提交于 2020-03-06 12:00:24
#include <stdio.h> #include <stdlib.h> void swap_t(int*a,int*b) {int p; p=*a; #借助指针,交换变量值 *a=*b; *b=p; } int main() { int a,b; a=6,b=5; #a,b的地址不变,但是经指针操作后其中的值交换 int *p,*q; #声明变量上,一般变量是被分配合法地址的,但是指针变量p是有地址的,但是p的内容可能是非法地址。 p=&a; q=&b; swap_t(p,q); #单向传递:只进不出(数值无法回传)swap函数结束后,p,q不变 printf("%d,%d",*p,*q); } 指针与数组的关系,&a[i]=(a+i),a[i]=*(a+i)#每次从a(首地址算起)即重新计算地址,p++(有规律的改变当前地址的值省去了重新计算)效率更高,但是其不够直观,数组a 不能a++的原因:a即是数组首地址是一个常量,而p对应是变量,他可以改变内部存储的地址实现p++ 区分几种形式: 0x0001 p++; //p++可以把p++看成两步,第一步返回了p的值,第二步对p自加操作有;p实现了自增 *p; //*(p+1) 0x0002 *p++ 与*(p++)//++与*同优先级,右结合性,有因为是后加加,所以第一步返回p的值,后*p,后p自增 0x0003 *(++p)

排序算法之快速排序(Quicksort)解析

旧街凉风 提交于 2020-03-06 11:47:29
一.快速排序算法的优点,为什么称之为快排? Quicksort是对归并排序算法的优化,继承了归并排序的优点,同样应用了分治思想。 所谓的分治思想就是对一个问题“分而治之”,用分治思想来解决问题需要两个步骤: 1.如何“分”?(如何缩小问题的规模) 2.如何“治”?(如何解决子问题) 快排的前身是归并,而正是因为归并存在不可忽视的缺点,才产生了快排。归并的最大问题是需要额外的存储空间,并且由于合并过程不确定,致使每个元素在序列中的最终位置上不可预知的。针对这一点,快速排序提出了新的思路:把更多的时间用在“分”上,而把较少的时间用在“治”上。从而解决了额外存储空间的问题,并提升了算法效率。 快排之所以被称为“快”排,是因为它在平均时间上说最快的,主要原因是硬件方面的,每趟快排需要指定一个“支点”(也就是作为分界点的值),一趟中涉及的所有比较都是与这个“支点”来进行比较的,那么我们可以把这个“支点”放在寄存器里,如此这般,效率自然大大提高。除此之外,快排的高效率与分治思想也是分不开的。 二.算法思想 按照快排的思想,对一已知序列排序有如下步骤: 1.指定“支点” 注意,是“指定”,并没有明确的约束条件,也就是说这个支点是任意一个元素,一般我们选择两种支点:当前序列首元,或者随机选取 两种方式各有优劣,前者胜在简单,但可能影响算法效率 快排中,支点的最终位置越靠近中间位置效率越高

《C++ Primer(第五版)》第六章笔记

旧城冷巷雨未停 提交于 2020-03-06 08:53:59
6.1 函数基础   通过 调用运算符 来执行函数。函数的调用完成两项工作:用实参初始化函数的形参;将控制权转移给被调用函数。   当遇到一条 return 语句时函数结束执行过程。return 也完成两项工作:返回 return 语句中的值;将控制权从被调用函数转移回主调函数。 形参和实参   形参出现在函数定义的地方,实参出现在函数调用的地方。实参是形参的初始值,实参的类型必须与对应的形参类型相匹配。   任意两个形参都不能同名,而且函数最外层作用域中的局部变量也不能使用与函数形参一样的名字(外层局部变量被内部形参隐藏)。 6.1.1 局部对象   对象的 生命周期 是程序执行过程中该对象存在的一段时间。   形参和函数体内部定义的变量统称为 局部变量 。局部变量会 隐藏 在外层作用域中同名的其他所有声明中。   只存在于块执行期间的对象称为 自动对象 。    局部静态对象 在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁。内置类型的未初始化局部变量产生未定义的值,内置类型的局部静态变量初始化(值初始化)为 0。 6.2 参数传递   形参的类型决定了形参和实参交互的方式。当形参是引用类型时,其对应的实参被 引用传递 或函数被 传引用调用 ;当实参的值被拷贝给形参时,实参被 值传递 或函数被 传值调用 。 6.2.1 传值参数  

Data Structures[翻译]

a 夏天 提交于 2020-03-05 14:24:52
Data Structures 【原文见: http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=dataStructures 】 作者 By timmac TopCoder Member 翻译 农夫三拳@seu drizzlecrj@gmail.com 即使计算机能够毫不夸张的每秒执行上百万次的数学运算,当一个问题变得庞大且复杂时,性能仍然是一个很重要的考虑方面。最至关紧要的关于快速解决问题的方面之一就是数据在内存中是如何存储的。 为了举例说明这点,可以试想你进入一个图书馆去查找某个学科的一本书。最有可能的是你能够使用一些电子参考或者在最坏情况下,有一个卡片目录来帮助你找到你想要的书的名称和作者。由于书籍都是按目录进行排放的并且在每一个目录中是按照作者的姓名排序的,因此这是一个直接并且轻松的过程,那么然后你就可以在书架上找到你想要的书了。 现在,假定你去图书馆找一本特定的书,然而这里没有排放好的书架,只有在房间角落有一些排成行的袋子,里面放满了可能相关可能不相关的书。这样就可能需要数个小时甚至数天来找到你需要的书了,这是一个对比性强的道理。这就是数据在没有存储为与应用相关的格式时软件运行的情况。 简单的数据结构(Simple Data Structures) 最简单的数据结构是原生的变量。他们存放单个值,并且使用中受限

原生JS实现双向链表

旧街凉风 提交于 2020-03-05 14:01:35
1.前言 双向链表和单向链表的区别在于,在链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素,如下图所示: 从图中可以看到,双向链表中,在每个节点 Node 里有 prev 属性(指向上一个节点的指针)和 next 属性(指向下一个节点的指针),并且在链表中也有 head 属性(用来存储链表第一项的引用)和 tail 属性(用来存储链表最后一项的引用)。 2.代码实现 首先,我们可以先创建一个双向链表DoublyLinkedList类: //创建一个Node辅助类,用来生成节点 class Node{ constructor(value){ this.value = value; this.next = null; this.prev = null; } } class DoublyLinkedList{ constructor(){ this.head = null; this.tail = null; this.length = 0; } append(element){ } find(value){ } insert(position,element){ } remove(value) { } removeAt(position){ } size(){ } isEmpty(){ } nextPrint() { }

指针(六)

為{幸葍}努か 提交于 2020-03-05 08:47:22
今天继续对指针进行探讨,请看下面: 函数指针: 下面通过一个程序,简单明了的对函数指针有个基本认识: #include <stdio.h> void test(int n) { printf("test %d ...\n", n); } int main(void) { void (*f)(int); // 这里的f就是函数指针变量 void (*f2)(int); // 这里的f就是函数指针变量 // 以下两种写法是等价的 f = &test; f2 = test; // 以下两种写法也是等价的 f(100); // 调用函数 (*f2)(200); // 调用函数 return 0; } 运行: 需要特别说明的是: void (*f)(int);代表的是函数指针变量,但是 void* f(int);则代表的含义就完全不一样了,由于()运算符的优先级比*要高,所以f(int)代表一个函数,void*代表函数的返回值。 下面再通过几个小例子,来进一步加深对函数指针的认识: 示例 1: 运行结果: 如果不用函数指针,也不可能用一个函数可以包含多个函数的功能,从代码复用的角度来说,用它也是非常好的体现。 示例 2 【它有一个很重要的意义,需好好理解】 : 这个示例主要是用到系统函数, 对结构体数组元素进行排序 ,这个函数为 qsort ,通过man帮助查看一下: 具体代码如下:

智能指针

岁酱吖の 提交于 2020-03-05 07:27:53
title: 智能指针 date: 2018-04-02 15:21:32 categories: C/C++ tags: 指针 为什么使用动态指针? 在C++中,动态内存的管理是通过一对运算符来完成的: new: 在动态内存中为对象分配空间并返回一个指向该对象的指针,同时可以对这个对象初始化。 delete: 接受一个动态对象的指针,销毁该对象并释放与之关联的内存。 这样动态内存的使用就很容易出现问题: 忘记释放内存(delete)就会产生内存泄漏的问题。 过早释放内存(在还有指针引用该内存的时候就释放了它)就会产生引用非法内存的指针。 为了防止出现这种情况,更容易更安全地使用动态内存, 自C++11开始提供了两种智能指针类型来管理动态对象。 什么是智能指针? 智能指针是存储指向动态分配(堆)对象指针的类。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。 智能指针的原理是什么? 资源分配即初始化RAII(Resource Acquisition Is Initialization):RAII 的做法是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源。 定义一个类来封装资源的分配和释放,在构造函数完成资源的分配 和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。

数据结构与算法单排日记-2020/2/29-队列

生来就可爱ヽ(ⅴ<●) 提交于 2020-03-05 06:25:27
1.队列是一个有序列表,可以用数组或者链表表示。 2.遵循先入先出的原则:先存入队列的数据,要先取出。后存入的要后取出。 数组模拟队列 队列本身是一个有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下。其中 maxSize是该队列的最大容量 。 因为队列的输出、输入分别从前后端来处理,因此需要两个 变量front及rear分别记录前后端 的下标。 初始化 rear初始值默认为-1; rear指向队列尾的位置(就是队列尾) front初始值默认为-1; front指向队列首的前一个位置(不是队列首) 将数据存入队列(addQueue): 将尾部指针往后移,rear+1,如果front=rear,则队列为空 若rear小于最大下标maxSize-1,那么将数据存入rear所指的数组元素中。否则无法存入。 rear==maxSize-1,则队列已满。 当数据出队列时: 首指针往后移:front+1 代码实现: public class DemoQueue { /* 当将数据存入队列时: 1.将尾指针往后移:rear+1,当front==rear,队列为空 2.若尾指针rear==maxSize-1时,队列满,无法存入数据 当数据出队列时: 首指针往后移:front+1 */ private int maxSize ; //数组最大容量 private int rear ;

JVM学习【二】---对象的内存布局

两盒软妹~` 提交于 2020-03-05 02:29:15
二、对象(实例)的内存布局 1.对象的创建 虚拟机遇到一个new指令 检查这个指令的参数是否能在常量池中定位到一个类的符号引用 检查这个符号引用代表的类是否已经被加载、解析、初始化过。 如果没有,则执行类加载过程。(如果有,直接为新对象分配内存) 类加载检查通过后,vm为新生对象分配内存。(对象所需要的内存大小,在类加载完成后就能完全确定) 根据不同情况选取,内存分配策略:1)指针碰撞。2)空闲列表。(采取哪种分配方式由内存是否规整决定,内存是否规整由GC策略决定) 指针碰撞:堆中的内存是足够规整的,占用中内存和空闲内存以一个指针为分割,各占内存的一边。此时分配内存,只需要移动指针到对象大小的距离。这种分配方式叫做指针碰撞。 空闲列表:堆中的内存不规整,无法通过一个指针去标识,vm必须维护一个空闲内存列表,在分配时找出一块足够大的内存去分配,并更新列表记录,这种分配方式叫做空闲列表。 在TLAB中分配空间。(TLAB本地线程分配缓存,用于解决并发问题,线程1给A分配内存,刚分配完,指针还没修改或是列表还没更新,线程2又使用了刚刚的指针分配给B了内存,为了保证内存分配的安全,每个线程都预分配了一个独立的内存缓冲区,每个线程分配内存时,都在自己的缓冲区内存里分配,等缓冲区内的内存用完了,再使用同步锁定保证原子性。) 内存分配完成后(指针移位,列表同步),已分配的内存空间都初始化为0