C++ | C++入门总结(一)引用&、指针*

  • C++:#include指令,包含来自标准库的头文件时,用尖括号<>包围头文件名;对于不属于标准库的头文件,则用双引号""包围。对于<>,先去系统目录中找头文件,如果没有在到当前目录下找;对于"",首先在当前目录下寻找,如果找不到,再到系问统目录中寻找。

  • C ++ 语言并未定义任何输入输出 ( IO ) 语句 , 取而代之 , 包含了一个全面的标准库( standard library ) 来提供 IO 机制 ( 以及很多其他设施 ) 。

iostream 库包含两个基础类型istream和 ostream , 分别表示输入流和输出流。

标准库定义了 4 个IO对象:

  1. 为了处理输入 , 我们使用一个名为 cin的 istream 类型的对象,这个对象也被称为标准输入 ( standardinput ) 。

  2. 对于输出 , 我们使用一个名为 cout的ostream 类型的对象, 此对象也被称为标准输出 ( standard output )。

  3. 标准库还定义了其他两个ostream 对象 , 名为 cerr 和 clog。我们通常用 cerr 来输出警告和错误消息 , 因此它也被称为标准错误 ( standard error ) 。

  4. clog用来输出程序运行时的一般性信息。


  • std:

  1. 标准命名空间。
  2. C++标准库中的函数或者对象都是在命名空间std中定义的,所以我们要使用标准函数库中的函数或对象都要使用std来限定。
  3. 例如:使用 string 类型必须首先包含string头文件。作为标准库的一部分, string 定义在命名空间 std 中:
#include <string>
using std::string;

  •  初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。

  • 初始化

  1. 定义一个名为 num 的 int 变量并初始化为 0 ,有以下四种方式:
	int num = 0;
	int num = { 0 };
	int num{ 0 };
	int num(0);

用花括号来初始化变量的形式称为列表初始化,当用于内置类型(字符、整型、浮点数等)的变量时,这种初始化形式有一个重要特点:如果我们使用列表初始化且初始值存在丢失信息的风险,则编译器将报错:

	long double num = 3.14;
	int a = num;
	cout << a << endl;//警告,输出3

	int b = { num };
	cout << b << endl;//报错

	int c{ num };
	cout << c << endl;//报错

	int d(num);
	cout << d << endl;//警告,输出3
	return 0;


  • 如果是内置类型的变量未被显式初始化,它的值由定义的位置决定。
  • 定义于任何函数体之外的变量被初始化为 0。一种例外情况是 , 定义在函数体内部的内置类型变量将不被初始化。
  • 一个未被初始化的内置类型变量的值是未定义的 ,如果试图拷贝或以其他形式访问此类值将引发错误。
  • string类规定如果没有指定初始值则生成一个空串。
void Test()
{
	int num;
	cout << num;//报错
	string str;
	cout << str;//输出空串
}

  •  extern:

  1. 当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去编译;
  2. 当它修饰变量时,如extern int i;则表示声明了一个变量,而不是定义。(定义:申请了存储空间,而且也可能为变量赋一个初值)

a.任何包含了显式初始化的声明即成为定义。(我们可以给由extern标记的变量赋一个初值,但是就抵消了extern的作用。

b.在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。

c.变量能且只能被定义一次,但可以被多次声明。(如果要在多个文件中使用同一个变量,就必须将声明和定义分离。此时,变量的定义必须出现在且只能出现在一个文件中,而其他用到该变量的文件必须对其进行声明,却绝对不能重复定义。

extern int a;//声明a
extern int b = 10;//定义b
int c;//声明并定义c
void TestExtern() {
	extern int d = 10;//错误
}

  • 为一个已有的类型取一个新的名字。 
  1. typedef 类型 别名
  2. using 别名=类型
#include <iostream>
using namespace std;

int main()
{
	typedef int inter;
	inter a = 1;
	cout << a;
}
	typedef int NewInt;
	NewInt num = 20;
	using _NewInt = int;
	_NewInt num2 = 10;

  •  枚举类型:

  1. 默认情况下,第一个名称的值为 0,第二个名称的值为 1,第三个名称的值为 2,以此类推。但是,当给一个名称赋予一个值时,其后面的都会比前面一个名称大 1,但其前面的还是按默认0,1,2...赋值。
  2. C++:枚举类型中的每个元素,可以直接使用,不必通过类型.元素的方式调用
#include <iostream>
using namespace std;
enum testEnum
{
	spring,
	summer=5,
	fall,
	winter
} testc;
int main()
{
	testc = spring;
	cout << testc;//输出0

	testc = fall;
	cout << testc << endl;//输出6
}

3.C#:枚举类型中的每个元素必须通过类型.元素的形式调用

    enum TestEnum
    {
        spring,
        summer=5,
        fall,
        winter
    } 
    private void Init()
    {
        TestEnum testEnum = new TestEnum();

        testEnum = TestEnum.spring;
        Debug.Log((int)testEnum);//输出0
        testEnum = TestEnum.fall;
        Debug.Log((int)testEnum);//输出6
    }

【2020/05/25补充】

  • 引用:&d(d是变量名)

  1. 引用为对象起了另一个名字,引用本身不是对象,不开辟内存单元。
  2. 引用必须初始化:定义引用时,程序把引用和它的初始值绑定在一起,而不是把初始值拷贝到引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另一个对象,所以引用必须初始化。
  3. 定义了一个引用后,对其进行的所有操作都是在与之绑定的对象上进行的。
  4. 为引用赋值,实质是把值赋给了与引用绑定的对象;获取引用的值,实际上是获取了与引用绑定的对象的值;以引用作为初始值,实际上是以与引用绑定的对象作为初始值。
  5. 大部分情况下,引用的类型要和与之绑定的对象严格匹配。
  6. 引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。
	int val1 = 10;
	int &refVal1 = val1;//refVal1 是val1的另外一个名字。

	int val2 = 20;
	&refVal1 = val2;//报错,无法令引用重新绑定到另外一个对象。

	int &refVal2;//报错,引用必须被初始化。
	int val1 = 10;
	int &refVal1 = val1;

	refVal1 = 20;//把20赋值给refVal1绑定的对象,即val1;
	cout << val1<<" "<< refVal1<<endl;//输出20 20

	int val2 = refVal1; //获取refVal1的值,实际上是获取了val1的值。
	cout <<val2<<" "<< val1 << " " << refVal1;//输出20 20 20
	float timer = 20;
	int &refTimer = timer;//报错,类型不同

	int &refVal1 = 20;//报错,引用类型的初始值必须是一个对象

  • 指针:*d(d是变量名)

  1. 指针本就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。
  2. 指针无须在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
  3. 指针存放某个对象的地址,要想获得该地址,需要使用取地址符(&)。
  4. 一般情况下,指针的类型要和它所指向的对象严格匹配。
  5. 如果一个指针指向了一个对象,则允许使用解引用符(*)来访问该对象。
	int a = 10;

	int *p1 = &a;//p1存放变量a的地址

	int *p2 = p1;//p2存放p1,即存放变量a的地址

	cout << *p1 << " " << *p2 << endl;//*解引用符,得到p1、p2所指的对象a,输出10 10

	*p1 = 10;//*解引用符,得到p3所指的对象b,为变量b赋值。

	cout << *p1 << " " << *p2;//*解引用符,得到p1、p2所指的对象a,输出10 10
	int num = 10;
	int &a = num;//&紧随类名出现,a是一个引用
	int *p = &a;//*紧随类名出现,p是一个指针;
	            //&出现在一个表达式中,是一个取地址符
	*p = 20; //*出现在一个表达式中,是一个解引用符,获得num对象

  • 空指针:

  1. 得到空指针最直接的办法就是用字面值 nullptr 来初始化指针,nullptr是一种特殊类型的字面值, 它可以被转换成任意其他的指针类型。
  2. 任何非0指针对应的条件值都是true。
	int *p = nullptr;//等价于int *p = 0;
	int *p = 0;//直接将p初始化为字面常量0;
	int *p = NULL;//等价于int *p = 0;

  • void* 指针:

  1. void* 是一种特殊的指针类型,可用于存放任意对象的地址。
  2. 不能直接操作void* 指针所指的对象,因为我们并不知道这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。
	int num = 10;
	double d = 20;

	void *v = &num;
	v = &d;

  • const :如果想在多个文件之间共享 const 对象,必须在变量的定义之前添加 extern关键字。(只在一个文件中定义 const ,而在其他多个文件中声明并使用它。)

【2020/05/26补充】

  • 对指针的引用

格式:类型 *&指针引用名=指针;

	int num = 10;
	int *p = &num;
	int *&q = p;
	*q = 11;
	cout << num << endl;//11
	*p = 12;
	cout << num << endl;//12

  • 对常量的引用:

  1. 对常量的引用不能被用作修改它所绑定的对象。
  2. 不可以让一个非常量引用指向一个常量对象。
	const int num = 20;
	const int &refNum = num;
	refNum = 30;//错误:不可以修改它所绑定的对象
	int &refNum2 = num;//错误:不可以让一个非常量引用指向一个常量对象

  •  指向常量的指针:

  1. 指向常量的指针不能用于改变其所指对象的值。
  2. 要想存放常量对象的地址,只能使用指向常量的指针。
  3. 指向常量的指针所指的对象不一定必须是个常量,仅仅要求不能通过该指针改变对象的值。
	int num = 30;
	const int *cNum = &num;
	*cNum =20;//错误,指向常量的指针不能用于改变其所指对象的值。即:不能改变num的值
	cout << *cNum;
	const int num = 30;
	int *cNum = &num;//错误:cNum是一个普通指针。
	const int *cNum = &num;//正确
	const int num = 30;
	const int *cNum = &num;
	int num2 = 20;
	cNum = &num2;

  • const 指针:指针本身为常量

  1. 常量指针必须初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了。
  2. 把 * 放在 const 关键字之前用以说明指针是一个常量。
  3. 指针本身是一个常量并不意味着不能通过指针修改其所指对象的值,能否这样做完全依赖于所指对象是否为常量。
  • coust靠近谁谁就不能变;
  • 一个比较好记的方法来区分 int const *p与 int* const p:把*读作pointer to然后从后往前读。
  1. int const *p就可以读作 p is a pointer to const int,p是指向常量的指针
  2. int* const p就可以读作 p is a const pointer to int,p是指向int型的常指针
	int num = 30;
	int *const cNum = &num;

	*cNum = 20;//正确,指针指向的那个地址中的值可以变。
	cout << *cNum;

	int num2 = 20;
	cNum = &num2;//错误:指针本身的值不能变
	const int num = 30;
	const int *const cNum = &num;//cNum是一个指向常量的常量指针

	*cNum = 20;//错误,num为常量

	int num2 = 20;
	cNum = &num2;//错误:指针本身的值不能变

  • 顶层const:

  1. 常量指针;
  2. 本身是常量:对任何数据类型都适用。
  • 底层const:

  1. 指向常量的指针;
  2. 与指针和引用等复合类型的基本类型有关。
  • 指针类型既可以是顶层 const 也可以是底层 const。
	int num = 10;
	int *const p1 = &num;//p1是常量指针,p1的值不可改,p1是顶层const

	const int num2 = 20;//num2是整型常量,num2的值不可改,num2是顶层const

	//指向常量的指针所指的对象不一定必须是个常量
	const int *p2 = &num;//p2的值可改,p2是底层const

  • auto类型说明符:

  1. 让编译器通过初始值来推算变量的类型;
  2. auto定义的变量必须初始化。
	auto num = 10;
	num = "s";//错误,num是int类型,不能更改数据类型
  • decltype

  1. 选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值:
	decltype(fun()) sum = x;//sum的类型就是fun()的返回类型

*编译器并不实际调用函数 fun ,而是使用当调用发生时 fun 的返回值类型作为 sum 的类型。
 

猜你喜欢

转载自blog.csdn.net/weixin_39766005/article/details/106210574