首页 > 编程语言 >C++笔记(一)

C++笔记(一)

时间:2023-04-07 23:24:34浏览次数:43  
标签:arr int 笔记 assert C++ sizeof include 指针

C++笔记(一)

反复考量之后,还是决定将C++作为我的第二语言以及以后的主力开发语言。

目录

语法基础

基本数据类型

基本有四种类型:

  • 整型(修饰符:short、long、signed、unsigned)
  • 浮点型(包括float和double,修饰符:long)
  • 字符型
  • 布尔型

注意数字类型存在有无符号的区别,有无符号的计算参考下面的[补码](# 补码)

变量、常量

#include <iostream>

using namespace std;

int main()
{
	// 变量
	string color;  // 声明变量,标识符基本是通用约束:字母数字下划线,不能以下划线开头,不能使用关键字,大小写敏感
	int age;  // 其他还有16位short int和32位long int等
	double weight;  // 还有float和long double等
	char c;  // 以上多数类型包含有符号和无符号类型
	bool b;

	color = "三花"; // 首次赋值,初始化变量,变量需要初始化才可以引用,没有其它语言中的默认零值
	age = 3;
	weight = 4.0;
	c = 'a';
	b = false;

	cout << color << age << weight << c << b << endl;

	// 常量
	// 整数前缀进制基数0x表示十六进制,0表示八进制,不带前缀默认十进制
	// 整数后缀可以是U或者L,U表示无符号,L表示长整数
	const double PI = 3.1415926;
	cout << PI;

}

作用域

#include <assert.h>

int get_var();

int get_static_var();

int x = 1;

int main()
{
	int a = get_var();
	int b = get_static_var();
	assert(a == 1 && b == 2);

	a = get_var();
	b = get_static_var();
	assert(a == 1 && b == 3);

	int x = 0;
	assert(::x == 1);  // 通过::调用被shadow掉的全局变量

}

int get_var()
{
	int a = 0;
	a++;
	return a;
}

int get_static_var()
{
	// 静态局部变量只会初始化一次,生命周期和程序相同
	// 全局变量和静态局部变量可以自动初始化,局部变量不会自动初始化
	static int b = 1;
	b++;
	return b;
}

基本运算

#include <assert.h>

int main()
{
	int x = 5, y = 2;

	// 算数运算符
	assert(x / y == 2);  // 地板除
	assert(5.0 / y == 2.5);
	assert(++x == 6);  // 当自增/自减符前置时,变量先于当前语句的执行进行自增自减操作并更新值
	assert(x-- == 6);  // 当自增自减符后置时,变量会在当前语句执行后再进行自增自减操作并更新值
	
	// 关系运算符
	// 等于==;不等于!=;大于>;小于<;大于等于>=;小于等于<=
	assert(x != y);

	// 逻辑运算符
	// 与&&;或||;非!
	bool t = true, f = false;
	assert(t || f);

	// 赋值运算符
	// 赋值=;加赋+=;减赋-=;乘赋*=;除赋/=;模赋%=;左移后赋值<<=;右移后赋值>>=;按位与后赋值&=;按位异或后赋值^=;按位或后赋值|=
	f += 1;
	assert(f);
	y <<= 1;
	assert(y == 4);

	// 位运算符
	// 按位与&:仅当两个操作数都为1时为1;按位或:仅当两个操作数都为0时为0;按位异或:仅当两个操作数不同时为1;按位取反~
	int z = 10;
	assert(~z == -11);

	// 其他运算符
	// 三目运算符:条件语句?真时值:假时值;逗号运算符:顺序执行多个运算,值为最后表达式的值;...
	assert(true?1:2 == 1);
	assert(sizeof(x) == 4);
	assert((x, y, z) == 10);

}
#include <assert.h>


int main()
{
	// c++也有条件判断短路
	int x = 0;
	if (x && ++x) {}
	assert(x == 0);

	int y = 1;
	if (y || ++y) {}
	assert(y == 1);
}
#include <iostream>

using namespace std;


int main()
{
	float a = 0.1;
	float b = 0.0;
	cout << a / b << endl;  // inf

	float c = 0.0;
	float d = 0.0;
	cout << c / d << endl;  // -nan(ind)
	
}

补码

无符号数表示:按位加权求和即可

有符号数表示:计算机中统一使用补码,补码可以统一符号位和数值域、加减法运算,对于计算机来说,对于不同位(符号位、数值域)上的值的无差别处理可以简化底层硬件设计和实现。

通过补码可以构造出一张映射表,这样减法就可以通过:

减数加上被减数的映射值x得出y,通过映射表得到y的映射值z,z即减法结果

#include <assert.h>

unsigned int B2U(unsigned int num)
{
	return (unsigned int)(num);
}

int B2T(int num)
{
	return (int)(num);
}


int main()
{
	assert(B2U(0xFFFFFFFF) == 4294967295);
	assert(B2T(0xFFFFFFFF) == -1);
	assert(B2T(0x80000000) == -2147483648);
}

对于有符号数不要使用右移

反码:区分正数和负数,正数正常表示即可,负数保留符号位,将数值域按位取反,然后加1

反码更接近人类思考方式,但不能用。很多时候,如果有多种方案作为计算机运作时的解决方案,首先应该排除更接近人类常规思维方式的方案,因为这种方案很可能不适合计算机发挥性能。

字节序

一个字(32位机器的4个byte或32个bit)以byte存放的方式

大端序:IBM大型机或者网络传输,高位在前,整体和字节内部都有序

小端序:intel兼容机,高位在后,每个字节内部有序

基本结构

顺序结构

分支结构

#include <iostream>

using namespace std;


int main()
{
	cout << "请输入x:" << endl;
	string x;
	cin >> x;
	if (x == "if")
	{
		if (1)
		{
			cout << "if分支" << endl;
		}
	}
	// else if实际上是嵌套的if语句
	else if (x == "else-if")
	{
		cout << "else if分支" << endl;
	}
	else
	{
		cout << x << endl;
		cout << "else分支" << endl;
	}cout << "请输入y:" << endl;
	int y;
	cin >> y;
	switch (y)
	{
	case 1:
		cout << 3 << endl;
		break;  // 默认是不跳出的
	case 2:
		cout << 4 << endl;
		break;
	default:
		cout << "default" << endl;
	}
	
}

循环结构

#include <assert.h>


int main()
{
	int x = 0;
	while (x < 10) {
		if (x == 6)
		{
			x += 2;
			continue;
		}
		else if (x == 8)
		{
			break;
		}
		x++;
		
	}
	assert(x == 8);

	for (int y = 0; y < 10; y++)
	{
		if (x == 6)
		{
			x += 2;
			continue;
		}
		else if (x == 8)
		{
			break;
		}
	}
	assert(x == 8);
	// 支持do...while...
	// 支持goto
	++x;
	goto here;
	++x;
	++x;
	++x;
here:
	--x;
	assert(x == 8);

}

指针

指针是基于基本数据类型的复合数据类型,占8个字节。

#include <iostream>
#include <assert.h>

using namespace std;


void print_p(void* p);

int main()
{
	int n = 1;
	int* p = &n;
	n = 2;
	assert(*p == 2);

	int a = 1;
	const int* pa = &a;
	a = 2;
	// *pa = 3; // 常量指针,不能通过指针直接修改变量的值,可以重新指向其他变量(也不可通过指针修改值)
	assert(*pa == 2);

	int b = 1;
	int* const pb = &b;
	b = 2;
	// pb = &a; // 指针常量,可以通过指针修改变量的值,不可以重新指向其他变量
	assert(*pb == 2);
	// 另外有常指针常量,不可通过指针修改变量的值,也不可重新指向其他变量

	print_p(&b);
}

void print_p(void* p)
{
	cout << p << "指向的值是:" << *((int*) p) << endl;
}

内存空间

  • 内核空间
  • 用户空间
    • 栈:局部变量、函数参数和返回值(降序分配内存地址)
    • 堆:动态开辟内存的变量(升序分配内存地址)
    • 数据段:全局变量、静态变量
    • 代码段:可执行代码、常量(程序开始运行后不变)

动态分配内存

主要是为了使用更大空间的堆区内存和手动控制内存释放

#include <assert.h>

void settle_mem(int** pp)
{
	*pp = new int(6);
}

int main()
{
	int* n = new int{ 5 };
	*n += 5;
	assert(*n == 10);
	delete n;
}

二级指针

#include <assert.h>

void settle_mem(int** pp)
{
	*pp = new int(6);
}

int main()
{
	// 二级指针
	int x = 6;
	int* px = &x;
	int** ppx = &px;
	assert(*ppx == &x);
	assert(**ppx == x);

	// 可以通过二级指针为指针分配内存
	int* p;
	settle_mem(&p);
	assert(*p == 6);
}

空指针

可以用0或者NULL表示空指针,可以用来屏蔽编译错误。

解引用空指针会引起程序崩溃,delete空指针会被忽略。

无论一个指向0、NULL、nullptr,都可以用三者中的任意一个值与指针比较来确认是否是空指针。

#include <assert.h>

int main()
{
	// 空指针
	int* p = NULL;
	assert(p == 0);
	assert(p == NULL);
	assert(p == nullptr);
}

野指针

主要是指没有初始化的、动态分配的内存已被释放的、自动分配的内存已被回收的或者数组越界的指针,访问野指针可能导致程序崩溃。至于解决办法,就是针对可能出现野指针的情形进行规避,不出现野指针就解决了野指针的问题。

函数指针

#include <iostream>
using namespace std;

int my_add(int a, int b);
int calculate(int (*f)(int, int), int a, int b);

int main()
{
	// 函数指针
	calculate(my_add, 1, 2);
}

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

int calculate(int (*f)(int, int), int a, int b)
{
	// 只是演示,实际上这里可以直接访问到全局标识符my_add
	int res = f(a, b);
	cout << "a=" << a << ", b=" << b << ", res=" << res << endl;
	return res;
}

常见容器类型

数组

数组要求数据类型相同。

数组空间在内存中是连续的,数组名多数时候被认为是第0个元素的地址(少数语句中代表其他含义,例如sizeof运算符作用在数组名时将返回数组的字节数),通过数组地址+n可以访问到下标为n的数组元素,数组名是常量,不可修改。

当编译器遇到地址[下标]时会认为是**(地址与下标之和)*

对数组取址将会得到行指针(值与数组第0个元素地址相同),行指针+1将得到下一个行指针即,第0个元素地址+数组字节数。

#include <iostream>
#include <assert.h>
using namespace std;


void print_2d_arr(int rp[][6], int rows);
void print_arr(int arr[], int len);
int comp_asc(const void* p1, const void* p2);
int comp_desc(const void* p1, const void* p2);
int bin_search(int arr[], int len, int target);

int main()
{
	// int arr[get_len()]; 表达式必须在编译器可被计算
	// int num = 6; int arr[num];表达式应包含常量
	const int num = 6; int arr[num];
	for (int i = 0; i < 6; i++)
	{
		arr[i] = i * i;
	}
	assert(arr[5] == 25);
	// 数组支持使用{}声明时直接初始化赋值,并且支持长度推导,支持手动初始化时自动零值
	// 数组拷贝
	int arr1[num];
	memcpy(arr1, arr, sizeof(arr));

	// 数组清零
	memset(arr, 0, sizeof(arr));
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		assert(arr[i] == 0);
	}

	

	// 当编译器遇到  地址[下标]  时会认为是  *(地址与下标之和)
	int* p = arr1;
	for (int i = 0; i < sizeof(arr1) / sizeof(int); i++)
	{
		assert(arr1[i] == *(p+i));
	}

	// 数组排序
	int to_sort[6] = { 6, 0, 5, 2, 3, 1 };
	//qsort(to_sort, sizeof(to_sort) / sizeof(int), sizeof(int), comp_desc);
	//print_arr(to_sort, sizeof(to_sort) / sizeof(int));



	// 二分查找
	qsort(to_sort, sizeof(to_sort) / sizeof(int), sizeof(int), comp_asc);
	print_arr(to_sort, sizeof(to_sort) / sizeof(int));
	assert(bin_search(to_sort, sizeof(to_sort) / sizeof(int), 0) == 0);

	// 指针长度为8字节
	// 对数组取址将会得到行指针(值与数组第0个元素地址相同),行指针+1将得到下一个行指针,即第0个元素地址+数组字节数。
	int (*rp)[6] = &arr1;
	assert((long long)(rp + 1) == (long long)(&arr1[0] + 6));



	// 二维数组
	// 二维数组空间在内存中是连续的
	int r2d[3][6] = { {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6}, {6, 5, 4, 3, 2, 1} };
	print_2d_arr(r2d, sizeof(r2d) / sizeof(int[6]));
	cout << (long long)&r2d[0][0] << endl;
	cout << (long long)&r2d[2][5] << endl;
	assert((long long)&r2d[2][5] - (long long)&r2d[0][0] == (sizeof(r2d) / sizeof(int) - 1) * sizeof(int));

}


void print_2d_arr(int rp[][6], int rows)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < 6; j++)
		{
			cout << "第" << i << "行第" << j << "列:" << rp[i][j] << endl;
			// assert(rp[i][j] == j * j);
		}
	}
}

void print_arr(int arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << endl;
	}
}

int comp_asc(const void* p1, const void* p2)
{
	return *((int*)p1) - *((int*)p2);
}

int comp_desc(const void* p1, const void* p2)
{
	return *((int*)p2) - *((int*)p1);
}

int bin_search(int arr[], int len, int target)
{
	int front = 0, back = len - 1, mid = 0;
	while (front <= back)
	{
		mid = (front + back) / 2;
		if (target == arr[mid]) return mid;
		else if (target < arr[mid]) back -= mid;
		else front += mid;
	}
	return -1;
}

标签:arr,int,笔记,assert,C++,sizeof,include,指针
From: https://www.cnblogs.com/missfxy/p/17297661.html

相关文章

  • 删边最短路学习笔记
    删边最短路前言删边最短路是一种科技,用于解决一类问题:给定非负权图\(G=(V,E)\)。设\(n=|V|\),保证\(1\)可达\(n\)。设\(\Delta(e)\)为图\(G'=(V,E\setminus\{e\})\)上\(1\rightsquigarrown\)的最短路,若\(G'\)上\(1\)不可达\(n\)则为\(+\infty\)......
  • C++竞赛常用函数库stl快捷查询手册(vector,map,set,queue,string等)
    1.控制输出流<iomanip>;cout<<setprecision(<span="">int);保留int位有效数字cout<<setprecision(<span="">int)<<fixed;保留int位有效小数为不足4位数的数填充0(如1填充变成0001),cout<<setfill('0')<<setw(4)(一次性效果)......
  • 【进阶11】【自学笔记】Python _解包的操作
    一、Python解包定义Python解包是指将一个可迭代对象(如列表、元组、字典等)中的元素分别赋值给多个变量的过程。解包可以通过在变量前添加星号`*`来实现,也可以通过在变量前添加双星号`**`来实现字典解包。解包可以简化代码,使代码更加清晰易懂。二、解包实例1、最简单的解包......
  • 回调函数 C++
    回调函数(CallbackFunction)是一种常见的编程模式,它是一段可以被传递给其他函数的代码,可以在特定的条件满足时被调用执行。回调函数通常作为参数传递给其他函数,以便在某些事件发生时执行。在C++中,回调函数通常是一个指向函数的指针,它可以作为参数传递给其他函数,这些函数可以在需要......
  • C/C++模拟ATM机存取款管理系统[2023-04-07]
    C/C++模拟ATM机存取款管理系统[2023-04-07]2、模拟ATM机存取款管理系统模拟银行的自动取款机使用过程中的界面和用户交互过程。实现查询银行卡余额、取款修改密码、退出系统等功能。(一)功能要求及说明:(1)将银行账户的卡号,户名,密码和账户余额从外部文件(银行账户.txt)中读入......
  • 强化学习笔记
    1.1.简介强化学习(reinforcementlearning)是机器学习的一个重要分支,其具有两个重要的基本元素:状态和动作。类似于编译原理中的自动机,或数据结构中的AOE图,强化学习研究的就是怎样找到一种最好的路径,使得不同状态之间通过执行相应动作后转换,最终到达目标状态。先介绍几个名词:状态......
  • 1+X-网络系统建设与运维(中级)理论笔记
    1+X-网络系统建设与运维(中级)链路聚合技术原理与配置基本原理 提升链路带宽:设备之间存在多条链路时,由于STP的存在,实际只会有一条链路转发流量,设备间链路带宽无法得到提升手工模式 Eth-Trunk的建立、成员接口的加入均由手动配置,双方系统之间不使用LACP进行协商LACP模式 采用LACP协......
  • 软件杯大赛-A5-学习笔记-Kubernetes
    一、kubernetes1.基础知识1.1硬件1.1.1节点(Node)节点是kubernetes中最小的计算硬件单元。是集群中单个机器的表示。可以对节点进行抽象的理解,即简单的将每台机器看作一组可以使用的CPU和RAM资源。这样,任何机器都可以替代Kubernetes集群中的任何其他机器。1.1.2集群集群......
  • salesforce学习笔记(3-1)- JavaScript Promise(LWC)
    在JS代码中,Promise到底有什么作用?首先,我们知道的是,Javascript是单线程的,什么意思呢?就是说JS在同一时间只能做一个操作,代码的执行是一行一行进行的:  这种执行方式带来的问题就是在我们打开某个画面的时候,画面可能会卡住转圈、加载中状态很久,用户体验感很差。Promise可用于......
  • LateX学习笔记
    什么是LateXLateX是一种高质量的排版系统,它包含了为制作技术和科学文档而设计的功能。LateX是科学文档的交流和出版的事实标准。编译器在线编译器https://www.overleaf.com/提示你怎么写的网站https://editor.codecogs.com/怎么在typroa中引入敲击两个$$,然后回车输......