初面网初面网

C++基础

基本变量类型

  • 整形

整形有四种定义:

short a = 10;
int b = 10;
long c = 10;
long long d = 10;

// 也可以用下面的形式声明
// 用花括号包裹变量是C++11开始允许的
int _age{10}, _name = {"Tom"};

声明与定义的区别:

int b; // 这个是声明

int b = 10; // 这个是定义

虽然都可以表示10这个数值,但是它们占用的内存空间大小,以及最大、最小值是不同的。

类型占用字节取值范围
short2-2^15~2^15-1
int4-2^31~2^31-1
long8-2^63~2^63-1
long long8-2^63~2^63-1

想知道类型大小可以使用sizeof关键字。例如:sizeof(int);

  • 浮点型

  • 字符型

字符型变量创建需要使用单引号

ASCII编码要记住两个:a-97; A-65

如下语句可以查看ASCII码

cout<< (int)a<<endl;
类型占用字节取值范围
char12^1

  • 字符串型

如下语句可以定义字符串:

char str1[] = "hello";  // 变量名后要有中括号,等号后要用双引号

- 布尔

布尔,又叫bool类型,它只有两个值

true1
false0

运算符

  • 加减乘除
int a = 9;
int b = 2;

cout << a + b;
cout << a - b;
cout << a * b;
cout << a / b;        // 注意除数不可以为 0 !!!
cout << a % b;        // 取模,即取余数。小数不可做取模运算
  • 递增递减
int a = 1;

cout << a++;    // 输出1
cout << ++a;    // 输出2
cout << a--;    // 输出1
cout << --a;    // 输出0
  • 赋值运算符
// =,以及   符号=   如:

int a = 2;
a += 1;     // 等同于  a = a + 1;
a -= 1;     // 等同于  a = a - 1;
a *= 1;     // 等同于  a = a * 1;
a /= 1;     // 等同于  a = a / 1;
a %= 1;     // 等同于  a = a % 1;
  • 比较运算符
// 用于比较,并返回一个真值或假值

int a = 2;
int b = 199;

cout << (a > b) << endl;    // 假,返回0
cout << (a < b) << endl;    // 真,返回1
cout << (a >= b) << endl;   // 返回0
cout << (a <= b) << endl;   // 返回1
cout << (a != b) << endl;   // 返回1
cout << (a == b) << endl;    // 返回0
  • 逻辑运算符
// 用于根据表达式的值返回真值或假值

int a = 0;
int b = -1;

cout << !a << endl;         // a真则取假,a假则取真
cout << (a && b) << endl;     // a、b同时为真才为真,否则为假
cout << (a || b) << endl;     // a或b有真就真,都假才假
  • 三目运算符
int a = 2;
int b = 3;
int c = a>b?a:b;        // 如果a大于b则返回a,否则返回b

流程结构

任何程序语言必然包含三种流程结构:顺序结构,选择结构,循环结构。

  • 顺序结构,即代码逐行执行,没有任何跳转
  • 选择结构,即代码视条件是否满足选择性地执行
  • 循环结构,即代码视情况反复执行

着重介绍选择结构和循环结构。

选择结构

选择结构需要使用判断语句来实现。判断语句分为if判断语句和switch判断语句。 判断语句以if为主干,分成单条件情况和多条件情况。

if...else... 该语句用于处理单条件情况

if...else if... 该语句用于处理多条件情况

int a;
cout << "请输入a的值:" << endl;
cin >> a;
// 可以没有else
if( a > 2 ){
    cout << "a是大于2的" << endl;
}

// 单条件情况
if( a > 2 ){
    cout << "a是大于2的" << endl;
}else{                              // else后没有小括号
    cout << "a是小于等于2的" << endl;
}

// 多条件情况
if (a <= 2) {
    cout << "a是小于等于2的" << endl;
}else if(a > 2 && a < 4){                       // else if 后需要小括号
    cout << "a是大于2小于4的" << endl;
}else{
    cout << "a是大于等于4的" << endl;
}

switch判断语句可以视为方便的多条件判断语句,不用频繁写if...else if...结构。

int a;

cout << "请输入a的值:" << endl;
cin>>a;

switch(a){
    case 0:
        cout << "a是0" << endl;
        break;
    case 1:
        cout << "a是1" << endl;
        break;
    case 2:
        cout << "a是2" << endl;
        break;
    default:
        cout << "a是其他值" << endl;
        break;
}
/*
switch 小括号里需要判断的必须是个具体的值(数字、字符、字符串)
break 代表退出当前 switch 判断结构。不写 break 意味着继续执行下一个判断
default 代表所有条件都不满足的情况
*/

循环结构

循环结构有三种,for、while、do while 循环结构控制语句有三种:break、continue、goto(不建议使用)

// while循环结构——演示
int i = 0;
while(i<10){        // 一定注意不要写死循环,即判断条件永远为真
    i++;

    if(i==5){       
        break;      // 意味着当i等于5的时候跳出while循环
    }
}

cout << i << endl;

/* 
可以尝试去掉if结构再运行
while(i<10){        // 一定注意不要写死循环,即判断条件永远为真
    i++;

    if(i==5){       
        break;      // 意味着当i等于5的时候跳出while循环
    }
}
*/

// do-while循环结构——演示
int i = 0;
do{
    i++;
    cout << i << endl;
}while(i<10);

// do-while循环结构——演示
int i = 0;
int b = 0;
for(int i = 0;i<10;i++){        // 注意这里的i与外面的i是不同的
    b++;
    if(i==5){
        continue;               // 由于这句的存在,循环体会跳过后面的代码,所以b会少输出一个数
    }
    cout << b << endl;
}
cout << i << endl;

// for循环的结构内相当于一个新的区域

数组

// 一维数组
// 定义方法:
// 1. 数据类型 数组名[数组长度];
// 2. 数据类型 数组名[数组长度] = { 值1,值2, ...};
// 3. 数据类型 数组名[] = { 值1, 值2, ...};

int arr1[5];                        // 数组元素下标从0开始,数组值默认为0
int arr2[5] = { 1,2,3,4,5};
char arr3[] = {'a','b','c'};

// 修改\添加
arr3[0] = 'b';         // 修改
arr3[3] = 'd';           // 添加

cout << arr3[0] << endl;
cout << arr3[3] << endl;

// 二维数组

// 定义方法:
/*
1. 数据类型 数组名[行数][列数];
2. 数据类型 数组名[行数][列数] = { {值1,值2},{值3,值4}, ...};
3. 数据类型 数组名[行数][列数] = { 值1,值2, ...};
4. 数据类型 数组名[][列数] = { 值1, 值2, ...};

花括号内部不分成更多组花括号的话,系统会自动推测长度,从而匹配各个下标对应的值
*/

int arr1[2][2];                        // 两行两列,总共能存4个值
char arr2[2][3] = {'a','b','c','d','e','f'};

cout << arr2[0][2] << endl;
cout << arr2[1][2] << endl;

函数

/*
返回值类型 函数名(参数列表){
    函数体
}

注意,函数里不可以定义函数,但可以声明
*/

int add(int, int);      // 函数声明时参数名不重要,类型重要
int add(){      // 定义函数时,参数要写清类型
   return a+b; 
}

add(1,2);       // 调用函数,参数不用写类型

/*
如果有返回值,则要写对应的返回值类型。如果没有,返回值类型要写void
如果void,则没必要写return
*/

函数内容全部写在一处,修改和理解起来都很困难,所以最好是分多个文件去写。(基础篇中先介绍最简单的,后续的篇章中再涉及更复杂的分法)

// xxx.h    创建一个.h文件(头文件),用于声明变量和函数
// learncpp.h
void add(int a);

// learncpp.cpp
#include "learncpp.h"       // 非官方提供的,都需要通过双引号引用
void add(int a){
    cout << a+1 << endl;
}

指针

指针用于间接访问内存。32位操作系统下占用4个字节的内存空间,64位操作系统下占用8个字节。

Tips: 计算机有两个区域存储变量,一个叫栈,一个叫堆。一般的变量会直接在栈中存储,而有些变量则会存储到堆中(暂时可以不关心哪些存在栈中,哪些存在堆中)。当计算机想要寻获存在堆区域的某一些变量的时候,会首先访问存储地址,然后根据地址再进一步查找。

Tips2: 如果不理解上面这段,可以先把内存假想成一个超巨大的旅馆,变量是旅客,“变量存储”就是旅客住进旅店。当想要找到旅客时,只需要旅客所在的房间号即可。

int a = 100;
int* b = &a;        // 通过  类型* 变量名这种方式声明一个指针变量,然后使用 &符号,获取a的内存地址值
// 指针变量,存的是地址值,切记切记!

cout << b << endl;      // 会输出地址值。地址值是十六进制存储的
cout << *b << endl;     // 会输出地址里存储的值,也就是输出"旅客"

// 这里最大的问题是会记混。多书写几次记牢即可。要能够熟练写出:
// 1. 指针变量的声明和定义
// 2. 如何获取变量地址
// 3. 如何获取地址里存放的值

指针也有空指针、野指针。

  • 空指针,即指针变量指向编号为0的空间,用于初始化指针变量。该内存是不可访问的(0~255是系统占用的、不可访问的内存空间)
  • 野指针,指针变量指向非法的内存空间
int* p = NULL;  // 指向NULL,定义空指针

int* n = (int*)0x1100;  // 假设0x1100是一块已开辟空间,当前操作会指向该空间,但实际上不应该随意将指针指向当前空间,赋予其操作权限

const修饰 指针,称为 常量指针。常量指针的指向可改,但是指向地址内的值不可改

const修饰 变量,该变量类型为指针,则它被称为 指针常量。这种情况下,指针指向不可改,值可改

实际上,指针、变量都可以被const修饰。此时,指向和值都不可以改。

int a = 10;
int b = 100;
const int* p = &a;

*p = 20;    // 该句会有错误提示,因为它是一个常量指针,值不可更改
p = &b;

// ------------------------------------------

int* const n = &a;
*n = 10;
n = &b;    // 该句会有错误提示,因为它是一个指针常量,指向不可更改

// ------------------------------------------

int* const k = &a;
*k = 10;
k = &b;    // 都会有错误提示,指向和值都不可更改

指针和数组

int arr[3] = {0,1,2};
int* p = arr;   // 数组名即数组首地址
cout << *p << endl;
p++;
cout << *p << endl;
p++;  
cout << *p << endl;
p++;
cout << *p << endl;   // 该行是多写的。可以运行看一下是什么情况

// 最后一个输出超出了数组的内存空间
// 使用指针,可以快捷访问类似数组这样按顺序存储的数据结构

指针和函数

void swap(int* a,int* b){
    int temp = *a;
    *a = *b;
    *b = temp;

}

// 下面这些写在main函数里
int a = 10;
int b = 100;

swap(&a,&b);

cout << a << endl;
cout << b << endl;

// a和b的值被互换了

结构体

结构体是用户自定义数据类型,允许用户将不同数据类型组合成一个数据类型。

// 创建方式
//struct 结构体名 { 结构体成员列表 };

struct Student {
    string name;
    int age;
};

// 创建结构体变量
// struct 结构体名 变量名;
// struct 结构体名 变量名 = { 值1,值2,...};
struct Student student;
struct Student student = { "tony",16 };

// struct 结构体名 {} 变量名;
// 这种方式可以同时创建与声明变量。推荐使用上面两种。
struct People {
    string name;
    string gender;
} people;

// 声明变量之后可以为其中的内容赋值
people.name = "张三";
people.gender = "";

cout << people.name << endl;
cout << people.gender << endl;

结构体数组

// 定义方式
// struct 结构体名 数组名[元素个数] = {{}, {}, {}};
struct Student student[2] = {
    {"tony",16},
    {"tom",18}
};
cout << student[1].name << endl;

// struct 结构体名 {} 变量名[];     方括号内可以给定数组长度,也可不给。
struct People {
    string name;
    string gender;
} people[];

结构体指针

通过指针访问结构体中的成员。访问符号是->(结构体后打'.',当语句完成时系统会自动帮忙转换)。

结构体可以嵌套。

struct People {
    string name;
    string gender;
} people;

people.name = "张三";
people.gender = "";

People* p = &people;
cout << p->name << endl;

传址调用结构体

struct People {
    string name;
    string gender;
};

void printStructures(People* p) {
    p->name = "冬青";
}

int main() {
    struct People p = { "张三", "" };

    printStructures(&p);
    cout << p.name << endl;

	system("pause");

    return 0;
}

// 使用指针的原因如下:
/*
1. 函数中使用传值,会将整个值复制进内存,也就是当值的长度超长时,也不得不传递一个超长的值。如果使用指针,以传址方式传递,那么32位系统只需传递4字节,64位系统只需传递8字节,大大节省内存空间
*/

更新于 2025/2/26