Visual C++ 2008入门经典 第五章程序结构(二)

//5.2.4 给函数传递引用实参
//将函数的某个形参指定为引用,将改变给该形参传递数据的方法,使用的方法不是按值传递,
//其中实参在传递给函数之前被复制,
//而是按引用传递--即形参扮演被传递实参的别名角色,该机制消除了任何复制工作,允许函数直接访问调用函数中的实参,同时意味着,传递和使用指针时所需的取消引用操作也是多余的
/*int incr10(int& num);
int main(array<System::String ^> ^args)
{	
	int num = 3;
	int value = 6;
	int result = incr10(num);
	cout<<" incr10(num) : "<<result<<endl;
    cout<<" num :"<<num<<endl;

	result = incr10(num);
	cout<<" num :"<<num<<endl;

	result = incr10(value);
	cout<<" incr10(value) :"<<result<<endl;
	cout<<"value:"<<value<<endl;

	//result = incr10(20);
	//如果企图使用数值作为incr10()的实参,将输出一条出错消息,因为编译器知道在函数内可以修改引用形参,而我们的意图却是使用常量的不时改变,这样就给可有可无的程序带来一种活力
	system("pause");
	return 0;
}
int incr10(int& num)
{
    cout<<"value received = "<<num<<endl;
	num += 10;
	return num;
}*/
//注意: 输出结果清楚的说明了引用和指针之间的区别,引用是另一个变量的别名,因此可以用作引用该变量的替代方法,使用引用与使用原来的变量名是等价的



//5.2.5 使用const修饰符
/*int incr10(const int& num);
//当我们在函数头和原型中将num指定为const之后,即许下了不修改该变量的诺言,因此编译器要检查我们是否在遵守诺言
int main(array<System::String ^> ^args)
{	
	int num = 3;
	int value = 6;
	int result = incr10(num);
	cout<<" incr10(num) : "<<result<<endl;
    cout<<" num :"<<num<<endl;

	result = incr10(num);
	cout<<" num :"<<num<<endl;

	result = incr10(value);
	cout<<" incr10(value) :"<<result<<endl;
	cout<<"value:"<<value<<endl;

	result = incr10(20);
	cout<<"result:"<<result<<endl;

	system("pause");
	return 0;
}
int incr10(const int& num)
{
    cout<<"value received = "<<num<<endl;
	//num += 10;
	//return num;
	return num + 10;
}
//通过使用引用实参,我们现在得到两个方面的好处,一方面,我们可以编写直接访问调用者实参的函数,而且避免了按值传递机制中隐式的复制开销,
//另一方面,如果我们不打算修改某个实参,则只需要给引用使用const修饰符,就能避免该参数被意久修改
*/

//5.2.6 main()函数的实参
/*int main(int argc, char* argv[])
{
	//第一个形参是包括程序序名在内的命令行上出现的字符串数量,
	//第二个形参是个数组,它包含指向这些字符串的指针,有一个为空值的附加元素
	cout<<endl<<"argc="<<argc<<endl;
	cout<<"Command line arguments received are:"<<endl;
	for(int i=0; i<argc; i++)
	{
	   cout<<"argument "<<(i+1)<<":"<<argv[i]<<endl;
	}
	system("pause");
	return 0;
}
int main(array<System::String ^> ^args)
{	
	Console::WriteLine("args->Length:{0}",args->Length);

	system("pause");
	return 0;
}*/

//5.2.7 接受数量不定的函数参数
//可以将函数定义成能够接受任意数量的实参,通过将省略号(3个句点...)写在函数的定义中形参列表的最后,即可表示调用该函数时可以提供数量可变的实参
//int sumValues(int first, ...){}
//函数定义中至少要有一个普通形参,也可以有多个,省略号必须总是放在形参列表的最后
//本地C++库在stdarg.h头文件中定义了va_start va_arg 和va_end宏 以帮助我们做这件事,
//接收数量不定的实参
/*#include <cstdarg>
//第二个形参具有特殊的标记值,以使进行检查和确认
int sum(int count, ...)
{
	if(count <= 0)
	{
	    return 0;
	}
	//为了处理可变的实参列表,我们首先声明一个va_list类型的指针
	va_list arg_ptr;
	
	//va_start宏用来初始化arg_ptr,使其指向列表中的第一个实参
	va_start(arg_ptr, count);
	//这个宏的第二个实参是函数形参列表省略号前面固定形参的名称,用来确定第一个可变实参的位置

	int sum = 0;
	for(int i=0; i<count; i++)
	{
	     sum += va_arg(arg_ptr, int);
	}
	//va_arg宏返回arg_ptr指向的位置存储的实参值,并使arg_ptr递增,以指向下一个实参值
	//va_arg宏的第二个实参是第一个实参的类型,决定着我们得到的数值以及va_arg递增的方式,因此如果该实参不正确,将造成混乱
	//程序也许会执行,但是得到的数值将是无用的数据,而且有arg_ptr将被错误的递增,从而指向其它无用数据
	
	va_end(arg_ptr);
	//当结束检索实参值之后,用下面这条语句使arg_ptr复位

	return sum;
}
int main()
{
	cout<<sum(6,2,4,6,8,10,12)<<endl;
	cout<<sum(9,11,22,33,44,55,66,77,88,99)<<endl;
	system("pause");
	return 0;
}*/



//5.3 从函数返回值

//5.3.1 反回指针
// return &value;   返回写成
// double* treble(double data); //定义写成这样
/*
double* treble(double);
int main()
{
	double num = 5.0;
	double* pnum = 0;
	pnum = treble(num);
	cout<<"Three times num = "<<3.0*num<<endl;
	cout<<"result = "<<*pnum<<endl;
	delete pnum;
	system("pause");
    return 0;
}*/
/*double* treble(double data)
{
   double result = 0.0;
   result = 3.0 * data;
   return &result; //这里是错误的

   //这所以出现错误,是因为函数treble()中的变量result是在该函数开始执行时创建的,并在该函数退出时消毁,因此指针ptr指向的内存不再包含原来的变量值,先前分配给result的内存现在可用于其他目的
   //这里显然已经有其他数据使用过这块内存了
}*/
//1 返回地址的规则
//有一条绝对不能违反的规则是:
//永远不要从函数中返回局部自动变量的地址
/*
double* treble(double data)
{
	double* result = new double(0.0);
	*result = 3.0 * data;
	return result;
	//没有将result声明为double类型,我们现在将其声明为double*类型,并将new运算符返回的地址存入其中,因为result是指针,所以我们修改函数的其余部分以反映这一点,最后,result中包含的地址被返回给调用程序,我们可以用这个版本代替上一个示例中的treble()函数.

}*/


// 5.3.2 返回引用
/*double& lowest(double values[], int length);
int main()
{
	double ar[] = {3.0,10.0,1.5,15.0,2.7,23.0,
	               4.5,12.0,6.8,13.5,2.1,14.0};
	int len = sizeof(ar) / sizeof(ar[0]);

	for(int i=0; i<len; i++)
	{
	    cout<<setw(6)<<ar[i]<<" ";
	}
	cout<<endl;

	lowest(ar,len) = 6.9;
	lowest(ar,len) = 7.9;

	for(int i=0; i<len; i++)
	{
	    cout<<setw(6)<<ar[i]<<" ";
	}

	system("pause");
    return 0;
}
double& lowest(double values[], int length)
{
    int j=0;
	for(int i=1; i<length; i++)
	{
		if(values[j] > values[i]){ //找出最小值
		   j = i;
		}
	}
	return values[j];
	//尽管这条语句看起来与返回单值的语句相同,但因为返回类型被声明为引用,所以实际返回的数组元素a[j]的引用,
	//而不是该元素包含量的数值,a[j]的地址用来初始化被返回的引用,该引用是编译器创建的,因为返回类型被声明为引用
	//不要混淆返回&a[j]与返回引用,如果我们将返回值写作&a[j],则指定的是a[j]的地址-那是个针
	//如果我们将回类型指定为引用之后还这样写,

	//返回引用的规则
	//返回指针的规则同样适用于返回引用
	//永远不要从函数中返回对局部变量的引用
}
*/


//5.3.3 函数中的静态变量
//在具有多个执行线程的应用程序中,全局变量同样是危险的,因此我们必须特别注意管理从不同线和中访问全局变量的方式,
//当多个线程都可以访问某个全局变量时,必须处理的基本问题是:
//一个线程使用全局变量时,另一个线程可以修改访变量的值,这样的情况下,最好的解决方案是完全避免使用全局变量
//static int count = 0;
//注意: 函数内静态变量的初始化仅仅发生在第一次调用该函数的时候,事实上,初次调函数时将创建并初始化静态变量
//之后,该变量的程序执行期间将继承存在,退出函数时该变量包含的任何数值都可以在下次调用函数时使用
/*void record(void);
int main(array<System::String ^> ^args)
{	
	record();
	for(int i=0; i<=3; i++)
	{
	    record();
	}
	system("pause");
	return 0;
}
void record(void)
{
	static int count = 0;
	cout<<"This is count "<<++count;
	if((count > 3 ) && (count<21))
	{
	    cout<<" th ";
	}else{
		//如果取10的余数
		switch(count % 10)
		{
		case 1:
			cout<<" st ";
			break;
		case 2:
			cout<<" nd ";
			break;
		case 3:
			cout<<" rd ";
			break;
		default:
			cout<<"th";
			break;
		}
	}
	cout<<endl;
	cout<<" time i have been called "<<endl;
	cout<<"=============================="<<endl;
	return;
}*/
//注意:
//return语句,因为函数的返回类型是void,所以该语句如果返回数值将导致编译器错误,在这种特殊情况下,我们实际上不需要return语句
//因为直接写出函数体的闭大括号就等价于没有返回值的return语句,即使我们不包括return,该程序将也正确编译和运行


//5.4 递归函数调用
//当函数包含对自身的调用时,我们称之为递归函数,递归的函数调用也可以是间接的,即函数fun1调用函数fun2,后者再调用fun1
/*double power(double x, int n);
int main(array<System::String ^> ^args)
{	
	double x = 2.0;
	double result = 0.0;

	for(int i=-3; i<=3; i++)
	{
	    cout<<x<<" to the power "<<i<<" is "<<power(x, i)<<endl;
	}

	system("pause");
	return 0;
}
double power(double x, int n)
{
	if(n < 0)
	{
	    x = 1.0 / x;
		// 1.0 / 2 = 0.5 
		n = -n;
        //3 = -(-3);
		//n = 3;
	    //cout<<endl<<" n: "<<n<<endl;
		//处理负指数值(x-n 等价于1/xn次方)
	}
	//支持负数次幂很容易,只需要昨用x(-n)等价于(1/x)(n)的事实即可,
	//因此如果n是负数,我们就将x修改为1.0/x,
	//并改变n的符号使其成为正数
	if(n>0)
	{
	   return x*power(x, n-1);
	}else{
	   return 1.0;
	}
}*/

//5.5 C++/CLI编程
//C++/CLI与本地C++的细微差别
//1 CLR程序中函数形参和返回值可以是数值类类型,跟踪句柄,跟踪引用和内部指针
//2 当某个形参是数组是,不需要别一个单独的形参来指定该数组的大小,因为C++/CLI数组的大小存储在Length属性中
//3 在C++/CLI程序中,我们不能像在本地C++程序中那样执行地址算术,因此必须始终使用数组索引
//4 返回CLI堆上分配的内丰的句柄不是什么难题,因为垃圾回收器负责释放那些不再被使用的内存
//5 C++/CLI中接收数量可变实参的机制与本地C++程序的机制不同
//6 在C++/CLI程序中,main()函数访问命令行实参的机制也与本地C++不同

//5.5.1 接受数量可变实参的函数
//int sum(... array<int>^ args){}
/*double sum(... array<double>^ args)
{
    double sum = 0.0;
	for each(double va in args)
	{
	    sum += va;
	}
	return sum;
}
int main(array<System::String ^> ^args)
{	
	Console::WriteLine(sum(3.0,4.0,6.0,8.0,10.0,12.0));
	Console::WriteLine(sum(1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9));
	system("pause");
	return 0;
}*/


//5.5.2 main()的实参
/*int main(array<System::String ^> ^args)
{	
	Console::WriteLine(L"There were {0} command line arguments.", args->Length);
	Console::WriteLine(L"Command line arguments received are:");
	int i = 1;
	for each(String^ str in args){
		Console::WriteLine(L"Argument {0} : {1}", i++, str);
	}
	system("pause");
	return 0;
}*/

//5.6 小结
//1 函数应该是具有明确目的小型代码单元,通常情况下,程序应该是由大量的小函数,而非少量大函数组成
//2 必须在调用程序中定义的函数之前,为该函数提供函数的原型
//3 使用引用给函数传值可以避免传值调用的实参传递机制中隐含和复制开销,应该将函数中不需要个和改的形参指定为const
//4 从本地C++函数中返回引用的指针时,应该确保被返回的对像具有正确的作用域,永远不要返回本地C++函数的局部对像的指针或引用
//5 在C++/CLI程序中,返回动态分配的内存的句柄没有任何问题,因为垃圾回收器,负责删除哪些不再需要的内存
//6 给函数传递C++/CLI数组时,不需要要另一个形参来指定数组的长度,因为在函数体中可以访问数组的Length属性来得到元素的个数

//5.7 练习
//练习题一
/*int Rank(int i);
int main(array<System::String ^> ^args)
{	
	for(int i = 5; i>= 3; i--)
	{
	     cout<<"Rank(i): "<<Rank(i)<<endl;
	}
	system("pause");
	return 0;
}
//i 值为5
//index 值为需要向下的值
int Rank(int i)
{	
	//刚才写的,一直没判断1的情况下该返回什么值,只知道递归,而递归到最后就不知道返回什么了
	//向你太二了解
	if(i == 1){
	   return i;
	}else{
	   return i * Rank(i-1); 
	}
}*/


//练习题二
/*void Swap(int* x, int* y);
int main(array<System::String ^> ^args)
{	
	int x=5, y= 55;
	cout<<"x:"<<x<<" y:"<<y<<endl;
	Swap(&x, &y);
	cout<<"x:"<<x<<" y:"<<y<<endl;
	system("pause");
	return 0;
}
void Swap(int* x, int* y)
{
	int i = *x;
	*x = *y;
	*y = i;
}*/

//练习题三
/*const double DEC_TO_RAD = 57.2957795;
double sind(double d)
{
    return sin(d/DEC_TO_RAD);
}
double cosd(double d)
{
    return cos(d/DEC_TO_RAD);
}
double tand(double d)
{
     return tan(d/DEC_TO_RAD);
}

int main(array<System::String ^> ^args)
{	
	cout<<"cos(30) = "<<cosd(30.0)<<endl;
	cout<<"sin(30) = "<<sin(30.0)<<endl;
	cout<<"tan(30) = "<<tan(30.0)<<endl;
	system("pause");
	return 0;
}*/


//练习题四
/*void GetData(int& number, char name[])
{
    cout<<"请输入一个数值(0退出):";
	cin>>number;
	if(number != 0)
	{
	     cout<<"请输入一个小于15和字符串"<<endl;
		 cin>>name;		 
	}
}
void PrintData(const int& number,const char name[])
{
	cout<<"输入的number:"<<number<<endl;
	cout<<"输入的name:"<<name<<endl;
}

int main(array<System::String ^> ^args)
{	
	int number=0;
	char name[15];

	for(;;)
	{
	    GetData(number, name);
		if(number == 0){
		    break;
		}
		PrintData(number,name);
	}
	system("pause");
	return 0;
}*/


//练习题五
/#include <cstring>
char* parse(const char* str)
{
     static char* pStr = 0; //定义一个静态char型指针pStr
	 static size_t len;     
	 static size_t start = 0;
	 size_t pos;
	 char* pReturn;
	 //如果存在str
	 if(str)
	 {
	      delete pStr; //释放指针
		  len = strlen(str); //取得字符串长度
		  pStr = new char(len+1); //实例化一下pStr指针,长度为str的长度加1,因为后面的一个字符串结束符
		  strcpy_s(pStr,len+1, str); //将str中的内容copy到pStr中去
	 }

	 if(start >= len)
	 {
	     return 0;
	 }

	 //从'开始'遍历字符串,直到我们找到一个空白或结束
	 for(pos = start; pStr[pos] != ' ' && pStr[pos]!='\0'; pos++);
	 //将pos设置为pStr的长度

	 //复制的字符串,如果我们一个词来返回,否则返回NULL
	 if(pos != start) //当pos不等于start时进行if
	 {
	      pReturn = new char[pos - start + 2];
		  //第一次运行
		  //pos为字符的长度,start为0,+2
		  size_t i = 0;
		  for(size_t j = start; j<pos; i++,j++)
		  {
		       pReturn[i] = pStr[j];
		  }
		  pReturn[i] = '\0';
		  start = pos+1;
		  return pReturn;
	 }else{
	      return 0;
	 }
}
int main(array<System::String ^> ^args)
{	
	char s1[] = "seventy-one fruit balls, please Doris";
	cout<<"string is :"<<s1<<"Parsing......"<<endl;
	char *p = parse(s1);
	while(p)
	{
	    cout<<p<<endl;
		//cout<<"s1:"<<s1<<endl;
		p = parse(0);//想通了,因为里面用的是静态变量值,和静态量指针,所以这里用0也是可以的

	}	
	system("pause");
	return 0;
}

  

转载于:https://www.cnblogs.com/xiangxiaodong/archive/2012/10/27/2742468.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一直在找这本Ivor Horton(霍顿)写的《Visual C++2008入门经典》中文版的书,据说非常经典。今天有幸终于找到了,赶紧上传和大家一起分享。请下载过的朋友支持鉴定一下。 注意:网上那些所谓的《Visual C++2008入门经典》如果附件大小小于60M的,如果不是英文版那肯定是假的。 文件大小:136M 页数:1142页 共6个部分 如果喜欢,请购买正版! 《Visual C++2008入门经典》内容提要 内容简介: 本书系编程语言先驱者Ivor Horton的经典之作,是C++编程方面最畅销的图书品种之一,不仅涵盖了Visual C++ 2008编程知识,还全面介绍了标准C++语言和C++/CLI。本书延续了Ivor Horton讲解编程语言的独特方法,从中读者可以学习Visual C++ 2008的基础知识,了解如何使用MFC进行本地ISO/ANSI C++ Windows应用程序开发以及如何使用Windows Forms进行C++/CLI Windows应用程序开发,并全面掌握在MFC和Windows Forms中访问数据源的技术。此外,本书各章后面的习题将有助于读者温故而知新,并尽快成为C++高效程序员。 《Visual C++2008入门经典》图书目录 第1章 使用Visual C++ 2008编程 第2章 数据、变量和计算 第3章 判断和循环 第4章 数组、字符串和指针 第5章 程序结构(1) 第6章 程序结构(2) 第7章 自定义数据类型 第8章 深入理解类 第9章 类继承和虚函数 第10章 标准模板库 第11章 调试技术 第12章 Windows编程的概念 第13章 使用MFC编写Windows程序 第14章 处理菜单和工具栏 第15章 在窗口中绘图 第16章 创建文档和改进视图 第17章 使用对话框和控件 第18章 存储和打印文档 第19章 编写自己的DLL 第20章 连接到数据源 第21章 更新数据源 第22章 Windows Forms应用程序进阶 第23章 在Windows Forms 应用程序中访问数据源 附录A C++关键字 附录B ASCII码 附录C Windows消息类型
如果您想学习利用Visual Basic 2008创建强大的、数据驱动的应用程序,那么本书就是最好的选择。它将带领您学习这门强大的编程语言,介绍如何构建多种Windows应用程序和web服务。在这个过程中,您将学习到如何利用面向对象技术,以及创建自己的业务对象和Windows控件。 在对Visual Studio 2008和.NET Framework 3.5作了简单介绍后,本书讲解了Visual Basic语言的基本原理。每章末尾的练习帮助读者更深入地理解如何使用这些功能为Microsoft Windows、Intranet和Internet,以及移动设备构建丰富且具有专业外观的应用程序。本书中的概念非常有用,将使您的Visual Basic开发技能更上一层楼。   本书主要内容   ◆Visual Studio 2008的功能及Windows编程   ◆在应用程序中集成错误处理的方法   ◆如何创建和使用Windows Forms控件   ◆使用Microsoft Access和Visual Basic 2008访问数据库的策略   ◆在Visual Basic 2008中集成XML的技巧   ◆如何使用Windows Presentation Foundation编写移动设备应用程序   本书读者对象   本书适合想学>习Visual Basic 2008和.NET Framework 3.5的初级编程人员。 本书全面介绍了Visual Basic 2008的各种基础知识和,NET Framework 3.5的最新特性,适合任何一个想学习Visual Basic 2008编程知识的初学者。该书由初版到现在的2008版已经过4次修订,内容体系十分完善,技术讲解也十分到位,示例、习题、代码非常精炼,是一本不可多得的权威著作,能够帮助您更加轻松、快捷地掌握Visual Basic 2008这门语言。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值