昨天和赵崇说了一下工作的事情,说起了性能问题就讨论起了数据结果和指针对性能的影响。曾经一直没有想到这方面的事情,这几天专门抽时间回想一下这方面的知识,然后一点一点的总结一下,看看数据结构和指针在咱们代码中是怎样实现效率的提升的。

今天咱们先说一下指针。关于指针,在学C++的时候到时接触过指针。可是当时学的云里雾里,也没能好好的总结一下,以至于忘的差点儿相同了,假设大家也有对指针不熟悉的地方。我们先来回想一下C++的指针吧。

在C++中。指针是这样子定义的:指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。

要搞清一个指针须要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区。还有指针本身所占领的内存区。让我们分别说明。

int *ptr;
char *ptr;
int **ptr;
int (*ptr)[3];
int *(*ptr)[4];

通过上边的样例。大家把指针的申明语法去了。剩下的就是指针了。所以上边的指针就是“ptr”。

然后我们看一下指针的类型:

int *ptr; //指针的类型是int *
char *ptr; //指针的类型是char *
int **ptr; //指针的类型是 int **
int (*ptr)[3]; //指针的类型是 int(*)[3]
int *(*ptr)[4]; //指针的类型是 int *(*)[4]

怎么样?找出指针的类型的方法是不是非常easy?

指针所指向的类型

当你通过指针来訪问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。

指针所指向的类型

int *ptr; //指针的类型是int
char *ptr; //指针的类型是char
int **ptr; //指针的类型是 int *
int (*ptr)[3]; //指针的类型是 int()[3]
int *(*ptr)[4]; //指针的类型是 int *()[4]

指针的值

这个须要看操作系统,假设咱们的系统是32位的。那么咱们的指针就是32位长度的一个值,由于计算机的内存长度是32位。同理,64位的就是64位长度的值,当然这个64和32。都是用0和1表示的,由于计算机仅仅能知道0和1.

指针所指向的内存区就是从指针的值所代表的那个内存地址開始,长度为sizeof(指针所指向的类型)的一片内存区。

以后,我们说一个指针的值是XX。就相当于说该指针指向了以XX为首地址的一片内存区域。我们说一个指针指向了某块内存区域。就相当于说该指针的值是这块内存区域的首地址。

运算符&和*

这里&是取地址运算符,*是...书上叫做“间接运算符”。

&a的运算结果是一个指针。指针的类型是a的类型加个*(比如int*)。指针所指向的类型是a的类型(int)。指针所指向的地址嘛。那就是a的地址。

*p的运算结果就五花八门了。

总之*p的结果是p所指向的东西。这个东西有这些特点:它的类型是p指向的类型。它所占用的地址是p所指向的地址。

说过来翻过去。就是一个咱们手机导航过程。a就是你家,&a是指向你家的地址,比如p=&a,那么p就是我家的地址。那么*p的*就相当于咱们手机的导航过。通过你输入的地址,来找到你家。

上边的样例,仅仅是简单的说了一下什么叫做地址。那么假设大家想要更深层次的理解指针的话。给大家推荐一篇博客,写的很的基础http://www.cnblogs.com/basilwang/archive/2010/09/20/1831493.html

那么为什么要有指针呢,如不你设计一个函数

struct get(){

.........

}

返回一个结构体对象的函数,你要知道,C++中,这种返回值都是复制传递的过程。也就是说,你返回这个结构体的时候,程序会复制一个一样的结构体对象在栈里面,然后接受的变量在通过拷贝构造函数,复制一个新的变量。

最后程序在析构掉这个暂时的。

假设结构体非常小。没什么问题,假设非常大呢?这样一构造,一析构,会非常浪费时间。可是指针就不一样了,管你怎么弄,反正就是4字节。和一个int一样,全然没差别。

那么接下来咱们说一下C++到C#的”进化史”吧,平时我们见的代码好像没有再像C++的代码用到了指针,后来人们就说微软是不是就没有指针。事实上微软是有的,大家右击咱们的解决方式下的类库-à生成à不安全代码,大家勾选一下啊,一样能够用。仅仅只是写类和方法的时候前边加上个一个unsafe。比如:

public partial unsafe class Demo

static unsafe void Copy(byte[] src, int srcIndex,
byte[] dst, int dstIndex, int count)
{
//。。。。。
}

另一个keyword要注意,那就是Fixed。他的作用就是一个钉子,大家看了上边的介绍会发现指针事实上也是计算机中的0和1。

指针也占用内存。仅仅是他的大小是固定的。

而fixed语句可用于设置指向托管变量的指针并在
statement 运行期间“钉住”该变量。假设没有 fixed语句。则指向可移动托管变量的指针的地址可变。由于垃圾回收可能不可预知地重定位变量。

C# 编译器仅仅同意在 fixed语句中分配指向托管变量的指针,但无法改动在 fixed
语句中初始化的指针。

能够用数组或字符串的地址初始化指针:

fixed (int* p = arr) ...  // equivalent to p = &arr[0]
fixed (char* p = str) ... // equivalent to p = &str[0]

下边为大家呈现一个完整的样例,一个C#使用指针的样例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace cursorTest
{
class Program
{
// 使用unsafe标注该方法
static unsafe void Copy(byte[] src, int srcIndex,
byte[] dst, int dstIndex, int count)
{
if (src == null || srcIndex < 0 ||
dst == null || dstIndex < 0 || count < 0)
{
throw new ArgumentException();
}
int srcLen = src.Length;
int dstLen = dst.Length;
if (srcLen - srcIndex < count ||
dstLen - dstIndex < count)
{
throw new ArgumentException();
} // 用fixed钉住指针。不让他改变
fixed (byte* pSrc = src, pDst = dst)
{
byte* ps = pSrc;
byte* pd = pDst; // 循环复制
for (int n = 0; n < count / 4; n++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
} //完毕赋值
for (int n = 0; n < count % 4; n++)
{
*pd = *ps;
pd++;
ps++;
}
}
} static void Main(string[] args)
{
byte[] a = new byte[100];
byte[] b = new byte[100];
for (int i = 0; i < 100; ++i)
a[i] = (byte)i;
Copy(a, 0, b, 0, 100);
Console.WriteLine("The first 10 elements are:");
for (int i = 0; i < 10; ++i)
Console.Write(b[i] + " ");
Console.WriteLine("\n");
Console.ReadLine();
} }
}

可是为什么我们的代码如今都不怎么用指针呢,由于在公共语言执行库 (CLR)
中,不安全代码是指无法验证的代码。C# 中的不安全代码不一定是危急的,仅仅是其安全性无法由 CLR进行验证的代码。

因此。CLR
仅仅对在全然受信任的程序集中的不安全代码运行操作。假设使用不安全代码。由您负责确保您的代码不会引起安全风险或指针错误。所以你假设对你的代码很有保证的话,用也是没问题的。

C++和C#的指针小解的更多相关文章

  1. TODO:Golang指针使用注意事项

    TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...

  2. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  3. C++虚函数和函数指针一起使用

    C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...

  4. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  5. c 数组与指针的使用注意事项

    数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...

  6. Marshal.Copy将指针拷贝给数组

    lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...

  7. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  8. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  9. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

随机推荐

  1. PHP 在线 编辑 解析

    http://www.w3schools.com/php/default.asp    http://www.w3schools.com/php/showphp.asp?filename=demo_s ...

  2. Spring Cloud (10) Hystrix-监控面板

    Hystrix DashBoard 断路器是根据一段时间窗内的请求状况来判断并操作断路器的打开和关闭状态的.Hystrix Dashboard是作为断路器状态的一个组件,提供了数据监控和友好的图形化界 ...

  3. Android sensor 系统框架 (一)

    这几天深入学习了Android sensor框架,以此博客记录和分享分析过程,其中难免会有错误的地方,欢迎指出! 这里主要分析KERNEL->HAL->JNI这3层的流程.主要从以下几方面 ...

  4. iis设置404错误页,返回500状态码

    一般在II6下,设置自定义404错误页时,只需要在错误页中选择自定义的页面,做自己的404页面即可.但是在IIS7.0及以上时,设置完404错误页后,会发现状态码返回的是500,并且可能会引起页面乱码 ...

  5. JS——this与new

    this: 1.this只出现在函数中 2.谁调用函数,this就指的是谁 3.new People的this指的就是被创建的对象实例 new: 1.开辟内存空间,存储新创建的对象 2.把this设置 ...

  6. windows phone 8 使用页面传对象的方式 实现页面间的多值传递

    在做windows phone 开发的时候,会经常碰到页面间之间的跳转和传递数据,如果传递的值不多,只有两三个,我们通常使用NavigationService.Navigate(new Uri(&qu ...

  7. xamarin.forms模拟rem动态大小值,实现屏幕适配

    开发app的时候,比较麻烦的地方,就是处理屏幕适配,比如文字设为12的大小,测试的时候,看得文字挺正常,可是,放到高分辨率设备一看,文字就变得特别小, 怎样实现随着分辨率变大或者变小,所有的size数 ...

  8. select2下拉插件

    下拉单选: 1.行内 1)初始化数据: <select class="form-control select5"> <option selected>张三1 ...

  9. charAt 写一个反序函数

    function reverStr(str){ var tmpStr = ""; for(var i=str.length-1;i>=0;i--){ tmpStr += st ...

  10. STL中队列queue的用法

    头文件:#include <queue> 建立一个队列queue < 类型 > q 加入一个新的元素q.push(a) 询问队首元素q.front() 弹出队首元素q.pop( ...