类型互相转换

1. string 和 double 互相转换并保留小数

1
2
3
4
5
6
7
8
//doule转string 
string str1 = to_string(3.14);
//int转string
string str2 = to_string(4);
//string转int
int x= atoi(str2.c_str());
//string转double
double y = stof(str1.c_str());

使用模版保留小数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<typename T>
string ToString(T val) //doule转string
{
stringstream ss;
ss << setiosflags(ios::fixed) << setprecision(2) << val; //保留两位小数
string str = ss.str();
return str;
}

template<typename T>
T ToDouble(string input) //string转double
{
T result;
stringstream ss;
ss << input;
ss >>result;
result = round(result * 100) / 100; //四舍五入保留两位小数
return result;
}

查看更多

类型转换

C++ 类型转换

c++ 类型转换包括隐式类型转换和显式类型转换

一、隐式类型转换

自动执行,无需显式的操作符。比如函数参数到形参的类型转换、函数返回值类型的自动转换等等

1. 数值类型转换

小类型转成大类型不会有问题。比如从小整数类型(char、short)转换到 int,或者从 float 转换到 double,这种“提升型”的转换不会造成有任何问题。但是有些大类型转成小类型就会有可能出现问题。

  • 负数转换为无符号类型,会使数值表示的意义发生改变。通常会采用二进制补码表示(编译器不警告有符号和无符号整数类型之间的隐式转换)

查看更多

获取环境变量值

获取环境变量

使用 std::getenv 访问

getenv 是在 C 标准库中实现的符合 POSIX 标准的函数。要求参数字符串不能用小写字母

1
2
3
4
5
6
7
8
const char* tmp = std::getenv("HOME_HELLO");
if (tmp == nullptr) {
std::cout << "no found ENV: HOME_HELLO" << std::endl;
return -1;
} else {
std::cout << "ENV: HOME_HELLO: " << tmp << std::endl;
return 0;
}

环境变量在必要的时候要检查它的正确性。他有可能会攻击我们的程序。

查看更多

undefined

1. 向文件中写入浮点数的格式

1
2
3
4
5
6
double pi = 3.14;
std::cout << std::setw(20) << std::setfill('0') << std::setiosflags(std::ios::fixed) << std::setprecision(6) << pi << std::endl;

setw(n): 控制域宽为 n 个字符,默认用资格补齐
setfill(ch): 设置 setw 缺少的字符
setiosflags(ios::fixed) 与 setprecision(n): 一起控制小数点后有几位

2. 字符串分割方法

  1. 使用 strtock 函数进行字符串分割

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char *strtok(char *str, const char *delim);
    strtok 函数线程不安全,可以使用 strtok_r 替代

    void strtok_test() {
    char s[] = "Golden global View,disk * desk";
    const char* delim = " ,*";
    char* p;
    p = strtok(s, delim);
    while (p) {
    printf("%s\n", p);
    p = strtok(NULL, delim);
    }
    }

查看更多

undefined

问题记录

  1. C ++标准说:

可以转移到块中,但不能以初始化绕过声明的方式转移。从具有自动存储持续时间的局部变量不在范围内的点跳转到其处于范围内的点的程序是错误的,除非该变量具有POD类型(3.9)且声明时没有初始化程序。

1
2
3
4
5
6
7
8
switch(k) 
{
    case1:
    int t = 4;  
  break;    
  default:
  break;
}

查看更多

undefined

1. string

string 是模版 basic_string 对于char 类型的特化,可以认为是一个只存放字符 char 类型数据的容器。string 一般并不被认为是一个C++的容器,但是和容器有很多共同点

1
2
3
4
对于对外暴露的接口,一般不建议在接口中使用 const string&,除非确知调用者已经持有 string,如果函数里不对字符串做复杂处理的话,使用 const char* 可以避免在调用者只有 C 字符串时编译器自动构造 string,这种额外的构造和析构代码并不低。如果实现较为复杂、希望使用 string 的成员函数的话,那应该考虑下面的策略:
1. 如果如果不修改字符串的内容,使用 const string& 或 C++17 的 string_view 作为参数类型。后者是最理想的情况,因为即使在只有 C 字符串的情况,也不会引发不必要的内存复制
2. 如果需要在函数内修改字符串内容、但不影响调用者的该字符串,使用 string 作为参数类型(自动拷贝)
3. 如果需要改变调用者的字符串内容,使用 string& 作为参数类型(通常不推荐)

2. vector

vector 底层是一个动态数组,他维护了一段连续的动态内存空间,然后有三个成员变量分别保存开始位置、当前已使用位置、申请的动态内存的最后一个位置的下一个位置。每当当前所申请的动态内存已经用完时,他会按照原来空间大小的两倍重新申请内存块,并把原来的元素都拷贝过去。

特别注意:当 push_back、insert、reserve、resize 等函数导致内存重分配时,或当 insert、erase 导致元素位置移动时,vector 会试图把元素“移动”到新的区域。vector 通常保证强异常安全性,如果元素类型没有提供一个保证不抛出异常的移动构造函数,vector 通常会使用拷贝构造函数。解决办法:我们应该定义移动构造函数,并标其为 noexcept,或只在容器中放置对象的智能指针

查看更多

undefined

一、const 和 constexpr

1. 区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void dis_1(const int x){
//错误,x是只读的变量,但本质上是变量
array <int,x> myarr{1,2,3,4,5};
cout << myarr[1] << endl;
}

void dis_2(){
// 正确,x是只读变量的同时,还是个常量
const int x = 5;
array <int,x> myarr{1,2,3,4,5};
cout << myarr[1] << endl;
}

int main() {
dis_1(5);
dis_2();
}

C++ 11标准中,为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,而将“常量”的语义划分给了新添加的 constexpr 关键字。因此 C++11 标准中,建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。

2. 只读和常量

“只读“和”不允许修改“这两个没有必然的联系。对于只读的变量也可以被修改,如下例子:

1
2
3
4
5
6
7
8
int main() {
int a = 10;
const int & con_b = a;
cout << con_b << endl; // 10

a = 20;
cout << con_b << endl; // 20
}

查看更多