C++

逐语句(代码的执行过程)、逐过程(只逐行执行main中代码)运行可用于调试代码。
在这里插入图片描述
右键->
运行到光标处将执行程序,直到执行到达您的鼠标光标选择的语句为止。(若是循环的某条语句则第二次循环到达此处不会停止

调试->继续运行程序,直到程序终止或遇到断点。从程序的开头
开始就与继续相同。

一个断点是特殊的标记,告诉调试器程序的停止执行到达断点。(若是循环的某条语句则每次循环到达断点处都会停止)(与运行到光标处有所区别)

在这里插入图片描述
在代码调试过程中->调试->监视->监视1(在其中手动添加变量名)
监视变量可让您在程序以调试模式执行时检查变量的值。在监视窗口允许你检查的变量或表达式的值。

在代码调试过程中->调试->调用堆栈(从下至上是进栈顺序)
该调用堆栈是所有已执行去执行的当前点的活跃函数的列表。在调用堆栈窗口是一个调试窗口,显示调用堆栈。
在这里插入图片描述

常量(const、exprconst、define常量)
C ++实际上有两种不同的常量。
运行时常量是那些只能在运​​行时(程序正在运行时)解析其初始值的常量。上面摘录中的usersAge和myValue之类的变量是运行时常量,因为编译器无法在编译时确定其初始值。 usersAge依赖于用户输入(只能在运行时给出),而myValue取决于传递给函数的值(仅在运行时才知道)。但是,一旦初始化,这些常量的值就无法更改。
编译时常量是那些其初始化值可以在编译时(程序正在编译时)解析的常量。上面的可变重力是编译时常数的一个示例。编译时常量使编译器可以执行运行时常量无法提供的优化。例如,每当使用重力时,编译器都可以简单地用文字双精度9.8标识符代替重力。

声明const变量时,编译器将隐式跟踪它是运行时常量还是编译时常量。
在大多数情况下,这无关紧要,但是在一些奇怪的情况下,C ++需要编译时常量而不是运行时常量,C ++ 11引入了关键字constexpr,以确保常量必须是编译时常量。
define常量(#define xx xx 定义):在程序中使用define常量会使程序更难以理解和修改。符号常量(const、exprconst)可帮助记录数字实际代表的内容,更改符号常量的声明将更改使用该符号常量的值。#define常量不会显示在调试器中,并且更可能出现命名冲突。

从输入中读取信息一行两种方式和区别:

std::string name{};
//若下面还有一个std::cin 或者std::getline()则会将换行赋给它
std::cin >> name; //会自动忽略空格,如输入“hello Li!”保存为“hello”,且会将剩余内容继续保留在缓冲区中

std::getline(std::cin, name); //从输入框中读取一行信息保留空格,并忽略换行符(不放入缓冲区)

强制类型转换:

double age{12};
int a{static_cast<int>(age)}; //将double类型age强制转换为int类型赋值给a,age的类型还是double不变

静态变量(static变量,命名以s_开头)提供了全局变量的某些优点(直到程序结束它们才被销毁),同时将其可见性限制在块范围内,避免使用static局部变量,除非永远不需要重置该变量。static局部变量会降低可重用性,并使函数难以推理。
具有内部链接的全局变量(或函数): static、const、exprconst在某个文件中声明后,对其他文件不可见、不可用。
函数默认具有外部链接(即在一个文件中声明定义后,在其他文件中也可用)
具有外部链接的全局变量有时称为外部变量。要将全局变量设置为外部变量(从而可被其他文件访问),可以使用extern关键字。
非常量全局变量默认情况下是外部的(如果使用,则extern关键字将被忽略)。
在这里插入图片描述
constexpr变量即使具有外部链接也无法向前声明。(因为constexpr必须是一个常量表达式,不能进行前向声明)
内联变量(inline)是一个允许在多个文件中定义而不违反一个定义规则的变量。内联全局变量默认具有外部链接。
在这里插入图片描述
类型别名(typedef、using)可以提高代码可读性、使复杂类型变得简单

//两者在功能上等效
typedef double distance_t; //将double取别名为distance_t
using distance_t = double; //对于更高级的类型定义情况,此类型别名语法更干净,因此应首选。

String字符串

//使用字符串必须添加头文件
#include <string>
int main()
{
    std::string name{};
    std::cin>>name;  //遇到空格或者换行符就会停止
    std::string age{};
    std::cin>>age; 
    std::cout<<"name is "<<name<<"and age is "<<age;
    //如果第一次输入的字符串中有空格,则会违背我们的意愿
    //如输入name为Alex Li,则name为Alex,age为Li
    //改进:使用std::getline(std::cin, name)来读取一行输入
    //或者std::cin.getline(name, name.length());
    //如果使用std :: cin读取值,则最好紧接着加一句std :: cin.ignore()删除多余的换行符
    //std::cin.ignore(32767, ‘\n’);
    return 0;
}

可以直接使用 str1 + str2 将两个字符串合并
str.length() 求字符串长度
str.erase(4, 11); 删除字符串从第5个字符开始共11个字符

枚举

在这里插入图片描述

enum ParseResult //枚举增强代码文档的可读性
{
    // 为其默认赋予整数,如SUCCESS=0
    SUCCESS,   //0 
    ERROR_OPENING_FILE, //1 
    ERROR_READING_FILE, //2
    ERROR_PARSING_FILE  //3
};
 
ParseResult readFileContents()
{
    if (!openFile())
        return ERROR_OPENING_FILE;
    if (!readFile())
        return ERROR_READING_FILE;
    if (!parsefile())
        return ERROR_PARSING_FILE;
 
    return SUCCESS;
}

在这里插入图片描述

随机数

//会发现每次运行此代码,得到的100个数是一样的,因为设定了初始种子数值
#include <iostream>
#include <cstdlib> // for std::rand() and std::srand()
 
int main()
{
    std::srand(5323); // 将初始种子数值设为 5323(0-32767)
    // 输出任意100个数
    for (int count{ 1 }; count <= 100; ++count)
    {
        std::cout << std::rand() << '\t'; //0-32767
        // 一行打印五个数
        if (count % 5 == 0)
            std::cout << '\n';
	}
    return 0;
}
//std :: time()的函数,该函数返回自1970年1月1日午夜以来的秒数,这样每次运行此代码 得到的100个随机数将不同,除非是同一秒同时运行此代码
#include <iostream>
#include <cstdlib> // for std::rand() and std::srand()
#include <ctime> // for std::time()
int main()
{
    std::srand(static_cast<unsigned int>(std::time(nullptr))); // set initial seed value to system clock 
    for (int count{ 1 }; count <= 100; ++count)
    {
        std::cout << std::rand() << '\t';
        // If we've printed 5 numbers, start a new row
        if (count % 5 == 0)
            std::cout << '\n';
	}
    return 0;
}
//在两个任意值之间生成随机数
// Generate a random number between min and max (inclusive)
// Assumes std::srand() has already been called
// Assumes max - min <= RAND_MAX
int getRandomNumber(int min, int max)
{
    static constexpr double fraction { 1.0 / (RAND_MAX + 1.0) };  // static used for efficiency, so we only calculate this value once
    // evenly distribute the random number across our range
    return min + static_cast<int>((max - min + 1) * (std::rand() * fraction));
}
//1. 我们将std :: rand()的结果乘以分数。这会将rand()的结果转换为介于0(含)和1(不含)之间的浮点数。
//如果rand()返回0,则0 *分数仍为0。如果rand()返回RAND_MAX,则RAND_MAX *分数为RAND_MAX /(RAND_MAX + 1),该值略小于1。rand()返回的任何其他数字。 )将均匀地分布在这两点之间。

//2. 接下来,我们需要知道我们可以返回多少个数字。换句话说,最小(含)和最大(含)之间有多少个数字?
//这很简单(最大-最小+ 1)。例如,如果max = 8且min = 5,则(max-min +1)=(8-5 +1)=4。5和8之间有4个数字(即5、6、7和8) )。

//3. 我们将前面两个结果相乘。如果我们的浮点数介于0(含)和1(不含)之间,然后乘以(min-max + 1),则现在有一个浮点数介于0(含)和(max-min + 1)之间)(独家)。
//4. 我们将之前的结果转换为整数。这将删除任何小数部分,使我们得到0(含)和(max-min)(含)之间的整数结果。
//5. 最后,我们添加min,这会将我们的结果转换为min(含)和max(含)之间的整数。

数组

确定数组长度

#include <iterator> // 必须添加的头文件,for std::size
std::size(array); //求array数组长度

交换

#include <algorithm> //for std::swap
// 则可以使用swap(x,y),交换x,y的值
std::swap(x,y);

排序

#include <algorithm> //for std::sort
//对数组array从小到大排序
std::sort(std::begin(array), std::end(array));
//输出排序后的数组
for (int i{ 0 }; i < static_cast<int>(std::size(array)); ++i)
    std::cout << array[i] << ' ';
//反向排序
#include <algorithm>
#include <array>
#include <iostream>
bool greater(int a, int b)
{
  // Order @a before @b if @a is greater than @b.
  return (a > b);
}
int main()
{
  std::array arr{ 13, 90, 99, 5, 40, 80 };
  // 反向排序
  std::sort(arr.begin(), arr.end(), greater);
  //排序后为:99 90 80 40 13 5
  return 0;
}

C风格的字符串

#include <iostream>
#include <iterator> // for std::size
 //尽管“字符串”只有6个字母,但是C ++会自动为我们在字符串的末尾添加一个空终止符(我们不需要自己包含它)。
 //因此,myString实际上是长度为7的数组!(std::size())
int main()
{
    char myString[]{ "string" };
    const int length{ static_cast<int>(std::size(myString)) };
    std::cout << myString << " has " << length << " characters.\n";
    for (int index{ 0 }; index < length; ++index)
        std::cout << static_cast<int>(myString[index]) << ' ';
    std::cout << '\n';
    //输出115116114105110103 0 
    //0是已添加到字符串末尾的空终止符的ASCII码。
    return 0;
}
//strlen()函数,不将空终止符算在内
#include <cstring>
char name[20]{"Alex"};
auto i{std::strlen(name)};  //返回 4

注意strlen()和std :: size()之间的区别。strlen()打印空终止符之前的字符数,而std :: size则返回整个数组的大小,而不管其中的内容是什么。

strcat()-将一个字符串附加到另一个
strncat()-将一个字符串附加到另一个(使用缓冲区长度检查)
strcmp()-比较两个字符串(如果相等则返回0)
strncmp() -比较两个字符串,直到特定数量的字符(如果相等则返回0

循环

std::string array[]{"pretty", "likes"};
for (auto element: array)  //for-each循环,循环将遍历数组中的每个元素,将当前数组元素的值分配给element中声明的变量
//element应该与数组元素有相同的类型
{
    std::cout << element << " ";
}

std::array

//下标运算符([])和at()函数的范围基于向量的长度,而不是容量。

#include <array>
std::array<int ,3> myArray = { 1, 2, 3 };
std::array<double, 4> myArray2 = { 1.2, 2.2, 3.2 }; //缺省值默认补全0.0
//std::array 使用下标运算符访问值,不进行边界检查,如果提供了无效索引,则可能会发生不良情乱
std::cout << myArray[1] << '\n';
//std::array支持数组元素访问的第二种形式(at()函数),该形式进行边界检查
myArray.at(1)=6;  
//使用size()函数检索长度
std::cout << "length: " << myArray.size() << '\n';

std::vector

和数组下标或者at()不同,基于堆栈的函数在有必要时会调整std::vector的大小(即可以不用在声明是确定大小)

#include <vector>

std::vector<int> array{9,7,5};
auto num=array.size();
printLength(array); //打印 The length is: 5
//调整向量大小,现有元素值会保留下来,其次新元素会被初始化
array.resize(5); //set length to 5

长度seize和容量capacity

#include <vector>
#include <iostream>
int main()
{
  std::vector<int> array{};
  array = { 0, 1, 2, 3, 4 }; // okay, array length = 5,capacity = 5
  std::cout << "length: " << array.size() << "  capacity: " << array.capacity() << '\n';
  array = { 9, 8, 7 }; // okay, array length is now 3! capacity = 5,长度变了 但是数组容量没变
  std::cout << "length: " << array.size() << "  capacity: " << array.capacity() << '\n';
  return 0;
}

可以使用reserve()函数告诉向量预先分配一定的容量

std::vector<int> stack{};
stack.reserve(5); //set the capacity to (at least) 5

向量可能会分配额外的容量
当调整向量的大小时,向量可能会分配比所需更多的容量。这样做是为了为其他元素提供一些“呼吸空间”,以最大程度地减少所需的调整大小操作的次数。

#include <vector>
#include <iostream>
int main()
{
	std::vector<int> v{ 0, 1, 2, 3, 4 };
	std::cout << "size: " << v.size() << "  cap: " << v.capacity() << '\n';
	v.push_back(5); // add another element
	std::cout << "size: " << v.size() << "  cap: " << v.capacity() << '\n';
	return 0;
}
// 输出为:
//size: 5  cap: 5
//size: 6  cap: 7

迭代器

#include <algorithm>
#include <array>
//限于array数组,在string中find()的返回值为size_t
std::array<int, 6> arr{13, 90, 99, 5, 40, 80};
//std::find在容器中搜索值的首次出现
//std::find(序列中起始元素的迭代器,序列中结束元素的迭代器,要搜索的值)
//返回一个指向该元素的迭代器(如果找到),或容器的末尾(如果找不到该元素)
auto found{ std::find(arr.begin(), arr.end(), search) }
*found=replace; //用其他值替换掉,会改变原数组

递归
斐波那契算法,1205次递归

#include <iostream>
 
int fibonacci(int count)
{
    if (count == 0)
        return 0; // base case (termination condition)
    if (count == 1)
        return 1; // base case (termination condition)
    return fibonacci(count-1) + fibonacci(count-2);
}
 
// And a main program to display the first 13 Fibonacci numbers
int main()
{
    for (int count=0; count < 13; ++count)
        std:: cout << fibonacci(count) << " ";
 
    return 0;
}

递归斐波那契算法的记忆版本,减少了递归次数,共使用35次递归

//减少了递归次数
#include <iostream>
#include <vector>
 
// h/t to potterman28wxcv for a variant of this code
int fibonacci(int count)
{
	// We'll use a static std::vector to cache calculated results
	static std::vector<int> results{ 0, 1 };
 
	// If we've already seen this count, then use the cache'd result
	if (count < static_cast<int>(std::size(results)))
		return results[count];
	else
	{
		// Otherwise calculate the new result and add it
		results.push_back(fibonacci(count - 1) + fibonacci(count - 2));
		return results[count];
	}
}
 
// And a main program to display the first 13 Fibonacci numbers
int main()
{
	for (int count = 0; count < 13; ++count)
		std::cout << fibonacci(count) << " ";
 
	return 0;
}

assert 断言语句

个断言语句是一个预处理宏在运行时计算一个条件表达式。如果条件表达式为true,则assert语句不执行任何操作。如果条件表达式的计算结果为false,则会显示一条错误消息并终止程序。此错误消息包含失败的条件表达式,以及代码文件的名称和断言的行号。这样不仅可以很容易地分辨出问题所在,而且可以分辨出代码在哪里发生了。这可以极大地帮助调试。
assert功能存在于标头中

#include <cassert>

//若执行到此句gravity>0.0则程序继续执行后面的内容,否则程序终止并打印错误信息
assert(gravity > 0.0);
//错误信息举例
//Assertion failed: gravity > 0.0, file d:\file\vs项目\test_c++primer\test_c++primer\1.cpp, line 6

//如果found为false,则false && true = false。如果发现为true,则true && true = true。
//因此,对字符串进行逻辑AND运算不会影响断言的评估。并会提供一些错误信息给程序员
assert(found && "Car could not be found in database");

断言应该(理想情况下)在生产代码中绝不遇到(因为您的代码应该已经过全面测试)。因此,许多开发人员更喜欢断言仅在调试版本中有效。
C ++提供了一种关闭生产代码中的断言的方法:#define NDEBUG。

#define NDEBUG
// 文件中所有的断言语句都将被忽略

另一种断言static_assert,与assert(在运行时执行)不同,static_assert设计为在编译时运行,如果条件不成立,则会导致编译器出错。如果条件不成立,则会打印诊断消息。条件部分必须能够在编译时评估。

#include <assert>
//在C ++ 11中,必须提供诊断消息作为第二个参数。从C ++ 17开始,提供诊断消息是可选的。
static_assert(sizeof(long) == 8, "long must be 8 bytes");
static_assert(sizeof(int) == 4, "int must be 4 bytes");

使用 istream 输入

#include <iostream>

char buf[10];
std::cin>>buf; //当一次输入超过10个字符则缓冲区溢出,程序意外终止

如何解决?

//该程序将仅读取流中的前9个字符(为终止符留出空间)。所有剩余的字符将保留在流中,直到下一次提取。
#include <iomanip.h>
char buf[10];
std::cin >> std::setw(10) >> buf;

get() 函数 不会读取换行符-----一直保留在缓冲区中
对字符操作:

int main()
{
//get()函数是最有用的函数,它仅从输入流中获取一个字符,保留空格
    char ch;
    while (std::cin.get(ch))
        std::cout << ch;
    return 0;
}

字符串版本:

int main()
{
    char strBuf[11];
    std::cin.get(strBuf, 11);  //get(str, maxChar)
    std::cout << strBuf << '\n';
    return 0;
}

getline() 函数 功能与get()完全相同,会读取换行符
getline()的特殊版本,用于std :: string
有一个特殊版本的getline()驻留在istream类之外,该类用于读取std :: string类型的变量。此特殊版本不是ostream或istream的成员,而是包含在字符串标题中。这是一个用法示例:

#include <string>  //std::getline()使用
#include <iostream>
 
int main()
{
    std::string strBuf;
    std::getline(std::cin, strBuf);
    std::cout << strBuf << '\n';
 
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值