C++学习问题记录
1、数组
C语言中数组的大小必须是在编译时就能确定的,它有以下几种初始化方法:
// 声明时,使用 {0} 初始化。例如:
int a[10] = {0}; // 将数组a的所有元素初始化为0
// 使用 memset 函数初始化。这个函数可以将一段内存区域的内容全部设置为指定的值,通常用于字符数组或结构体的初始化。例如:
char s[20];
memset(s, 'a', 20); // 将数组s的所有元素初始化为字符'a'
// 用 for 循环赋值。这个方法可以对数组的每个元素进行自定义的赋值操作,比较灵活。例如:
int b[10];
for (int i = 0; i < 10; i++) {
b[i] = i * i; // 将数组b的每个元素初始化为其下标的平方
}
现有一个数组arr,当你直接使用arr时,它表示该数组第一个元素的指针;但
当你使用sizeof(arr)时,它表示整个数组。
数组的传参,数组通过函数传参后会退化为指针,因此传参时必须传递数组大小:
void print_array(int *arr, int n) {
for (int i = 0; i < n; i++) {
printf("%d ", *(arr + i));
}
printf("\n");
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
print_array(arr, 5); // arr是一个指针,指向数组第一个元素
}
求一个数组的大小,是很麻烦的,必须通过以下方法:
int len_arr = sizeof(arr) / sizeof(int);
2、左值右值
左值和右值的概念是从C语言继承过来的,原始的意思是根据赋值符号而定,在赋值符号左边的称为左值,在右边称为右值。左值一般是指可以被取地址并且可以修改的变量,而右值则是指不能被取地址并且不能修改的变量。
int a = 10; // a是一个左值,10是一个右值
int b = a + 5; // b是一个左值,a + 5是一个右值
int &c = b; // c是一个左值引用,绑定到b
int &&d = a + 5; // d是一个右值引用,绑定到a + 5
在C++11中,为了支持移动语义和完美转发等特性,右值又被细分为纯右值(prvalue)和将亡值(xvalue)。纯右值表示临时的、不具名的、不可修改的对象,如字面量或函数返回非引用类型的对象。将亡值表示即将被销毁或者转移所有权的对象,如函数返回非常量引用类型或者std::move返回的对象。例如:
std::string foo() {
return "hello";
}
std::string& bar() {
static std::string s = "world";
return s;
}
std::string s1 = foo(); // foo()返回一个纯右值
std::string s2 = bar(); // bar()返回一个将亡值
std::string&& s3 = std::move(s1); // std::move(s1)返回一个将亡值
通过一个案例说明std::move
#include <iostream>
#include <cstring>
using namespace std;
class Person {
public:
char* name; // 指针成员
Person(const char* n) { // 构造函数
name = new char[strlen(n) + 1];
strcpy(name, n);
}
Person(const Person& p) { // 拷贝构造函数
cout << "Copy constructor called" << endl;
name = new char[strlen(p.name) + 1];
strcpy(name, p.name);
}
Person(Person&& p) { // 移动构造函数
cout << "Move constructor called" << endl;
name = p.name; // 直接将p的资源转移到自身
p.name = nullptr; // 将p置为空
}
~Person() { // 析构函数
delete[] name;
}
};
int main() {
Person p1("Alice"); // 调用构造函数
cout << "p1's name: " << p1.name << endl;
Person p2(p1); // 调用拷贝构造函数,深拷贝p1的资源
cout << "p2's name: " << p2.name << endl;
Person p3(std::move(p1)); // 调用移动构造函数,移动p1的资源
cout << "p3's name: " << p3.name << endl;
return 0;
}