1. 変数
1バイト | 2バイト | 4バイト | 8バイト |
文字 | 短い | 整数 |
長い (linux64 ビット) |
浮く | 長い長い | ||
ロング(win/linux32位) | ダブル |
スイッチ (整数または文字のみ) {}
0 ~ 99 の乱数を生成します: rand()%100;
//随机数种子生成随机数每次不同:
#include <ctime>
srand((unsigned int)time(NULL));
-
水仙数: 3 桁の数の各 3 桁の累乗の合計がそれ自体に等しい
-
ジャンプステートメント
-
Break: ループ全体を終了します
-
continue: 次のステートメントをスキップして、次のループを実行します。
-
goto (純粋な大文字の後): 無条件ジャンプ
-
2. 配列
2.1. 1次元配列
配列の末尾の添字: sizeof(arr)/sizeof(arr[0]-1)
//冒泡
int arr[9] = {5,8,2,3,4,1,6,2,7};
//总共排列的轮数
for(int i = 0 ; i < 9 - 1 ; i++)
{
//总共排列的次数
for(int j = 0 ; j < 9 - i - 1 ; j++)
{
if(arr[j]<arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for(int i = 0 ; i < 9 ; i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
2.2. 二次元配列
2 次元配列を定義するには 4 つの方法があります。
1. データ型配列名 [行数] [列数];
2. (推奨)データ型配列名 [行番号] [列番号] =
{
//直観的には 2 行 2 列です
{ データ 1, データ 2 },
{ データ 3、データ 4 }
};
3. データ型配列名 [行数] [列数] = { データ 1, データ 2, データ 3, データ 4 };// 行数を列数に応じて自動分割
4. データ型配列名[ ][列数] = { データ 1, データ 2, データ 3, データ 4 };// 行数は列数に応じて自動的に分割されます
//计算二维数组的行数
sizeof(arr)/sizeof(arr[0])
//计算二维数组的列数
sizeof(arr[0])/sizeof(arr[0][0])
最初のアドレスにアクセスします: arr
最初の行の最初のアドレスにアクセスします: arr[0]
2 行目の最初のアドレスにアクセスします: arr[1]
最初の要素の最初のアドレスにアクセスします: & arr[0][0] // アドレス記号が必要です
//二维数组案例-考试成绩统计
#include <iostream>
using namespace std;
#include <string>
int main()
{
//1、列出成绩
int scores[3][3] =
{
{100,100,100},
{90,80,70},
{60,50,40}
};
string names[3] = {"张三","李四","狗五"};
//2、统计每人的总分
//控制行数
for(int i=0 ; i<3 ; i++)
{
int sum = 0;//统计分数总和变量
//控制列数
for(int j=0 ; j<3 ; j++)
{
sum += scores[i][j];
}
cout<<names[i]<<"的总分为:"<<sum<<endl;
}
return 0;
}
3. 機能
3.1. 関数の基本形式: 引数なしおよび反転なし、引数なしおよび反転なし、パラメータおよび反転なし、およびパラメータおよび反転
语法:
返回值类型 函数名 (参数列表)
{
声明和语句;
return x;
}
//若返回值类型为:void ,则最后写成 return;
3.2. 関数宣言は複数回記述できますが、定義は 1 回のみ記述できます。
3.3. 関数ファイルの書き込み
//1、在“头文件”新建.h后缀名的头文件
//2、在“源文件”新建.cpp后缀名的源文件
//3、在头文件中写函数的声明
#include <iostream>
using namespace std;
//写函数声明
//4、在源文件中写函数的定义
#include "函数名.h"
//写函数定义
4. ポインタ
4.1. ポインタの定義
int a = 10;
//定义指针:数据类型 * 指针变量名 或者 数据类型 * 指针变量名 = &地址变量名
int * p;
//引用:&放在一个变量声明或者是函数的形参声明前
//取地址:&放在一个已经定义的变量前
p = &a;
//两者打印结果一样
cout<<"a的地址为:"<<&a<<endl;
cout<<"指针p为:"<<p<<endl;
//指针前加 * 代表解引用,找到指针指向内存中的数据,即 a 的值
*p = 1000;
//两者打印结果一样
cout<<"a="<<a<<endl;
cout<<"*p="<<*p<<endl;
4.2. Null ポインタ (ポインタ変数はメモリ内の番号 0 の空間を指します)
//用途:初始化指针变量
int * p = NULL;
//注意:空指针指向的内存是不可以访问的
//0~255之间的内存编号是系统占用的,不可访问
*p = 100;//运行报错
4.3. ワイルドポインタ(ポインタ変数が不正なメモリ空間を指している)
//在程序中,尽量避免出现野指针
int * p = (int *)0x1100;//未声明就访问
cout<<*p<<endl;//报错
Null ポインタとワイルド ポインタは、当社が申請する領域ではないため、アクセスしないでください。
4.4. const はポインタまたは定数を変更します (原則: const の前にあるものは不変です)
int a=10;
int b=10;
//1、const 修饰指针:常量指针(把const读成常量,把*读成指针)
const int * p = &a;
//指针指向的值不可以改,指针的指向可以改
*p = 20;//报错
p = &b;//正确
//2、const 修饰常量:指针常量
int * const p2 = &a;
*p2 = 100;//正确
p2 = &b;//报错
//3、const 修饰指针和常量
const int * const p3 = &a;
*p3 = 100;//报错
p3 = &b;//报错
4.5. 配列へのポインタアクセス
int arr[3] = {1,2,3};
int * p = arr;//指向数组的指针,arr就是数组首地址
cout<<"指针访问第一个元素:"<<*p<<endl;
//利用指针遍历数组
for(int i=0 ; i<3 ; i++)
{
cout<<*p<<endl;
p++;//让指针向后偏移4个字节
}
4.6. アドレス転送 (値の転送は実パラメータを変更しません、アドレス転送は実パラメータを変更します)
void swap(int * p1,int * p2)
{
//函数体
}
int main()
{
int a = 10;
int b = 20;
swap(&a,&b);//地址传递会改变实参
return 0;
}
4.7. バブリングを実現するポインタ配列関数
//指针数组函数实现冒泡排序
//冒泡排序函数
void bubbleSort(int * arr, int len)
{
for(int i=0 ; i<len-1 ; i++)
{
for(int j=0 ; j<len-i-1 ; j++)
{
if(arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
void printArray(int * arr , int len)
{
for(int i=0 ; i<len ; i++)
{
cout<<arr[i]<<endl;
}
}
int main()
{
//1、创建数组
int arr[10] = {3,2,9,8,3,9,5,7,4,5};
//数组长度(关键:可灵活处理数组长度)
int len = sizeof(arr)/sizeof(arr[0]);// 40/4=10
//2、创建函数,实现冒泡排序
bubbleSort(arr,len);
//3、打印排序后的数组
printArray(arr,len);
return 0;
}
5. 構造
5.1. 概念: ユーザーがさまざまなデータ型を保存できるようにするユーザー定義のデータ型
/*
语法:(定义结构体时的关键字struct不可省)
struct 结构体名
{
数据类型 变量名1;
数据类型 变量名2;
};
*/
struct Student
{
string name;
int age;
};
//3种通过结构体创建变量的方式
//1、struct 结构体名 变量名
struct Student s1;//(创建结构体变量时的关键字struct可省)
//可直接写成:Student s1;
s1.name = "张三";//用操作符 . 访问成员
s1.age = 10;
//2、struct 结构体名 变量名 = { 成员1值 , 成员2值...}
struct Student s2 = {"李四",19};//(此struct可省略)
//3、定义结构体时顺便创建变量(不建议用)
struct Student
{
string name;
int age;
}s3;//尾括号加变量名就顺便创建结构体变量
s3.name = "张三";
s3.age = 10;
5.2、構造体配列
機能: メンテナンスを容易にするためにカスタム構造を配列に配置します。
//语法:struct 结构体名 数组名[元素个数] = {
{},{},{}};
struct Student
{
string name;
int age;
};
int main()
{
struct Student arr[2] =
{
{"张三",10},
{"李四",20}
};
//访问数组中的元素
cout<<arr[0].name<<endl;
}
5.3. 構造体ポインタ
役割: ポインタを介して構造体のメンバーにアクセスします。
struct Student
{
string name;
int age;
};
//1、创建学生结构体变量
struct Student s = {"小明",19};
//2、通过指针指向结构体变量
struct Student * p = &s;
//3、利用操作符 -> 访问结构体中的成员
cout<<p->name<<endl;
5.4. 構造体のネスト
#include <iostream>
#include <string>
using namespace std;
struct Student
{
string name;
int age;
};
struct Teacher
{
string name;
int id;
struct Student stu;//结构体中再嵌套结构体
};
int main()
{
//创建结构体
struct Teacher t1;
t1.name = "老师";
t1.id = 10;
t1.stu.name = "学生";//对结构体中的结构体赋值操作
t1.stu.age = 18;
cout<<t1.name<<endl;
cout<<t1.id<<endl;
cout<<t1.stu.name<<endl;
cout<<t1.stu.age<<endl;
return 0;
}
5.5. 構造体は関数のパラメータとして使用されます(値の転送ではメイン関数のデータは変更されませんが、アドレスの転送は変更されます)
#include <iostream>
#include <string>
using namespace std;
struct Student
{
int age;
};
//代码检测时把函数printStudent1或者printStudent2注释其中之一
//值传递
void printStudent1(struct Student s)
{
s.age = 19;
cout<<"值传递值:"<<s.age<<endl;//值传递输出为19,主函数输出仍为18,不改主函数的值
}
void printStudent2(struct Student * p)
{
p->age = 20;
cout<<"地址传递值:"<<p->age<<endl;//地址传递输出为20,主函数输出也为20,改变主函数的值
}
int main()
{
//创建结构体
struct Student s;
s.age = 18;
printStudent1(s);
//printStudent2(&s);
cout<<"主函数值:"<<s.age<<endl;
return 0;
}
5.6、構造体 const の使用
機能: const を使用して誤操作を防止します
#include <iostream>
using namespace std;
struct Student
{
int age;
};
//将函数中的形参改为指针,可以减少内存空间,而且不会复制新的副本出来
void printStudent1(const struct Student *s)//形参改为指针
{
//s->age = 19;//报错
cout<<s->age<<endl;
}
int main()
{
//创建结构体
struct Student s;
s.age = 18;
printStudent1(&s);//加个取地址符
return 0;
}
5.7. 構造体のケース
/*
案例描述1 :学校正在做毕设项目,每名老师带领5个学生,总共有3名老师,需求如下。
设计学生和老师的结构体,其中在老师的结构体中,有老师姓名和一个存放5名学生的数组作为成员。
学生的成员有姓名、考试分数。
创建数组存放3名老师,通过函数给每个老师及所带的学生赋值。
最终打印出老师数据以及老师所带的学生数据。
*/
#include <iostream>
using namespace std;
#include <string>
#include <ctime>
//1、创建老师和学生的结构体
//学生的结构体
struct Student
{
//学生姓名
string sName;
//学生分数
int score;
};
//老师的结构体
struct Teacher
{
//老师姓名
string tName;
//每名老师所带学生的数组
struct Student sArray[5];
};
//tips:赋值函数和打印函数有许多相同的地方
//3、给老师和学生赋值的函数
void allocateSpace(struct Teacher tArray[],int len)
{
string nameSeed = "ABCDE";
//循环给老师赋值
for(int i=0 ; i<len ; i++)
{
tArray[i].tName = "Teacher_";
tArray[i].tName += nameSeed[i];
//循环给每名老师所带的学生赋值
for(int j=0 ; j<5 ; j++)
{
tArray[i].sArray[j].sName = "Student_";
tArray[i].sArray[j].sName += nameSeed[j];
int random = rand()% 61+40; //40~100
tArray[i].sArray[j].score = random;
}
}
}
//4、打印所有老师及所带学生信息
void printInof(struct Teacher tArray[],int len)
{
//循环打印老师的信息
for(int i=0 ; i<len ; i++)
{
cout<<"老师姓名:"<<tArray[i].tName<<endl;
//循环打印每名老师所带的学生信息
for(int j=0 ; j<5 ; j++)
{
cout<<"\t学生姓名:"<<tArray[i].sArray[j].sName
<<" 考试分数:"<<tArray[i].sArray[j].score
<<endl;
}
}
}
int main()
{
//随机数种子
srand((unsigned int)time(NULL));
//2、创建3名老师的数组
struct Teacher tArray[3];
//tips:赋值函数和打印函数有许多相同的地方
//3、通过函数给3名老师的信息赋值,并给老师带的学生信息赋值
int len = sizeof(tArray)/sizeof(tArray[0]);
allocateSpace(tArray,len);
//4、打印所有老师及所带学生信息
printInof(tArray,len);
return 0;
}
/*
案例描述2 :设计一个英雄的结构体,包括成员姓名,年龄,性别;
创建结构体数组,数组中存放5名英雄。
通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,
最终打印排序后的结果。
*/
#include <iostream>
using namespace std;
#include <string>
//1、设计英雄结构体
struct Hero
{
//姓名
string name;
//年龄
int age;
//性别
string sex;
};
//冒泡排序:实现年龄升序排序
void bubbleSort(struct Hero heroArray[],int len)
{
for(int i=0 ; i<len-1 ; i++)
{
for(int j=0 ; j<len-i-1 ; j++)
{
//此处是关键
if(heroArray[j].age>heroArray[j+1].age)
{
struct Hero temp = heroArray[j];
heroArray[j] = heroArray[j+1];
heroArray[j+1] = temp;
}
}
}
}
//打印排序后数组中的信息
void printHero(struct Hero heroArray[],int len)
{
for(int i=0 ; i<len ; i++)
{
cout<<"姓名:"<<heroArray[i].name
<<"年龄:"<<heroArray[i].age
<<"性别:"<<heroArray[i].sex
<<endl;
}
}
int main()
{
//2、创建数组存放5名英雄
struct Hero heroArray[5] =
{
{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"}
};
int len = sizeof(heroArray)/sizeof(heroArray[0]);
cout<<"排序前的打印:"<<endl;
//可作为测试代码
for(int i=0 ; i<len ; i++)
{
cout<<"姓名:"<<heroArray[i].name
<<"年龄:"<<heroArray[i].age
<<"性别:"<<heroArray[i].sex
<<endl;
}
//3、对数组进行排序,按照年龄进行升序排序
bubbleSort(heroArray,len);
cout<<"排序后的打印:"<<endl;
//4、将排序后结果打印输出
printHero(heroArray,len);
return 0;
}
6. 小規模プロジェクト: アドレス帳管理システム
//
// Created by mac on 2021/2/8.
//
//封装函数显示该界面 如 void showMenu()
//在 main 函数中调用封装好的函数
#include <iostream>
using namespace std;
#include <string>
#define MAX 1000
#include <unistd.h>
//3、设计联系人和通讯录的结构体
//设计联系人的结构体
struct Person
{
//姓名
string m_Name;
//性别:男1 女2
int m_Sex;
//年龄
int m_Age;
//电话
string m_Phone;
//住址
string m_Addr;
};
//通讯录的结构体
struct Addressbook
{
//通讯录中保存的联系人数组
struct Person personArray[MAX];
//通讯录中当前记录联系人个数
int m_Size;
};
//1、菜单界面
void showMenu()
{
cout<<"***********************"<<endl;
cout<<"***** 1、添加联系人 *****"<<endl;
cout<<"***** 2、显示联系人 *****"<<endl;
cout<<"***** 3、删除联系人 *****"<<endl;
cout<<"***** 4、查找联系人 *****"<<endl;
cout<<"***** 5、修改联系人 *****"<<endl;
cout<<"***** 6、清空联系人 *****"<<endl;
cout<<"***** 0、退出通讯录 *****"<<endl;
cout<<"***********************"<<endl;
}
//5、利用地址传递,可以修饰实参
void addPerson(struct Addressbook * abs)
{
//判断通讯录是否已满,如果满了就不再添加
if(abs->m_Size == MAX)
{
cout<<"通讯录已满,无法添加!"<<endl;
return;
}
else
{
//添加具体联系人
//添加姓名
string name;
cout<<"请输入姓名:"<<endl;
cin>>name;
abs->personArray[abs->m_Size].m_Name = name;
//添加性别
cout<<"请输入性别:"<<endl;
cout<<"1--男;2--女"<<endl;
int sex = 0;
while(true)
{
cin>>sex;
//输入1或者2正确退出循环,输入其他则重新输入
if (sex == 1 || sex == 2)
{
abs->personArray[abs->m_Size].m_Sex = sex;
break;
}
cout<<"输入有误,请从新输入!"<<endl;
}
//添加年龄
cout<<"请输入年龄:"<<endl;
int age = 0;
cin>>age;
abs->personArray[abs->m_Size].m_Age = age;
//添加电话
cout<<"请输入联系电话:"<<endl;
string phone;
cin>>phone;
abs->personArray[abs->m_Size].m_Phone = phone;
//添加住址
cout<<"请输入家庭住址:"<<endl;
string addr;
cin>>addr;
abs->personArray[abs->m_Size].m_Addr = addr;
//更新通讯录人数(关键)
abs->m_Size++;
cout<<"添加成功"<<endl;
//pause();//请按任意键继续 mac下似乎不能用这两个函数,此问题暂时还为解决
//system("clear");//清屏操作
}
}
//6、显示所有的联系人
void showPerson(struct Addressbook * abs)
{
//判断通讯录中人数是否为0,如果为0,提示记录为空
//如果不为0,显示记录的联系人信息
if(abs->m_Size == 0)
{
cout<<"当前联系人为空"<<endl;
}
else
{
for(int i=0 ; i<abs->m_Size ; i++)
{
cout<<"姓名:"<<abs->personArray[i].m_Name<<"\t";
cout<<"性别:"<<(abs->personArray[i].m_Sex ==1 ? "男":"女")<<"\t";//关键
cout<<"年龄:"<<abs->personArray[i].m_Age<<"\t";
cout<<"电话:"<<abs->personArray[i].m_Phone<<"\t";
cout<<"住址:"<<abs->personArray[i].m_Addr<<endl;
}
}
//pause();//按任意键继续
//system("clear");//请屏
}
//7、检测联系人是否存在,如果存在,返回联系人所在数组中的具体位置,不存在返回-1
//参数1 通讯录 参数2 对比姓名
int isExist(struct Addressbook * abs , string name)
{
for(int i=0 ; i<abs->m_Size ; i++)
{
//找到用户输入的姓名了
if(abs->personArray[i].m_Name == name)
{
return i;//找到了,返回这个人在数组中的下标编号
}
return -1;//如果遍历结束都没有找到,返回-1
}
}
//8、删除指定联系人
void deletePerson(struct Addressbook *abs)
{
cout<<"请输入您要删除的联系人"<<endl;
string name;
cin>>name;
//ret == -1 未查到
//ret != -1 查到了
int ret = isExist(abs,name);
if(ret != -1)
{
for(int i=0 ; i<abs->m_Size ; i++)
{
//数据前移
abs->personArray[i] = abs->personArray[i+1];//只能按顺序删除,把后一个数据覆盖调前一个数据,此代码有缺陷
}
abs->m_Size--;//更新通讯录中的人员数
cout<<"删除成功"<<endl;
}
else
{
cout<<"查无此人"<<endl;
}
//pause();
//system("clear");
}
//9、查找指定联系人:此代码有缺陷,必须先创建一个联系人信息才能执行完整代码
void findPerson(struct Addressbook * abs)
{
cout<<"请输入您要查找的联系人"<<endl;
string name;
cin>>name;
//判断指定的联系人是否存在通讯录
int ret = isExist(abs,name);
if(ret != -1)//找到联系人
{
cout<<"姓名:"<<abs->personArray[ret].m_Name<<"\t";
cout<<"性别:"<<abs->personArray[ret].m_Sex<<"\t";
cout<<"年龄:"<<abs->personArray[ret].m_Age<<"\t";
cout<<"电话:"<<abs->personArray[ret].m_Phone<<"\t";
cout<<"住址:"<<abs->personArray[ret].m_Addr<<endl;
}
else
{
cout<<"查无此人"<<endl;
}
//pause();
//system("clear");
}
//10、修改指定联系人的信息
void modifyPerson(struct Addressbook * abs)
{
cout<<"请输入您要修改的联系人"<<endl;
string name;
cin>>name;
int ret = isExist(abs,name);
if(ret != 1) {
//修改姓名
cout << "请输入姓名:" << endl;
string name;
cin >> name;
abs->personArray[ret].m_Name = name;
//修改性别
cout << "请输入性别:" << endl;
cout << "1--男" << endl;
cout << "2--女" << endl;
int sex = 0;
while (true)
{
cin >> sex;
if (sex == 1 || sex == 2)
{
abs->personArray[ret].m_Sex = sex;
break;
}
cout<<"输入有误,请重新输入"<<endl;
}
//修改年龄
cout<<"请输入年龄:"<<endl;
int age = 0;
cin>>age;
abs->personArray[ret].m_Age = age;
//修改电话
cout<<"请输入联系电话:"<<endl;
string phone;
cin>>phone;
abs->personArray[ret].m_Phone = phone;
//修改住址
cout<<"请输入家庭住址:"<<endl;
string addr;
cin>>addr;
abs->personArray[ret].m_Addr = addr;
}
else
{
cout<<"查无此人"<<endl;
}
}
//11、清空所有的联系人
void cleanPerson(struct Addressbook * abs)
{
cout<<"是否确定清空?"<<endl;
cout<<"1 -- 是"<<endl;
cout<<"2 -- 否"<<endl;
int num = 0;
while(true)
{
cin >> num;
if (num == 1)
{
abs->m_Size = 0;//将当前记录联系人的数量置为0,做逻辑清空操作
cout << "通讯录已清空" << endl;
break;
}
else if (num == 2)
{
cout << "停止清空" << endl;
break;
}
cout<<"输入有误,请重新输入"<<endl;
}
//pause();
//system("clear");
}
int main()
{
//4、创建通讯录结构体变量
struct Addressbook abs;
//初始化通讯录中当前人员个数
abs.m_Size = 0;
int select = 0;//2、创建用户选择输入的变量
while(true)
{
//1、菜单调用
showMenu();
//2、创建用户选择输入的变量
cin>>select;
//只有选择0的时候才退出,其他选择则继续循环
switch (select) {
case 1: //1、添加联系人
addPerson(&abs);//5、增加联系人。利用地址传递,可以修饰实参
break;
case 2://2、显示联系人
showPerson(&abs);//6、显示所有的联系人
break;
case 3://3、删除联系人
/*
* 测试代码
{
cout << "请输入需要删除的联系人姓名:" << endl;
string name;
cin >> name;
if (isExist(&abs, name) == -1) {
cout << "查无此人" << endl;
} else {
cout << "找到此人" << endl;
}
}
*/
deletePerson(&abs);//7和8、删除指定联系人
break;
case 4://4、查找联系人
findPerson(&abs);//9、查找指定联系人
break;
case 5://5、修改联系人
modifyPerson(&abs);//10、修改指定联系人的信息
break;
case 6://6、清空联系人
cleanPerson(&abs);//11、清空所有的联系人
break;
case 0://0、退出通讯录
cout << "欢迎下次使用" << endl;
pause();
return 0;
default:
break;
}
}
}
7. プログラムのメモリモデル
7.1、メモリ領域 4
7.1.1. コンセプト
C++ プログラムが実行されると、メモリの大まかな方向は 4 つの領域に分割されます。
- コード領域(バイナリ): OSが管理する関数本体のバイナリコードを格納します。
- グローバル領域(ストレージ):グローバル変数、スタティック変数、定数を格納します(const修飾されたグローバル変数と文字列定数は定数領域に格納されます)
・スタック領域(関数パラメータ、ローカル):コンパイラにより自動的に確保・解放され、関数パラメータの値やローカル変数などが格納されます。
- ヒープ領域 (コーダ割り当て): プログラマによって割り当ておよび解放されます。プログラマが解放しない場合、プログラムの終了時にオペレーティング システムによって再利用されます。
7.1.2. 重要性 (地域ごとに寿命が異なります)
さまざまな領域に保存されたデータにはさまざまなライフサイクルが与えられ、より柔軟なプログラミングが可能になります。
7.2. プログラムを実行する前に
プログラムがコンパイルされると、exe 実行可能プログラムが生成され、プログラムが実行される前に 2 つの領域に分割されます。
7.2.1、コード領域
CPUが実行する機械命令を保存する
コード領域は共有され、頻繁に実行されるプログラムはメモリ内にコードを 1 つだけ置くだけで済みます。
コード領域は読み取り専用なので、プログラムが誤って命令を変更することを防ぎます。
7.2.2. 大域ゾーン
この領域のデータは、プログラム終了後にオペレーティング システムによって解放されます。
#include <iostream>
using namespace std;
//全局变量(凡函数体外的变量称为全局变量)
int g_a = 10;
//const修饰的全局变量称为全局常量
const int c_g_a = 10;
int main()
{
//全局区:全局变量、静态变量、常量
//创建普通局部变量(在函数体内的变量称为局部变量)
int a = 10;
cout<<"局部变量a的地址为:"<<&a<<endl;
cout<<"全局变量g_a的地址为:"<<&g_a<<endl;
//静态变量(在普通变量前加static,属于静态变量)
static int s_a = 10;
cout<<"静态变量s_a的地址为:"<<&s_a<<endl;
//常量
//字符串常量
cout<<"字符串常量的地址为:"<<&"字符串常量地址"<<endl;
//const修饰的变量
//const修饰的全局变量
cout<<"全局常量 c_g_a的地址为:"<<&c_g_a<<endl;
//const修饰的局部变量称为局部常量
const int c_l_a = 10;//c代表const l代表local g代表global
cout<<"局部常量 c_l_a的地址为:"<<&c_l_a<<endl;
return 0;
}
7.3. プログラムの実行後
7.3.1. スタック領域
//由编译器自动分配释放, 存放函数的参数值,局部变量等
//注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
#include <iostream>
using namespace std;
int* func(int b)//形参数据也会放在栈区
{
b = 100;
int a = 10;//局部变量,存放在栈区,栈区的数据在函数执行完成后自动释放
return &a;//不能返回局部变量的地址
}
int main()
{
int * p = func(1);
cout<<*p<<endl;//第一次可以打印正确的数字是因为编译器做了保留
cout<<*p<<endl;//第二次这个数据就不再保留了
return 0;
}
7.3.2. ヒープ領域
//由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
//在C++中主要利用new在堆区开辟内存
#include <iostream>
using namespace std;
int * func()//形参数据也会放在栈区
{
//利用new关键字可以将数据开辟到堆区
//指针,本质也是局部变量,放在栈上;指针保存的数据是放在堆区
int * p = new int(10);
return p;
}
void test01()
{
int * p = func();
cout<<*p<<endl;
cout<<*p<<endl;
cout<<*p<<endl;
cout<<"---------"<<endl;
//1、堆区开辟的数据,由程序员手动开辟,手动释放,释放利用关键字 ==delete==
delete p;
cout<<*p<<endl;//内存已经被释放,再次访问就是非法操作,会报错
}
//2、在堆区利用new开辟数组
void test02()
{
//创建10整形数据的数组,在堆区
int * arr = new int[10];
for(int i=0 ; i<10 ; i++)
{
arr[i] = i+100;//给10个元素赋值 100~109
}
for(int i=0 ; i<10 ; i++)
{
cout<<arr[i]<<endl;
}
//释放堆区数组
//释放数组的时候要加[]才可以
delete[] arr;
}
int main()
{
//在堆区开辟数据
//int * p = func();
test01();
test02();
//
return 0;
}
8. 引用
関数: 変数のエイリアス
8.1. 基本的な文法と引用の注意点
#include <iostream>
using namespace std;
int main()
{
//语法: 数据类型 &别名 = 原名
int a = 10;
//创建引用
int &b = a;
//int &b;//1、错误,必须初始化
//2、引用在初始化后不可以改变
int c = 30;
b = c;//赋值操作,而不是更改引用
cout<<"原名:"<<a<<endl;
cout<<"别名:"<<b<<endl;
cout<<"c的值:"<<c<<endl;
cout<<"--------"<<endl;
b = 20;
cout<<"原名:"<<a<<endl;
cout<<"别名:"<<b<<endl;
return 0;
}
8.2. 関数パラメータとしての参照
機能: 関数がパラメーターを渡すとき、参照テクニックを使用して、仮パラメーターによって実際のパラメーターを変更させることができます。
利点: 実際のパラメータを変更するためのポインタを簡素化できる
#include <iostream>
using namespace std;
void Swap(int &a,int &b)//其实 &a 是 a 的别名,&b 是 b 的别名
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 1;
int b = 2;
Swap(a,b);//引用传递和地址传递一样,都可以形参修饰实参
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
return 0;
}
8.3、関数の戻り値として参照
役割: 参照は関数の戻り値として存在できます
使用法: 左辺値としての関数呼び出し
#include <iostream>
using namespace std;
//引用做函数的返回值
//1、注意:不要返回局部变量的引用
int& test01()
{
int a = 10;//局部变量存放在四区中的 栈区
return a;
}
//2、用法:函数的调用可以作为左值
int& test02()
{
static int a = 10;//静态变量,存放在全局区,全局区上的数据在程序结束后系统释放
return a;
}
int main()
{
int &ref1 = test01();
cout<<"ref1 = "<<ref1<<endl;//第一次结果正确,是因为编译器做了保留
cout<<"ref1 = "<<ref1<<endl;//第二次结果错误,是因为a的内存已经释放
cout<<"------"<<endl;
int &ref2 = test02();
cout<<"ref2 = "<<ref2<<endl;
cout<<"ref2 = "<<ref2<<endl;
test02() = 1000;//如果函数的返回值是引用,这个函数调用可以作为左值(左边的值)
cout<<"-------"<<endl;
cout<<"ref2 = "<<ref2<<endl;
cout<<"ref2 = "<<ref2<<endl;
return 0;
}
8.4. 引用の性質
本質: C++ の内部実装はポインター定数です
結論: C++ では、構文が便利であり、参照の本質はポインター定数であるため、参照テクノロジの使用をお勧めしますが、すべてのポインター操作はコンパイラによって行われます。
8.5、定数リファレンス
#include <iostream>
using namespace std;
void showValue(const int &val)//const修饰形参,防止误操作
{
//val = 1000;//加了const防止形参改变实参 assignment:分配 ,reference:引用
cout<<"val="<<val<<endl;
}
int main()
{
//作用:常量引用主要用来修饰形参,防止误操作
int a = 10;
//int &ref = 10;//10是在常量区,引用必须引一块合法的内存空间
//加上const之后编译器将代码修改 int temp = 10;const int & ref = temp;
//const int &ref = 10;
//ref = 20;//加入const之后变为只读,不可以修改
showValue(a);
cout<<"a = "<<a<<endl;
return 0;
}