C++入门(3)

前言

C++定义了很多新的语法,可以在一定程度上补上C语言的短板,我们废话不多说,来了解一下这些特殊的语法吧

1.内联函数

1.1概念

我们之前在C语言中学习过宏,如果我们在C语言中想要用宏写一个ADD函数,那么它的写法如下:

#define ADD(x,y) ((x)+(y))

int main(void)
{
	printf("%d\n", ADD(1, 2));
	printf("%d\n", ADD(1, 2)*3);
	int a = 0, b = 1;
	printf("%d\n", ADD(a | b, a & b));
	return 0;
}

如果我们没有按要求加入3个括号,在进行乘除等运算的过程中,由于优先级的问题,可能会出现计算错误

所以我们可以知道宏有以下的缺点:

1.容易出错,语法的坑比较多

2.不能调试,在预处理阶段就已经被替换了

3.没有类型的检查

但是宏也有它的优点:
1.没有类型的严格限制,可以在一定程度上兼容不同的类型

2.针对频繁调用的小函数,不需要建立栈帧,提高了效率

针对这一情况,为了减少栈帧的调用,C++创建了一个东西叫做内联函数,就解决了这个问题

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调 用建立栈帧的开销,内联函数提升程序运行的效率(debug版本因为考虑到调试的问题所以默认不会展开,在release版本中会直接展开,可以在设置中更改

inline int add(int x, int y)
{
	return x + y;
}

int main(void)
{
	printf("%d\n", add(1, 2));
	return 0;
}

1.2 内联函数的特征

1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用。缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率

2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性

3. inline不建议声明和定义分离在两个文件中,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到

2.auto关键字

2.1 概念

我们编写的程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:

1. 类型难于拼写

2. 含义不明确导致容易出错

C++为了解决这个问题创建了auto关键字,auto的具体使用方式如下:

如果我们想要定义一个变量a,再定义一个变量b存入a的取值,我们在C语言中通常会这么写:

int a = 0;
int b = a;

而在C++中auto关键字会自动识别类型,所以我们可以这么写:

int a = 0;
auto b = a;
auto c = &a;
auto& d = a;

auto关键字在普通的场景没有太大的价值,当类型很长的时候auto关键字就能够发挥它的作用,能够简化代码,我们来举一个例子说明(不需要理解,仅仅作为示例,能看懂就行):

#include <vector>
#include <string>
int main(void)
{
	std::vector<std::string> v;

	std::vector<std::string>::iterator it = v.begin();
	//这一串代码可以简化为 auto it = v.begin();
	return 0;
}

2.2 使用auto的注意事项

1.auto不能作为函数的参数

//代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

2.auto不能直接用来声明数组

//这种情况下编译会错误
void TestAuto()
 {
 int a[] = {1,2,3};
 auto b[] = {4,5,6};
 }

额外补充

C++中有一个东西可以帮助我们查看实际类型,叫做 typeid() ,具体的使用方式如下:

int main(void)
{
	int a = 0;
	auto b = &a;
	cout << typeid(b).name() << endl;
	return 0;
}

3.基于范围的for循环(C++11)

我们用之前学过的知识在C++中访问数组会很麻烦:

int main(void)
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
		array[i] *= 2;
	
	for (int* p = array; p < array + sizeof(array) / sizeof(array[0]); ++p)
		cout << *p << endl;
	
	return 0;
}

而在C++11中有一种新语法叫做基于范围的for循环,它的具体使用方法如下:

int main(void)
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
		array[i] *= 2;
	
	for (int* p = array; p < array + sizeof(array) / sizeof(array[0]); ++p)
		cout << *p << " ";
	cout << endl;
	
	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

基于范围的for循环会依次取数组中的数据赋值给e,它会自动判断结束和自动迭代,范围for一般会结合auto使用

我们来看一下下面这种情况:

int main(void)
{
	int array[] = { 1, 2, 3, 4, 5 };
	
	
	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;
	
	for (auto e : array)
	{
		e *= 2;
	}

	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

此时我们可能会产生疑问,为什么我们这里使用了 *= 操作,但是打印出来的值没有发生变化呢?

因为我们是依次取出数组中的元素赋值给e,对e的修改并不会影响原数组,如果想要对e的修改影响原数组,我们可以这样修改:

int main(void)
{
	int array[] = { 1, 2, 3, 4, 5 };
	
	
	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;
	
	for (auto& e : array)
	{
		e *= 2;
	}

	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

要想完成这个操作,我们这里只能使用引用而不能使用指针

4.指针空值nullptr(C++11)

我们需要知道的是:NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量,而C语言中不存在这样的情况。不论采取何 种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
int main()
{
	f(0);
	f(NULL);
	f((int*)NULL);
	return 0;
}

程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的 初衷相悖

在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器 默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强制转换为 (void *)0

为了解决这个问题,我们可以使用nullptr:

void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
int main()
{
	f(0);
	f(nullptr);
	f((int*)NULL);
	return 0;
}

在使用nullptr的时候我们需要注意:

1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的

2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同

3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr

结尾

本节我们学习了一些C++的新语法,下一节我们就要进入C++中一个很重要的内容——类和对象,希望能给你带来帮助,谢谢您的浏览!!!

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C入门PDF是一种提供初学者学习C语言基础知识的电子文档。C语言被广泛应用于软件开发领域,是一种高级计算机编程语言。学习C语言是许多计算机科学专业学生和编程爱好者的首选。 C入门PDF通常包含基本的C语言语法和常用的编程概念。它们可能包括变量、数据类型、运算符、条件语句、循环语句和函数等基础知识的介绍。此外,它们还可能包含一些简单的编程示例和练习,帮助初学者理解并应用所学知识。 通过学习C入门PDF,初学者可以逐步建立对C语言的理解和掌握。他们可以学习如何编写简单的C程序,并逐渐提高他们的编程能力。C语言是一种结构化的编程语言,因此通过学习C语言,初学者也可以培养良好的编程习惯和逻辑思维能力。 对于初学者来说,C入门PDF是一个方便而有效的学习工具。他们可以根据自己的进度和需要,在任何时间和地点学习C语言。通过自主学习,初学者可以在自己的学习节奏和理解能力下进行学习,不受时间和空间的限制。 C入门PDF是许多在线教育平台、编程社区和计算机科学教育机构提供的免费资源。因此,初学者可以轻松获取这些资源,并根据自己的学习需求选择最适合自己的C入门PDF。 总之,C入门PDF是一种方便且有效的学习资源,可以帮助初学者掌握C语言的基础知识和编程技能。通过学习C语言,初学者可以为自己的编程之路打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值