• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C++—函数

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

一、函数的基本知识

  要使用C++函数,必须完成一下工作:

  (1)提供函数定义;

  (2)提供函数原型;

  (3)调用函数。

1、定义函数

  可以将函数分为两类,有返回值的函数和没有返回值的函数。没有返回值的函数称为void函数,其通用格式如下:

  void functionName(parameterList){

    statement(s);

    return;//可以使用不带任何返回值的return,返回语句也可以省略

  }

  有返回值的函数的通用格式如下:

  typeName functionName(parameterList){

    statement(s);

    return value; //其中value的类型必须和声明中函数的返回值类型typeName一致;并且返回语句不能省略

  }

  C++对于返回类型有一定的限制:不能是数组,但可以使其他任何类型——整数、浮点数、指针,甚至可以使结构和对象(虽然C++函数不能直接返回数组,但是将数组作为结构和对象的组成部分来返回)。

  函数在执行返回语句后结束。如果函数包含多条返回语句,则函数在执行遇到的第一条返回语句后结束。

2、函数原型和函数调用

  (1)为什么需要原型?

    原型描述了函数到编译器的接口,即原型将函数返回值的类型以及参数的类型和数量告诉编译器。

  (2)原型的语法

    函数原型是一条语句,所以必须以分号结束。并且,函数原型不要求必须提供参数名,有类型列表就足够了。

  (3)原型的功能  

    具体来说,原型确保一下几点:

    1)编译器正确处理返回值;

    2)编译器检查使用的参数数目是否正确;

    3)编译器检查使用的参数类型是否正确。如果不正确就转换成正确的类型(如果可能的话)。

 

二、函数参数和按值传递

  C++通常按值传递参数,这意味着将数值参数传递给函数,而后者将其赋给一个新的变量。

  在函数中声明的变量(包括参数)是该函数私有的。在函数调用时,计算机将为这些变量分配内存;在函数结束时,计算机将释放这些变量占用的内存。这样的变量称为局部变量,因为他们被限制在函数内部。函数可以有多个参数。

1 补充:局部变量、全局变量、静态全局变量和静态局部变量之间的区别
2 
3     (1)局部变量,指的是在代码块中(大括号之间)声明的变量,在执行这些块的时候,计算机将为这些变量分配内存;在函数结束的时候,计算机将释放这些变量占用的内存。如果局部变量的名称和全局变量的名称一致,在包含该局部变量的代码块中,声明局部变量之后的代码中局部变量优先;如过要在声明局部变量后面的代码中要使用相同名字的全局变量,需要在变量前加上::。
4 
5     (2)全局变量,指的是在代码块(包括函数)之外声明的变量,全局变量能够被该文件中的所有函数反问并修改,并且在其他文件中使用了extern声明的也可以访问该全局变量。
6 
7     (3)静态局部变量,静态局部变量和局部变量的区别在于其生命周期。局部变量的声明周期时包含该局部变量的块的声明周期,而静态局部变量的生命周期时整个程序。
8 
9     (4)静态全局变量,静态全局变量和全局变量的区别在于其作用域。全局变量的作用域是声明该变量的文件以及其他使用了extern声明的文件;而静态全局变量的作用域被限制在声明该变量的文件中,其他文件无权访问。

 

 

 

 三、 函数和数组

1、

 11)、
 2   对静态数组名进行sizeof运算时,结果是整个数组占用空间的大小;
 3   因此可以用sizeof(数组名)/sizeof(*数组名)来获取数组的长度。
 4   int a[5]; 则sizeof(a)=20,sizeof(*a)=4.因为整个数组共占20字节,首个元素(int型)占4字节。
 5   int *a=new int[4];则sizeof(a)=sizeof(*a)=4,因为地址位数为4字节,int型也占4字节。
 62)、
 7   静态数组作为函数参数时,在函数内对数组名进行sizeof运算,结果为4,因为此时数组名代表的指针即一个地址,占用4个字节的内存(因为在传递数组名的参数时,编译器对数组的长度不做检查)。对动态数组的函数名,无论何时进行sizeof运算,得到的结果都是4.
 83)、
 9   new还需要你delete,是在堆分配空间,效率较低;而静态数组直接在栈上分配,会自动释放,效率高,但是栈空间有限。
104)、通过函数返回一个数组的问题
11   函数声明的静态数组不可能通过函数返回,因为生存期的问题,函数调用完其内部变量占用的内存就被释放了。如果想通过函数返回一个数组,可以在函数中用new动态创建该数组,然后返回其首地址。  
12   其原因可以这样理解,因为静态数组是在栈中申请的,而函数中的局部变量也是在栈中的,而new动态数组是在堆中的分配的,所以函数返回后,栈中的东西被自动释放,而堆中的东西如果没有delete不会自动释放。

 

 

 

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 int *getStaticArr();
 6 int *getActivityArr();
 7 int main(int argc, const char * argv[]) {
 8 
 9     int *arr = getStaticArr();
10     for (int i = 0; i < 4;  i++) {
11         cout <<"arr["<< i << "] is "<< arr[i]<< " at " << &arr[i] << endl;
12     }
13     cout << endl << endl;
14     arr = getActivityArr();
15     for (int i = 0; i < 4;  i++) {
16         cout <<"arr["<< i << "] is "<< arr[i]<< " at " << &arr[i] << endl;
17     }
18     delete [] arr;
19     return 0;
20 }
21 
22 int *getStaticArr(){
23     int arrn[4] {1,2,3,4};
24     for (int i = 0; i < 4; i ++) {
25         cout << "arrn[" <<i <<"] is " << arrn[i] << " at " << &arrn[i] << endl;
26     }
27     return arrn;
28 }
29 int *getActivityArr(){
30     int *arrm = new  int[4]{2,3,4,5};
31     for (int i = 0;  i < 4; i++) {
32         cout << "arrm[" <<i <<"] is " << arrm[i] << " at " << &arrm[i] << endl;
33     }
34     return arrm;
35 }
36 
37 输出结果:
38 arrn[0] is 1 at 0x7fff5fbff750
39 arrn[1] is 2 at 0x7fff5fbff754
40 arrn[2] is 3 at 0x7fff5fbff758
41 arrn[3] is 4 at 0x7fff5fbff75c
42 arr[0] is 1958675192 at 0x7fff5fbff750
43 arr[1] is 32767 at 0x7fff5fbff754
44 arr[2] is 7977 at 0x7fff5fbff758
45 arr[3] is 1 at 0x7fff5fbff75c
46 
47 
48 arrm[0] is 2 at 0x100200000
49 arrm[1] is 3 at 0x100200004
50 arrm[2] is 4 at 0x100200008
51 arrm[3] is 5 at 0x10020000c
52 arr[0] is 2 at 0x100200000
53 arr[1] is 3 at 0x100200004
54 arr[2] is 4 at 0x100200008
55 arr[3] is 5 at 0x10020000c
  说明:
    (1)在函数中,不能将静态数组作为返回值进行返回,因为在调用完函数之后静态数组将被释放;但是动态数组被存储在堆区,在函数调用完后,如果没有用delete进行释放,动态数组将不会被释放。
    (2)但是,我们可以利用静态数组和动态数组的这一特性,在创建返回从外部输入得到的字符串的函数时,用来节省内存空间。因为在读取输入的时候,并不知道需要创建多大的数组来存储输入字符串,因此需要创建一个比较大的静态数组;读取完输入以后,可以根据静态数组中字符的数量来创建一个刚好能够存储输入的动态数组来保存输入数据,再将保存有输入数据的动态数组返回,再该函数调用结束后,静态数组将会被释放,而动态数组只要还没有被delete就依然存在,一次来达到节省内存空间的目的,代码如下:
  
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 char *getEnter();
 6 int main(int argc, const char * argv[]) {
 7     char *str = getEnter();//返回的得到的是一个动态数组的第一个元素的地址
 8     cout << str << endl;
 9     delete [] str;//使用完后,需要将动态数组释放掉,避免内存泄漏
10     return 0;
11 }
12 char *getEnter(){
13     char enter[100];
14     cout << "请输入一段字符:\n";
15     cin >> enter;
16     char *str = new char[strlen(enter) + 1];//根据输入的长度来创建一个刚好能够保存输入数据的动态数组,+1是为了保存字符串结尾的空字符。
17     strcpy(str, enter);
18     return str;
19 }
20 
21 输出结果:
22 请输入一段字符:
23 WhatIsYourMother'sName?//用户输入
24 WhatIsYourMother'sName?

    (3)在编写数组函数时,如果把数组作为参数传给函数,并且在函数中直接对接受数组的形式参数进行操作,那么等同于对原数组进行操作。如下:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 int getEnter(int *arr,int max);
 6 int main(int argc, const char * argv[]) {
 7     int arr[5]{0};
 8     int m = getEnter(arr,sizeof(arr)/sizeof(*arr));
 9     cout << "m :" << m << endl;
10     for (int i = 0; i < sizeof(arr)/sizeof(*arr); i++) {
11         cout << "arr[" << i << "] is " << arr[i] << endl;
12     }
13     return 0;
14 }
15 int getEnter(int* arr, int max){
16     double num;
17     int i;
18     for (i = 0 ; i < max; i++) {
19         cout << "Enter value #" << (i + 1) << ":\n";
20         cin >> num;
21         if (!cin) {
22             cin.clear();
23             while (cin.get() != '\n')
24                 continue;
25             cout << "Bad input;input process terminated.\n";
26             break;
27         }
28         else if(num < 0){
29             break;
30         }
31         arr[i] = num;
32     }
33     return i ;
34 }
35 
36 输出结果:
37 Enter value #1:
38 90
39 Enter value #2:
40 45
41 Enter value #3:
42 123
43 Enter value #4:
44 221
45 Enter value #5:
46 1001
47 m :5
48 arr[0] is 90
49 arr[1] is 45
50 arr[2] is 123
51 arr[3] is 221
52 arr[4] is 1001

  (3)显示数组和使用const关键字保护数组  

    显示数组很简单,只需要把数组名和填充的元素数目传递给函数就可以了。一般来说,给函数传递参数时,函数都是使用参数副本,不会对实际参数产生影响;但是在传递数组名的时候,由于传递的是指针,形式参数和实际参数都指向同一个地址,对形式参数进行某些操作时可能会影响数组本身;为防止函数无意中修改数组的内容,可在声明形参时使用const关键字,这样该函数中就不能修改数组的内容。

2、使用数组区间的函数

  对于处理数组的C++函数需要将数组的起始位置、数组元素类型和数组元素的数目传递给函数;另一种给函数提供所需信息的方法是指定元素区间,这可以通过传递两个指针来完成:一个指针标识数组的开头,另一个指针标识数组的结尾。C++标准库(STL)使用“超尾”概念来指定区间。对于数组而言,标识数组结尾的参数将是指向最后一个元素后面的指针。例如:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 void showArr(const int *begin, const int *end);
 6 int main(int argc, const char * argv[]) {
 7     int arr[6] = {16,21,45,23,80,100};
 8     showArr(arr, arr+sizeof(arr)/sizeof(*arr));
 9     return 0;
10 }
11 void showArr(const int *begin, const int *end){
12     const int *ps;//可以将一个常量赋给一个变量,但是不能将一个指向常量的指针赋给一个指向变量的指针;const int *begin表示begin是一个指向常量的指针。
13     for (ps = begin; ps != end; ps++) {//循环条件
14         cout << "The value at " << ps << " is " << *ps << endl;
15     }
16 }
17 
18 输出结果:
19 The value at 0x7fff5fbff7f0 is 16
20 The value at 0x7fff5fbff7f4 is 21
21 The value at 0x7fff5fbff7f8 is 45
22 The value at 0x7fff5fbff7fc is 23
23 The value at 0x7fff5fbff800 is 80
24 The value at 0x7fff5fbff804 is 100

 3、指针和const关键字

   指针使用CONST

 (1)指针本身是常量不可变
       (char*) const pContent; 
       const (char*) pContent; 
 (2)指针所指向的内容是常量不可变
       const (char) *pContent; 
       (char) const *pContent; 
 (3)两者都不可变
       const char* const pContent; 
 (4)还有其中区别方法,沿着*号划一条线:
如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量; 如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。在不带小括号的情况下,关键在于const修饰的是指针指向的值(即带*号的指针,const在*号前,指针指向的值不可变),还是直接修饰指针本身(即不带*号的指针,const在*后面,指针本身不可变)。 (5)指向常量的指针,并不意味着指针指向的一定就是常量,只是对于这个指针而言,这个值是常量。 (6)不能将常量的地址赋给一个指向变量的指针,这是自相矛盾的;只能将常量的地址赋给指向常量的指针。注意常量指针和指向常量的指针的区别,常量指针是指指针本身不能变,指向常量的指针指的是指针指向的内容不可变。
 1  #include <iostream>
 2  
 3  using namespace std;
 4  
 5  void showArr(const int *begin, const int *end);
 6  int main(int argc, const char * argv[]) {
 7      int m = 10;
 8      const int n = 15;
 9      const int * ptr = &m;
10      //int *pts = &n;不将常量的地址赋给一个指向变量的指针,这样是矛盾的;只能将常量的地址赋给一个指向常量的指针
11      const int *pts = &n;
12      //*ptr = 19; 指向常量的指针,并不意味着指向的一定就是一个常量,只是对于这个指针而言指向的是一个常量,即不能通过该指针来修改指向的内容
13      cout << "修改变量m前*ptr的值:" << *ptr << endl;
14      m = 19;
15      cout << "修改变量m后*ptr的值:"<< *ptr << endl;
16      
17      return 0;
18  }
19  
20 输出结果:
21 修改变量m前*ptr的值:10
22 修改变量m后*ptr的值:19

  

四、函数和二维数组

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 int sum(int (*arr)[4], int size);
 6 int main(int argc, const char * argv[]) {
 7     int num[3][4] = {{12,22,32,10},{11,45,34,18},{89,21,42,16}};
 8     cout << sum(num, 3) << endl;
 9     
10     return 0;
11 }
12 int sum(int (*arr)[4], int size ){
13     int sum = 0;
14     for (int i = 0; i < size; i ++) {
15         for (int m = 0 ; m < 4; m ++) {
16             sum += arr[i][m];
17         }
18     }
19     return sum;
20 }
21 
22 输出结果:
23 352

 

五、函数和C—风格字符串

  C-风格字符串有一些列字符组成,以空字符结尾。大部分有关数组的函数的知识也适用于字符串函数。将字符串作为参数,意味着传递的是地址。
1、将C-风格字符串作为参数的函数
  假设将字符串作为参数传递给函数,则表示字符串的方式有三种:
  (1)char数组;
  (2)用引号括起来的字符串常量(也称为字符串字面值);
  (3)被设置成字符串地址的char指针。
将字符串作为参数来传递,实际传递的是字符串第一个字符的地址。意味着字符串函数原型声明应将其表示字符串的形参声明为char*类型。
  C-风格字符串与常规char数组的一个重要区别是,字符串有内置的结束空字符(包含字符,但是不是以空字符结尾的char数组只是数组,而不是字符串)。因此,不必将字符串长度作为参数传递给字符串函数,而函数可以使用循环一次检查字符串中的每个字节,直到遇到结尾的空字符为止。
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 unsigned int c_in_str(const char *str, char ch);//由于不需要函数对字符串做出修改,所以将指针声明为const
 6 int main(int argc, const char * argv[]) {
 7     char str[] = "aidfionifeoiaosdf";
 8     cout << "在字符串str中有"<< c_in_str(str, 'f')<<"个字符f." << endl;
 9     return 0;
10 }
11 unsigned int c_in_str(const char *str, char ch){
12     unsigned int num = 0;
13     while (*str) {//通过检查字符是不是空字符来作为字符串结尾条件
14         if (*str == ch) {
15             num ++;
16         }
17         str +=1;
18     }
19     return num;
20 }
21 
22 输出结果:
23 在字符串str中有3个字符f.

2、返回C-风格字符串的函数

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 char *getStr();
 6 int main(int argc, const char * argv[]) {
 7     char *str = getStr();
 8     cout << "获得的字符串:"<< str << endl;
 9     delete [] str;
10     return 0;
11 }
12 char *getStr(){
13     char str[100];
14     cout << "请输入一个字符串:\n";
15     cin >> str;
16     char *str1 = new char[strlen(str) + 1];
17     strcpy(str1, str);
18     return str1;//不能返回字符数组,因为常规数组保存在栈区,为自动变量
19 }
20 
21 输出结果:
22 请输入一个字符串:
23 adfadse
24 获得的字符串:adfadse

 

六、函数和结构      

  可以将一个结构赋给另一个结构,可以按值传递结构(函数将使用结构的副本),函数也可以返回结构。

1、传递和返回结构
 1 #include <iostream>
 2 
 3 using namespace s 

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap