C++学习(1)
1.ASSERT( 条件表达式 , 错误说明字符串 );
第 1 个参数:必须是 bool 表达式 ;第 2 个参数:人类可读的错误信息
ASSERT(arg == 5, "arg should be 5");
如果arg != 5为 false,→ 输出 "arg should be 5"→ 程序终止(或标记测试失败)
一句话总结(考试 / 面试级)
ASSERT(arg == ?, "...")的意思是:
“我断言arg的值必须等于某个明确的期望值,否则程序就是错的。”
2.代码风格:先在main()前声明函数,在main()后定义完整函数
3.parameter &argument
parameter 形参,出现在函数定义或声明中,属于函数定义的一部分
argument 实参,出现在函数调用处,是传给函数的具体值或对象,属于函数调用的一部分
是否影响实参,与是不是全局变量无关,只与参数传递方式有关。
-
T x→ 值传递 → 不影响 -
T& x→ 引用传递 → 影响 -
T* x→ 指针传递 → 可能影响指针传递时:
-
修改“指针指向的内容” → 会影响实参
-
修改“指针变量本身” → 不会影响实参
所以结论是:可能影响。
-
4.return static_++;后置自增:返回旧值,再自增
5.constexpr 函数 ≠ 一定编译期执行,只是“如果条件允许,可以编译期执行”
constexpr变量一定编译器确定值
6.unsigned long long arr[90]{0,1};
如果初始化列表元素数量 < 数组长度,剩余元素全部被零初始化,全部清零:unsigned long long arr[90]{};等价于unsigned long long arr[90]={0};
斐波那契数列:
unsigned long long fib[90]{0, 1};
for (int i = 2; i < 90; ++i) {
fib[i] = fib[i - 1] + fib[i - 2];
}
unsigned long long 最大 Fibonacci 大约是:fib(93) 之前不溢出(93已经溢出),90 是一个非常安全的上限,但80,90都算不出来,因为此种写法计算斐波那契数列效率太低,太多嵌套
7.数组退化为指针
作为实参传递时一定会退化为指针,数组名在使用时被当作指针值来用
以下三种写法完全等价:
void f(int arr[]);
void f(int arr[10]);
void f(int* arr);
不会发生退化的三个“例外”:
例外 1:sizeof
int arr[10];
sizeof(arr); // 40(假设 int 为 4 字节)
如果退化了,结果应该是 8(指针大小),但实际上不是。
但:
void f(int a[]) {
std::cout << sizeof(a) << std::endl;
}
int main() {
int arr[10];
f(arr);
}
输出为4
两者不同:
void f(int a[]) // ❌ 这不是数组参数
void f(int* a) // ✅ 实际类型,实际上编译器看到的
补:int型在32位系统是4B,在64位系统是8B
例外 2:&arr
int arr[10];
&arr // 类型是 int (*)[10]
arr → int*
&arr → 指向整个数组的指针
这两个完全不同:
&arr + 1 // 跳过整个数组(10 个 int)
arr + 1 // 跳过 1 个 int
例外 3:字符串字面量(特殊但相关)
const char* p = "hello";
这里:
-
"hello"是一个const char[6] -
在赋值时退化为
const char*
但不能:
"hello"[0] = 'H'; // ❌ 未定义行为
数组是一块连续内存,指针是一个变量;
数组名在大多数表达式中会退化为“指向首元素的指针”。
数组作为参数会退化为指针;
指针运算得到的是“地址”,斐波那契判断必须比较“解引用后的值”。
区分
-
ptr -
ptr + k -
*(ptr + k)
斐波那契数列注意:
//i范围
for( i = 0; i + 2 < n; i++)
//指针是地址,要用*解地址才是值
*(ptr + (i + 2) * stride) != *(ptr + (i + 1) * stride) + *(ptr + stride);
面试题:
✅ 问题 1:类型与含义
int arr[10];
表达式 类型 含义 arrint*指向 arr[0]&arrint (*)[10]指向整个数组 arr + 1int*指向 arr[1]&arr + 1int (*)[10]跳过整个数组(10 个 int),指向下一个int[10]数组,实际地址arr+10,是one-past-the-end,合法,但不可解引用成数组元素
*(&arr + 1) int* 指向arr[10],标准允许形成一个指向 one-past-the-end 的对象表达式,
只要不访问其元素。没有发生UB❌ UB 的情况
int* p = *(&arr + 1); *p = 42; // ❌ UB原因:
p == arr + 10这是 one-past-the-end
解引用得到元素 = 访问不存在的对象
合法的使用方式
int* end = *(&arr + 1); if (end > arr) { } // ✅ 比较 int size = end - arr; // ✅ 计算长度“
*(&arr + 1)这个表达式本身是合法的,它只是产生一个指向 one-past-the-end 的指针;真正的 UB 是对这个指针再次解引用,去访问元素。”面试官期望你说出的关键句:
“
arr在表达式中退化为int*,而&arr的类型是指向整个数组的指针。”✅ 问题 2:是否等价
p + 1 // int* &arr + 1 // int (*)[10]结论:不等价。
原因必须说清楚:
p + 1:地址增加sizeof(int)
&arr + 1:地址增加sizeof(arr)(即10 * sizeof(int))指针算术由“指向的类型”决定
加分句式:
“虽然数值地址可能看起来相近,但指针类型不同,语义完全不同。”
✅ 问题 3:终极问题(面试官最爱)
目标:得到一个
int*,指向arr[10]唯一正确答案:
int* end = arr + 10;追问:那怎么用
&arr得到int*?你应该答:
int* end = *(&arr + 1);解释(必须一口气说完):
&arr + 1→ 指向“下一个数组”
*(&arr + 1)→ 该数组的首元素类型退化为
int*指向
arr[10](one-past-the-end,合法但不可解引用)“数组到指针的退化只发生在表达式中,
sizeof、&、decltype 等上下文不会发生退化。”
int (*p)[10];//“p 是一个指针,指向一个包含 10 个 int 的数组。”
UB = Undefined Behavior(未定义行为)
程序做了标准没有规定结果的事情,
编译器可以“随便处理”,任何结果都是合法的。
int (*p)[10]
是一个声明,其中 p 的类型是 int (*)[10]。
更多推荐

所有评论(0)