栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++程序结构

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++程序结构

函数的命名规则与变量相同。

调用时指定的实参传递信息。

函数 函数的结构

函数头

return_type function_name (parameter_list)

  • 返回值类型
  • 函数名
  • 函数形参

函数体

{}内的代码块

形参和函数体内声明的所有变量都是该函数的局部变量,返回值是生成的副本。

同名局部变量会屏蔽全局变量。

#include "pch.h"
#include 

int a = 99;
int main() 
{
	int a = 88;
	std::cout << a;
}

输出88

return语句

return expression

expression 的结果必须是函数头中为返回值指定类型。

没有返回值的return可以省略。

拖尾返回类型

函数的返回类型放在函数头中->的后面,auto关键字告诉编译器返回类型在以后确定。

#include "pch.h"
#include 

auto calc(int a, int b)->double
{
	return static_cast(a)/b;
}

int main() 
{
	std::cout.precision(4);
	std::cout<< calc(1, 2)< 
使用函数 

如果函数定义没有出现在相同源文件的前面,就必须使用函数原型语句来声明函数。

函数原型:函数原型指定要传递给函数的形参、函数名、返回值类型,声明时最后跟一个分号。

函数原型和函数定义中函数头中的形参名称可以不同,甚至可以省略函数名,但类型和数量必须对应。

#include "pch.h"
#include 

double calc(int, int);	//声明函数
int main() 
{
	std::cout.precision(4);
	std::cout<< calc(1, 2)<double
{
	return static_cast(a) / b;
}

给函数传递实参 按值传递机制

按值传递机制中,指定的实参变量、常量或表达式的值并没有传递给函数,而是创建这些实参的副本,再传递给函数。

 给函数传递指针实参

当使用指针作为实参时,按值传递机制一样工作。

#include "pch.h"
#include 

int add(int*,int);	//声明函数

int main() 
{
	int num{0};
	int num1{ 10 };
	int* ptrm{ &num };
	
	std::cout<< add(ptrm,num1)< 
给函数传递数组 

数组是唯一不能按值传递的类型。

编译器将数组名转换为指针,指向数组头部的指针副本通过按值传递机制被传递给函数。

#include "pch.h"
#include 

int add(int [],int);	//声明函数

int main() 
{
	int a[]{ 1,2,3,4,5};
	std::cout << typeid(a).name() << std::endl;//a类型是数组
	std::cout<< add(a,_countof(a))< 

数组没有记录其大小信息,所以不能作为实参传递给函数的数组使用基于范围的for循环。

给函数传递多维数组

当定义多维数组作为形参时,可以省略第一维度值。

int add(int arr[][4],int count)

给函数传递引用实参

将函数的某个形参指定为引用,将改变该形参传递数据的方法。该机制不再赋值提供的实参,允许函数直接访问调用实参。

#include "pch.h"
#include 

int add(int& );	//声明函数

int main() 
{	
	int a{ 5 };
	std::cout<< add(a)< 

不能对lvalue引用形参对应的实参使用表达式,除非此表达式是一个lvalue。

lvalue引用形参对应的实参使用表达式,必然会导致某些数据永久地存储在内存中。

rvalue引用类型的形参允许传递到函数的表达式是rvalue。

使用const修饰符

const 修饰形参,阻止程序修改实参。

rvalue引用形参

rvalue引用形参可以引用一个rvalue(表达式的临时结果),但rvalue引用形参本身并不是一个rvalue,是一个lvalue。

#include "pch.h"
#include 

int add(int&&);	//声明函数

int main()
{
	std::cout << add(3+4) << std::endl;
}

int add(int&& a)    //rvalue引用传递
{
	int b = a;
	return b;
}
main函数的实参

可以将main函数定义成不带任何形参,也可以指定一个参数列表。

int main(int argc,char* argv[])
{

}

第一个形参时命令行上出现的,包括程序名在内的字符串数量。argc至少是1,至少要输入程序名。

第二个形参是一个数组,它包含指向这些字符串的指针,还有一个为空值的附加元素。

接收不良不定的函数实参

可以将函数定义成能够接收任何数量的实参。将省略号(...)写在函数定义中形参列表的最后,即可表示调用函数时可以提供可变的实参。

int add(int count,...)    //一般传递一个可变参数数量的普通参数
{

}

函数中至少要有一个普通形参。

c++库在cstdarg头文件中定义了va_start、va_arg和va_end宏,帮助我们获取可变实参。

//va_list 用来依次指向各个可变实参

//va_arg 返回arg_ptr指向的实参值,并使指针递增
type va_arg(
   va_list arg_ptr,    //arg_ptr 指向参数列表的指针。
   type                //type 要检索的参数类型。
);                    //va_arg 返回当前参数。 


//va_copy、va_start、和 va_end 不返回值。
//复制可变参数
void va_copy(
   va_list dest,            //复制源va_list ,指向要从 src 中初始化的参数列表的指针
   va_list src              //复制目标va_list,指向要复制到 dest 的参数初始化列表的指针。
); // (ISO C99 and later)

//将arg_ptr置空
void va_end(
   va_list arg_ptr        //arg_ptr 指向参数列表的指针。
);

//使其指向可变参数列表的第一个值(第一个实参)
void va_start(
   va_list arg_ptr,        //arg_ptr 指向参数列表的指针。
   prev_param                //位于第一个可选实参之前的形参。即可变形参前面的普通形参。
); // (ANSI C89 and later)


void va_start(
   arg_ptr
);  // (deprecated Pre-ANSI C89 standardization version)

在 中定义的 C 标准 STDARG.H宏按如下方式使用:

  • va_start 将 arg_ptr 设置为传递到此函数的参数列表中的第一个可选参数。 参数 arg_ptr 必须拥有 va_list 类型。 参数 prev_param 是紧跟在参数列表中的第一个可选参数之前的必需参数的名称。 如果 prev_param 使用注册存储类声明,则不定义宏的行为。 在首次使用 va_arg 前必须使用 va_start。

  • va_arg 从 arg_ptr 指定的位置中检索 type 的值,并增加 arg_ptr 以通过使用 type 的大小来确定下一个参数的开始位置,来指向列表中的下一个参数。 可以在函数中使用 va_arg 任意次,以检索列表中的参数。

  • va_copy 复制当前转态下的参数列表。 src 参数必须已使用 va_start 进行初始化;可以使用 va_arg 调用进行过更新,但是不能使用 va_end 进行过重置。 va_arg 从 dest 中检索到的下一个参数与从 src 中检索到的下一个参数相同。

  • 检索所有参数后,重置 va_end 指向 的指针 NULL。 在函数返回前必须在已使用 va_start 或 va_copy 初始化的各个参数列表上调用 va_end。


从函数返回值 返回指针

return_type* function_name(parameter)

{

        return_type variable;

        return &variable;        //注意返回类型必须同函数头中的返回类型一致

}

返回地址的规格:永远不要从函数中返回局部自动变量(局部作用域变量)的地址。

#include "pch.h"
#include 

double* treble(double);

int main()
{
	double num{5.0};
	double* ptr{};
	ptr = treble(num);
	std::cout << "3.0*num: " << num*3.0 << std::endl;
	std::cout << "Result : " << *ptr << std::endl;
}

double* treble(double data)
{
	double result{};        //在函数返回时销毁
	result = 3.0 * data;
	return &result;        //销毁后指针指向的变量不再包含原来的值。
}

输出:
3.0*num: 15
Result : -9.25596e+61       //

正确的方法可以使用动态内存分配。

#include "pch.h"
#include 

double* treble(double);

int main()
{
	double num{5.0};
	double* ptr{};
	ptr = treble(num);
	std::cout << "3.0*num: " << num*3.0 << std::endl;
	std::cout << "Result : " << *ptr << std::endl;
}

double* treble(double data)
{
	double* result{ new double{} };
	*result = 3.0 * data;
	return result;    //该变量一致存在,直到用delete销毁。此处没有删除,内存会逐渐消耗。
}

输出:
3.0*num: 15
Result : 15

使用delete释放内存

#include "pch.h"
#include 

double* treble(double);

int main()
{
	double num{5.0};
	double* ptr{};
	ptr = treble(num);
	std::cout << "3.0*num: " << num*3.0 << std::endl;
	std::cout << "Result : " << *ptr << std::endl;
	delete ptr;		//释放内存
	ptr = nullptr;
}

double* treble(double data)
{
	double* result{ new double{} };
	*result = 3.0 * data;
	return result;
}

输出:
3.0*num: 15
Result : 15
返回引用

可以从函数中返回一个lvalue的引用。

lvalue引用不能独自存在(它总是其他对象的别名),所以必须确保其引用的对象在函数执行完之后仍然存在。

从函数返回lvalve引用意味着可以在赋值语句的左边使用函数的结果。

返回引用的规则:永远不要从函数中返回对局部变量的引用。

#include "pch.h"
#include 
#include 

using std::cout;
using std::endl;
using std::setw;

double& lowest(double values[], int length);   // Function prototype

int main()
{

    double data[]{ 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{ _countof(data) };                         // 
    for (auto value : data)
        cout << setw(6) << value;

    lowest(data, len) = 6.9;                            // 返回引用将允许在赋值语句的左边使用函数。
    lowest(data, len) = 7.9;                            // 返回引用将允许在赋值语句的左边使用函数。

    cout << endl;
    for (auto value : data)
        cout << setw(6) << value;

    cout << endl;
    return 0;
}

// 返回引用的函数
double& lowest(double a[], int len)                    //& lvalue的申明
{
    int j{};                                           // 最低元素的索引
    for (int i{ 1 }; i < len; i++)
        if (a[j] > a[i])                                   // 找出小值
            j = i;
    return a[j];                                        // 返回对最低元素的引用。
                                                         //不要混淆返回&a[j]与返回引用。&a[j]指定的是a[j]的地址,那是一个指针。
}
函数中的静态变量

可以在函数内部将某个变量声明为static。

static int count {};

函数内静态变量的初始化仅发生在第一次调用该函数的时候。

事实上,初次调用函数时将创建并初始化静态变量。之后该变量在程序执行期间将继续存在,退出函数时该变量包含的任何值都可以在下次调用函数时使用。

#include "pch.h"
#include 
#include 

int increment();

int main()
{
	for (int i = 0; i < 10; i++)
	{
		std::cout << increment() << std::endl;
	}
}

int increment()
{
	static int a {0};	//静态变量,仅在函数第一次调用时初始化,下次调用时继续存在
	return ++a;
}
递归函数

除非遇到的问题特别适用于使用递归函数,或者没有明显的代替方法,否则使用其他方法一般会更好。

使用循环比使用递归的函数调用效率更好。

#include "pch.h"
#include 
#include 

int factorial(int);

int main()
{
	std::cout << factorial(5) << std::endl;
}

int factorial(int a)
{
	if (a >= 1)
		return factorial(a - 1) * a;
	if (a == 1)
		return 1;
}

函数指针

指向函数的指针必须包含想调用的函数的内存地址,还必须包含被指向函数的形参列表以及返回类型等信息。

声明函数指针

return_type (*pointer_name)(list_of_parameter_types) 

  • 指向函数的返回类型return_type
  • 指针名称pointer_name(注意括号内包含*和函数指针名)
  • 指向函数的形参类型list_of_parameter_types

这种指针只能指向具有声明中指定的return_type和list_of_parameter_types的函数。如果视图赋给指针一个与指针声明中的类型不相符的函数,编译器将生成一条错误消息。

long sum(long num1,long num2);    //函数原型
long (*pfun)(long,long){sum};     //函数指针指向函数sum
auto pfun2 = sum;                //可以使用auto关键字
#include "pch.h"
#include 
#include 

int add(int,int);
int mul(int, int);

int main()
{
	int (*funptr)(int, int) {};
	funptr = add;
	std::cout << funptr(3,4) << std::endl;
	funptr = mul;
	std::cout << funptr(3, 4) << std::endl;
}

int add(int a,int b)
{
	return a + b;
}

int mul(int a, int b)
{
	return a * b;
}

输出:
7
12
函数指针作为实参
#include "pch.h"
#include 
#include 

int add(int, int);
int mul(int, int ,int (*funptr)(int, int));

int main()
{
	int (*funptr)(int, int) {};    //指针作为函数的形参
	funptr = add;
	std::cout << mul(3, 4,add) << std::endl;
}

int add(int a,int b)
{
	return a + b;
}

int mul(int a, int b, int (*funptr)(int, int))    //指针作为函数的形参
{
	funptr(a, b);
	std::cout << funptr(3, 4) << std::endl;
	return a * b;
}
函数指针的数组

用常规指针相同的方式来声明函数指针的数组。

return_type (*pointer_name[size]) ( list_of_parameter_types ) 

return_type (*pointer_name[])(list_of_parameter_types) { function_list };

//函数声明
double sum(cosnt double,const double);    
double product(cosnt double,const double);
double difference(cosnt double,const double);

//申明指针数组并初始化
//不能用auto推测出数组的类型,必须明确指定类型
double (*pfun[]) (cosnt double,const double) {sum,product,difference};    

//使用指针数组调用函数
pfun[1](2.5,2.5);
初始化函数形参

函数指定默认的形参值,如果在调用该函数时省略了实参,就使用其默认值。

应该将拥有默认值的参数依次全部放在函数原型中形参列表的最后,使最可能被省略的参数最后出现。

#include "pch.h"
#include 
#include 

void show(const char s[] = "default value");	//函数声明(函数原型)时指定默认值
int main()
{
	show();
	show("new value");
}

void show(const char s[] )		//函数定义
{
	std::cout << s << std::endl;
}
异常
  • try:标志可能出现异常的代码块,后面必须紧跟至少一个catch块
  • throw: 使异常状态产生,并抛出特定类型的异常
  • catch:标志处理异常的代码块。try后面可以跟几个catch块。
抛出异常

try代码块中的任何位置都可以使用throw语句抛出异常,throw语句的操作数决定着异常的类型。

 捕获异常

如果希望使某个catch代码块处理try代码块中抛出的任何异常,则必须将省略号(...)放入包围异常声明的圆括号内。

 重新抛出异常

使用没有操作数的throw,会重新排除要处理的异常。

 MFC中的异常处理

MFC函数通常抛出的异常是特定的类类型(CDBException)。

如果抛出的异常是CDBException类型,则作为catch代码块形参出现的类型应该是CDBException*。如果没有重新抛出该异常,就还必须在catch块中调用其Delete()函数,删除异常对象。

不应使用delete删除异常对象,因为该对象可能没有在堆上分配内存。

 CDBException是所有MFC异常的基类,所以这里的catch块会捕获任何类型的MFC异常。

处理内存分配错误
#include                    // For bad_alloc type
#include
using std::bad_alloc;
using std::cout;
using std::endl;

int main()
{
  char* pdata {};
  size_t count { ~static_cast(0) / 2 };
  try
  {
    pdata = new char[count];
    cout << "Memory allocated." << endl;
  }
  catch(const bad_alloc& ex)
  {
    cout << "Memory allocation failed." << endl
         << "The information from the exception object is: "
         << ex.what() << endl;
  }
  delete[] pdata;
  return 0;
}

new操作符抛出的异常时std::bad_alloc类型。bad_alloc是new标准头文件中定义的类类型。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/925868.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号