VC++入门经典学习笔记--函数

这里是源码:
A.函数是具有用途的自包含的代码块。函数名既是函数的标识,用来在程序中调用函数。如果函数名不在名称空间中定义,它就是全局的,否则就要用名称空间的名称来限定他。
B.函数的主要优点之一是根据需要可以在程序的不同位置执行任意次。如果不能将代码块封装到函数中,则程序将最终成为庞然大物,因为那样通常需要再程序的不同位置复制相同的代码。使用函数还可以将程序分为易于管理的代码块,以方便开发和测试,复杂的大型程序如果包含几个小代码块,就比编写为一个大代码块更容易理解和测试。
C.函数头
int num(double a,int b);
本行由三部分组成:
a.返回值的类型(本例中int)
b.函数名(本例中num)
c.圆括号中的函数形参(本例中是a和b,分别为double和int类型)
注意:函数头末尾和函数体右大括号后面都不需要分号。如果函数没有返回值,则由void来指定返回类型。(void myNum(int a));

简单介绍完函数,下面其实是好几个例子组成的:
下面这是main主函数和一些要调用函数的声明:

#include "stdafx.h"

using std::cin;
using std::cout;
using std::endl;
//1.值传递(pass by value )
int _value(int a,int b);
//2.地址传递(pass by pointer)
int _pointer(int* a);
//3.引用传递(pass by reference)
int _reference(int &a,int &b);
//4.函数返回指针
int*  _rpointer(int a,int b);
//5.函数中的静态变量
int _countNum(int a,int b);
//6.递归函数调用
int _chengNum(int n);
int _tmain(int argc, _TCHAR* argv[])
{
    int a{ 5 };
    int b{ 5 };
    int _vNum{};
    int* _pNum{&a};
    int _rNum{};

    int* _pRNum{};
    int _cNum{};
    //1.值传递
    printf("调用传值前:a=%d,b=%d,vNum=%d\n", a, b, _vNum);
    _vNum = _value(a, b);
    printf("传值后:a=%d,b=%d,vNum=%d\n", a, b, _vNum);
    //2.地址传递
    printf("调用传地址前:a=%d,*_pNum=%d\n", a, *_pNum);
    *_pNum = _pointer(&a);
    printf("传地址后:a=%d,*_pNum=%d\n", a, *_pNum);
    //3.引用传递
    printf("调用传引用前:a=%d,b=%d,_rNum=%d\n", a, b, _rNum);
    _rNum = _reference(a, b);
    printf("传引用后:a=%d,b=%d,_rNum=%d\n", a, b, _rNum);

    //4.函数返回指针
    _pRNum = _rpointer(a,b);
    cout << "_pRnum = " << *_pRNum << endl;

    delete _pRNum;                       //释放掉内存
    _pRNum = nullptr;

    //5.函数中的静态变量
    _vNum = _countNum(a, b);
    _vNum = _countNum(a, b);
    _vNum = _countNum(a, b);
    _vNum = _countNum(a, b);

    //6.递归
    int c{ 5 };
    _cNum = _chengNum(c);
    cout << c << "的阶乘是:" << _cNum << endl;

    system("pause");
    return 0;
}

实现被调用的函数
1.给函数传递实参:

int _value(int a, int b)
{
    a += 5;        //改变形参a的值
    b += 5;        //改变形参b的值
    return a + b;
}

2.地址传递
当使用指针作为实参时,按值传递机制仍然像以前一样工作。但指针是另一个变量的地址,如果创建该地址的副本,则副本仍然指向相同的变量。以指针作为形参可以使函数处理调用者实参。

int _pointer(int* a)
{
    //return &a;
    *a += 5;       //改变指针指向的地址
    return *a;
}

3.引用传递
给函数传递实参的第二种方法:形参其实是引用被传递实参的别名,该机制不再复制所提供的实参。允许函数直接访问调用函数中的实参。
当使用类类型对象时,对函数使用引用形参具有特殊的意义。对象可能会很大,很复杂,此时复制过程中,可能会耗费很多时间。在这样的情况下,使用引用形参可以大大加快代码的执行速度。
可以给函数的形参使用const修饰符,以告诉编译器我们不想以任何方式修改这个形参。

int _reference(int &a, int &b)
{
    a += 5;        //改变形参a的值
    b += 5;        //改变形参b的值
    return a + b;
}

4.函数返回指针
返回地址的规则:永远不要从函数中返回局部自动变量的地址。
这样做很危险的,因为:函数_rpointer(a,b)中的变量num是在该函数开始执行时创建的,并在该函数退出时被销毁,因此指针ptr指向的内存不在包含原来的变量值。先前分配给num的内存现在可能用于其他目的。
改正:我们的意图是返回指向某些有用数据的指针,以便最终能够返回多想数据。一种方法是动态分配内存。使用操作符new,可以在空闲存储器中创建一个新变量,该变量一直存在,知道最终被delete销毁,或者知道程序结束。
注意:动态分配内存时,每次调用该函数时都要多分配一些内存。当然不需要内存时,主调程序需要将其删除,但实践中
人们很容易忘记这么做,结果就是空闲存储器的内存被逐渐消耗,知道某个时刻内存用尽且程序失败。这类问题称为内存泄漏。

int* _rpointer(int a, int b)
{
    //int num = a + b;
    //num += 10;

    //改正后
    int* num{ new int{} };
    *num = a + b;
    *num += 10;
    return num;
}

5.函数中的静态变量
有些时候用自动变量不能完成的。例如不能计算调用函数的次数,因为无法再多次调用中累积数值。有多重方法可以解决该问题。例如,可以使用引用形参来更新调用程序中的计数器,但如果程序中的许多不同位置都调用该函数,这种方法将无济于事。还可以使用在函数中递增的全局变量,但这样做是有风险的,因为程序中任何位置都可以访问全局变量,他们非常容易被以外修改。在具有多个访问全局变量的执行线程的应用程序中,全局变量同样是危险的,因此必须特别注意管理从不同线程中访问全局变量的方式。当多个线程都可以访问某个全局变量时,必须处理的基本问题:一个线程使用全局变量时,另一个线程可以修改该变量的值。在这样的情况下,最好的解决方案是完全避免使用全局变量。
函数内静态变量的初始化仅仅发生在第一次调用该函数的时候。事实上,初次调用函数时该变量包含的任何值都可以在下次调用时使用。

关于Static关键字
a.静态变量,分配在静态存储区,在数据段中。函数退出之后,变量值不变。
b.作用域,全局的静态变量、静态函数只能在本文件中使用。(不同于一般全局变量)
局部的静态变量同函数的局部变量
注:局部静态变量占用内存时间较长,并且可读性差,因此,除非必要,尽量避免使用局部静态变量。
作用:
a、非静态全局变量的作用域是整个源程序 ,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
b、静态全局变量则限制了其作用域, 即只在定义该变量的源文件 内有效,在同一源程序的其它源文件(即声明了该变量的CPP文件, 或包含该变量声明头文件的CPP文件)中不能使用它。

在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局 / 静态存储区和常量存储区。

int _countNum(int a, int b)
{
    a += 5;
    b += 5;
    static int countNum{};
    countNum++;
    cout << "调用次数:"<<countNum << endl;
    return a+b;
}

6.递归函数
递归函数调用:当函数包含自身的调用时,称之为递归函数。递归的函数调用也可以是间接的,即函数fun1
调用函数fun2,后者再调用fun1。
递归可以看做实现无穷循环的一种方法,如果我们不小心,就会发生这种情况。无穷循环将锁住计算机,需要按Ctrl+Alt+Del组合键才能终止程序,这永远是件非常令人讨厌的事情。避免无穷循环的前提是函数包含某种使递归调用过程停止的方法。
在物理和数学方面,有许多问题可以被视为包含递归。整数的阶乘就是个简单的例子。对于给定的整数N来说,其阶乘就是乘积1*2*3*。。。*N

注意:除非遇到的问题特别适用于使用递归函数,或者没有明显的替代方法,否则使用其他方法一般(如循环)会更好。使用循环比使用递归的函数调用的效率更高。在深度适中的递归调用中,系统开销也可以大大超过使用循环时的开销。当然这样说的意思不是我们永远不应该使用递归。当问题适于用递归函数调用来解决时,递归就是非常强大的技术可以大大简化代码。

int _chengNum(int n)
{
    static int countNum{n};                           //声明一个静态变量;
    countNum *= (n - 1);
    cout << countNum << endl;
    if (n > 2)
        return _chengNum(n - 1);
    else
    {
        return countNum;
    }
}

源码下载:

写在前面 在我还在上学的时候,我选择了C++,最初我用VC6作为我的IDE,我看过很多本C++的教材,有的适合我,有的不适合我,其中有一本叫《Visual C++ 2005入门经典》的书帮了我不少的忙。因为通常的C++教材都只会介绍C++的语法什么的,很少会告诉我们如何去编译、运行,告诉我们什么是控制台程序,什么事Win程序,什么是GUI程序,C++能干什么,VC和C++的区别是什么。现在有很多的朋友应该也有这些问题吧? 学C++C++也有几年了,算不上熟悉,算是初窥门径吧,我想我应该做点什么帮助一下那些和曾经的我一样困惑的朋友,特别是学生朋友,告诉他们他们所困惑的问题的答案。记得我学C++的时候,没有人教,有的时候也走了不少弯路,甚至连调试也不会,也不知道可以通过看调用堆栈看调用次序,还自己慢慢的去搜索,好傻啊。 接下来我会做一个《Visual C++ 2010入门教程》系列,用来帮助初学者。刚开始学的时候是很痛苦的,这个我深有体会,特别是身边还没有人能够指导一二的。内容主要涵盖在Windows下面使用C++进行开发的常见内容,Visual Studio 2010的使用,如何创建新项目,如何调试,如果配置项目属性等等,另外还会介绍Visual C++ 2010中新加如的一些内容,包括一些新的STL组建,一些新的语法支持等等。 由于本人水平有限,其中难免有错误,希望大家谅解,如果大家有发现问题还请务必及时指出来,否则误导了他人我就罪不容恕了。 注意,本教程非C++教程,不会教你C++,只会教你如何使用 Visual C++ 2010去练习去学习其它C++教材上面的程序。因此建议大家认真的去看其他的C++教程,在使用Visual C++ 2010实践的时候如果遇到问题可以到这里来参考。推荐《C++ Primer》、《C++程序设计语言》《Visual C++ 2008入门经典
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值