浅谈变量和函数——函数基本问题解析

浅谈完C++入门后,我再来说说复杂点的,变量和函数,对于每个学习C++编程的同学都会很头疼一直弄不懂这变量和函数的关系,那今天我就来和大家聊聊我对这些的理解。

与之前的介绍不同,这次我要先讲讲理论知识,先弄清楚这一些名词是什么意思,当然长篇大论的定义到处都有,我就我的理解说一些通俗易懂的解释,当然可能在有些特殊情况不是很精确,准确的理解还是要围绕定义来的,我只做辅助理解。

变量:定义

因为我们的程序不可能所有数据都是既定设计好的,没有任何与用户互动的话,这程序也就没有什么意义,那么所有用户输入的值或者做的操作都需要储存起来,再在后续的程序运行中进行处理,这就是变量存在的意义。

所以,我把变量比作一个盒子,他的作用就是用来存储这个随时会变的值,那就可以理解成把这个随时会变化的数据放到这个盒子里面。

变量里有什么呢,变量里有变量名、变量类型、变量存储值和变量地址四哥个,

变量名顾名思义就是所定义的变量人为赋予的名字,好比这个盒子他有编号,但是我们更愿意给他取个名字,让他方便被我们取出。

变量类型其实是限制这个变量的数据类型,是数字还是字符,如果是数字就可以加减乘除,如果是两个字符则不能直接运算,常用的类型有int整数型,float浮点型(小数类型但位数较小),double长小数型,char字符类型,string字符串类型(详解

这变量储存值比较好理解,就是变量被赋予的值,当一个变量a被定义的时候,需要给他赋一个值,而这个赋予值其实就是把一个值存储到这个变量里面,好比把他放进这个盒子里面,在程序里面直接运用这个变量的变量名的时候吗,进行操作的数据往往是存储值,什么意思呢?就是把这盒子里面的值拿出来参与计算。每当有新的值赋予到这个变量里面,这里面的值也就随之更新被其覆盖,这不难理解,因为每个盒子里面只能存储一个数据,当有一个新数据需要存储的时候,旧数据就会被删除,让新数据存储进来。

而这变量地址就好比盒子的编码代号,用来标识这个盒子,一般程序操作不会涉及到它,如果要对这地址操作,需要在所定义的变量前加上&,也就是地址符号,当变量名前加上这个符号的时候意味着操作的是地址而不是存储数据。

举些例子:

#include<iostream>
using namespace std;
void main()
{
	int LyuTa , LyuTb;
	LyuTa = 10; 
	cout << "LyuTa: " << LyuTa << endl;
	cout << "LyuTa的地址是: " << &LyuTa << endl << endl;
	LyuTb = LyuTa;
	cout << "LyuTb: " << LyuTb << endl;
	cout << "LyuTb的地址是: "<< &LyuTb << endl;
	getchar();
}

下面是执行结果是:

 

int是整数的意思,也就是说,这里定义了一个变量名叫LyuTa的变量,他的类型是整数型,里面可以存储整数,在没有地址符号的时候,他表示的是他存储的值,有地址符号的时候传递的就是他的唯一标识地址字段。

 

函数:定义

这很好理解,就是不把所有程序写到main函数里面,把一部分放在函数里面,函数分两种,一种是无返回值函数,一个是有返回值函数;

无返回值函数也就是void函数,这个最容易理解,其实就是主函数运行时遇到这个函数的语句的时候,把这函数内需要的数据传递到指定函数中,执行完毕后就会返回到main函数中,继续完成主函数的代码,常常为了使主函数的代码精简,更容易读阅,把一个功能模块的代码做成一个函数,比如一些搭建界面框架的代码,也比如面对由一个比较大的数据结构定义的两个变量需要进行交换操作的时候,用无返回值函数较多一点。

在介绍比较复杂的有返回值函数前,给大家分析一下函数变量录入的一些常见问题。

最常见的问题就是,为什么我明明写了这个函数,主函数中却说没有呢?很简单因为没有调用,你需要在你要用该函数的函数中调用一下,但有同学又要问了,为什么有时候我不用调用我也可以用呢?

下面给大家看一个例子:

#include<iostream>
using namespace std;

void Lyu_f1()
{
	cout << "function-1" << endl;
}

void main()
{
	void Lyu_f2();
	Lyu_f1();
	Lyu_f2();
	getchar();
}

void Lyu_f2()
{
	cout << "function-2" << endl;
}

执行结果是:

 

原理就是,当你写的函数在你调用该函数的函数上方的时候,你可以不调用,但如果在下方,你必须要调用,当然作为一个好习惯,在没有头文件的情况下,把不管什么情况都调用写进去。

困扰大家最久的问题就是,为什么我传入了一个值,在函数里面操作修改了,但在外函数里面却还是没变呢?下面给大家看一个例子:

 

#include<iostream>
#include<string>
using namespace std;

void print(int a, char b, string c , int d[])
{
	cout << "Lyu_Int 的值" << a << endl;
	cout << "Lyu_Char 的值" << b << endl;
	cout << "Lyu_String 的值" << c << endl;
	cout << "Lyu_Array 的值"  << endl;
	for (int i = 0; i < 5; i++)
		cout << d[i] << '\t';
	cout << endl;
}

void Lyu_f3(int a, char b, string c, int d[])
{
	void print(int a, char b, string c, int d[]);
	a++;
	b++;
	c.append("!");
	d[4] ++;
	cout << endl << "在函数中的情况:" << endl;
	print(a, b, c,d);
}

void Lyu_f4(int &a, char &b, string &c, int *d)
{
	void print(int a, char b, string c, int d[]);
	a++;
	b++;
	c.append("!");
	d[4] ++ ;
	cout << endl << "在函数中的情况:" << endl;
	print(a, b, c, d);
}

void main()
{
	void print(int a, char b, string c, int d[]);
	void Lyu_f3(int a, char b, string c, int d[]);
	void Lyu_f4(int &a, char &b, string &c, int d[]);

	int Lyu_Int = 0;
	char Lyu_Char = 'a';
	string Lyu_String = "I love C++";
	int Lyu_Array[5] = { 1 , 2 , 3 , 4 , 5 };

	cout << "当前初始化情况为:" << endl;
	print(Lyu_Int, Lyu_Char, Lyu_String, Lyu_Array);

	Lyu_f3(Lyu_Int, Lyu_Char, Lyu_String, Lyu_Array);
	cout << endl << "没有地址符,在主函数中数据情况为:" << endl;
	print(Lyu_Int, Lyu_Char, Lyu_String, Lyu_Array);

	Lyu_f4(Lyu_Int, Lyu_Char, Lyu_String, Lyu_Array);
	cout << endl << "有地址符,在主函数中数据情况为:" << endl;
	print(Lyu_Int, Lyu_Char, Lyu_String, Lyu_Array);

	getchar();
}

执行结果就是:

 

从刚刚的实验中,我们可以发现两点,第一,普通变量在传值后,在函数中虽然改变但函数执行完毕后,却没有返回给外函数,但是,数组和指针的值可以返回出去!第二,只是在函数传入值定义中加入地址符就可以实现数据传出。这是为什么呢,这就涉及到刚刚讲的变量的相关知识了,如果直接使用变量实际传入的知识其存储的值,而函数用一个自己定义的变量存储了这个值,修改的只是这个值,当然外部没有变化,而换成地址符,传递的就是变量,在函数中的操作的也就是变量本身,在传出函数后,变量的值也会有所改变。而数组和指针本身就是地址,所以不用加地址符。


当然还有关于自定义的类创建的变量不能调用进去,这问题就在自定义类里面讲吧。下面讲讲有返回值函数:

有返回值函数,就复杂许多了,首先,他有很多种类,int、float、double、string、自定义的类等等,而他的函数中必须有返回值,而且这个返回值必须和函数初始定义的类型一样,然后在调用该函数的位置通过赋值将值传出。

不过这个函数可不是这么简单的,他是迭代算法、回溯算法的关键工具,而正因为这些算法的存在,有返回值函数,一直是比较复杂的部分,很多核心算法都与这个函数有很大关系。

下面我就和大家解释一下,为什么说他能成为多个软件实用功能核心算法,其实很简单,原因就是他的一个特点,自己调用自己,什么意思呢?

下面看一个简单的例子:

著名的谷角猜想:对于任意一个自然数n,若n为偶数,则将其除以2;若n为奇数,则将其乘以3,然后再加1。如此经过有限次运算后,总可以得到自然数1。

实现代码:

int Lyu_f1(int a)
{
	if (a == 1)
		return a;
	if (a % 2 == 0)
	{
		return Lyu_f1(a / 2);
	}
	else
	{
		return Lyu_f1(a * 3 + 1);
	}
}

执行结果是:

 

这就是著名的谷角猜想,这就是迭代,当然,这个比较简单,可以直接用循环执行,但是也可以用函数迭代,我们可以看到,在函数中我们还调用了一次自身,不断迭代,知道当i=1才开始返回值。

再来看一个大家熟悉的例子,

一个数列通项公式为:

求他的前n项和,当然我们可以从1开始向前一项一项算,但如果实现从不损耗内存的实现运算呢?

代码:

int Lyu_f1( int n , int &s )
{
	if (n == 1)
		return 1;
	else if (n == 2)
	{
		n--;
		int a = Lyu_f1(n, s);
		s = a + s;
		return 2;
	}
	else
	{
		n--;
		int a = Lyu_f1(n, s);
		s = a + s;
		return a * a + a + 1;
	}
}

执行结果是:

 

当然这些相对简单的可以用循环运行,但像旅行最短路径计算这些比较复杂的事件就必须用函数内调来完成了。在后面我对这些算法会有具体讲解,今天只讲解一些基础的。

打牢基础才能完成上层建筑,希望今天大家能有不少收获。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值