函数_函数机 - CSDN
函数 订阅
函数(function)的定义通常分为传统定义和近代定义,函数的两个定义本质是相同的,只是叙述概念的出发点不同,传统定义是从运动变化的观点出发,而近代定义是从集合、映射的观点出发。函数的近代定义是给定一个数集A,假设其中的元素为x,对A中的元素x施加对应法则f,记作f(x),得到另一数集B,假设B中的元素为y,则y与x之间的等量关系可以用y=f(x)表示,函数概念含有三个要素:定义域A、值域B和对应法则f。其中核心是对应法则f,它是函数关系的本质特征。 [1]  函数,最早由中国清朝数学家李善兰翻译,出于其著作《代数学》。之所以这么翻译,他给出的原因是“凡此变数中函彼变数者,则此为彼之函数”,也即函数指一个量随着另一个量的变化而变化,或者说一个量中包含另一个量。 展开全文
函数(function)的定义通常分为传统定义和近代定义,函数的两个定义本质是相同的,只是叙述概念的出发点不同,传统定义是从运动变化的观点出发,而近代定义是从集合、映射的观点出发。函数的近代定义是给定一个数集A,假设其中的元素为x,对A中的元素x施加对应法则f,记作f(x),得到另一数集B,假设B中的元素为y,则y与x之间的等量关系可以用y=f(x)表示,函数概念含有三个要素:定义域A、值域B和对应法则f。其中核心是对应法则f,它是函数关系的本质特征。 [1]  函数,最早由中国清朝数学家李善兰翻译,出于其著作《代数学》。之所以这么翻译,他给出的原因是“凡此变数中函彼变数者,则此为彼之函数”,也即函数指一个量随着另一个量的变化而变化,或者说一个量中包含另一个量。
信息
中文名
函数
外文名
function
提出时间
17世纪
表达式
y=f(x)
提出者
莱布尼茨(G.W.Leibniz)
表示法
列表法、图像法、解析法
三要素
自变量、因变量、对应法则
应用学科
数学、计算机科学等
函数详细介绍
首先要理解,函数是发生在集合之间的一种对应关系。然后,要理解发生在A、B之间的函数关系不止且不止一个。最后,要重点理解函数的三要素。函数的对应法则通常用解析式表示,但大量的函数关系是无法用解析式表示的,可以用图像、表格及其他形式表示 [2]  。在一个变化过程中,发生变化的量叫变量(数学中,常量为x,而y则随x值的变化而变化),有些数值是不随变量而改变的,我们称它们为常量。自变量(函数):一个与它量有关联的变量,这一量中的任何一值都能在它量中找到对应的固定值。因变量(函数):随着自变量的变化而变化,且自变量取唯一值时,因变量(函数)有且只有唯一值与其相对应。函数值:在y是x的函数中,x确定一个值,y就随之确定一个值,当x取a时,y就随之确定为b,b就叫做a的函数值 [2]  。设A和B是两个非空集合,如果按照某种对应关系 ,对于集合A中的任何一个元素a,在集合B中都存在唯一的一个元素b与之对应,那么,这样的对应(包括集合A,B,以及集合A到集合B的对应关系f)叫做集合A到集合B的映射(Mapping),记作 。其中,b称为a在映射f下的象,记作: ; a称为b关于映射f的原象。集合A中所有元素的象的集合记作f(A)。则有:定义在非空数集之间的映射称为函数。(函数的自变量是一种特殊的原象,因变量是特殊的象) [2]  函数与不等式和方程存在联系(初等函数)。令函数值等于零,从几何角度看,对应的自变量的值就是图像与X轴的交点的横坐标;从代数角度看,对应的自变量是方程的解。另外,把函数的表达式(无表达式的函数除外)中的“=”换成“<”或“>”,再把“Y”换成其它代数式,函数就变成了不等式,可以求自变量的范围 [2]  。如果X到Y的二元关系 ,对于每个 ,都有唯一的 ,使得 ,则称f为X到Y的函数,记做: 。当 时,称f为n元函数 [2]  。输入值的集合X被称为f的定义域;可能的输出值的集合Y被称为f的值域。函数的值域是指定义域中全部元素通过映射f得到的实际输出值的集合。注意,把对应域称作值域是不正确的,函数的值域是函数的对应域的子集。计算机科学中,参数和返回值的数据类型分别确定了子程序的定义域和对应域。因此定义域和对应域是函数一开始就确定的强制进行约束。另一方面,值域是和实际的实现有关 [2]  。 单射函数,将不同的变量映射到不同的值。即:对于所有 和 ,当 时有 。满射函数,其值域即为其对应域。即:对映射f的对应域中之任意y,都存在至少一个x满足 y=f(x)。双射函数,既是单射的又是满射的。也叫一一对应。双射函数经常被用于表明集合X和Y是等势的,即有一样的基数。如果在两个集合之间可以建立一个一一对应,则说这两个集合等势 [2]  。 元素在的象就是f(x),他们所取的值为0 [2]  。函数f的图象是平面上点对 的集合,其中x取定义域上所有成员的。函数图象可以帮助理解证明一些定理。如果X和Y都是连续的线,则函数的图象有很直观表示注意两个集合X和Y的二元关系有两个定义:一是三元组(X,Y,G),其中G是关系的图;二是索性以关系的图定义。用第二个定义则函数f等于其图象 [2]  。
收起全文
  • 学习神经网络的时候我们总是听到激活函数这个词,而且很多资料都会提到常用的激活函数,比如Sigmoid函数、tanh函数、Relu函数。那么我们就来详细了解下激活函数方方面面的知识。本文的内容包括几个部分: 什么是...

    引言

    学习神经网络的时候我们总是听到激活函数这个词,而且很多资料都会提到常用的激活函数,比如Sigmoid函数、tanh函数、Relu函数。那么我们就来详细了解下激活函数方方面面的知识。本文的内容包括几个部分:

    1. 什么是激活函数?
    2. 激活函数的用途(为什么需要激活函数)?
    3. 有哪些激活函数,都有什么性质和特点?
    4. 应用中如何选择合适的激活函数?

    如果你对以上几个问题不是很清楚,下面的内容对你是有价值的。

    什么是激活函数?

    首先要了解神经网络的基本模型。(不熟悉的同学请去看本人另外一篇介绍:人工神经网络基本原理
    单一神经元模型如下图所示。
    这里写图片描述
    神经网络中的每个神经元节点接受上一层神经元的输出值作为本神经元的输入值,并将输入值传递给下一层,输入层神经元节点会将输入属性值直接传递给下一层(隐层或输出层)。在多层神经网络中,上层节点的输出和下层节点的输入之间具有一个函数关系,这个函数称为激活函数(又称激励函数)。

    激活函数的用途(为什么需要激活函数)?

    如果不用激励函数(其实相当于激励函数是f(x) = x),在这种情况下你每一层节点的输入都是上层输出的线性函数,很容易验证,无论你神经网络有多少层,输出都是输入的线性组合,与没有隐藏层效果相当,这种情况就是最原始的感知机(Perceptron)了,那么网络的逼近能力就相当有限。正因为上面的原因,我们决定引入非线性函数作为激励函数,这样深层神经网络表达能力就更加强大(不再是输入的线性组合,而是几乎可以逼近任意函数)。

    有哪些激活函数,都有什么性质和特点?

    早期研究神经网络主要采用sigmoid函数或者tanh函数,输出有界,很容易充当下一层的输入。
    近些年Relu函数及其改进型(如Leaky-ReLU、P-ReLU、R-ReLU等)在多层神经网络中应用比较多。下面我们来总结下这些激活函数:

    Sigmoid函数

    Sigmoid 是常用的非线性的激活函数,它的数学形式如下:
    f(z)=11+ez f(z)=\frac{1}{1+e^{-z}}
    Sigmoid的几何图像如下:
    这里写图片描述
    特点:
    它能够把输入的连续实值变换为0和1之间的输出,特别的,如果是非常大的负数,那么输出就是0;如果是非常大的正数,输出就是1.
    缺点:
    sigmoid函数曾经被使用的很多,不过近年来,用它的人越来越少了。主要是因为它固有的一些 缺点。
    缺点1:在深度神经网络中梯度反向传递时导致梯度爆炸和梯度消失,其中梯度爆炸发生的概率非常小,而梯度消失发生的概率比较大。首先来看Sigmoid函数的导数,如下图所示:
    这里写图片描述
    如果我们初始化神经网络的权值为 [0,1][0,1] 之间的随机值,由反向传播算法的数学推导可知,梯度从后向前传播时,每传递一层梯度值都会减小为原来的0.25倍,如果神经网络隐层特别多,那么梯度在穿过多层后将变得非常小接近于0,即出现梯度消失现象;当网络权值初始化为 (1,+)(1,+∞) 区间内的值,则会出现梯度爆炸情况。
    详细数学分析见文章:http://neuralnetworksanddeeplearning.com/chap5.html 中文译文:深度神经网络为何很难训练
    缺点2:Sigmoid 的 output 不是0均值(即zero-centered)。这是不可取的,因为这会导致后一层的神经元将得到上一层输出的非0均值的信号作为输入。 产生的一个结果就是:如x&gt;0, f=wTx+bx&gt;0, \ f= w^Tx+b,那么对w求局部梯度则都为正,这样在反向传播的过程中w要么都往正方向更新,要么都往负方向更新,导致有一种捆绑的效果,使得收敛缓慢。 当然了,如果按batch去训练,那么那个batch可能得到不同的信号,所以这个问题还是可以缓解一下的。因此,非0均值这个问题虽然会产生一些不好的影响,不过跟上面提到的梯度消失问题相比还是要好很多的。
    缺点3:其解析式中含有幂运算,计算机求解时相对来讲比较耗时。对于规模比较大的深度网络,这会较大地增加训练时间。

    tanh函数

    tanh函数解析式:
    tanh(x)=exexex+extanh(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}
    tanh函数及其导数的几何图像如下图:
    tanh(x)及其导数的几何图像
    tanh读作Hyperbolic Tangent,它解决了Sigmoid函数的不是zero-centered输出问题,然而,梯度消失(gradient vanishing)的问题和幂运算的问题仍然存在。

    Relu函数

    Relu函数的解析式:
    Relu=max(0,x)Relu=max(0,x)
    Relu函数及其导数的图像如下图所示:
    这里写图片描述
    ReLU函数其实就是一个取最大值函数,注意这并不是全区间可导的,但是我们可以取sub-gradient,如上图所示。ReLU虽然简单,但却是近几年的重要成果,有以下几大优点:
    1) 解决了gradient vanishing问题 (在正区间)
    2)计算速度非常快,只需要判断输入是否大于0
    3)收敛速度远快于sigmoid和tanh

    ReLU也有几个需要特别注意的问题:
    1)ReLU的输出不是zero-centered
    2)Dead ReLU Problem,指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。有两个主要原因可能导致这种情况产生: (1) 非常不幸的参数初始化,这种情况比较少见 (2) learning rate太高导致在训练过程中参数更新太大,不幸使网络进入这种状态。解决方法是可以采用Xavier初始化方法,以及避免将learning rate设置太大或使用adagrad等自动调节learning rate的算法。

    尽管存在这两个问题,ReLU目前仍是最常用的activation function,在搭建人工神经网络的时候推荐优先尝试!

    Leaky ReLU函数(PReLU)

    函数表达式:f(x)=max(αx,x)f(x)=max(\alpha x,x)
    Leaky Relu函数及其导数的图像如下图所示:
    (有同学在评论中反映下图有误,其实没有错误,左半边直线斜率非常接近0,所以看起来像是平的。就不改了,α=0.01\alpha=0.01看起来就是这样的。感谢大家提意见 ^ _ ^)
    这里写图片描述
    人们为了解决Dead ReLU Problem,提出了将ReLU的前半段设为αx\alpha x而非0,通常α=0.01\alpha=0.01。另外一种直观的想法是基于参数的方法,即ParametricReLU:f(x)=max(αx,x)Parametric ReLU:f(x) = \max(\alpha x, x),其中α\alpha
    可由方向传播算法学出来。理论上来讲,Leaky ReLU有ReLU的所有优点,外加不会有Dead ReLU问题,但是在实际操作当中,并没有完全证明Leaky ReLU总是好于ReLU。

    ELU (Exponential Linear Units) 函数

    函数表达式:
    f(x)={x,if x&gt;0α(ex1),otherwisef(x)= \begin{cases}x,&amp; \text{if } x &gt; 0\\ \alpha(e^x - 1), &amp; \text{otherwise} \end{cases}
    函数及其导数的图像如下图所示:
    这里写图片描述

    ELU也是为解决ReLU存在的问题而提出,显然,ELU有ReLU的基本所有优点,以及:

    不会有Dead ReLU问题
    输出的均值接近0,zero-centered
    

    它的一个小问题在于计算量稍大。类似于Leaky ReLU,理论上虽然好于ReLU,但在实际使用中目前并没有好的证据ELU总是优于ReLU。

    MaxOut函数

    这个函数可以参考论文《maxout networks》,Maxout是深度学习网络中的一层网络,就像池化层、卷积层一样等,我们可以把maxout 看成是网络的激活函数层,我们假设网络某一层的输入特征向量为:X=(x1,x2,……xd),也就是我们输入是d个神经元。Maxout隐藏层每个神经元的计算公式如下:
    这里写图片描述

    上面的公式就是maxout隐藏层神经元i的计算公式。其中,k就是maxout层所需要的参数了,由我们人为设定大小。就像dropout一样,也有自己的参数p(每个神经元dropout概率),maxout的参数是k。公式中Z的计算公式为:

    这里写图片描述

    权重w是一个大小为(d,m,k)三维矩阵,b是一个大小为(m,k)的二维矩阵,这两个就是我们需要学习的参数。如果我们设定参数k=1,那么这个时候,网络就类似于以前我们所学普通的MLP网络。
    我们可以这么理解,本来传统的MLP算法在第i层到第i+1层,参数只有一组,然而现在我们不这么干了,我们在这一层同时训练n组的w、b参数,然后选择激活值Z最大的作为下一层神经元的激活值,这个max(z)函数即充当了激活函数。

    应用中如何选择合适的激活函数?

    这个问题目前没有确定的方法,凭一些经验吧。
    1)深度学习往往需要大量时间来处理大量数据,模型的收敛速度是尤为重要的。所以,总体上来讲,训练深度学习网络尽量使用zero-centered数据 (可以经过数据预处理实现) 和zero-centered输出。所以要尽量选择输出具有zero-centered特点的激活函数以加快模型的收敛速度。
    2)如果使用 ReLU,那么一定要小心设置 learning rate,而且要注意不要让网络出现很多 “dead” 神经元,如果这个问题不好解决,那么可以试试 Leaky ReLU、PReLU 或者 Maxout.
    3)最好不要用 sigmoid,你可以试试 tanh,不过可以预期它的效果会比不上 ReLU 和 Maxout.

    参考资料

    1.聊一聊深度学习的activation function—夏飞
    2.http://blog.csdn.net/cyh_24/article/details/50593400
    3.http://www.cnblogs.com/tornadomeet/p/3428843.html
    4.《maxout networks》

    展开全文
  • 定义一个函数为虚函数,不代表函数为不被实现的函数。 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。 定义一个函数为纯虚函数,才代表函数没有被实现。 定义纯虚函数是为了实现一个接口,起到一个...
    首先:强调一个概念
    定义一个函数为虚函数,不代表函数为不被实现的函数。
    定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
    定义一个函数为纯虚函数,才代表函数没有被实现。

    定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
    1、简介
    假设我们有下面的类层次:
    class A
    {
    public:
        virtual void foo()
        {
            cout<<"A::foo() is called"<<endl;
        }
    };
    class B:public A
    {
    public:
        void foo()
        {
            cout<<"B::foo() is called"<<endl;
        }
    };
    int main(void)
    {
        A *a = new B();
        a->foo();   // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
        return 0;
    }
         这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。
        虚函数只能借助于指针或者引用来达到多态的效果。

    C++纯虚函数
    一、定义
     纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
     virtual void funtion1()=0
    二、引入原因
      1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。
      2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
      为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。

    声明了纯虚函数的类是一个抽象类。所以,用户不能创建类的实例,只能创建它的派生类的实例。
    纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。
    定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。
    纯虚函数的意义,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。


    抽象类的介绍
    抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。
    (1)抽象类的定义:  称带有纯虚函数的类为抽象类。
    (2)抽象类的作用:
    抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。所以派生类实际上刻画了一组子类的操作接口的通用语义,这些语义也传给子类,子类可以具体实现这些语义,也可以再将这些语义传给自己的子类。
    (3)使用抽象类时注意:

    •   抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。
    •   抽象类是不能定义对象的。


    总结:

    1、纯虚函数声明如下: virtual void funtion1()=0; 纯虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口。包含纯虚函数的类是抽象类,抽象类不能定义实例,但可以声明指向实现该抽象类的具体类的指针或引用。
    2、虚函数声明如下:virtual ReturnType FunctionName(Parameter);虚函数必须实现,如果不实现,编译器将报错,错误提示为:
    error LNK****: unresolved external symbol "public: virtual void __thiscall ClassName::virtualFunctionName(void)"
    3、对于虚函数来说,父类和子类都有各自的版本。由多态方式调用的时候动态绑定。
    4、实现了纯虚函数的子类,该纯虚函数在子类中就编程了虚函数,子类的子类即孙子类可以覆盖该虚函数,由多态方式调用的时候动态绑定。
    5、虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。
    6、在有动态分配堆上内存的时候,析构函数必须是虚函数,但没有必要是纯虚的。
    7、友元不是成员函数,只有成员函数才可以是虚拟的,因此友元不能是虚拟函数。但可以通过让友元函数调用虚拟成员函数来解决友元的虚拟问题。
    8、析构函数应当是虚函数,将调用相应对象类型的析构函数,因此,如果指针指向的是子类对象,将调用子类的析构函数,然后自动调用基类的析构函数。

    有纯虚函数的类是抽象类,不能生成对象,只能派生。他派生的类的纯虚函数没有被改写,那么,它的派生类还是个抽象类。
    定义纯虚函数就是为了让基类不可实例化化
    因为实例化这样的抽象数据结构本身并没有意义。
    或者给出实现也没有意义
    实际上我个人认为纯虚函数的引入,是出于两个目的
    1、为了安全,因为避免任何需要明确但是因为不小心而导致的未知的结果,提醒子类去做应做的实现。
    2、为了效率,不是程序执行的效率,而是为了编码的效率。
    展开全文
  • 指针函数函数指针

    2012-11-25 21:57:51
    1.指针函数 先看下面的函数声明,注意,此函数有返回值,返回值为int *,即返回值是指针类型的。 int *f(int a, int b);上面的函数声明又可以写成如下形式: int* f(int a, int b); 让指针标志 * 与int紧贴...

    1.指针函数

    先看下面的函数声明,注意,此函数有返回值,返回值为int *,即返回值是指针类型的。

    int *f(int a, int b);
    上面的函数声明又可以写成如下形式:

    int* f(int a, int b);
    让指针标志 * 与int紧贴在一起,而与函数名f间隔开,这样看起来就明了些了,f是函数名,返回值类型是一个int类型的指针。

    下面看指针函数的实现:

    int *f(int a, int b); // 声明指针函数
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	printf("------------------------------ Start\n");
    
        int *p1 = NULL;
    	printf("The memeory address of p1 = 0x%x \n", p1);
    
        p1 = f(1, 2);
    
    	printf("The memeory address of p1 = 0x%x \n", p1);
    	printf("*p1 = %d \n", *p1);
    
    	printf("------------------------------ End\n");
    	getchar();
    	return 0;
    }
    
    /*
     * 指针函数的定义
     * 返回值是指针类型int *
     */
    int *f(int a, int b) {
    	int *p = (int *)malloc(sizeof(int));
    	printf("The memeory address of p = 0x%x \n", p);
    	memset(p, 0, sizeof(int));
    	*p = a + b;
    	printf("*p = %d \n", *p);
    
    	return p;
    }
    通过运行结果,可以看出,指针函数f返回的类型是一个指针类型,因为f是赋值给int类型指针p1的,如果不是指针类型,编译就会出错。

    下面是运行结果:


    从上图的运行结果可以看出,指针函数f的返回值p和f赋值给的指针p1的地址是相同的,都是指向指针函数内部申请的内存地址0x3b88d0。


    下面是debug查看的指针p1和指针p的内存地址。

    (1)指针p1刚定义时的指向NULL,也就是空指针,地址是0。p1的地址如红色框内所示,p1地址为0x00000000。


    (2)指针函数f内的返回值p的地址如下图中红色框内所示,p的地址是0x003b88d0:


    (3)执行完指针函数f后,把f的返回值p赋给先前定义的地址p1,此时p1的地址和p的地址相同。p1的地址如下图中红色框内所示,p1的地址是0x003b88d0,与p的地址相同,p的地址如下图中蓝色框内所示,并且两者的值也都是3,因为是指向同一个地址,所以值必然相同:


    所以,指针函数就是返回一个地址给调用者,用于需要地址的情况。


    2.函数指针

    顾名思义,函数指针说的就是一个指针,但这个指针指向的函数,不是普通的基本数据类型或者类对象。

    函数指针的定义如下:

    int (*f)(int a, int b); // 声明函数指针
    通过与1中指针函数的定义对比可以看到,函数指针与指针函数的最大区别是函数指针的函数名是一个指针,即函数名前面有一个指针类型的标志型号“*”。

    当然,函数指针的返回值也可以是指针。

    上面的函数指针定义为一个指向一个返回值为整型,有两个参数并且两个参数的类型都是整型的函数。

    下面是利用函数指针分别求两个整数的最大值和最小值的用法。

    /*
     * 求最大值
     * 返回值是int类型,返回两个整数中较大的一个
     */
    int max(int a, int b) {
    	return a > b ? a : b;
    }
    
    /*
     * 求最小值
     * 返回值是int类型,返回两个整数中较小的一个
     */
    int min(int a, int b) {
    	return a < b ? a : b;
    }
    
    int (*f)(int, int); // 声明函数指针,指向返回值类型为int,有两个参数类型都是int的函数
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	printf("------------------------------ Start\n");
    
    	f = max; // 函数指针f指向求最大值的函数max
        int c = (*f)(1, 2);
    
    	printf("The max value is %d \n", c);
    
    	f = min; // 函数指针f指向求最小值的函数min
        c = (*f)(1, 2);
    
    	printf("The min value is %d \n", c);
    
    	printf("------------------------------ End\n");
    	getchar();
    	return 0;
    }

    执行结果如下:


    
    
    
    
    
    
    
    
    
    
    
    
    
    
    展开全文
  • 在编写C++程序时,不可避免会遇到strcpy()函数和其安全版本strcpy_s()函数,其实之所以会推出_s版本的函数,就是为了使编程更加安全,然而为了保证安全,也就会更容易使我们编写的代码“被报错”。所以这里来简略说...

    在编写C++程序时,不可避免会遇到strcpy()函数和其安全版本strcpy_s()函数,其实之所以会推出_s版本的函数,就是为了使编程更加安全,然而为了保证安全,也就会更容易使我们编写的代码“被报错”。所以这里来简略说一下strcpy()函数和strcpy_s()函数的使用及注意事项。

    首先,我们知道原函数strcpy()函数和安全版本strcpy_s()函数都是存在于头文件<cstring>中的,所以程序一开始必须要有以下语句:

    #include <cstring>

    其次,原函数strcpy()函数是存在于标准名称空间std中的成员,所以要使用strcpy()函数,还需要加上以下语句:

    using namespace std;

    或者:

    using std::strcpy;

    或者在每次使用strcpy()函数时,前面加上名称空间:

    std::strcpy(str1, str2);

    但是对于最新的编辑器,往往你正常使用strcpy()函数,还是会报错,例如下面这个简单的例子:

    // strcpy.cpp -- test the strcpy function and strcpy_s function
    
    #include "stdafx.h"
    #include <iostream>
    #include <cstring>
    
    
    int main()
    {
        char str1[20];
        char str2[20];
        std::cout << "Please enter str2: ";
        std::cin.get(str2, 20);
        std::strcpy(str1, str2);
        std::cout << "str1 is " << "\" " << str1 << "\".\n";
        system("pause");
        return 0;
    }

    正常来说,语法上没有任何问题,但是运行时,Visual Studio 2017 会报错,显示如下:

    意义很简单,就是告诉你,strcpy()函数不安全,必须改为使用strcpy_s()函数,首先不管改成strcpy_s()函数之后会发生什么后续问题,其实从理论上来说,上面的代码语法上和逻辑上来说都是对的,那么怎么避免编辑器强制要求你使用安全版本呢?

    其实解决方法有很多,单单是避免上图中的错误代码4996的情况,可以使用编辑器的选择性提供warning功能,在include语句前面加上下句:

    #pragma warning( disable : 4996)

    但是这种解决方法有时候不能解决问题,例如VS2017我就试过好像不行,那么我们就索性关闭warning功能就好了,完成这个任务的方法是在#include<stdio.h>的前面加上一句,如下所示:
     

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>

    VS2017里面,这句应该是加在头文件“stdafx.h”里面。

    加完之后,再次运行相同的程序,就可以正常运行了,显示结果如下图所示:

    那么解决了不使用安全版本的问题,接下来就来说一下使用安全版本的情况。

    如果我们选择相信编辑器,那么我们就会把strcpy()函数改成使用strcpy_s()函数,改完之后运行首先会遇到以下错误:

    这是因为之前使用strcpy()函数时,我们知道该函数是标准名称空间std的成员,而安全版本strcpy_s并不是该名称空间的成员,所以“std::”应该被去掉,去掉之后再次运行,就会正常运行了。

    但是有时候,编辑器在你去掉“std::”还是会出现错误,错误说明是:1.没有与参数列表匹配的 重载函数"strcpy_s"实例;2."strcpy_s":函数不接受2个参数。

    如下图所示:

    这是因为strcpy_s()函数是有两个版本,用两个参数、三个参数都可以,只要可以保证缓冲区大小。
    三个参数时:
    errno_t strcpy_s( 
    char *strDestination, 
    size_t numberOfElements, 
    const char *strSource 
    );
    两个参数时:
    errno_t strcpy_s( 
    char (&strDestination)[size], 
    const char *strSource 
    ); // C++ only 

    所以,若我们使用new来分配储存空间时,就会出现上面说的不能保证缓冲区大小的问题了

    看下面的代码:
     

    char * str;
    str = new char[4];
    strcpy_s(str, "C++");

    语法来说没有什么问题,但是因为str的储存空间是使用new临时分配的,所以并不能保证缓冲区大小,点击运行就会出现上述的两种错误了。

    这种情况的解决方法其实很简单,那就是不符合2个参数的版本就使用3个参数的版本呗。在两个str之间,加上一个参数,标识长度。

    所以完整代码如下:

    // strcpy.cpp -- test the strcpy function and strcpy_s function
    
    #include "stdafx.h"
    #include <iostream>
    #include <cstring>
    
    
    int main()
    {
        char str1[20];
        char str2[20];
        std::cout << "Please enter str2: ";
        std::cin.get(str2, 20);
        strcpy_s(str1, str2);
        std::cout << "str1 is " << "\"" << str1 << "\".\n";
        char * str;
        str = new char[20];
        strcpy_s(str, strlen(str1)+1, str1);
        std::cout << "str is " << "\"" << str << "\".\n";
        system("pause");
        return 0;
    }

    这里分别使用了2个参数和3个参数的strcpy_s()函数版本。

    后面使用3个参数的版本时,一般的做法就是将长度定为被复制的字符串长度+1,因为strlen()返回字符串长度,但是不包括字符串末尾的空字符,所以+1。

    上述代码运行结果如下图所示:

    以上就是strcpy()函数和strcpy_s()函数的基本使用和注意事项了,希望对大家有所帮助~

    展开全文
  • 之前好好的能远程桌面连接到...要求的函数不受支持。猜想可能是Windows又更新了什么鬼,后面查询资料知道是由于CredSSP加密Oracle修正的原因,这里我整理了下解决方案,希望能帮到你。 微软给出解决方案: ...

    PhpStorm 绝对是PHP开发最好的开发工具。


    之前好好的能远程桌面连接到服务器,但是今天来就不能连接上了,并提示:身份验证错误。要求的函数不受支持。猜想可能是Windows又更新了什么鬼,后面查询资料知道是由于CredSSP加密Oracle修正的原因,这里我整理了下解决方案,希望能帮到你。

     

    微软给出解决方案:

    https://support.microsoft.com/zh-cn/help/4093492/credssp-updates-for-cve-2018-0886-march-13-2018

    2018 年 5 月 8 日

    罪魁祸首:是由于Windows将默认设置,从“易受攻击”更改为“缓解”的更新引起的。

     

    通用解决方案:

    方案一 :安装补丁强烈推荐)

    本地电脑和服务器端都同时安装更新补丁,更新以后重启服务器。

    补丁单独下载地址:

    win 7、win2008 R2:KB4103718 

    win 8、win2012:KB4103730

    win10、win2016 :KB4103721

    注意下载对应版本补丁进行安装,该方案博主没有亲测,请谨慎操作,如有探索的同学,可以试试,欢迎和博主一起交流学习。

     

    方案二:修改组策略设置(适用于windows专业版以上

    打开运行:gpedit.msc

    打开组策略编辑器

    应用确定完之后就可以进行远程连接

     

    方案三:删除卸载更新(适用于windows10家庭版

    Windows10家庭版,卸载KB4103727和KB4131372两个补丁包即可。

    选择查看已安装的更新

    选择你要卸载的卸载即可

     

    补丁包需要逐个卸载,等第一个卸载完再卸载第二个,两个都卸载完毕后,重启电脑。你又可以进行远程桌面连接了。

     

    方案四:windows10家庭版找回组策略(适用于windows10家庭版

     

    以为windows 10 家庭版也可以通过组策略配置就可以了,就把组策略搞了出来,进入组策略发现没有那一项,,最后还是卸载了最后的那个更新补丁

    新建一个TXT文档,在里面写入

    @echo off
    pushd "%~dp0"
    dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >List.txt
    dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-Package~3*.mum >>List.txt
    for /f %%i in ('findstr /i . List.txt 2^>nul') do dism /online /norestart /add-package:"C:\Windows\servicing\Packages\%%i"
    pause

    最后将后缀改为.cmd结尾即可

    双机运行,等待他执行完,任意键退出即可

    重启PC,运行中再输入gpedit.msc即可调出组策略编辑器,再进行方案二的操作。

     

    展开全文
  • 出现这种错误一般是因为定义的函数和当前的工作环境不在一块导致。 一般情况MATLAB工作环境默认为C盘,但我们有时候会将自己编写的函数放在其他盘。当我们调用这个函数是就会出现 未定义函数或变量:‘’xxx‘’。 ...
  • sigmod(x)函数sigmod函数的数学公式为: Θ(x)=11+e−x \Theta(x)=\frac {1}{1+e^{-x} } 函数取值范围(0,1),函数图像下图所示:二. tanh(x) 函数tanh(x)函数的数学公式为:tanh(x)=sinh(x)cosh(x)tanh(x) = \frac{...
  • 本篇文章是在《应该如何理解概率分布函数和概率密度函数?》的基础上整理来的。非常感谢原作者。 目录 1先从离散型随机变量和连续性随机变量说起 2离散型随机变量的概率函数,概率分布和分布函数 2.1概率函数和...
  • 转自:c++虚函数 大牛的文章,就是通俗易懂,言简意赅。 前言 C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数...
  • C++ 析构函数

    2016-09-21 00:06:10
    C++ 析构函数我使用的继承开发环境: Visual Studio 2010设计一个类时,如何写析构函数? 析构函数如果我们不写的话,C++ 会帮我们自动的合成一个,就是说:C++ 会自动的帮我们写一个析构函数。很多时候,自动生成...
  • 关于静态库和动态库的使用和制作方法。...什么是回调函数?...如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实...
  •  概率密度函数:用于直观地描述连续性随机变量(离散型的随机变量下该函数称为分布律), 表示瞬时幅值落在某指定范围内的概率,因此是幅值的函数。连续样本空间情形下的概率称为 概率密度,当试验次数无限增加,...
  • C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法。 构造函数就是当创建一个类的对象时,它被调用来对类的数据成员进行初始化和分配内存。拷贝构造函数是一种特殊的构造函数,用...
  • 所谓函数,就是把具有独立功能的代码块组织成为一个小模块,在需要的时候调用 函数的使用包含两个步骤 1.定义函数–封装独立的功能 2.调用函数–享受封装的成果 函数的作用:在开发时,使用函数可以提高编写的...
  • matlab求导命令diff调用格式:diff(函数) , 求的一阶导数;diff(函数, n) ,求的n阶导数(n是具体整数);diff(函数,变量名),求对的偏导数;diff(函数, 变量名,n),求对的n阶偏导数;matlab求雅可比矩阵命令...
  • js函数的回调

    2019-07-31 19:09:41
    平常的前端开发工作中,编写js时会有很多地方用到函数的回调。 最简单的例子就是: <script language="javascript" type="text/javascript"> function doSomething(callback) { if(typeof callback == ...
  • C++的const类成员函数

    2020-05-13 17:51:23
    我们知道,在C++中,若一个变量声明为const类型,则试图修改该变量的值的操作都被视编译错误。例如, const char blank = ‘’;...为了保证const对象的常量性,编译器须区分不安全与安全的成员函数
  • C++ Template 基础篇(一):函数模板Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第一部分。C Template 基础篇一函数模板 为什么要...
  • 说起函数调用,相信大家也不会陌生,然而对于初学Shell的我来说,Shell中函数调用方式却有点让我不太习惯,自己也走了不少的弯路,因为传递参数时出了一个很“自然”的错误,也让我吃了不少的苦头,所以总结一下...
  • 一:损失函数,代价函数,目标函数定义首先给出结论:损失函数(Loss Function )是定义在单个样本上的,算的是一个样本的误差。代价函数(Cost Function )是定义在整个训练集上的,是所有样本误差的平均,也就是...
1 2 3 4 5 ... 20
收藏数 7,133,197
精华内容 2,853,278
关键字:

函数