C++自学笔记(基础入门篇)

using namespace std

在C++中,`cout` 是 `std::cout` 的一个实例,它属于标准命名空间 `std` 中的 `ostream` 类。命名空间提供了一种逻辑上将相关的名称组织在一起的方式,以避免命名冲突。

使用 `using namespace std;` 语句可以简化代码,使得您可以在不使用 `std::` 前缀的情况下直接使用 `cout`、`cin`、`endl` 等标准库中的名称。这样做的目的是为了减少编写代码时的冗余,并提高可读性。

如果没有使用 `using namespace std;`,那么您需要在使用标准库的成员时加上 `std::` 前缀,比如 `std::cout`、`std::endl`,以明确指定所使用的成员来自于 `std` 命名空间。

但需要注意的是,过度使用 `using namespace std;` 可能导致命名冲突和代码可读性的降低。所以,在大型项目或与其他库有命名冲突的情况下,最好是仅在需要的地方使用 `std::` 前缀,而不是全局使用 `using namespace std;`。

system("pause");

system("pause"); 是一个在Windows系统中常见的用法,它用于在程序执行结束后暂停控制台窗口的运行,以便查看程序的输出结果。在其他操作系统(如Linux和Mac)中,可能不需要使用此语句。

具体地说,system("pause"); 调用了操作系统的命令行解释器来执行命令 "pause",这个命令会使控制台窗口暂停,直到用户按下任意键才会继续执行或关闭窗口。

在C++程序中使用 system("pause"); 通常用于调试目的,因为它可以防止程序运行结束后立即关闭控制台窗口,从而方便查看程序输出的信息。

然而,需要注意的是,在正式的生产代码中,推荐使用更加可靠和跨平台的方法来实现暂停控制台的功能,而不是依赖于系统调用。例如,可以使用特定的库函数或自定义的等待输入的代码来替代 system("pause");

字符串类型

作用:用于表示一串字符
两种风格
C风格字符串: char 变量名[] = "字符串值"
注意:C风格的字符串要用双引号括起来


C++风格字符串: string 变量名 = "字符串值"
注意:C++风格字符串,需要加入头文件 #include <string> 没有写using namespace std时要用std::string name = "xxx";

    char str1[]="c style";

    string str2="c++ style";

    cout << str1 << endl;

    cout << str2 << endl;

输入和输出io

在VSC中run code 不能进行输入,需要运行C/C++文件 中的g++运行,g++运行c++, gcc运行c

    int input;//有无初始化都可以正常运行

    cout << "input an integer:" << endl;

    cin >> input;

    cout << "input =" << input << endl;

若输入的是小数 例如1.56,其结果为1

若输入的是字符或者字符串, 其结果为0

算术运算符

1、除数不能为0

2、两小数可以相除,不可以取模

3、只有整型变量可以进行取模运算,取模运算时,除数也不能为0

4、前置递增先对变量进行++,再计算表达式,后置递增相反

//区别
//前置递增先对变量进行++,再计算表达式
int a2 = 10;
int b2 = ++a2 * 10;
cout << b2 << endl;        //result 110
//后置递增先计算表达式,后对变量进行++
int a3 = 10;
int b3 = a3++ * 10;
cout << b3 << endl;         //result 100

数组

所谓数组,就是一个集合,里面存放了相同类型的数据元素
特点1:数组中的每个==数据元素都是相同的数据类型==
特点2:数组是由==连续的内存==位置组成的

一维数组定义的三种方式:


1. 数据类型 数组名[ 数组长度 ];
2. 数据类型 数组名[ 数组长度 ] = { 值1,值2 ...};
3. 数据类型 数组名[ ] = { 值1,值2 ...};

注意

//第二种定义方式
//数据类型 数组名[元素个数] = {值1,值2 ,值3 ...};
//如果{}内不足10个数据,剩余数据用0补全

一维数组名称的用途:


1. 可以统计整个数组在内存中的长度
2. 可以获取数组在内存中的首地址

最好转换成16进制来表示,需要先导入 #include <iomanip> 再用hex

或者把它改成void指针,

若改成int会报错,因为一般指针的大小都比int能存的大小要大,加上精度不同,程序会报错

        //#include <iomanip>

   

    //1、可以获取整个数组占用内存空间大小

    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

    cout << "整个数组所占内存空间为: " << sizeof(arr) << endl;

    cout << "每个元素所占内存空间为: " << sizeof(arr[0]) << endl;

    cout << "数组的元素个数为: " << sizeof(arr) / sizeof(arr[0]) << endl;

    //2、可以通过数组名获取到数组首地址

    cout << "数组首地址为: " << static_cast<void*>(arr) << endl;

    cout << "数组中第一个元素地址为: " << hex << &arr[0] << endl;

    cout << "数组中第二个元素地址为: " << &arr[1] << endl;

    //arr = 100; 错误,数组名是常量,因此不可以赋值

    //system("pause");

/*

整个数组所占内存空间为: 40

每个元素所占内存空间为: 4

数组的元素个数为: 10

数组首地址为: 0x61fd50

数组中第一个元素地址为: 0x61fd50

数组中第二个元素地址为: 0x61fd54

*/

二维数组


二维数组定义的四种方式:


1. 数据类型 数组名[ 行数 ][ 列数 ];
2. 数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2 } ,{数据3,数据4 } };
3. 数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4};
4. 数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4};
建议:以上4种定义方式,利用==第二种更加直观,提高代码的可读性==


示例:
```C++ int main() {


方式1


//数组类型 数组名 [行数][列数]
int arr[2][3];
arr[0][0] = 1;
arr[0][1] = 2;
arr[0][2] = 3;
arr[1][0] = 4;
arr[1][1] = 5;
arr[1][2] = 6;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{cout << arr[i][j] << " ";
}
cout << endl;
}


方式2


//数据类型 数组名[行数][列数] = { {数据1,数据2 } ,{数据3,数据4 } };
int arr2[2][3] =
{
{1,2,3},
{4,5,6}
};


方式3


//数据类型 数组名[行数][列数] = { 数据1,数据2 ,数据3,数据4 };
int arr3[2][3] = { 1,2,3,4,5,6 };


方式4


//数据类型 数组名[][列数] = { 数据1,数据2 ,数据3,数据4 };
int arr4[][3] = { 1,2,3,4,5,6 };
system("pause");
return 0;
} ```


总结:在定义二维数组时,如果初始化了数据,可以省略行数

 二维数组数组名


查看二维数组所占内存空间
获取二维数组首地址
示例:
```C++ int main() {

//二维数组数组名

    int arr1[2][3] =

    {

    {1,2,3},

    {4,5,6}

    };

    cout << "二维数组大小: " << sizeof(arr1) << endl;

    cout << "二维数组一行大小: " << sizeof(arr1[0]) << endl;

    cout << "二维数组元素大小: " << sizeof(arr1[0][0]) << endl;

    cout << "二维数组行数: " << sizeof(arr1) / sizeof(arr1[0]) << endl;

    cout << "二维数组列数: " << sizeof(arr1[0]) / sizeof(arr1[0][0]) << endl;

    //地址

    cout << "二维数组首地址:" << hex << arr1 << endl;

    cout << "二维数组第一行地址:" << hex << arr1[0] << endl;

    cout << "二维数组第二行地址:" << hex << arr1[1] << endl;

    cout << "二维数组第一个元素地址:" << hex << &arr1[0][0] << endl;

    cout << "二维数组第二个元素地址:" << hex << &arr1[0][1] << endl;

} ```

输出

二维数组大小: 18

二维数组一行大小: c

二维数组元素大小: 4

二维数组行数: 2

二维数组列数: 3

二维数组首地址:0x61fd30

二维数组第一行地址:0x61fd30

二维数组第二行地址:0x61fd3c

二维数组第一个元素地址:0x61fd30

二维数组第二个元素地址:0x61fd34

总结


总结1:二维数组名就是这个数组的首地址
总结2:对二维数组名进行sizeof时,可以获取整个二维数组占用的内存空间大小

函数

值传递


所谓值传递,就是函数调用时实参将数值传入给形参
值传递时,==如果形参发生,并不会影响实参==

指针

指针所占内存空间

 int a = 10;

    int * p;

    p = &a; //指针指向数据a的地址

    cout << *p << endl; //* 解引用         10

    cout << sizeof(p) << endl;        8

    cout << sizeof(char *) << endl;        8

    cout << sizeof(float *) << endl;        8

    cout << sizeof(double *) << endl;        8

空指针和野指针

在C++中,空指针和野指针是两种不同的指针概念。

空指针(Null Pointer): 空指针表示指针不指向任何有效的内存地址。在C++中,可以使用字面值 nullptr 来表示空指针。空指针通常用于初始化指针变量,或者在需要判断指针是否为空时使用。例如:

int* ptr = nullptr; // 初始化为空指针

if (ptr == nullptr) { // 指针为空 }

野指针(Dangling Pointer): 野指针指向的内存地址是无效的、未定义的或已释放的。在使用野指针之前,需要确保其指向的内存是有效的。否则,访问野指针可能会导致程序崩溃或产生未定义行为。野指针通常是由于对已释放的内存进行访问或者忘记初始化指针而产生的。为避免出现野指针,应始终将指针初始化为 nullptr 或有效的内存地址,并在释放内存后将指针设置为 nullptrs

int* ptr; // 这是一个未初始化的野指针 // 分配一块内存并将其地址赋给指针

ptr = new int;

*ptr = 10; // 使用指针后,应当释放内存并将指针置为空

delete ptr;

ptr = nullptr;

const修饰指针

const修饰指针有三种情况


1. const修饰指针 --- 常量指针
2. const修饰常量 --- 指针常量
3. const即修饰指针,又修饰常量

int a = 10;
int b = 10;


//const修饰的是指针,指针指向可以改,指针指向的值不可以更改
const int * p1 = &a;
p1 = &b; //正确
//*p1 = 100; 报错


//const修饰的是常量,指针指向不可以改,指针指向的值可以更改
int * const p2 = &a;
//p2 = &b; //错误
*p2 = 100; //正确


//const既修饰指针又修饰常量
const int * const p3 = &a;
//p3 = &b; //错误
//*p3 = 100; //错误

技巧

看const右侧紧跟着的是指针还是常量, 是指针就是常量指针,是常量就是指针常量

当数组名传入到函数作为参数时,被退化为指向首元素的指针

结构体(大体上和c一样)

定义

在C++中,有三种常用的方法来定义结构体。

直接定义结构体变量:
这是最简单的方法,直接在需要使用结构体的地方定义结构体变量。例如:


struct Person {
    std::string name;
    int age;
};

int main() {
    Person p1; // 直接定义结构体变量
    p1.name = "Alice";
    p1.age = 20;

    return 0;
}
在这个例子中,我们在 main 函数内部直接定义了一个名为 p1 的结构体变量,并对其进行初始化和赋值。

使用 typedef 定义结构体别名:
使用 typedef 可以为结构体类型定义一个新的别名,使其更方便使用。例如:


typedef struct {
    std::string name;
    int age;
} Person;

int main() {
    Person p1; // 使用结构体别名定义变量
    p1.name = "Bob";
    p1.age = 25;

    return 0;
}
在这个例子中,我们使用 typedef 将结构体定义与别名 Person 关联起来。然后我们可以使用别名 Person 来定义结构体变量。

使用 struct 关键字定义结构体类型:
可以使用 struct 关键字定义结构体类型,并在需要使用结构体的地方声明结构体变量。例如:


struct Person {
    std::string name;
    int age;
};

int main() {
    struct Person p1; // 使用结构体类型定义变量
    p1.name = "Charlie";
    p1.age = 30;

    return 0;
}
在这个例子中,我们使用 struct 关键字定义了一个名为 Person 的结构体类型,并在 main 函数中声明了一个结构体变量 p1
结构体指针
在C++中,您可以使用指针来引用结构体对象或者动态分配结构体对象。以下是关于结构体指针的基本用法:

引用结构体对象的指针:
可以通过使用 . 运算符或者 -> 运算符来引用结构体对象的成员。下面是一个示例:


struct Person {
    std::string name;
    int age;
};

int main() {
    Person p1;
    p1.name = "Alice";
    p1.age = 20;

    Person* ptr = &p1;  // 获取结构体对象的地址

    std::cout << "Name: " << ptr->name << std::endl;
    std::cout << "Age: " << ptr->age << std::endl;

    return 0;
}
在这个例子中,我们首先创建了一个名为 p1 的 Person 类型的结构体对象,并对其成员进行赋值。
然后,通过将结构体对象的地址赋给指针 ptr,
我们可以使用 -> 运算符来访问指针指向的结构体对象的成员。

动态分配结构体对象的指针:
使用 new 运算符可以在堆上动态地分配结构体对象,并返回指向该对象的指针。下面是一个示例:

struct Person {
    std::string name;
    int age;
};

int main() {
    Person* ptr = new Person;  // 动态分配结构体对象

    ptr->name = "Bob";
    ptr->age = 25;

    std::cout << "Name: " << ptr->name << std::endl;
    std::cout << "Age: " << ptr->age << std::endl;

    delete ptr;  // 删除动态分配的结构体对象

    return 0;
}
在这个例子中,我们使用 new 运算符在堆上动态地分配了一个 Person 类型的结构体对象,
并将返回的指针赋给 ptr。
然后,我们通过 -> 运算符访问结构体对象的成员。
最后,别忘了使用 delete 关键字释放通过 new 分配的内存空间。

使用结构体指针可以方便地操作结构体对象,允许动态分配和管理内存。但要注意,在使用指针访问结构体对象的成员之前,应确保指针指向有效的结构体对象,并在不需要时正确释放相关的内存空间。
const修饰结构体
在C++中,您可以使用 const 修饰符来创建常量结构体。
通过将 const 关键字放在结构体定义前面,可以确保定义的结构体对象是不可修改的常量。
以下是一个示例:

cpp
struct Point {
    int x;
    int y;
};

const struct Point p = {1, 2}; // 常量结构体对象

int main() {
    // 以下代码会导致编译错误,因为p是常量,不能被修改
    // p.x = 3;
    // p.y = 4;

    std::cout << "Point: (" << p.x << ", " << p.y << ")" << std::endl;

    return 0;
}
在这个示例中,我们使用 const 关键字将结构体对象 p 声明为常量。
这意味着一旦 p 对象被初始化,它的值就不能被修改。

由于 p 是常量结构体对象,所以在 main 函数中对它的成员进行赋值操作会导致编译错误。
只能通过读取 p 的成员来访问它的值。

声明常量结构体对象可以确保结构体对象在创建后不会被修改,
从而提供了更强的程序安全性和可靠性。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值