c++基础


helloworld.cpp:

c++
#include <iostream>  // 引入输入输出库
#include <string>  // 引入字符串库
#include <cmath>  // 引入数学库
#include <fstream>  // 引入文件读写库
using namespace std;  // 使用std命名空间,这样就不用每次都写成std::cout
// using std::cout;  // 使用标准包中的cout命名空间

void classTest();  // 函数声明,声明一般在文件开头,函数的实现在main函数后面
void fileTest(); // 申明一个用于读写文件的函数

// 宏定义,常量,在编译时会替换字符,不会额外占用内存,建议使用
#define LED_PIN 2

/* main() 是程序开始执行的地方
多行注释 */
int main()  // 主函数,主函数必须是int类型,返回0代表正常结束
{
    cout << "Hello World"; // 输出 Hello World
    cout << "嗨\n"
         << "你好"
         << "呀" << endl; // 连续输出,并换行 \n和 endl都是换行

    int a = 10; // 整型变量a
    int b; // 声明整型变量b
    b = 5; // 更改b的值
    cout << a + b << endl; // 输出a+b的值

    double c = 3.14; // 双精度浮点型变量
    char d = 'A'; // 单个字符变量
    char e = 25; // ASCII码为25的字符
    string e2 = "这是字符串"; // 字符串变量
    cout << e2 << endl;
    bool f = true; // 布尔型变量
    // 定义多个变量
    int g = 1, h = 2, i = g + h;
    const int j = 10; // 常量

    // 运算 + - * / % ++ --
    int m = 10;
    cout << "--m输出是" << --m << endl;  // 先减1再输出,此时m=9,输出9
    cout << "m--输出是" << m-- << endl; // 先输出再减1,此时m=8,但是输出9

    // 赋值运算符 += -= *= /= %= 
    a += 10; // a = a + 10
    b -= 5; // b = b - 5

    // 逻辑运算符 && || !
    bool n = true, o = false;
    cout << (n && o) << endl; // 逻辑与,只有两个都为真时才为真
    cout << (n || o) << endl; // 逻辑或,只要有一个为真就为真
    cout << !n << endl; // 逻辑非,取反

    // 比较运算符 == != > < >= <=
    cout << (a == b) << endl; // 判断a是否等于b
    cout << (a != b) << endl; // 判断a是否不等于b
    cout << (a > b) << endl; // 判断a是否大于b
    cout << (a <= b) << endl; // 判断a是否小于等于b

    // 位运算符 & | ^ ~ << >>
    int p = 5, q = 10;
    cout << (p & q) << endl; // 与运算
    cout << (p | q) << endl; // 或运算
    cout << (p ^ q) << endl; // 异或运算
    cout << "5的二进制取反:" << (~p) << endl; // 取反运算
    cout << (p << 2) << endl; // 左移2位


    // sizeof运算符,返回变量类型的大小
    cout << "int的大小:" << sizeof(int) << endl;
    cout << "float的大小:" << sizeof(float) << endl;

    // 字符串拼接
    string u2 = "Hello", v2 = "World";
    cout << "字符串拼接:" << u2 + v2 << endl;
    // 字符串方法,长度,大小,查找,截取,下标
    cout << "字符串长度:" << u2.length() << endl; // 字符串长度
    cout << "字符串大小:" << u2.size() << endl; // 字符串大小
    cout << "查找字符e的位置:" << u2.find("e") << endl; // 查找字符e的位置,初始位置是0
    cout << "截取字符串:" << u2.substr(2, 3) << endl; // 截取字符串,从位置2开始,截取3个字符
    cout << "字符串下标:" << u2[0] << endl; // 字符串下标第一个字符,结果是H
    u2[0] = 'J'; // 修改字符串下标第一个字符,注意这里是单引号
    cout << "修改u2[0]后的u2:" << u2 << endl; // 字符串下标第一个字符,结果是Jello

    // 浮点数整数类型转换
    int u = 10;
    double v = 3.14;
    cout << int(v) << endl; // 浮点型转换为整型,只保留整数部分
    cout << double(u) << endl; // 整型转换为浮点型
     cout << (double)u << endl; //C语言风格的强制类型转换
    cout << (int)v << endl; // c语言风格的强制类型转换

    
    // 输入和输出
    float k; // 浮点型变量
    cout << "请输入一个浮点数:";
    cin >> k; // 读取输入并赋值给k
    cout << "你输入的值是" << k << endl;
    float l;
    l = k + a;
    cout << "你输入的值加上10等于" << l << endl; // 相加后它可能只显示整数部分

    // 数学库
    cout << max(5,6) << endl; // 返回两个数中的最大值
    cout << min(5,6) << endl; // 返回两个数中的最小值
    cout << sqrt(64) << endl; // 返回64的平方根
    cout << round(2.6) << endl; // 四舍五入
    cout << log(2) << endl; // 返回2的自然对数
    cout << pow(2,3) << endl; // 返回2的3次方
    cout << abs(-4.7) << endl; // 返回-4.7的绝对值
    cout << acos(0.5) << endl; // 返回0.5的反余弦值
    cout << asin(0.5) << endl; // 返回0.5的反正弦值
    cout << atan(0.5) << endl; // 返回0.5的反正切值
    cout << cos(60) << endl; // 返回60度的余弦值
    cout << sin(60) << endl; // 返回60度的正弦值
    cout << tan(60) << endl; // 返回60度的正切值
    cout << ceil(2.3) << endl; // 返回大于等于2.3的最小整数
    cout << floor(2.3) << endl; // 返回小于等于2.3的最大整数

    // 条件语句
    if (a > b) // 如果a大于b
    {
        cout << "a大于b" << endl;
    }
    else if (a == b) // 如果a等于b
    {
        cout << "a等于b" << endl;
    }
    else // 其他情况
    {
        cout << "a小于b" << endl;
    } // 所有的{}后面都没有;分号
 
    // switch语句
    switch (a) {
        case 1:
            cout << "a的值是1" << endl;
            break;
        case 2:
            cout << "a的值是2" << endl;
            break;
        case 3:
            cout << "a的值是3" << endl;
            break;
        default:
            cout << "a的值不是1, 2或3" << endl;
            break;
    }

    // 条件运算符 (三目运算) ?:
    int r = 10, s = 20;
    int t = (r > s) ? r : s; // 如果r大于s,则t=r,否则t=s

    // 循环
    for (int x = 0; x < 5; x++) // for循环,第一个是初始化,第二个是条件,第三个是增量
    {
        cout << x << endl;
        if (x == 3) // 如果x等于3,跳出循环
        {
            break;
        }

        if (x == 1) // 如果x等于1,跳过本次循环
        {
            continue;
        }
    }

    int y = 0;
    while (y < 5) // while循环,先判断条件再执行
    {
        cout << y << endl;
        y++;
    }

    int z = 0;
    do // do while循环,先执行再判断条件
    {
        cout << z << endl;
        z++;
    } while (z < 5); // 注意:do while 最后加;分号

    
    int arr[5] = {1, 2, 3, 4, 5}; // 定义一个固定长度的数组
    // 遍历数组
    for (int i = 0; i < 5; i++)
    {
        cout << arr[i] << endl;
    }

    // 定义一个非固定长的数组
    string arr2[] = {"apple", "banana", "cherry"};
    
    // 指针
    int *ptr = &a; // 定义一个指向a的指针
    cout << "a的值是" << a << endl;
    cout << "a的地址是" << &a << endl; // &是取地址符
    cout << "ptr的值是" << ptr << endl; // 值是a的地址
    cout << "ptr的地址是" << &ptr << endl; 
    cout << "ptr指向的值是" << *ptr << endl; // *是取指针的值,结果是a的值
    classTest(); // 调用函数
    fileTest(); // 调用函数
    return 0; // 返回值
}

// 函数

// 无返回值的函数
void printStr(string text = "这是一个默认值") // 指定默认值
{
    cout << text << endl; // 输出text
}


// 定义一个函数,返回值是int类型
int add(int x, int y)
{   
    printStr("这是一个函数"); // 调用print函数
    return x + y; // 返回x+y的值
}


// 函数重载,函数名相同,参数不同,会根据参数的不同来调用不同的函数
int add(int x, int y, int z) // 函数名相同,参数不同
{   
    add(1, 2); // 调用add函数,因为函数出现在main函数前面,所以不需要再声明
    return x + y + z;
}


// 类是对象的模板,对象是类的实例,类是用户自定义的数据类型,类的成员包括属性和方法,类的访问修饰符有public, private, protected
// 类的声明有分号;
// 声明一个类
class MyClass // 定义一个类
{   int a; // 默认是private,只能在类的内部访问
    public: // 访问修饰符,public表示公共的,可以在类的外部访问
        int myNum; // 类的属性
        string myString; // 类的属性
        void myMethod(string str = "Lee") // 类的方法
        {
            cout << "Hello "+str << endl;
        }
        
    private: // private表示私有的,只能在类的内部访问
        int b;
    
    protected: // protected表示受保护的,只能在类的内部和子类的内部中访问,无法被对象访问
        int myProtectedNum = 10; // 受保护的属性
};

// 再创建一个类
class MyClass2 // 定义一个类
{
    public:
        MyClass2(int x) // 构造函数,创建对象时自动调用,没有返回值,函数名和类名相同,如果构造函数有参数,创建对象时需要传递参数
        {
            cout << "对象已创建" << x << endl;
        }
        ~MyClass2() // 析构函数,对象销毁时自动调用
        {
            cout << "对象已销毁" << endl;
        }
    
};


// 继承
class MyOtherClass: public MyClass // 继承MyClass
{
    public:
        string myOtherString = "新的属性"; // 子类自己的属性
        void myOtherMethod() // 子类自己的方法
        {
            cout << "访问父类保护属性" << myProtectedNum << endl;
        }

};

// 多继承
class MyOtherClass2: public MyClass, public MyClass2 { // 继承MyClass和MyClass2
};



// 函数中引用类
void classTest()
{
    MyClass myObj; // 创建一个对象
    
    myObj.myNum = 15; // 给对象的属性赋值
    myObj.myString = "Some text"; // 给对象的属性赋值
    cout << myObj.myNum << endl; // 输出对象的属性
    cout << myObj.myString << endl; // 输出对象的属性
    myObj.myMethod("Ken"); // 调用对象的方法
    // cout << myObj.myProtectedNum << endl; // 输出受保护的属性,这里会出错,因为是受保护的属性,只能在类的内部和子类中访问

}


// 多态,字类可以重写父类的方法
class Animal // 定义一个类
{
    public:
        virtual void animalSound() // 虚函数
        {
            cout << "动物发出声音" << endl;
        }
};

class Pig: public Animal // 继承Animal
{
    public:
        void animalSound() // 重写父类的方法
        {
            cout << "猪发出声音" << endl;
        }
};

class Dog: public Animal // 继承Animal
{
    public:
        void animalSound() // 重写父类的方法
        {
            cout << "狗发出声音" << endl;
        }
};

// 多态引用类,多态是指父类的指针可以指向子类的对象
void polymorphism()
{
    Animal myAnimal;
    Pig myPig;
    Dog myDog;
    myAnimal.animalSound(); // 调用父类的方法,输出"动物发出声音"
    myPig.animalSound(); // 调用子类的方法,输出"猪发出声音"
    myDog.animalSound(); // 调用子类的方法,输出"狗发出声音"
}

// 文件读写
void fileTest()
{   
    // 写
    ofstream MyFile("test.txt"); // 创建一个文件对象
    MyFile << "写入文件" << endl; // 写入文件
    MyFile.close(); // 关闭文件

    // 读
    ifstream MyFile2("test.txt"); // 创建一个文件对象
    string text;
    while (getline(MyFile2, text)) // 读取文件
    {
        cout << "读取到的文件内容:"+text << endl; // 输出文件内容
    }
    MyFile2.close(); // 关闭文件
}

// 异常处理
void exceptionTest()
{
    try // 尝试执行代码
    {
        int age = 15;
        if (age >= 18) // 如果年龄大于等于18
        {
            cout << "你已经成年" << endl;
        }
        else // 如果年龄小于18
        {
            throw(age); // 抛出异常
        }
    }
    catch(int myNum) // 捕获异常
    {
        cout << "你还未成年,你的年龄是" << myNum << endl;
    }

    // 捕获所有异常
    try
    {
        int age = 15;
        if (age >= 18)
        {
            cout << "你已经成年" << endl;
        }
        else
        {
            throw "你还未成年"; // 抛出异常
        }
    }
    catch(...) // 捕获所有异常
    {
        cout << "发生了异常" << endl;
    }
}


输入输出

cout 输出
cin 输入

g++ helloworld.cpp //简单编译
g++ helloworld.cpp -o helloworld //编译为指定名称
g++ -Wunused-variable main.cpp -o main //编译某个文件,并检查未使用变量

不同数据类型在内存中的存放

整型(int、short、long):通常使用补码表示。补码的最高位用于表示符号(0 为正,1 为负)。
浮点型(float、double):遵循 IEEE 754 标准,包括符号位、指数部分和尾数部分,不使用补码。
字符型(char):通常是无符号整数,表示单个字符,存储 ASCII 或 Unicode 编码。

数据对齐
数据在内存中通常会按照特定的对齐规则进行存储,以提高访问效率。例如,int 可能会在 4 字节边界上对齐,而 double 可能会在 8 字节边界上对齐。

位运算

位运算就是将对象先转为二进制,直接偏移它们的位
// 位运算符 & | ^ ~ << >>

十进制对应二进制
10001
20010
30011
40100
50101
60110
70111
81000
91001
101010
c++
int a = 5;  // 二进制:0101
int b = 3;  // 二进制:0011
// 位与 取两个都相同的1,才算1
std::cout << "a & b: " << (a & b) << std::endl; // 结果:1 (0001)
// 位或 只要有一个是1,则都算1
std::cout << "a | b: " << (a | b) << std::endl; // 结果:7 (0111)
// 位异或 不相同算1,相同则算0
std::cout << "a ^ b: " << (a ^ b) << std::endl; // 结果:6 (0110)
// 位反 取相反的位
std::cout << "~a: " << (~a) << std::endl;       // 结果:-6 (二进制补码表示)
// 左移1位,所有在二进制后再添加一个0,相当于值*2
std::cout << "a << 1: " << (a << 1) << std::endl; // 结果:10 (1010)
// 右移1位,相当于删除二进制后删除了一个数,十进制2,3 右移一位都是十进制的1,相当于除以2取整
std::cout << "a >> 1: " << (a >> 1) << std::endl; // 结果:2 (0010)