C++ primer plus (第6版)里的技术点(1)

本文概要介绍了C++编程的基础知识,包括结构初始化、枚举取值范围、指针与数组的区别、数组的地址、复合语句特性、字符函数库、函数和二维数组的应用、临时变量与引用参数、函数的默认参数、模板函数及其具体化、关键字decltype、说明符和限定符、链接性、定位new运算符等核心概念与技术。文章还涵盖了C++编程的高级技术,如模板函数的具体化与实例化、关键字decltype在C++11中的应用、说明符与限定符的使用、链接性概念以及定位new运算符的实践。

1, 结构的初始化:


struct fish
{
	int type;
	double weight;
	double length;
};

typedef struct {
	int type;
	double w;
	double h;
} cat;


int main(int argc, std::string argv[])
{
	fish f = { 1, 8.0, 10.0 };
	cat c = { 1, 10, 20 };
	exit(0);
}

2, 枚举的取值范围(CPP 97):


书上说的取值范围是: 先找到枚举量的最大值(如8), 再找到大于这个最大值的, 最小2的幂, 将它减去1(2^4-1 = 15), 这样就得到了取值范围的上限.

但是, 在G++和VS2012下测试, 无论是什么值(int的取值范围), 都是行的通的.

enum test_e {
	TYPE1 = 0,
	TYPE2 = 1, 
	TYPE3 = 2, 
	TYPE4 = 4
};


int main(int argc, std::string argv[])
{
	test_e e = (test_e)-800000;
	std::cout<<e<<std::endl;
	std::cin.get();
	exit(0);
}


3, 指针与数组(CPP 108):


它们两个的区别之一是, 可以修改指针的值, 但数组名是常量.

下面是错误的用法:

	int arr[10] = {0};
	int * p = arr;

	p += 3;
	arr += 3;

另一个区别是, 对数组应用sizeof运算符得到的是数组的长度, 而指针应用sizeof得到的是指针的长度, 即使指针指向的是一个数组.


4, 数组的地址(CPP 109):


数组名被解释为其第一个元素的地址, 而对数组名应用地址运算符时, 得到是整个数组的地址.

	short tell[10];
	std::cout<<tell<<std::endl;
	std::cout<<&tell<<std::endl;

	short (*pas)[10] = &tell;
从数字上说, 这两个地址相同;但从概念上说, &tell(即tell)是一个2字节内存块的地址, 而&tell是一个20字节内存块的地址.因此, 表达式tell + 1将地址值加2, 而表达式&tell + 1将地址加20.(书上的印刷错误多的离谱).换句话说, tell是一个short指针(* short), 而&tell是一个指向包含10个元素的short数组的指针(short(*)[10]).

声明这样一个指针如上, 如果省略括号, 优先级规则将使得pas先与[10]结合, 导致pas是一个short指针数组, 它包含10个元素, 因此括号是必不可少的.因此, pas的类型为short(*)[10].另外, 由于pas被置为&tell, 因此*pas与tell等价, 所以(*pas)[0]为tell数组的第一个元素.


这里详细描述一下strncpy和strncat 这两个函数(个人说明部分):

	char buf[10] = {0};
	strncpy(buf, "1234567890", sizeof(buf) - 5);
	std::cout<<buf<<std::endl;
	strncat(buf, "1234567890", sizeof(buf) - strlen(buf) - 1);
	std::cout<<buf<<std::endl;
输出为:

12345

123451234


以上strncpy的调用, 只是将第二个参数中的n(sizeof(buf) - 5)字符copy到buf, 而strncat的调用是将第二个参数的n(这里是buf的剩余空间)个字符加到buf中.


5, C++中复合语句的一条有趣的特性(CPP 137):


如果在语句块中定义一个新的变量, 则仅当程序执行该语句块中的语句时, 该变量在才在, 执行完该语句块后, 变量将被释放.

注意: 这条规则适用于复合语句, 并非是for循环的专属.


6, 字符函数库(CPP 177):


这个没什么重点, 只是如果平常如果需要的时候可以看一下, 而不用过多的编写已有的函数.

	std::isalnum(c);			//参数是否是字母或数字
	std::isalpha(c);			//参数是否是字母
	std::iscntrl(c);			//是否是控制符
	std::isdigit(c);				//是否是数字(0-9)
	std::isgraph(c);			//是否是除空格之外的打印字符
	std::islower(c);			//是否是小写字母
	std::isprint(c);			//是否是打印字符(包括空格)
	std::ispunct(c);			//是否是标点符号
	std::isspace(c);			//是否是空白字符, 如空格, 回车, 制表符, 换行符等.
	std::isupper(c);			//是否是大写字母
	std::isxdigit(c);			//是否是16进制数 (1-9, abcdef)
	std::tolower(c);			//如果c是大写, 则转成小写, 否则返回c
	std::toupper(c);			//如果c是小写, 则转成大写, 否则返回c

7, 函数和二维数组(CPP 224):


int sum(int (*ar2)[4], int size)
{
	int sum = 0;
	for (int i = 0; i < size; i++)
		for (int j = 0; j < 4; j++)
			sum += ar2[i][j];
	return sum;
}

int main(int argc, std::string argv[])
{
	int data[3][4] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
	std::cout<<sum(data, 3)<<std::endl;

	int (*pas)[4] = data;

	std::cout<<**pas<<std::endl;

	std::cin.get();
	exit(0);
}



pas 等同于data

pas + 1等同于data + 1, pas为行首地址, pas + 1为第二行首地址, 表示整行

*(pas + 1)为元素地址, 为第二行第一个元素的地址.

**(pas + 1)为元素地址的值, 为第二行第一个元素的地址所存储的值.

*(*(pas + 2) + 2)为元素地址的值 , 为第三行第三个元素的地址所存储的值.


注意sum函数的签名, 不能定义为int **ar2, 

**ar2表示一个int类型指针的指针, 即int * 的指针,  它还可以表示为指针数组, 如 int * p[10] 可以于 int **pa的形参匹配.

而int (*ar2)[4]表示一个ar2是一个指向一个4个int类型的数组的指针.

二维数组指针一定要给出第二维的宽度值.

而二维数组的指针也一定要给出表示二维数组第二维的宽度下标. 


注意: 传递二维数组的数组名不能使用二级指针来接收他们, 类型是不匹配的.


8, 临时变量, 引用参数和const(CPP 262):

如果实参与引用参数不匹配, C++将生成临时变量.仅当数为const引用, C++才允许这样做.


什么时候将创建临时变量呢?如果引用参数是const, 则编译器将在下面两种情况下生成临时变量:

 1) 实参的类型正确, 但不是左值.

 2) 实参的类型不正确, 但可以转换为正确的类型.


这里主要注意一下左值的概念, 左值是可以被赋值的变量.


9, 函数的默认参数(CPP 275): 

只有原型指定默认值. 函数定义与没有默认参数时完全相同.

就是说在声明函数的时候给定默认值, 在定义的时候不要加了, 否则编译会出错.


10, 模板函数, 常规模板, 具体化模板和实例化模板.

这里主要是要注意一下语法, 具体化模板是要给定针对某种类型的定义, 而实例化模板只是将实际类型的代入到函数声明中而以, 并不用重新给出定义.

#include <iostream>

//常规模板 1#
template <typename T>
void Fun(T a)
{
	std::cout<<a + 1<<std::endl;
}

//实例化 2#
template 
void Fun<int>(int a);

//实例化 3#
template
void Fun(long a);

//具体化 4#
template<>
void Fun(char c)
{
	std::cout<<"Fun (char c)"<<std::endl;
}

//具体化 5#
template<>
void Fun<double>(double c)
{
	std::cout<<"Fun (double)"<<std::endl;
}


int main(int argc, std::string argv[])
{
	Fun(10L);			//3#
	Fun(10);			//2#
	Fun(14.1F);		//1#
	Fun(18.0);			//5#	
	Fun('F');				//6#
	std::cin.get();
	exit(0);
}

在调用时, 也可以显示调用 

Fun<int>('F');

这样的话将调用2#函数

 编译器在调用时如果发现无法确定调用哪一个函数时, 将出现编译错误.


11, 关键字decltype(C++11)(CPP 295)


这是一个可以推断出的类型.

template<class T1, class T2>
auto Fun(T1 t1, T2 t2) -> decltype(t1 + t2)
{
	decltype(t1 + t2) t3;
	return t3;
}
只有C++11.才支持这种语法.


12, 说明符和限定符(CPP 317):


说明符:

auto 自动类型推断.

register 在现有的系统中, 以不在有效, 是否是用寄存器, 由操作系统决定.

extern 表明引用声明, 表示所引用的变量或是函数在其他地方文件中定义.

thread_local C++11指出变量的持续性与其所属线程的持续性相同.

mutable 该说明指出, 即使结构或类的对象声明为常对象, 但用mutable修饰过的变量, 也可以修改.


限定符:

const  常量

volatile 尽止编译器优化的变量


13, 链接性

链接性有 外部链接 即全局变量或函数. 在头文件中声明的对象(如果是在源文件中声明或定义的, 在其他文件中需要用extern声明引用一下)

内链接性 只有声明定义变量或函数的文件才能使用. 在文件中级经过static所修饰的对象.

无链接性 只有声明的域中才能使用, 无链接性只是用来指定变量. 在函数级中经过static修饰的对象

在全局范围的变量将会被初化始为默认值.而局部变量不会.


14, 定位new运算符(CPP 321):


使用new的定位操作方式, 不一定需要手动调用delete来释放, 因为定位的new操作可以分配到动态内存区也可能只是全局静态内存区, 

想要定位需要事先定义一块有内存, 而该内存的作用域必需有效, 否则将出现预期以外的事情.

#include <iostream>

char buffer[1024];

int main(int argc, std::string argv[])
{
	int * p1 = new(buffer) int[10];
	int * p2 = new(buffer + sizeof(int) * 10) int[20];

	std::cout<<(int)&buffer<<std::endl;
	std::cout<<(int)p1<<std::endl;
	std::cout<<(int)p2<<std::endl;

	std::cin.get();
	exit(0);
}
源码地址: https://pan.quark.cn/s/3916362e5d0a 在C#编程平台下,构建一个曲线编辑器是一项融合了图形用户界面(GUI)构建、数据管理及数学运算的应用开发任务。 接下来将系统性地介绍这个曲线编辑器开发过程中的核心知识点:1. **定制曲线面板展示数据曲线**: - 控件选用:在C#的Windows Forms或WPF框架中,有多种控件可用于曲线呈现,例如PictureBox或用户自定义的UserControl。 通过处理重绘事件,借助Graphics对象执行绘图动作,如运用DrawCurve方法。 - 数据图形化:通过线性或贝塞尔曲线连接数据点,以呈现数据演变态势。 这要求掌握直线与曲线的数学描述,例如两点间的直线公式、三次贝塞尔曲线等。 - 坐标系统与缩放比例:构建X轴和Y轴,设定坐标标记,并开发缩放功能,使用户可察看不同区间内的数据。 2. **在时间轴上配置多个关键帧数据**: - 时间轴构建:开发一个时间轴组件,显示时间单位刻度,并允许用户在特定时间点设置关键帧。 时间可表现为连续形式或离散形式,关键帧对应于时间轴上的标识。 - 关键帧维护:利用数据结构(例如List或Dictionary)保存关键帧,涵盖时间戳和关联值。 需考虑关键帧的添加、移除及调整位置功能。 3. **调整关键帧数据,通过插值方法获得曲线**: - 插值方法:依据关键帧信息,选用插值方法(如线性插值、样条插值,特别是Catmull-Rom样条)生成平滑曲线。 这涉及数学运算,确保曲线在关键帧之间无缝衔接。 - 即时反馈:在编辑关键帧时,即时刷新曲线显示,优化用户体验。 4. **曲线数据的输出**: - 文件类型:挑选适宜的文件格式存储数据,例如XML、JSON或...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值