C++函数知识概要总结(一)

这章啃了好久
由于太长了,所以分三篇。


fact(3.5) 若要求参数是整数,3.5会被隐式转换成3

阐述一下名词 自动变量
自动变量是只存在于块执行期间的对象。
如果局部对变量对应的自动对象没有初始值,那就会产生未定义的值。

关于局部静态变量。
一个清晰明了的例子。

int a() {
static int c = 5;
c += 1;
return c;
}
int main()
{
int ans;
ans = a();
cout << ans; //输出6
ans = a();
cout << ans; //输出7
}

如果局部静态变量没有初始值,那就默认为0;

关于函数声明

函数声明也称与函数原型。

关于分离式编译

可以仔细阅读一下编译器的用户手册来进行深层了解。

关于传值参数
void reset(int *ip, int *jp){
	int tem = *ip;
	*ip = *jp;
	*jp = tem;
}
int main()
{
	int a=6, b = 9;
	reset(&a, &b);
	cout << a << b;
}
关于传引用参数

有个特殊的有点就是可以用来避免太大的拷贝。

关于const形参和实参

c++中运行函数重载,即好几个名字相同的函数只要形参列表有区别即可。

void fcn(const int i);
void fcn(int i);

这两个不能同时定以,因为形参的顶层const会被忽略。
本身是const就是顶层,只有指向的是const,才是底层。

因为形参需要拷贝实参的值,这种时候,是会忽略掉顶层const 的;

关于指针或引用形参于const
int i=0;
const int ci = i;
string::size_type ctr = 0;
reset(&i); 

这种容易搞不清的乱七八糟的式子,我的辨别方法是
每次都想像函数中自带一个值t,其实就是有一个形参值。
对于rest(&i)
可以看作是 *t=&i; 然后再判断正确与否。

reset(&ci);  //*t = &ci,ci是const int 所以很明显是错误的

接下来是对于reset中是引用参数的例子。

reset(ci); // &t = ci; 同理,错误;
reset(42); //&t=42;错误
reset(ctr); //&t = ctr; 类型不匹配 错误

尽量使用常量引用

为什么呢。

string::size_type find_char(const string &s, char c, string::size &occurs){
auto ret = s.size();
occurs = 0;
for(decltype(ret) i=0; i != s.size(); ++i){
    if(s[i]==c){
        if(ret==size()) ret = i;
        ++ occurs;
    }
}
return ret;
}

为什么这个函数的第一个参数要定义成常量引用?

回答这个问题之前,我想过这个问题,这里又不需要改变string里的值,为什么要用引用??(⊙﹏⊙)

前面说了引用参数类型的有一个较特殊的优点,防止拷贝时间太耗时间而采用引用的方式。

很明显我刚记下一转眼就忘了。

那再回到现在的问题,为什么要定义成常量引用?

普通引用形式不接受传入常量
普通引用不接受直接写上的字符串形式

注意一下,

const string s = "666";
string ss =  s; 

这个是正确的写法,很明显,但是我被这个迷惑了好久。。。。

在这里插入图片描述

做一个小练习,b;

vector<int>::iterator change_val(int value, vector<int>::iterator &it){
 	*it = value;
	 return it;
}
int main()
{
	vector<int>v(2, -1);
	vector<int>::iterator i=v.begin();
	cout << *change_val(1, i)<<endl;
	for(auto c : v){
    	cout << c<<endl;
	}
}
关于数组形参

先回顾一下数组的两个特殊性质:

  • 不允许拷贝数组
  • 使用数组通常会将其转换为指针。

因此但我们向函数传递一个数组时,实际上传递的是指向数组首元素的指针。

void print(const int*);
void print(const int[]);
void print(cosnt int[10]);

上述三种等价。

管理数组形参一般有三种常见的技术

  • 使用标记指定的数组长度,char*里可以这么干。
  • 使用标准库规范,也是就是传入begin和end
  • 直接显式传递数组大小。
关于数组引用形参
print(int (&a)[10]);

这么写需要注意的有:

必须把&a用括号括起来,不然就不会变成 int &a[10],这个是引用的数组。而不是数组的引用。
必须加上数组大小。
所以就有了局限性,即大小已经确定。

当传递多维数组时

print(int (*a)[10], int rowsize);{/*..*/}

因为实际上多维数组就是数组的数组,形参就可以使指向数组的指针。

关于main处理命令行选项
int main(int argc, char *argv[]) {}

这里只要注意argv[0] 并不是第一个输入的字符串,而是程序名。

关于含有可变形参的函数

有好几种方法

  • 传递initializer_list形参
  • 编写可变参数模板
  • 省略符形参
关于initializer_list 形参

适用于全部实参的类型都相同的情况。
用法见例子即可。

int mix(initializer_list<int>li){
	int sum;
 	for(auto beg = li.begin(); beg!=li.end(); ++beg){
    	sum += *beg;
	}
return sum;
}
int main()
{
	int b=1,c=2,d=3,e=4;
 	cout << mix({b,c,d,e});
}

当然也可以用范围for
注意用到initializer_list的地方需要加上大括号{};

关于省略符形参

这是为了便于c++程序访问某些特殊的c代码而设置的。暂时没感觉到用处。

void foo(int, …);
void foo(…);
发布了75 篇原创文章 · 获赞 26 · 访问量 7655

猜你喜欢

转载自blog.csdn.net/qq_40962234/article/details/104681048