C++笔记

发布于:2025-08-16 ⋅ 阅读:(20) ⋅ 点赞:(0)

指针

类型*是该类型指针;

&变量是取地址;

*指针是取值;

int a=13;
int*p=&a;
cout<<*p;

指针运算

指针++就是内存移动它指向类型的字节数,指向下一个它指向的类型。

const修饰指针

常量指针

int a=10;
int b=412;
const int*p=&a;
*p=213;//不行
a=341;//可以
p=&b;//可以
*p=128;//不行
b=1344;//可以

指针的指向可以修改,指针指向的值不能修改,但是p指向的变量可以通过非指针方式修改。

指针常量

int a=10;
int f=432;
int* const p=&a;
p=&f;//不行
*p=4231;//可以

指针的指向不能修改,指针指向的值可以修改。

常量指针常量

int a=10;
int f=432;
const int* const p=&a;
p=&f;//不行
*p=4231;//不行

new、delete

在堆内存分配、释放内存。new返回类型的指针。释放数组时用delete[]。

int*p=new int(123);
delete p;

int* arr=new int[10];
delete[] arr;

引用

声明时必须初始化。初始化后不能改。

int a=10;
int &b=a;

引用参数

void MySwap(int &a, int &b){

}

引用的本质:指针常量。

引用做输入参数

void ShowValue(int &val){
    val=1000;
    cout<<val;
}
int main(){
    int a=13;
    ShowValue(a);
}

类和对象

和C#的区别:

有参构造函数

  1. class前面不用写public也能访问;
  2. 花括号结束后有分号;
  3. 公开成员可以只写一个public:多个成员;
  4. 实例化不用new
  5. 赋值、参数传入、返回传出是深拷贝
class Person{
int age;
public:
    Person(){}
    Person(int a){
        age=a;
    }

};
int main(){
    Person p0;
    Person p1(31);
    Person p2=Person(10);//显式
    Person(13);//匿名对象,当前行执行完立即回收
    Persons p4=10;//隐式转换,相当于p4(10);
}

拷贝构造函数:传入一个同类对象。

    class Person{
    public:
        Person(const Person &p){
            
        }
    };
    int main(){
        Person p;
        Person p2(p);
        Person p3=Person(p);
        Person p4=p3;//隐式转换法
    }

    问题

    sizeof()在C++和C#的区别

    在C# sizeof()只能输入值类型名,C++ sizeof()可以输入类型名或变量,输入

    1. 变量引用时返回被引用对象本身所占的内存空间大小。
    2. 指针时返回指针的字节数,4或8;
    3. 数组名字返回数组内容占的字节数;

    指针是内存地址,为什么声明指针还要声明类型?内存地址不是没有类型吗?deepseek回答

    这个问题的核心在于理解‌内存地址的本质‌和‌编程语言的类型系统‌之间的区别。让我为你详细解释:


    1. ‌内存地址的本质(硬件层面)

    • 内存地址本身确实是‌无类型‌的,它只是一个数字(比如 0x7ffeeb0b9bdc),代表内存中的一个位置
    • 在硬件层面,CPU 读取内存时并不关心数据类型,它只是按照指令访问特定地址
    • 但是‌:内存中的数据本身是有含义的!同样的二进制序列:

      0x00000041 (十六进制)

      可能是整数 65,也可能是字符 'A',还可能是浮点数 1.14e-43

    2. ‌指针类型的必要性(软件层面)

    指针的类型声明是为了告诉‌编译器‌如何解释和处理该内存地址:

    (1) ‌类型安全
    int num = 42; double* p = &num; // 编译器报错:类型不匹配
    • 防止意外错误访问(如把整数地址当作浮点数访问)
    • 编译时就能捕获大量类型错误
    (2) ‌解引用语义
    int a = 10; int* p_int = &a; char* p_char = (char*)&a; printf("%d", *p_int); // 正确:读取4字节整数 → 10 printf("%d", *p_char); // 读取1字节 → 10 (但含义完全不同)
    • 指针类型决定了‌读取多少字节‌(int* 读4字节,double* 读8字节)
    • 决定了‌如何解释‌这些字节(整数?浮点?结构体?)
    (3) ‌指针算术运算

    int arr[5] = {0}; int* p = arr; p++; // 前进sizeof(int)=4字节

    • p+1 实际增加的地址值 = sizeof(指向类型)
    • 如果没有类型信息,p++ 该前进多少字节?
    (4) ‌函数指针调用
    
    

    cCopy Code

    void (*func_ptr)(int); // 必须声明参数类型 func_ptr = &my_function; func_ptr(42); // 编译器知道如何传递参数


    3. ‌特殊案例:void* 万能指针

    C/C++ 中有一种无类型指针:

    void* p = malloc(100); // 分配100字节

    • 优点‌:可以指向任何数据类型
    • 缺点‌:
      • 不能直接解引用(编译器不知道如何解释)
      • 使用时必须强制转换:

      int* int_p = (int*)p; *int_p = 42;

    • 常见于底层系统编程(如内存管理)

    4. ‌类型系统的哲学意义

    类型系统本质上是‌赋予二进制数据以语义‌:

    • 硬件视角:内存只是0/1序列
    • 软件视角:我们需要知道:
      • 这段数据是整数还是字符串?
      • 它占多少字节?
      • 对它进行+1操作意味着什么?

    图解说明

    
    

    textCopy Code

    内存地址:0x1000 0x1001 0x1002 0x1003 二进制数据:01000001 01000010 01000011 01000100 char* 解释: 'A' 'B' 'C' 'D' → 字符串 "ABCD" int* 解释: 0x41424344 (十六进制) → 十进制整数 1,094,796,612


    总结

    特性 内存地址 (硬件) 指针 (软件)
    本质 无类型的数字 带类型的内存引用
    目的 标识位置 安全访问数据
    操作 直接读写 类型检查+解引用+运算
    必要性 物理存在 防止错误+提供语义

    指针类型是编程语言在‌无类型的内存物理层‌之上建立的‌类型安全层‌,它:

    1. 确保数据被正确解释
    2. 防止非法内存操作
    3. 使指针算术有意义
    4. 提供编译时类型检查

    这就是为什么虽然内存地址本身无类型,但我们仍需声明指针类型——它是连接底层硬件和高级抽象的桥梁。

    C++变量名编译后还存在吗

    根据编译原理和程序执行机制,C++变量名在编译后的可执行文件中不存在,其作用仅限于编译阶段。以下是具体分析:

    🔍 一、变量名的编译期作用
    1. 符号表映射
      编译器在编译时将变量名转换为内存地址或寄存器编号,生成汇编/机器指令时仅保留地址信息而非名称本身16。
      示例: 代码 int x = 5; 编译后可能变为 mov [ebp-4], 5ebp-4 即 x 的栈地址)。

    2. 内存分配依据
      变量名用于确定存储区域(栈、堆、静态区)和空间大小,但分配完成后名称即被丢弃24。

      • 局部变量‌:函数运行时在栈帧中动态分配,编译时确定偏移量4。
      • 全局/静态变量‌:编译时分配在静态存储区,链接阶段解析地址5。
    ⚙️ 二、运行期的变量表现
    • 无名称存储
      程序执行时内存仅存储二进制数据,变量通过硬编码地址访问。例如:

      • 栈区:通过基址寄存器(如 ebp)加偏移量定位局部变量46。
      • 全局区:直接使用绝对地址引用5。
    • 调试信息的例外
      调试版本(Debug)可能保留变量名符号表,但仅用于开发工具(如GDB),不影响程序实际执行1。

    📊 三、变量处理阶段对比
    阶段 变量名是否存在 作用 存储形式
    源代码 ✅ 是 程序员可读标识符 文本字符
    编译期 ️ 临时保留 生成地址映射表 符号表(临时)
    可执行文件 ❌ 否 被替换为地址/寄存器编号 二进制指令
    程序运行时 ❌ 否 通过内存地址直接访问数据 寄存器/内存单元
    💎 结论

    变量名是编译器与开发者的‌中间媒介‌,最终程序执行完全依赖‌硬件地址‌操作数据14。若需保留名称信息(如反射机制),需额外实现元数据系统,而非语言原生特性。

    Windows系统不自带C++编译器吗

    Windows操作系统本身‌不自带C++编译器‌。以下是关键说明:


    🔍 ‌核心结论

    1. 操作系统与编译器分离
      • Windows 作为操作系统仅提供程序运行环境,‌不包含任何编程语言的编译器‌(包括C/C++)。编译属于开发工具范畴,需额外安装。
      • 验证方法:
        • 打开命令提示符,输入g++ --versioncl → 若提示“不是内部命令”则未安装编译器36。
        • 控制面板 → “程序与功能”列表中‌无C/C++编译器项‌(仅有运行时库)38。

    ⚙️ ‌Windows下主流C++编译器

    编译器类型 安装来源 特点
    MSVC Visual Studio 自带 微软原生编译器,深度集成Windows SDK
    MinGW/GCC 手动下载配置(如MinGW-w64) GNU工具链移植,生成原生Windows程序
    Cygwin 独立安装包 模拟POSIX环境,依赖cygwin1.dll

    注:控制面板中的 Microsoft Visual C++ Redistributable ‌仅是运行时库‌(供程序调用),非编译器23。


    💡 ‌安装建议

    1. 初学者‌ → 安装 ‌Visual Studio‌:勾选“C++桌面开发”组件,自动配置MSVC编译器13。
    2. 轻量开发‌ → 选择 ‌MinGW-w64‌:
      • 下载地址:MinGW-w64
      • 配置环境变量至bin目录(如 C:\mingw64\bin)510。

    ❌ 常见误解

    • 误区‌:“Windows自带C++编译器”
      正解‌:系统仅预装运行时库(如msvcp140.dll),用于支持已编译程序的运行26。
    • 误区‌:控制面板中的VC++组件是编译器
      正解‌:这些组件是‌运行时环境‌(Redistributable Package),非开发工具38。

    💡 提示:验证编译器是否安装成功 → 命令行执行 g++ --version(MinGW)或 cl(MSVC),显示版本号即配置完成310。


    网站公告

    今日签到

    点亮在社区的每一天
    去签到