【漫漫转码路】Day 37 C++ day08

//例如
#define ABS(a) (a>0 ? a : a*-1)  //如果写成#define ABS(a) (a>0 ? a : -a)会报错,--缺少左值,因为--3.14无法无法被编译
int main()
{
	float a = ABS(-3.14);
	cout << a;
}
//显示
3.14

宏的应用

//按照WIN32的方式编译
//如果在WIN32下,打开FILE "D:\\"
//否则打开FILE "/user/.../doc/"
#define WIN32
#ifdef WIn32
#define FILE "D:\\"
#elif
#define FILE "/user/.../doc/"
#endif

常用标准宏

__LINE__:输出当前所处的行数
__FILE__:文件名
__DATE__:编译时候的日期
__TIME__:编译时候的时间
__FUNCTION__:当前所处的函数

//例如
void c()
{
	cout << "当前函数" << __FUNCTION__ << "\n";
}
int main()
{
	cout << "当前行" << __LINE__ << "\n";
	cout << "当前文件" << __FILE__ << "\n";
	cout << "当前日期" << __DATE__ << "\n";
	cout << "当前时间" << __TIME__ << "\n";
	c();
}
//显示
当前行18
当前文件D:\MySoftware\Visual Studio\class\ConsoleApplication2\ConsoleApplication2.cpp
当前日期Dec  8 2022
当前时间11:11:04
当前函数c

函数重命名

typedef int myint;  //给Int重命名为myint,后续可以直接使用myint,当做int来用

函数和结构体都可以用
方便跨平台通用

函数指针

//例如
#define ABS(a) (a>0 ? a : a*-1)
typedef int (*func) (int a, int b);  //函数指针,int是返回类型,*func是函数名称,不要去括号
int add(int a, int b)  //有一个函数add
{
	int c = a + b;
	return c;
}
int main()
{
	func(fadd) = add;  //这样可以直接使用fadd,像add一样
	int d = fadd(1, 3);
	cout << d;
}

用于回调函数

全局变量

放在最前面,然后后面使用的时候在前面加::,就可以,函数里面也可以用

//例如
int globalnum = 1;  //作为全局变量
int main()
{
	::globalnum++;  //使用
	for (int i = 0;i < 5;i++)
	{
		::globalnum++;  //循环内使用
	}
	cout << globalnum;  
}
//显示
7

memcpy / memset

memset

void *memset(void *s,int c,unsigned long n);
为指针变量s所指的 前n个字节,填充指定的int类型数值c,它可以为任何数值进行初始化;
就是,将
数值c以单个字节逐个拷贝的方式放到指针变量s所指的内存中去,
对结构体

//例如
struct student
{
	char name[12];
	int age;
	float num;
};
int main()
{
	student *s1 = new student();
	memset(s1, 2, sizeof(s1));
	cout << s1->name << " " << s1->age<<" " << s1->num;
}
//显示
 0 0  //可以做到初始化,只不过name是字符,在转换过程中会乱码

对数组

//例如
int main()
{
	int a[20];
	memset(a, 0, sizeof(a));  //如果将0换成其他数字,也可以填充,但是由于内存的排布,会显示成其他数字,这里不做赘述
	for (int i = 0;i < 20;i++)
	{
		cout << a[i]<<"\n";
	}

0换成1,显示不会填充1
如果将0换成1,会显示16843009
因为memset是内存填充
一个数字四个字节
数字以16进制的形式存储,如果填充1,会将1逐个填充到b的80个字节内存中去,一个数字占4个字节,所以这个16进制就成了0x01010101,这个再转换成10进制就是16843009

//显示
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

memcpy

void *memcpy(void *dest, const void *src, size_t n);
源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
const void *src:原地址
void *dest:要拷贝到的地址
size_t n:字节长度
内存整块拷贝

//例如
	int a = 1;
	int b;
	memcpy(&b, &a, sizeof(a));
	cout << b << "\n";
	
	int c[10];
	int d[15];
	memset(c, 0, sizeof(c));
	memcpy(d, c, sizeof(c));
	for (int i = 0;i < 15;i++)
	{
		cout << d[i] << "\n";
	}
//显示
1
0
0
0
0
0
0
0
0
0
0
-858993460
-858993460
-858993460
-858993460
-858993460

strcpy和memcpy主要有以下3方面的区别:
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。

enum

枚举
定义枚举空间之后,相关变量只能从枚举空间里面取值
枚举空间中的变量没有赋值的话,则默认从0开始,依次递增
枚举空间的值只能赋整型
if语句中变量不受枚举空间限制

//例如
enum studytype
{
	A,  //用逗号结尾
	B,
	C = 2,
	D = 3,
};
int main()
{
	cout << A<<" " << B << " " << C << " " << D << "\n";
	studytype a = A;
	studytype b = A;
	a = D;
	//a = 2;  //枚举的限制值只能是整型,但是整型不会自动转换为枚举类型,因此会报错
	cout << a;
	cout << int(a) + int(b); //转换成整型做加法
	if (a == 10000);
	{
		cout << "执行";
	}
//显示
0 1 2 3
33执行

***应用:***做编译器检查,防止赋奇怪的值
枚举变量不能直接做加法,但是可以转换成整型之后做加法

位运算

C++支持按位运算
并且运算规则和python的运算规则一致
&按位与
|按位或
~按位取反

数学库

导入

#include <math.h>

常用数学公式

//例如
int main()
{
	int a = 2;
	float b;
	b = sqrt(a);  //开平方
	cout << a << "\n";
	cout << pow(2,3) << "\n";  // 2的3次方
	cout << time(0) << "\n";  //返回当前格林尼治标准时间与格林尼治标准时间1970年0分0秒的时间间隔
}
//显示
2
8
1670507285

随机数

srand():随机数生成器
由随机种子根据一定的计算方法计算出来的数值。所以,只要计算方法一定,随机种子一定,那么产生的随机数就不会变。
在相同的平台环境下,编译生成exe后,每次运行它,显示的随机数都是一样的。这是因为在相同的编译平台环境下,由随机种子生成随机数的计算方法都是一样的,再加上随机种子一样,所以产生的随机数就是一样的。
因此通常,将time(0)扔进去,因为time(0)每时每刻都在发生变化
如果里面的整数固定,则相同变量得到的随机数是固定的

//例如
int main()
{
	srand(3);
	int c = rand();
	int d = rand();
	cout << c << "\n";
	cout << d << "\n";
}
//显示
48  //无论运行多少次,c都是48,如果换成e结果就不一样了
7196

因此通常和time来配个使用获得随机整数
rand获得的最大整数是0x7fff
因此,如果想要获得小数
需要做进一步的转换

//例如
int main()
{
	srand(3);
	int c = rand();
	int d = rand();
	cout << c << "\n";
	cout << d << "\n";
	float e = (c % 0x7fff) / (float)0x7fff;
	cout << e << "\n";
}
//显示
48
7196
0.00146489  //产生0到1的随机小数

命名空间

//例如
namespace KK
{
	int add(int a, int b)
	{
		return a + b;
	}
};
int main()
{
	int x = KK::add(1,3)  //使用KK命名空间下的add函数
	//如果不想每次写KK::,也可以在开头写using namespace KK
}

跟前面导入using namespace std一个道理
命名空间可以导入多个,也可以使用多个
如果两个命名空间里面的函数一样,在调用的时候会报错,因为不知道调用哪个
这时候就需要写明哪个空间的东西

头文件

1、在头文件里写入结构体,并且在项目文件中用#include"地址+名称"导入
则可以直接在int main()中使用结构体;
2、因此数学库,string,等等都是被写在头文件中的,导入之后可以直接用
3、将函数定义放在头文件中,导入头文件后,也可以直接使用函数;
4、将函数声明放在头文件中,将函数内容放在源文件中另一个cpp文件夹这种,也可以在int main()所在的cpp文件直接使用函数,是因为整个项目下的.cpp文件都会被编译,所以不会报错
5、所有的cpp文件只能有一个函数,结构体实体,如果重复,则会报错,但是可以写在不同的命名空间下
6、为了防止重复编译报错,就可以用到

#ifndef 函数名  //如果没有编译过,则进行编译,如果编译过了,则不编译
#define 函数体
#endif

7、导入的时候,<>表示先在系统库中找.h文件,如果是" ",则会先在项目目录下找该文件,如果找不到,再去系统库找

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值