C++小点总结(一)

C++小点总结(一)

说明

C++之所以难学,主要是其标准和知识点比较繁杂;之前的C++学习偏向理论,本专栏将以每20个小问题为一篇文章,主要记录实战中遇到的问题,难易程度不同,可根据标题参考;

1、文件名后缀的作用?

一般项目中会包含多个.cpp(源文件)和.h(头文件);

那有一些后缀为.c .cc .cxx的文件是怎么来的呢?

答:是由于不同的编译器导致的,一般在GNU编译器下会有这些后缀;

.hpp后缀的作用是什么呢?

答:实际上是.h和.cpp文件二合一,用来减少整个项目的编译过程;

2、C++11后的一种大括号初始化?

在变量后接大括号可实现初始化:

int a{16};
int a[] {1,2 3, 4, 5};	// 中间的等号可省略

3、头文件防卫式声明是什么?

是为了防止头文件重复引用造成的重定义现象;

具体做法:在每个头文件中加入条件编译(不同头文件中标识符设置应当不同)

#ifndef __head1__
#define __head1__

// 代码段

#endif

4、引用需要怎么理解?

本质:引用就是别名的意思,起到一个标识符的作用;

一些注意点:

  • 定义引用并不额外占用内存,可以理解成引用和原变量占用同一块内存;

  • 定义引用的时候必须初始化,并且不能绑定常量;

5、在Visual Studio中查看变量快捷键?

在Debug模式下,使用shift+F9可以查看变脸给的值,包括地址;

6、cout刷新缓冲区的情况?

刷新缓冲区的意思就是往终端上打印;

① 缓冲区满了;

② 程序执行到main的return语句;

③ 调用std::endl强制刷新缓冲区;

④ 系统不繁忙的时候,也会查看缓冲区内容,正常输出到终端;

7、范围for语句的使用技巧?

首先看一下正常的使用:

int x[]{1, 2, 3, 4};
for (auto v:x)
{
	cout << v <<endl;
}

其实上述代码有一个可优化的点,上述中其实执行了拷贝构造,将x的值赋值给了v,可修改为:

 for (auto &v:x)
{
	cout << v << endl;
}

采用引用别名的形式,去除拷贝的过程,提高系统效率;

8、C++内存分布?

可以简单理解成五个区域:

1、栈:函数内部的局部变量放置的区域,由编译器自动分配和释放;

2、堆:程序员malloc、new分配,再用free、delete释放;(忘记释放,程序结束后系统回收)

3、全局/静态存储区:全局变量和静态变量static,程序结束时系统释放;

4、常量存储区;

5、程序代码区;

9、malloc的使用?

首先需要说明一点,malloc是c中遗留下来的,在C++中建议使用new和delete替代malloc和free;

函数原型:

void *malloc(int NumBytes);		// NumBytes表示要分配的字节数

返回值:成功则返回指向被分配内存的指针,失败返回NULL;

使用的话也需要定义一个指针来接收:

// 分配int*的内存
int *p = NULL;
p = (int *)malloc(sizeof(int));
if (p != NULL)
{
	*p = 5;
}

// 分配char*的内存
char *p = NULL;
p = (char *)malloc(100 * sizeof(char));
if (p != NULL)
{
    strcpy_s(p, 10, "hello");	// 中间的数代表分配的大小,小于传入字符串大小则会报错
}

下面看一个简单指针的使用:

int *p = (int *)malloc(sizeof(int) * 100);	// 分配100个整形空间大小的内存空间
if (p != NULL)
{
	int *q = p;	// 目前的p值表示内存的首地址
	*q++ = 1;	// 由于++和*优先级相同(右结合),这里理解成*(q++),也就是q赋值为1,然后向后移动一个整数字节位数
	*q++ = 2;
	cout << *p << endl;		// 1
	cout << *(p+1) << endl;		// 2
}

需要对这段代码足够的理解,C++的底层都是指针操作,包括引用也是指针的操作;

10、new和delete的使用?

首先说明一下和malloc的区别,相比malloc和free做了更多的初始化工作;

一般使用形式有如下三种:

① 指针变量名 = new 类型标识符;

② 指针变量名 = new 类型标识符(初始值);

③ 指针变量名 = new 类型标识符[内存单元个数];

// 方法一
int *p = new int;
if (p != NULL)
{
	*p = 16;
	cout << *p << endl;
	delete p;
}

// 方法二
int *p = new int(16);

// 方法三
int *p = new int[100];	// 开辟了大小为100的整形数组空间
if (p != NULL)
{
	int *q = p;	
	*q++ = 1;
	*q++ = 2;
    delete[] p;		// 注意释放的时候也需要加入[]
}

11、NULL和nullptr二者有区别吗?

实际上nullptr是用来防止整型和指针类型的混乱,但二者通过if判断是相等的;

int *p = NULL;
int *q = nullptr;
if(p == q){}		// 二者比较是相等的

// 打印二者的类型又是不等的
cout << typeid(NULL).name() << endl;		// int
cout << typeid(nullptr).name() << endl;		// std::nullptr_t

12、private主要用处?

作用:从实际代码来看,一般用来将函数变量设置为私有的,这些变量仅供内部成员函数访问;

13、C++中类和结构有什么区别?

首先要说明,在C++中最好使用类,毕竟是C++后引入的;

不同点在于:类中成员函数和成员变量默认访问级别是private,结构中默认访问级别是pubilc;

14、后置返回类型函数?

在刷Leetcode题目时往往会看到返回类型在参数列表之后,实际上这种写法是可以的,在此记录一下:

auto fun(int a) -> void;

只需要理解即可,一般不是使用;

15、内联函数的作用?

在函数前加关键字inline,使该函数变为内联函数;

解决问题:函数体小,调用却很频繁的这种函数(频繁调用会压栈出栈,消耗内存且效率低);

作用:

① inline可以影响编译器,在编译阶段对inline这种函数进行处理,尝试将调用函数的动作替换为函数本体;

② inline只是开发者对编译器的建议,是否替换由编译器决定(决定权在编译器)

③ 内联函数的定义(本体)就需要写在头文件中;(include才能把源代码尝试替换进来)

④ constexpr函数可以看作是一个严格的内联函数;

缺点:可能带来代码膨胀的问题,所以函数体尽量小;

16、函数的一些杂合用法?

① 函数返回类型为void,表示函数不返回任何类型;可以返回一个返回类型是void的函数;

void funca(){}
void funcb()
{
	return funca();
}

② 函数返回值为指针

int *func()
{
	int tmp = 16;
	return &tmp;
}

上面函数返回一个局部变量的地址是不正确的,在调用完函数后,局部变量已经被系统回收,此时返回的地址不是可操控的地址,可能引发问题;

③ 函数没有形参可以保持形参列表为空(),或者为(void);

④ 如果一个函数我们不调用的话,则函数可以只有声明没有定义;

⑤ 普通函数,定义只能定义一次(放在.cpp文件中),声明可以声明多次;

⑥ 在C++的函数参数中,建议多使用引用的形式,能减少拷贝构造,提高效率;

17、初始化时const和指针组合的一些区别?

思考一下一下三种写法有什么区别?

char str[] = "hello";
# 写法一
const char* p = str;
# 写法二
char const *p = str;
# 写法三
char * const p = str;
p++;	// 错误的写法

上面三种写法中,第一第二种写法作用是相同的,都是不能修改p指向目标的内容,但可以修改p的指向;

第三种写法是指针的指向不能改变,指针指向的目标的内容可以修改;

18、函数形参中带const的作用?

作用:不允许修改形参的值,一般能加的都要加上;

好处:

① 可以防止无意间修改形参的值导致实参被修改;

② 实参类型更加灵活;(主要是支持的类型更多了)

19、string的几种初始化方式?

string作为C++标准库的类型,是我们最常用的一种类类型之一;

初始化方式有以下几种:

#include<string>
using namespace std;

string s;	//  默认初始化, s = ""空串,表示没有字符;
string s1 = "Hello World!";		// 把字符串拷贝到s1这一段内存中,不包括末尾的\0;
string s2("Hello World");		// 与s1的效果一致;
string s3 = s1;					// 把s1中的内容拷贝到s3代表的一段内存中;

int num = 10;
string s4(num,  's');	// ssssssssss,10个s组成的字符串,并不常用;

20、string的常见方法

主要有以下一些常见方法:

string s1;
// 判空
s1.empty()			
// 返回字节/字符数量,代表字符串的长度
s1.size();	s1.length();		
// 索引,类似数组
s1[n];					
// 返回字符串s1中的内容指针,以\0结尾,实际上是为了兼容C语言,将string对象转为C语言中的样式
const char *p = s1.c_str();
char s1[] = "hello";	// 这是C语言遗留下来的字符数组定义
// 范围for处理string对象
for(auto &a : s1)
{
    a = 'i';	// 将所有字符改为i,直接改变传入数据
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C++中的最小二乘法可以用来拟合2D圆。以下是一个简单的实现。 首先,定义一个Circle结构体来存储拟合出的圆的信息: ``` struct Circle { double x; double y; double r; }; ``` 然后,定义一个函数来执行最小二乘法拟合: ``` Circle fitCircle(vector<Point2d>& points) { int n = points.size(); double sum_x = 0.0, sum_y = 0.0, sum_x2 = 0.0, sum_y2 = 0.0, sum_xy = 0.0, sum_r2 = 0.0; for (int i = 0; i < n; i++) { Point2d p = points[i]; double x = p.x; double y = p.y; sum_x += x; sum_y += y; sum_x2 += x * x; sum_y2 += y * y; sum_xy += x * y; sum_r2 += x * x + y * y; } double A = n * sum_x2 - sum_x * sum_x; double B = n * sum_xy - sum_x * sum_y; double C = n * sum_y2 - sum_y * sum_y; double D = 0.5 * (n * sum_r2 - sum_x * sum_x - sum_y * sum_y); double a = (D * sum_y - B * sum_xy) / (A * C - B * B); double b = (D * sum_x - A * sum_xy) / (B * B - A * C); double r = sqrt(a * a + b * b + D / n); Circle circle = {a, b, r}; return circle; } ``` 最后,可以在程序中使用这个函数来拟合圆: ``` vector<Point2d> points; // 添加2D点到points中 Circle circle = fitCircle(points); cout << "Center: (" << circle.x << ", " << circle.y << ")" << endl; cout << "Radius: " << circle.r << endl; ``` 需要注意的是,这个实现并不是最优解,因为它没有考虑到噪声和异常值。真实的应用中,可能需要对数据进行预处理和滤波来提高拟合的准确性。 ### 回答2: 最小二乘法是一种常用的曲线拟合方法,可以通过找到最小化残差平方和的参数来拟合数据。 要拟合2D圆,我们需要知道圆的方程。一个标准的2D圆的方程可以表示为:(x - a)² + (y - b)² = r²,其中(a, b)是圆心的坐标,r是半径。 假设我们有一组数据点(x₁, y₁), (x₂, y₂), ..., (xₙ, yₙ),我们的目标是找到最小二乘法拟合的圆。 我们可以将圆的方程展开为:x² - 2ax + a² + y² - 2by + b² - r² = 0。我们可以用这个方程来构建一个线性方程组,然后利用最小二乘法求解。 首先,我们将方程重新排列为:x² + y² + ax + by - a² - b² = r²。然后我们用参数c₁ = a, c₂ = b, c₃ = -a² - b²来代替a、b、r²,我们的方程就变成了:x² + y² + c₁x + c₂y = c₃。 然后我们可以将每个数据点(xᵢ, yᵢ)代入这个方程,并整理成类似于y = mx + c的形式:yᵢ = -(xᵢ² + c₁xᵢ + c₃) / c₂。 然后我们可以构建一个线性方程组,其中每个方程都是:yᵢ = m₀xᵢ + n₀。将所有的数据点代入这些方程,我们可以得到由m₀和n₀构成的方程组。 最后,我们可以通过求解这个线性方程组来得到参数m₀和n₀,然后我们可以反推回到参数a、b、r²。 总结来说,通过最小二乘法,我们可以将2D圆的拟合问题转化为一个线性方程组的求解问题,然后通过求解这个方程组得到圆的参数。 ### 回答3: 最小二乘法是一种常用的曲线拟合方法,可以用于拟合2D圆。拟合2D圆的目标是寻找一个最优的圆心坐标和半径,使得样本点到这个圆的距离的平方和最小。 设圆心坐标为(a,b),半径为r,样本点的坐标为(xi,yi)。最小二乘法的目标是最小化误差函数E的值: E = Σ[(xi-a)^2 + (yi-b)^2 - r^2]^2 为了找到最小二乘法的解,可以对E分别对a、b和r求偏导,令偏导为0,得到联立方程组: ∂E/∂a = -4Σ[(xi-a)^2 + (yi-b)^2 - r^2](xi - a) = 0 ∂E/∂b = -4Σ[(xi-a)^2 + (yi-b)^2 - r^2](yi - b) = 0 ∂E/∂r = -4Σ[(xi-a)^2 + (yi-b)^2 - r^2]r = 0 解这个方程组,可以得到最优的圆心坐标a和b,以及半径r。 最小二乘法拟合2D圆的过程可以通过迭代算法实现。初始时可以选择任意的圆心坐标和半径作为初始值,然后代入联立方程组,求解新的圆心坐标和半径,再代入方程组,直到收敛。 最后,通过这种最小二乘法拟合的2D圆,可以用于估计圆的位置和大小,从而可以在实际应用中进行圆的检测、跟踪和测量等操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值