C/C++非常规问题(1.0)

 

@Shadow

记录C/C++学习 后续学Linux
偶遇明师指导
长期写作
连更大王

本文章旨在记录C/C++学习过程中遇到的疑难杂症知识点很杂但尽可能的清晰(强烈建议读者收藏)

目录

1.编译时的注释替换:

1.1占位忽略符:%*c %*d等

※2编译与链接

2.1汇编语言还是反汇编语言?

2.2程序的编译链接过程

3.数据类型值(根据不同情景可能变化)

4.※scanf返回EOF与0与非零

5.#ifdef ………… #endif 的合理使用

6.解决竞赛中需求高io效率的的代码

7.※C中NULL与C++中nullptr

8.C++中流提取运算符 << 流插入运算符 >>

8.1缓冲区 

8.1.1作用:

1/2批量处理

2/2.行缓冲(不同编译器优化程度不同,显示可能以下不符合描述)

8.1.2刷新缓冲区的目的:

8.2"cin 于 cout有各自的i/o流"怎么解释?

1/3.二者相互独立的一面:

2/3.二者相互关联的一面:

3/3#include快排

9.※区分:类作用限定符、域访问限定符

10.类内常量的初始化与非全局函数的初始化:

10.1关于类名Date和对象名d1的使用:   

11.运算符重载为全局函数与成员函数原因

11.1对称性与非对称性

11.2混合类型、类型隐式转换

12.友元函数的类内定义格式:

13.赋值运算符要注重考虑的有:

14.杂项


1.编译时的注释替换:

编译时注释会被替换为一个空格

如:integral/*wa bi ba bu*/type  编译后→integral type

1.1占位忽略符:%*c %*d等

图解

输入:1 2 3

※2编译与链接

2.1汇编语言还是反汇编语言?

int a = 10;
00007FF7470D1ACE  mov         dword ptr [a],0Ah  
	int& b = a;                        //!!!!!!!!!!!!!!!!!!!!!!!!!
00007FF7470D1AD5  lea         rax,[a]  //引用位于寄存器(一般位于栈中 具体位置还要看编译器)。
                                       //!!!!!!!!!!!!!!!!!!!!!!!!!
00007FF7470D1AD9  mov         qword ptr [b],rax  

答:这是汇编语言。来自于微软Visual的编译器,是机器码经过反汇编生成的汇编指令。
                                                                                                         ↓
                                                                                                   生成方式

2.2程序的编译链接过程

预处理————编译——————汇编—————————链接————————执行——

文本替换   转换为汇编语言   将汇编代码转换为机器指令  多个目标文件的合并    …………

                   语法语义检查           二进制形式不可读           函数定位函数间连接

                          优化

3.数据类型值(根据不同情景可能变化)

signed charSCHAR_MIN
shortSHRT_MIN
intINT_MIN
longLONG_MIN
long longLLONG_MIN
floatFLT_MIN

4.※scanf返回EOF与0与非零

scanf的返回值取决于scanf成功读取了几个数据    //Ctrl+Z 表示什么都不输入

※do {……}while();    //其后的" ; "不要落下

5.#ifdef ………… #endif 的合理使用

#define USE_OVERLOADING 1  //此处的define控制是否调用全缺省重载构造函数
class Date

{

public:

#ifdef USE_OVERLOADING

	// 全缺省的构造函数	//无参构造函数
	Date();
	//带参构造函数(与无参构成函数构成重载)  那么全缺省无法存在
	Date(int year, int month, int day);

#else

	Date(int year = 1900, int month = 1, int day = 1);
#endif  //必须具备

};

6.解决竞赛中需求高io效率的的代码

主要是解决缓冲区的问题以提高效率:

ios_base::sync_with_stdio(false);  //C++关联的C的绑定关系关闭

std::cin.tie(nullptr);  //cin与其绑定关系关闭

std::cout.tie(nullptr);  //cout与其所有绑定关系关闭

7.※C中NULL与C++中nullptr

1.C中NULL本质为0不是指针 在使用过程中可能会造成偏离。

2.而nullptr本质就是指针

3.nullptr可以转化为其他任意类型的指针。

4.使用nullptr可以避免类型转换的问题因为nullptr只能被隐式地转化为指针类型,而不能为整型。

8.C++中流提取运算符 << 流插入运算符 >>

由于缓冲区过于抽象理解其作用远远比理解其定义重要~

8.1缓冲区 

8.1.1作用:

暂存数据-集合输出——提高效率!!

1/2批量处理

***************************
没有缓冲区:每个字符都立即输出 (揭示了cout流插入运算符的本质)
***************************
cout << 'H';
cout << 'e';
cout << 'l';
cout << 'l';
cout << 'o';
// 每次都要系统调用,非常慢

// 有缓冲区:先存起来,一次性输出
cout << "Hello";  

对于hello:
// 先存在缓冲区
// 遇到换行或缓冲区满才真正输出
// 一次系统调用就搞定,效率高

2/2.行缓冲(不同编译器优化程度不同,显示可能以下不符合描述)

#include <iostream>
using namespace std;

int main() 
{
    cout << "正在计算";
    for (int i = 0; i < 5; i++) 
    {
        cout << ".";        // 这些点可能不会立即显示
        // 模拟计算
        for (int j = 0; j < 100000000; j++);
    }
    cout << "完成!" << endl;  // 在执行完这一行后才一次性显示所有点
    
    return 0;
}

8.1.2刷新缓冲区的目的:

保证数据的及时输出提高交互性。

前言:在执行流提取运算符cin前如果有cout先刷新其缓冲区(使得内容显示在屏幕上)。

8.2"cin 于 cout有各自的i/o流"怎么解释?

前言:i/o流是什么?

#include <iostream>
using namespace std;

int main() {
    cout << "输出到屏幕";  // cout 是输出流
    cin >> x;              // cin 是输入流
    cerr << "错误信息";    // cerr 也是输出流(无缓冲)
    clog << "日志信息";    // clog 也是输出流(有缓冲)
    return 0;
}

1/3.二者相互独立的一面:

(1).cout于cin有各自的数据结构:

// 简化理解(实际更复杂)
struct istream {  // cin 的类型
    streambuf* rdbuf;  // 输入缓冲区
    // ...
};

struct ostream {  // cout 的类型
    streambuf* rdbuf;  // 输出缓冲区
    // ...
};

(2).cout于cin有独立的缓冲区:

int main() {
    cout << "Hello";  // 数据进入 cout 的缓冲区
    // cout 的缓冲区:['H','e','l','l','o']
    
    int x;
    cin >> x;  // 数据进入 cin 的缓冲区
    // cin 的缓冲区:['1','2','3','\n']
    
    // 两个缓冲区是独立的,互不影响
    return 0;
}

2/3.二者相互关联的一面:

原因:二者虽然缓冲区相互独立但是它们共享一个底层终端 所以需要配合

这种关联在C++咨询网址中也被体现:

翻译:cin与cout相互关联,这种关联体现于在cin执行前cout的流会被刷新——以显示在屏幕上。

int main() {
    cout << "请输入:";  // 存在 cout 缓冲区
    // 如果没有关联,这行可能还没显示
    
    int x;
    cin >> x;  // cin 操作时,会先刷新 cout 缓冲区
               // 确保上面的提示先显示出来
    return 0;
}

3/3#include<algorithm>快排

#include<iostream>
#include<algorithm>

using namespace std;

bool mysort(int i, int j) { return i < j; }

int main()
{

	int arr1[] = { 12,32,14,314,325,435,345 };
	//默认升序 "mysort"可写可不写 若改为">"则降序
	sort(arr1, arr1 + sizeof(arr1) / sizeof(arr1[0]), mysort);
	
	int arr2[] = { 12,32,14,314,325,435,345 };
	//降序
	greater<int>l;
	sort(arr2, arr2 + sizeof(arr2) / sizeof(arr2[0]), l);

	return 0;
}

9.※区分:类作用限定符、域访问限定符

类作用限定符:public private protected,"作用"体现在限制区域能否被访问。

域访问限定符"::" 内用于名后访问内部成员。

10.类内常量的初始化与非全局函数的初始化:

10.1关于类名Date和对象名d1的使用:   

对比项Date::d1.
右侧静态成员非静态成员
本质告诉编译器去类的静态区告诉编译器去对象的内存
内存不依赖具体对象,类只有一份依赖具体对象,每个对象一份

11.运算符重载为全局函数与成员函数原因

如果你有以下疑问,那么这节可以解决你的问题:
1.赋值运算符为什么必须重载为成员函数?重载为全局函数会发生什么?
2.那为什么运算符,像"<"就可以重载为全局函数呢?

11.1对称性与非对称性

非赋值运算符的重载中(如对:比较运算符 )我们发现其运算符两侧的量的级别具有一致性原则。
而赋值运算符可能导致级别不同。

class Number {
    int value;
public:
    Number(int v = 0) : value(v) {}
    int get() const { return value; }
};
                        ************
 ✅ "<" 是对称操作:左右操作数地位平等
                        ************
bool operator<(const Number& a, const Number& b) {
    return a.get() < b.get();
}
                             *****************
❌ "=" 是非对称操作:左操作数被修改,右操作数只读
                             *****************
// Number& operator=(Number& lhs, const Number& rhs); // 不允许

11.2混合类型、类型隐式转换

比较运算符适合全局类型的关键在于其支持混合类型。

class Integer {
    int value;
public:
    Integer(int v = 0) : value(v) {}
    
    // 转换为int
    operator int() const { return value; }
};

// ✅ 全局函数可以处理多种组合
bool operator<(const Integer& i, int n) {
    return i.value < n;
}

bool operator<(int n, const Integer& i) {
    return n < i.value;
}

// 如果作为成员函数,只能处理一种情况:
// class Integer {
// public:
//     bool operator<(int n) const { return value < n; }  // Integer < int
//     // 无法处理 int < Integer 的情况(除非加转换)
// };

同样的全局函数也支持了隐式类型的转换。

由此可见赋值运算符只能定义为全局函数的规定利大于弊。此外还有原因,因此赋值运算符规定只能重载为全局函数。

12.友元函数的类内定义格式:

#include <iostream>
using namespace std;

class Point 
{
private:
    int x, y;
    
public:
    Point(int x = 0, int y = 0) 
    : x(x), y(y) 
    {}
    
    // 友元函数在类内定义
    friend void printPoint(const Point& p) 
    {
        cout << "Point(" << p.x << ", " << p.y << ")" << endl;
        // 可以直接访问私有成员 x, y
    }
};

int main() {
    Point p(10, 20);
    ****************************************
    printPoint(p);  // 直接调用,不需要通过对象
    return 0;
}

13.赋值运算符要注重考虑的有:

1.参数是否加const

2.返回是否为引用类型。

14.杂项

const定义常量可以类内初始化。
析构函数无参数。

本文到此结束,感谢观看。
不妨留下个是对我最大的支持
如果觉得有回顾意义不妨点个收藏 但收藏后一定要及时看哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值