C++ 基础与进阶实例
Xcode
xcode是苹果的集成开发环境(IDE)。你使用Xcode来为苹果设备创建app,比如,iPad、iPhone、Apple Watch、Apple TV、Mac。在app的创建、测试、优化、发布到AppStore这整个开发流程中,Xcode提供了一套工具来方便你进行管理。
支持C、C++、Objective-C、Swift等
/// main.cpp// 00-hello_world//// Created by YanErrol on 2020/9/1.// Copyright 2020 YanErrol. All rights reserved.//#includeintmain(int argc, constchar * argv[]){// insert code here...std::cout << "Hello, World!\n";int new_name=0;std::cout<<"请输入数据:";std::cin>>new_name;std::cout<<"输入的数据为:"<<new_name<<"\n";return0;}c++基础编程< p="">
编译过程
高级语言-> 词法解释器->解析为固定结构的数据-> 生成器 -> 生成低级语言1.IDE:集成开发平台:编辑 编译 调试 推荐VS20082.www.afanihao.cn3.win10 cd /d 文件夹路径
c++是静态编程语言、编程式的、通用的大小写敏感的,不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。
C++是一个中级语言,c++是c语言的超集合,任何合法的C都是合法的C++程序。
c++的文件扩展名,.cpp .cp .cC++ 中分号是结束符号,每个完整的句子都以;号结束。入门实例
#includeusing namespace std;int main(){ cout<< "hello,world"<<endl;return p="" 0;}<="">
C++ 特性:封装、继承、多态、抽象
C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。
Xcode 目前可从 developer.apple.com/technologies/tools/ 上下载。
在 C++ 中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。
标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)
bool 所占的字节数:sizeof(bool)
char 所占的字节数:sizeof(char)
numeric_limits::max
numeric_limits::min
enum 枚举名{ 标识符[=整型常数], 标识符[=整型常数], ... 标识符[=整型常数]} 枚举变量;
当您使用多个文件且只在其中一个文件中定义变量时(定义变量的文件在程序连接时是可用的),变量声明就显得非常有用。您可以使用 extern 关键字在任何地方声明一个变量。虽然您可以在 C++ 程序中多次声明一个变量,但变量只能在某个文件、函数或代码块中被定义一次。
编程实战
c++ 中小数表示:printf("%.1f\n",8.0/5.0)
解释型语言:边编译边执行;编译型语言:编译完成后再执行
C++ 变量
变量其实不过是程序可操作的存储区的名称。C++中每个变量指定类型,类型决定了变量存储的大小和布局。
变量名字:必须是以字母和下划线开头。
extern关键字在任何地方声明变量。linux 下编译c++
g++ name.cpp./a.out** iostream 是标准的输入和输出流的标准头文件
//---------------------// first.cpp// Author:YanErrol//--------------------#includeusing namespace std;int main(){cout << "hello world\n";return 0;}//---------------------程序=算法+数据结构
C++语句:说明语句、赋值语句、表达语句、过程控制语句。
分支为整数或者字符
default分支
case和break连用
do-while循环用于重复程序的一部分几次(或多次)。如果迭代次数不固定,并且必须至少执行一次循环,建议使用do-while循环。
goto语句也称为跳转语句。它用于将控制转移到程序的其他部分。它无条件跳转到指定的标签。它可用于从深层嵌套循环或switch case标签传输控制。
注释:/单行注释
注释多行:/* 多行注释 */
过程控制语句又包括条件语句、循环语句、转义语句。
switch 语句(switch statement)
函数
函数分为两类:库函数和用户自定义函数将参数传给函数的两种方式:值的调用或者通过引用的调用。在原始的调用中是不会被修改,在通过引用调用中会被修改。
C++存储类
静态变量只初始化一次,直到程序结束。它保留可在多个函数之间调用的值。静态变量由编译器提供的一个默认值:0。
extern变量对所有程序都可见。如果两个或多个文件共享相同的变量或函数,则使用它。
多维数字示例
数组
C++中声明一个数组,需要制定元素的类型和元素的数量。
type arrayName [ arraySize ];
变量
数据类型 变量名=初始值;
常量
C++定义常量两种方式#define 宏常量: #define 常量名 常量值==通常在文件上方定义==,表示一个常量const修饰的变量 const 数据类型 常量名 = 常量值==通常在变量定义前加关键字const==,修饰该变量为常量,不可修改//1、宏常量#define day 7intmain(){cout << "一周里总共有 " << day << " 天" << endl;//day = 8; //报错,宏常量不可以修改//2、const修饰变量constint month = 12;cout << "一年里总共有 " << month << " 个月份" << endl;//month = 24; //报错,常量是不可以修改的return0;}关键字
**作用:**关键字是C++中预先保留的单词(标识符)
在定义变量或者常量时候,不要用关键字
C++关键字如下:
提示:在给变量或者常量起名称时候,不要用C++得关键字,否则会产生歧义。
识符命名规则
作用:C++规定给标识符(变量、常量)命名时,有一套自己的规则
标识符不能是关键字
标识符只能由字母、数字、下划线组成
第一个字符必须为字母或下划线
标识符中字母区分大小写
建议:给标识符命名时,争取做到见名知意的效果,方便自己和他人的阅读
数据类型
C++规定在创建一个变量或者常量时,必须要指定出相应的数据类型,否则无法给变量分配内存
整型
作用:整型变量表示的是==整数类型==的数据
C++中能够表示整型的类型有以下几种方式,区别在于所占内存空间不同:
sizeof关键字
**作用:**利用sizeof关键字可以==统计数据类型所占内存大小==语法:sizeof( 数据类型 / 变量)整型结论:==short < int <= long <= long long==
intmain(){cout << "short 类型所占内存空间为: " << sizeof(short) << endl;cout << "int 类型所占内存空间为: " << sizeof(int) << endl;cout << "long 类型所占内存空间为: " << sizeof(long) << endl;cout << "long long 类型所占内存空间为: " << sizeof(longlong) << endl; system("pause");return0;}实型(浮点型)
作用:用于==表示小数==
浮点型变量分为两种:
单精度float
双精度double
两者的区别在于表示的有效数字范围不同。
示例:
intmain(){float f1 = 3.14f;double d1 = 3.14;cout << f1 << endl;cout << d1<< endl;cout << "float sizeof = " << sizeof(f1) << endl;cout << "double sizeof = " << sizeof(d1) << endl;//科学计数法float f2 = 3e2; // 3 * 10 ^ 2 cout << "f2 = " << f2 << endl;float f3 = 3e-2; // 3 * 0.1 ^ 2cout << "f3 = " << f3 << endl; system("pause");return0;}字符型
**作用:**字符型变量用于显示单个字符
语法:char ch = 'a';
注意1:在显示字符型变量时,用单引号将字符括起来,不要用双引号
注意2:单引号内只能有一个字符,不可以是字符串
C和C++中字符型变量只占用==1个字节==。
字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元
示例:
intmain(){char ch = 'a';cout << ch << endl;cout << sizeof(char) << endl;//ch = "abcde"; //错误,不可以用双引号//ch = 'abcde'; //错误,单引号内只能引用一个字符cout << (int)ch << endl; //查看字符a对应的ASCII码 ch = 97; //可以直接用ASCII给字符型变量赋值cout << ch << endl; system("pause");return0;}ASCII码表格:
ASCII 码大致由以下两部分组成:
ASCII 非打印控制字符:ASCII 表上的数字 0-31 分配给了控制字符,用于控制像打印机等一些外围设备。
ASCII 打印字符:数字 32-126 分配给了能在键盘上找到的字符,当查看或打印文档时就会出现。
转义字符
**作用:**用于表示一些==不能显示出来的ASCII字符==
现阶段我们常用的转义字符有:\n \\ \t
示例:
intmain(){cout << "\\" << endl;cout << "\tHello" << endl;cout << "\n" << endl; system("pause");return0;}布尔类型 bool
**作用:**布尔数据类型代表真或假的值
bool类型只有两个值:
true --- 真(本质是1)
false --- 假(本质是0)
bool类型占==1个字节==大小
示例:
intmain(){bool flag = true;cout << flag << endl; // 1 flag = false;cout << flag << endl; // 0cout << "size of bool = " << sizeof(bool) << endl; //1 system("pause");return0;}数据的输入
作用:用于从键盘获取数据
**关键字:**cin
语法:cin >> 变量
示例:
intmain(){//整型输入int a = 0;cout << "请输入整型变量:" << endl;cin >> a;cout << a << endl;//浮点型输入double d = 0;cout << "请输入浮点型变量:" << endl;cin >> d;cout << d << endl;//字符型输入char ch = 0;cout << "请输入字符型变量:" << endl;cin >> ch;cout << ch << endl;//字符串型输入string str;cout << "请输入字符串型变量:" << endl;cin >> str;cout << str << endl;//布尔类型输入bool flag = true;cout << "请输入布尔型变量:" << endl;cin >> flag;cout << flag << endl; system("pause");return EXIT_SUCCESS;}运算符
**作用:**用于执行代码的运算本章我们主要讲解以下几类运算符:
算术运算符
作用:用于处理四则运算算术运算符包括以下符号:
示例1:
//加减乘除intmain(){int a1 = 10;int b1 = 3;cout << a1 + b1 << endl;cout << a1 - b1 << endl;cout << a1 * b1 << endl;cout << a1 / b1 << endl; //两个整数相除结果依然是整数int a2 = 10;int b2 = 20;cout << a2 / b2 << endl; int a3 = 10;int b3 = 0;//cout << a3 / b3 << endl; //报错,除数不可以为0//两个小数可以相除double d1 = 0.5;double d2 = 0.25;cout << d1 / d2 << endl;return0;}
总结:在除法运算中,除数不能为0
赋值运算符
**作用:**用于将表达式的值赋给变量
赋值运算符包括以下几个符号:
#includeusingnamespacestd;intmain(int argc, constchar * argv[]){// insert code here...cout << "Hello, World!\n";//赋值运算符// =int a = 10; a = 100;cout << "a = " << a << endl;// += a = 10; a += 2; // a = a + 2;cout << "a = " << a << endl;// -= a = 10; a -= 2; // a = a - 2cout << "a = " << a << endl;// *= a = 10; a *= 2; // a = a * 2cout << "a = " << a << endl;// /= a = 10; a /= 2; // a = a / 2;cout << "a = " << a << endl;// %= a = 10; a %= 2; // a = a % 2;cout << "a = " << a << endl;return0;}比较运算符
**作用:**用于表达式的比较,并返回一个真值或假值
比较运算符有以下符号:
示例:
intmain(){int a = 10;int b = 20;cout << (a == b) << endl; // 0 cout << (a != b) << endl; // 1cout << (a > b) << endl; // 0cout << (a < b) << endl; // 1cout << (a >= b) << endl; // 0cout << (a <= b) << endl; // 1return0;}注意:C和C++ 语言的比较运算中, ==“真”用数字“1”来表示, “假”用数字“0”来表示。==
逻辑运算符
**作用:**用于根据表达式的值返回真值或假值
逻辑运算符有以下符号:
**示例1:**逻辑非
//逻辑运算符 --- 非intmain(){int a = 10;cout << !a << endl; // 0cout << !!a << endl; // 1 system("pause");return0;}//逻辑运算符 --- 或intmain(){int a = 10;int b = 10;cout << (a || b) << endl;// 1 a = 10; b = 0;cout << (a || b) << endl;// 1 a = 0; b = 0;cout << (a || b) << endl;// 0 system("pause");return0;}
总结:真变假,假变真
循环控制
多条件的if语句:if(条件1){ 条件1满足执行的语句 }else if(条件2){条件2满足执行的语句}... else{ 都不满足执行的语句}
intmain(){int score = 0;cout << "请输入考试分数:" << endl;cin >> score;if (score > 600) {cout << "我考上了一本大学" << endl; }elseif (score > 500) {cout << "我考上了二本大学" << endl; }elseif (score > 400) {cout << "我考上了三本大学" << endl; }else {cout << "我未考上本科" << endl; }return0;}三目运算符
作用:通过三目运算符实现简单的判断
语法:表达式1 ? 表达式2 :表达式3
解释:
如果表达式1的值为真,执行表达式2,并返回表达式2的结果;
如果表达式1的值为假,执行表达式3,并返回表达式3的结果。
示例:
intmain(){int a = 10;int b = 20;int c = 0; c = a > b ? a : b;cout << "c = " << c << endl;//C++中三目运算符返回的是变量,可以继续赋值 (a > b ? a : b) = 100;cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;return0;}
总结:和if语句比较,三目运算符优点是短小整洁,缺点是如果用嵌套,结构不清晰
switch
**作用:**执行多条件分支语句语法:
switch(表达式){case 结果1:执行语句;break;case 结果2:执行语句;break; ...default:执行语句;break;}#includeusingnamespacestd;intmain(int argc, constchar * argv[]){// insert code here...cout << "Hello, World!\n";//请给电影评分//10 ~ 9 经典// 8 ~ 7 非常好// 6 ~ 5 一般// 5分以下 烂片int score = 0;cout << "请给电影打分" << endl;cin >> score;switch (score) {case10:case9:cout << "经典" << endl;break;case8:cout << "非常好" << endl;break;case7:case6:cout << "一般" << endl;break;default:cout << "烂片" << endl;break; }return0;}for and break
作用:满足循环条件,执行循环语句**语法:**for(起始表达式;条件表达式;末尾循环体) { 循环语句; }
for (int i = 0; i < 10; i++) {cout << i << endl; }#includeusingnamespacestd;intmain(int argc, constchar * argv[]){// insert code here...cout << "Hello, World!\n";for (int i = 0; i < 10; i++) {for (int j = 0; j < 10; j++) {if (j == 5) {break; }cout << "*" << " "; }cout << endl; }return0;}continue
跳过本次循环,执行剩余的语句。
intmain(){for (int i = 0; i < 100; i++) {if (i % 2 == 0) {continue; }cout << i << endl; }return0;}goto语句
作用: 可以无条件跳转语句
语法:goto 标记;
解释: 如果标记的名称存在,执行到goto语句时,会跳转到标记的位置
#includeusingnamespacestd;intmain(int argc, constchar * argv[]){// insert code here...cout << "Hello, World!\n";cout << "1" << endl;goto FLAG;cout << "2" << endl;cout << "3" << endl;cout << "4" << endl; FLAG:cout << "5" << endl;return0;}4.3.2 continue语句
作用:在==循环语句==中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环示例:
intmain(){for (int i = 0; i < 100; i++) {if (i % 2 == 0) {continue; }cout << i << endl; } system("pause");return0;}
注意:continue并没有使整个循环终止,而break会跳出循环
数组
一维数组
数据类型 数组名[ 数组长度 ];
数据类型 数组名[ 数组长度 ] = { 值1,值2 ...};
数据类型 数组名[ ] = { 值1,值2 ...};
#includeusingnamespacestd;intmain(int argc, constchar * argv[]){// insert code here...cout << "Hello, World!\n";//定义方式1//数据类型 数组名[元素个数];int score[10];//利用下标赋值 score[0] = 100; score[1] = 99; score[2] = 85;//利用下标输出cout << score[0] << endl;cout << score[1] << endl;cout << score[2] << endl;//第二种定义方式//数据类型 数组名[元素个数] = {值1,值2 ,值3 ...};//如果{}内不足10个数据,剩余数据用0补全int score2[10] = { 100, 90,80,70,60,50,40,30,20,10 };//逐个输出//cout << score2[0] << endl;//cout << score2[1] << endl;//一个一个输出太麻烦,因此可以利用循环进行输出for (int i = 0; i < 10; i++) {cout << score2[i] << endl; }//定义方式3//数据类型 数组名[] = {值1,值2 ,值3 ...};int score3[] = { 100,90,80,70,60,50,40,30,20,10 };for (int i = 0; i < 10; i++) {cout << score3[i] << endl; }return0;}
总结1:数组名的命名规范与变量名命名规范一致,不要和变量重名总结2:数组中下标是从0开始索引
//数组名用途//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 << "数组首地址为: " << arr << endl;cout << "数组中第一个元素地址为: " << arr[0] << endl;cout << "数组中第二个元素地址为: " << arr[1] << endl;
注意:数组名是常量,不可以赋值总结1:直接打印数组名,可以查看数组所占内存的首地址总结2:对数组名进行sizeof,可以获取整个数组占内存空间的大小
二维数据
二维数组定义的四种方式:
数据类型 数组名[ 行数 ][ 列数 ];
数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2 } ,{数据3,数据4 } };
数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4};
数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4};示例:
intmain(){//方式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 };return0;}
总结:在定义二维数组时,如果初始化了数据,可以省略行数总结1:二维数组名就是这个数组的首地址总结2:对二维数组名进行sizeof时,可以获取整个二维数组占用的内存空间大小
函数
概述
作用:将一段经常使用的代码封装起来,减少重复代码一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。
函数的定义
函数的定义一般主要有5个步骤:1、返回值类型2、函数名3、参数表列4、函数体语句5、return 表达式语法:
返回值类型 函数名 (参数列表){ 函数体语句return表达式}
返回值类型 :一个函数可以返回一个值。在函数定义中
函数名:给函数起个名称
参数列表:使用该函数时,传入的数据
函数体语句:花括号内的代码,函数内需要执行的语句
return表达式:和返回值类型挂钩,函数执行完后,返回相应的数据
#includeusingnamespacestd;intadd(int num1,int num2){int sum =num1+num2;return sum;}intmain(int argc, constchar * argv[]){// insert code here...std::cout << "Hello, World!\n";int a = 10;int b = 10;//调用add函数int sum = add(a, b);//调用时的a,b称为实际参数,简称实参cout << "sum = " << sum << endl;return0;}函数的声明
作用:告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
函数的声明可以多次,但是函数的定义只能有一次示例:
//声明可以多次,定义只能一次//声明intmax(int a, int b);intmax(int a, int b);//定义intmax(int a, int b){return a > b ? a : b;}intmain(){int a = 100;int b = 200;cout << max(a, b) << endl; system("pause");return0;}C++ 指针
C++语言中的指针是一个变量,它也称为定位符或指示符,它是指向一个值的地址。
指针减少代码并提高性能,它用于检索字符串,树等,并与数组,结构和函数一起使用。
我们可以使用指针从函数返回多个值。
它能够访问计算机内存中的任何内存位置。
动态内存分配在c语言中,可以使用malloc()和calloc()函数动态分配内存,其中使用的就是指针。
数组,函数和结构体C语言中的指针被广泛用于数组,函数和结构体中。它减少了代码并提高了性能。
C++ Null指针:C++支持空指针。NULL指针是一个定义在标准中的值为零的常量。
C++ 指针的算术运算:可以指针进行四种算术运算:++,--,+,-
指针变量定义语法:数据类型 * 变量名;
内存编号是从0开始记录的,一般用十六进制数字表示
可以利用指针变量保存地址
示例
#includeusingnamespacestd;intmain(int argc, constchar * argv[]){// insert code here...std::cout << "Hello, World!\n";//1、指针的定义int a = 10; //定义整型变量a //指针定义语法: 数据类型 * 变量名 ;int * p;//指针变量赋值 p = &a; //指针指向变量a的地址cout <<"&a"<< &a << endl; //打印数据a的地址cout << "p"<< p << endl; //打印指针变量p//2、指针的使用//通过*操作指针变量指向的内存cout << "*p = " << *p << endl;return0;}指针变量和普通变量的区别
普通变量存放的是数据,指针变量存放的是地址
指针变量可以通过" * "操作符,操作指针变量指向的内存空间,这个过程称为解引用
总结1:我们可以通过 & 符号 获取变量的地址总结2:利用指针可以记录地址总结3:对指针变量解引用,可以操作指针指向的内存
#includeusingnamespacestd;intmain(int argc, constchar * argv[]){// insert code here...std::cout << "Hello, World!\n";//1、指针的定义int a = 10; //定义整型变量a//指针定义语法: 数据类型 * 变量名 ;int * p;//指针变量赋值 p = &a; //指针指向变量a的地址cout <<"&a"<< &a << endl; //打印数据a的地址cout << "p"<< p << endl; //打印指针变量p//2、指针的使用//通过*操作指针变量指向的内存cout << "*p = " << *p << endl;cout << sizeof(p) << endl;cout << sizeof(char *) << endl;cout << sizeof(float *) << endl;cout << sizeof(double *) << endl;return0;}
总结:所有指针类型在32位操作系统下是4个字节,64位操作系统下是8个字节。
空指针和野指针
空指针:指针变量指向内存中编号为0的空间用途:初始化指针变量注意: 空指针指向的内存是不可以访问的示例1:空指针
intmain(){//指针变量p指向内存地址编号为0的空间int * p = NULL;//访问空指针报错 //内存编号0 ~255为系统占用内存,不允许用户访问cout << *p << endl; system("pause");return0;}野指针 :指针变量指向非法的内存空间示例2:野指针
intmain(){//指针变量p指向内存地址编号为0x1100的空间int * p = (int *)0x1100;//访问野指针报错 cout << *p << endl; system("pause");return0;}
总结:空指针和野指针都不是我们申请的空间,因此不要访问。
指针和数组
作用:利用指针访问数组中元素
示例:
intmain(){int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int * p = arr; //指向数组的指针cout << "第一个元素: " << arr[0] << endl;cout << "指针访问第一个元素: " << *p << endl;for (int i = 0; i < 10; i++) {//利用指针遍历数组cout << *p << endl; p++; } system("pause");return0;}指针和函数
作用:利用指针作函数参数,可以修改实参的值
//值传递voidswap1(int a ,int b){int temp = a; a = b; b = temp;}//地址传递voidswap2(int * p1, int *p2){int temp = *p1; *p1 = *p2; *p2 = temp;}intmain(){int a = 10;int b = 20; swap1(a, b); // 值传递不会改变实参 swap2(&a, &b); //地址传递会改变实参cout << "a = " << a << endl;cout << "b = " << b << endl;return0;}
总结:如果不想修改实参,就用值传递,如果想修改实参,就用地址传递
结构体
结构体基本概念
结构体属于用户==自定义的数据类型==,允许用户存储不同的数据类型
结构体定义和使用
语法:struct 结构体名 { 结构体成员列表 };通过结构体创建变量的方式有三种:
struct 结构体名 变量名
struct 结构体名 变量名 = { 成员1值 , 成员2值...}
定义结构体时顺便创建变量
//结构体定义structstudent{//成员列表string name; //姓名int age; //年龄int score; //分数}stu3; //结构体变量创建方式3 intmain(){//结构体变量创建方式1structstudentstu1;//struct 关键字可以省略 stu1.name = "张三"; stu1.age = 18; stu1.score = 100;cout << "姓名:" << stu1.name << " 年龄:" << stu1.age << " 分数:" << stu1.score << endl;//结构体变量创建方式2structstudentstu2 = {"李四",19,60 };cout << "姓名:" << stu2.name << " 年龄:" << stu2.age << " 分数:" << stu2.score << endl; stu3.name = "王五"; stu3.age = 18; stu3.score = 80;cout << "姓名:" << stu3.name << " 年龄:" << stu3.age << " 分数:" << stu3.score << endl;return0;}
总结1:定义结构体时的关键字是struct,不可省略总结2:创建结构体变量时,关键字struct可以省略总结3:结构体变量利用操作符 "." 访问成员
结构体嵌套结构体
作用:结构体中的成员可以是另一个结构体例如: 每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体
//学生结构体定义structstudent{//成员列表string name; //姓名int age; //年龄int score; //分数};//教师结构体定义structteacher{//成员列表int id; //职工编号string name; //教师姓名int age; //教师年龄structstudentstu;//子结构体 学生};intmain(){structteachert1; t1.id = 10000; t1.name = "老王"; t1.age = 40; t1.stu.name = "张三"; t1.stu.age = 18; t1.stu.score = 100;cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl;cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl;return0;}**总结:**在结构体中可以定义另一个结构体作为成员,用来解决实际问题
C++ 引用
不存在空引用。引用必须连接到一块合法的内存。
一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
引用必须在创建时被初始化。指针可以在任何时间被初始化。
C++核心编程
内存分区模型
C++程序在执行时,将内存大方向划分为4个区域
代码区:存放函数体的二进制代码,由操作系统进行管理的
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收内存四区意义:不同区域存放的数据,赋予不同的生命周期, 给我们更大的灵活编程
程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域 代码区: 存放 CPU 执行的机器指令 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令 全局区: 全局变量和静态变量存放在此. 全局区还包含了常量区, 字符串常量和其他常量也存放在此. ==该区域的数据在程序结束后由操作系统释放==.
#includeusingnamespacestd;int g_a = 10;int g_b = 10;//全局常量constint c_g_a = 10;constint c_g_b = 10;intmain(int argc, constchar * argv[]){// insert code here...std::cout << "Hello, World!\n";//局部变量int a = 10;int b = 10;//打印地址cout << "局部变量a地址为: " << &a << endl;cout << "局部变量b地址为: " << &b << endl;cout << "全局变量g_a地址为: " << &g_a << endl;cout << "全局变量g_b地址为: " << &g_b << endl;//静态变量staticint s_a = 10;staticint s_b = 10;cout << "静态变量s_a地址为: " << &s_a << endl;cout << "静态变量s_b地址为: " << &s_b << endl;cout << "字符串常量地址为: " << &"hello world" << endl;cout << "字符串常量地址为: " << &"hello world1" << endl;cout << "全局常量c_g_a地址为: " <<&c_g_a << endl;cout << "全局常量c_g_b地址为: " << &c_g_b << endl;constint c_l_a = 10;constint c_l_b = 10;cout << "局部常量c_l_a地址为: " << &c_l_a << endl;cout << "局部常量c_l_b地址为: " << &c_l_b << endl;return0;}
C++中在程序运行前分为全局区和代码区
代码区特点是共享和只读
全局区中存放全局变量、静态变量、常量
常量区中存放 const修饰的全局常量 和 字符串常量
在定义的局部函数中,不可以返回局部变量地址,战区开辟的数据由编译器自动释放。
堆区数据由程序员管理开辟和释放
堆区数据利用new关键字进行开辟内存
new操作符
C++中利用==new==操作符在堆区开辟数据 堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符 ==delete== 语法:new 数据类型 利用new创建的数据,会返回该数据对应的类型的指针
int* func(){int* a = newint(10);return a;}intmain(){int *p = func();cout << *p << endl;cout << *p << endl;//利用delete释放堆区数据delete p;//cout << *p << endl; //报错,释放的空间不可访问return0;}引用的基本使用
作用:给变量起别名语法:数据类型 &别名 = 原名
引用必须初始化
引用在初始化后,不可以改变
intmain(){int a = 10;int &b = a;cout << "a = " << a << endl;cout << "b = " << b << endl; b = 100;cout << "a = " << a << endl;cout << "b = " << b << endl;return0;}
引用的本质:引用的本质在c++内部实现是一个指针常量.
引用做函数参数
作用:函数传参时,可以利用引用的技术让形参修饰实参优点: 可以简化指针修改实参示例:
//1. 值传递voidmySwap01(int a, int b){int temp = a; a = b; b = temp;}//2. 地址传递voidmySwap02(int* a, int* b){int temp = *a; *a = *b; *b = temp;}//3. 引用传递voidmySwap03(int& a, int& b){int temp = a; a = b; b = temp;}intmain(){int a = 10;int b = 20; mySwap01(a, b);cout << "a:" << a << " b:" << b << endl; mySwap02(&a, &b);cout << "a:" << a << " b:" << b << endl; mySwap03(a, b);cout << "a:" << a << " b:" << b << endl; system("pause");return0;}函数重载
C++重载
如果创建两个多个成员函数具有相同的名称,但是参数的数量和类型不同,则成为C++重载。
在C++中可以重载:方法,构造函数、索引属性
重载:分为函数重载和运算符号重载。
优点:函数的重载增加了函数的可读性,不要为同一个函数操作使用不同的函数名称。
在C++中,如果派生类定义了与其基类中定义的函数相同,则称函数重写。
C++虚函数是基类中的一个成员函数,您可以在派生类中重新定义它。它声明使用virtual关键字。它用于告诉编译器对函数执行动态链接或后期绑定。
**作用:**函数名可以相同,提高复用性函数重载满足条件:
同一个作用域下
函数名称相同
函数参数类型不同 或者 个数不同 或者 顺序不同
//函数重载需要函数都在同一个作用域下voidfunc(){cout << "func 的调用!" << endl;}voidfunc(int a){cout << "func (int a) 的调用!" << endl;}voidfunc(double a){cout << "func (double a)的调用!" << endl;}voidfunc(int a ,double b){cout << "func (int a ,double b) 的调用!" << endl;}voidfunc(double a ,int b){cout << "func (double a ,int b)的调用!" << endl;}//函数返回值不可以作为函数重载条件//int func(double a, int b)//{// cout << "func (double a ,int b)的调用!" << endl;//}intmain(){ func(); func(10); func(3.14); func(10,3.14); func(3.14 , 10);return0;}面向对象编程
对象、实例
继承:当一个对象获取父对象的所有属性和行为,称为继承。
多态:当一个任务通过不同的方式执行时,即被称为多态性。
封装构造函数时创建对象,向系统索取资源;析构函数时释放资源,向系统释放资源。
static 关键字
1.static是类的的关键字或修饰符。2.static 可以是字段,方法,构造函数,类,属性,操作符和事件。2.1 静态成员是属于整个类,不属于某一个对象。3.类和结构体(struct)用于创建类的实例的蓝图。结构体可用于轻量级对象。4.友元函数可以访问类的protected和private数据。
封装
封装的意义:
将属性和行为作为一个整体,表现生活中的事物
将属性和行为加以权限控制
#includeusingnamespacestd;classStudent{public:voidsetName(string name){ m_name = name; }voidsetID(int id){ m_id = id; }voidshowStudent(){cout << "name:" << m_name << " ID:" << m_id << endl; }public:string m_name;int m_id;};intmain(int argc, constchar * argv[]){// insert code here...std::cout << "Hello, World!\n"; Student stu; stu.setName("德玛西亚"); stu.setID(250); stu.showStudent();return0;}权限管理
public 公共权限
protected 保护权限
private 私有权限
//三种权限//公共权限 public 类内可以访问 类外可以访问//保护权限 protected 类内可以访问 类外不可以访问//私有权限 private 类内可以访问 类外不可以访问classPerson{//姓名 公共权限public:string m_Name;//汽车 保护权限protected:string m_Car;//银行卡密码 私有权限private:int m_Password;public:voidfunc(){ m_Name = "张三"; m_Car = "拖拉机"; m_Password = 123456; }};intmain(){ Person p; p.m_Name = "李四";//p.m_Car = "奔驰"; //保护权限类外访问不到//p.m_Password = 123; //私有权限类外访问不到return0;}struct和class区别
struct默认是为公共权限;
class 默认是权限为私有;`
classC1{int m_A; //默认是私有权限};structC2{int m_A; //默认是公共权限};intmain(){ C1 c1; c1.m_A = 10; //错误,访问权限是私有 C2 c2; c2.m_A = 10; //正确,访问权限是公共return0;}构造函数、析构函数
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
构造函数
**构造函数语法:**`类名(){}`1. 构造函数,没有返回值也不写void2. 函数名称与类名相同3. 构造函数可以有参数,因此可以发生重载4. 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次默认情况下,c++编译器至少给一个类添加3个函数1.默认构造函数(无参,函数体为空),* 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造2.默认析构函数(无参,函数体为空)3.默认拷贝构造函数,对属性进行值拷贝
析构函数
**析构函数语法:** `~类名(){}`1. 析构函数,没有返回值也不写void,* 如果用户定义拷贝构造函数,c++不会再提供其他构造函数2. 函数名称与类名相同,在名称前加上符号 ~3. 析构函数不可以有参数,因此不可以发生重载4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次#includeusingnamespacestd;classPerson{public://构造函数 Person() {cout << "Person的构造函数调用" << endl; }inttest(){cout<<"hello"<<endl;return0; p="" test01();return0;}构造函数调用规则<="" world!\n?;="" ?hello,="" <<="" here...std::cout="" code="" insert="" argv[]){="" *="" constchar="" argc,="" p.test();}intmain(int="" p;="" person="" }};voidtest01(){="" endl;="" ?person的析构函数调用?="" {cout="" ~person()="" 析构函数="" }="">
默认情况下,c++编译器至少给一个类添加3个函数
1.默认构造函数(无参,函数体为空)2.默认析构函数(无参,函数体为空)3.默认拷贝构造函数,对属性进行值拷贝构造函数调用规则如下:
如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
如果用户定义拷贝构造函数,c++不会再提供其他构造函数示例:
classPerson {public://无参(默认)构造函数 Person() {cout << "无参构造函数!" << endl; }//有参构造函数 Person(int a) { age = a;cout << "有参构造函数!" << endl; }//拷贝构造函数 Person(const Person& p) { age = p.age;cout << "拷贝构造函数!" << endl; }//析构函数 ~Person() {cout << "析构函数!" << endl; }public:int age;};voidtest01(){Person p1(18);//如果不写拷贝构造,编译器会自动添加拷贝构造,并且做浅拷贝操作Person p2(p1);cout << "p2的年龄为: " << p2.age << endl;}voidtest02(){//如果用户提供有参构造,编译器不会提供默认构造,会提供拷贝构造 Person p1; //此时如果用户自己没有提供默认构造,会出错Person p2(10); //用户提供的有参Person p3(p2); //此时如果用户没有提供拷贝构造,编译器会提供//如果用户提供拷贝构造,编译器不会提供其他构造函数 Person p4; //此时如果用户自己没有提供默认构造,会出错Person p5(10); //此时如果用户自己没有提供有参,会出错Person p6(p5); //用户自己提供拷贝构造}intmain(){ test01(); system("pause");return0;}深拷贝和浅拷贝
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作
静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员静态成员分为:
静态成员变量
所有对象共享同一份数据
在编译阶段分配内存
类内声明,类外初始化
静态成员函数
所有对象共享同一个函数
静态成员函数只能访问静态成员变量
#includeusingnamespacestd;classPerson{public:staticint m_A; //静态成员变量private:staticint m_B; //静态成员变量也是有访问权限的};int Person::m_A = 10;int Person::m_B = 10;voidtest01(){//静态成员变量两种访问方式//1、通过对象 Person p1; p1.m_A = 100;cout << "p1.m_A = " << p1.m_A << endl; Person p2; p2.m_A = 200;cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据cout << "p2.m_A = " << p2.m_A << endl;//2、通过类名cout << "m_A = " << Person::m_A << endl;//cout << "m_B = " << Person::m_B << endl; //私有权限访问不到}intmain(int argc, constchar * argv[]){// insert code here...std::cout << "Hello, World!\n"; test01();return0;}C++ 继承
1.继承是一个对象自动获取父对象的所有属性和行为的过程。派生类为子类。2.
//Java页面classJava :public BasePage{public:voidcontent(){cout << "JAVA学科视频" << endl; }};//Python页面classPython :public BasePage{public:voidcontent(){cout << "Python学科视频" << endl; }};//C++页面classCPP :public BasePage{public:voidcontent(){cout << "C++学科视频" << endl; }};继承特性
继承的好处:==可以减少重复的代码==
class A : public B;
A 类称为子类 或 派生类
B 类称为父类 或 基类
派生类中的成员,包含两大部分:
一类是从基类继承过来的,一类是自己增加的成员。
从基类继承过过来的表现其共性,而新增的成员体现了其个性。
继承方式一共有三种:
公共继承
保护继承
私有继承
classBase1{public: int m_A;protected:int m_B;private:int m_C;};//公共继承classSon1 :public Base1{public:voidfunc(){ m_A; //可访问 public权限 m_B; //可访问 protected权限//m_C; //不可访问 }};voidmyClass(){ Son1 s1; s1.m_A; //其他类只能访问到公共权限}//保护继承classBase2{public:int m_A;protected:int m_B;private:int m_C;};classSon2:protected Base2{public:voidfunc(){ m_A; //可访问 protected权限 m_B; //可访问 protected权限//m_C; //不可访问 }};voidmyClass2(){ Son2 s;//s.m_A; //不可访问}//私有继承classBase3{public:int m_A;protected:int m_B;private:int m_C;};classSon3:private Base3{public:voidfunc(){ m_A; //可访问 private权限 m_B; //可访问 private权限//m_C; //不可访问 }};classGrandSon3 :public Son3{public:voidfunc(){//Son3是私有继承,所以继承Son3的属性在GrandSon3中都无法访问到//m_A;//m_B;//m_C; }};继承中构造和析构顺序
子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题:父类和子类的构造和析构顺序是谁先谁后?
classBase{public: Base() {cout << "Base构造函数!" << endl; } ~Base() {cout << "Base析构函数!" << endl; }};classSon :public Base{public: Son() {cout << "Son构造函数!" << endl; } ~Son() {cout << "Son析构函数!" << endl; }};voidtest01(){//继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反 Son s;}intmain(){ test01(); system("pause");return0;}
总结:继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
继承同名成员处理方式
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
访问子类同名成员 直接访问即可
访问父类同名成员 需要加作用域
classBase {public: Base() { m_A = 100; }voidfunc(){cout << "Base - func()调用" << endl; }voidfunc(int a){cout << "Base - func(int a)调用" << endl; }public:int m_A;};classSon :public Base {public: Son() { m_A = 200; }//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域voidfunc(){cout << "Son - func()调用" << endl; }public:int m_A;};voidtest01(){ Son s;cout << "Son下的m_A = " << s.m_A << endl;cout << "Base下的m_A = " << s.Base::m_A << endl; s.func(); s.Base::func(); s.Base::func(10);}intmain(){ test01(); system("pause");return EXIT_SUCCESS;}总结:
子类对象可以直接访问到子类中同名成员
子类对象加作用域可以访问到父类同名成员
当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数
多继承语法
C++允许一个类继承多个类
语法:class 子类 :继承方式 父类1 , 继承方式 父类2...
多继承可能会引发父类中有同名成员出现,需要加作用域区分
C++实际开发中不建议用多继承
classBase1 {public: Base1() { m_A = 100; }public:int m_A;};classBase2 {public: Base2() { m_A = 200; //开始是m_B 不会出问题,但是改为mA就会出现不明确 }public:int m_A;};//语法:class 子类:继承方式 父类1 ,继承方式 父类2 classSon :public Base2, public Base1 {public: Son() { m_C = 300; m_D = 400; }public:int m_C;int m_D;};//多继承容易产生成员同名的情况//通过使用类名作用域可以区分调用哪一个基类的成员voidtest01(){ Son s;cout << "sizeof Son = " << sizeof(s) << endl;cout << s.Base1::m_A << endl;cout << s.Base2::m_A << endl;}intmain(){ test01(); system("pause");return0;}
总结:多继承中如果父类中出现了同名情况,子类使用时候要加作用域
C++ 多态
C++的主要特性是封装继承多态
多态分为两类
动态多态: 派生类和虚函数实现运行时多态
静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
静态多态和动态多态区别:
动态多态的函数地址晚绑定 - 运行阶段确定函数地址
静态多态的函数地址早绑定 - 编译阶段确定函数地址
纯虚函数和抽象类
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容因此可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名 (参数列表)= 0 ;
当类中有了纯虚函数,这个类也称为==抽象类==抽象类特点:
无法实例化对象
子类必须重写抽象类中的纯虚函数,否则也属于抽象类
classBase{public://纯虚函数//类中只要有一个纯虚函数就称为抽象类//抽象类无法实例化对象//子类必须重写父类中的纯虚函数,否则也属于抽象类virtualvoidfunc()= 0;};classSon :public Base{public:virtualvoidfunc(){cout << "func调用" << endl; };};voidtest01(){ Base * base = NULL;//base = new Base; // 错误,抽象类无法实例化对象 base = new Son; base->func();delete base;//记得销毁}intmain(){ test01(); system("pause");return0;}
虚析构语法:virtual ~类名(){}
纯虚析构语法:virtual ~类名() = 0;类名::~类名(){}
C++ 抽象类
抽象类是在C++中实现抽象的方式。C++抽象类是隐藏内部细节和仅显示功能的过程:抽象类和接口
在C++中将其函数中的至少一个声明为纯虚函数,使其变得抽象。通过在声明中放置“=0”来指定纯虚函数,它的实现必须由派生类提供。
C++命名空间
C++中的命名空间用于组织项目中的类。
对于访问命名空间的类,我们使用namespacename::classname. 使用using关键字。
在C++中全局命名空间是根命名空间,global::std总是引用C++框架的命名空间“std”。
C++字符串
C++ 字符串string 是一个表示字符串的std::string类的对象。
C++ 异常处理
try
catch
throw
C++文件和流
iostream标准库是提供了cin cout方法,分别从输入和输出流。
从文件读取和写入,fstream 标准C++库。
保存文件种类
文件类型分为两种:
二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
文本文件 - 文件以文本的ASCII码形式存储在计算机中
ofstream:写操作
ifstream:读操作
fstream :读写操作
写文件
包含头文件#include
创建流对象ofstream ofs;
打开文件ofs.open("文件路径",打开方式);
写数据ofs << "写入的数据";
关闭文件ofs.close();文件打开方式:| 打开方式 | 解释 || ----------- | -------------------------- || ios::in | 为读文件而打开文件 || ios::out | 为写文件而打开文件 || ios::ate | 初始位置:文件尾 || ios::app | 追加方式写文件 || ios::trunc | 如果文件存在先删除,再创建 || ios::binary | 二进制方式 |注意: 文件打开方式可以配合使用,利用|操作符**例如:**用二进制方式写文件 ios::binary | ios:: out
实例
#includevoidtest01(){ ofstream ofs; ofs.open("test.txt", ios::out); ofs << "姓名:张三" << endl; ofs << "性别:男" << endl; ofs << "年龄:18" << endl; ofs.close();}intmain(){ test01(); system("pause");return0;}总结:
文件操作必须包含头文件 fstream
读文件可以利用 ofstream ,或者fstream类
打开文件时候需要指定操作文件的路径,以及打开方式
利用<<可以向文件中写数据
操作完毕,要关闭文件
读文件
包含头文件#include
创建流对象ifstream ifs;
打开文件并判断文件是否打开成功ifs.open("文件路径",打开方式);
读数据四种方式读取
关闭文件ifs.close();
实例
#include#includevoidtest01(){ ifstream ifs; ifs.open("test.txt", ios::in);if (!ifs.is_open()) {cout << "文件打开失败" << endl;return; }//第一种方式//char buf[1024] = { 0 };//while (ifs >> buf)//{// cout << buf << endl;//}//第二种//char buf[1024] = { 0 };//while (ifs.getline(buf,sizeof(buf)))//{// cout << buf << endl;//}//第三种//string buf;//while (getline(ifs, buf))//{// cout << buf << endl;//}char c;while ((c = ifs.get()) != EOF) {cout << c; } ifs.close();}intmain(){ test01(); system("pause");return0;}总结:
读文件可以利用 ifstream ,或者fstream类
利用is_open函数可以判断文件是否打开成功
close 关闭文件
二进制文件
以二进制的方式对文件进行读写操作打开方式要指定为 ==ios::binary==
写文件
二进制方式写文件主要利用流对象调用成员函数write函数原型 :ostream& write(const char * buffer,int len);参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
#include#includeclassPerson{public:char m_Name[64];int m_Age;};//二进制文件 写文件voidtest01(){//1、包含头文件//2、创建输出流对象ofstream ofs("person.txt", ios::out | ios::binary);//3、打开文件//ofs.open("person.txt", ios::out | ios::binary); Person p = {"张三" , 18};//4、写文件 ofs.write((constchar *)&p, sizeof(p));//5、关闭文件 ofs.close();}intmain(){ test01();return0;}
文件输出流对象 可以通过write函数,以二进制方式写数据
读文件
二进制方式读文件主要利用流对象调用成员函数read
函数原型:istream& read(char *buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
#include#includeclassPerson{public:char m_Name[64];int m_Age;};voidtest01(){ifstream ifs("person.txt", ios::in | ios::binary);if (!ifs.is_open()) {cout << "文件打开失败" << endl; } Person p; ifs.read((char *)&p, sizeof(p));cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;}intmain(){ test01();return0;}
文件输入流对象 可以通过read函数,以二进制方式读数据
C++哪些事
const
1.const含义:是指类型修饰符const说明的类型,常类型的变量或对象是不能被更新。
const int a=100
const常量与#define宏定义常量的区别:
const常量具有类型,编译器可以进行安全检查;#define宏定义没有数据类型,只是简单的字符串替换,不能进行安全检查。
const 对象默认为文件局部变量
小结:可以发现未被const修饰的变量不需要extern显式声明!而const常量需要显式声明extern,并且需要做初始化!因为常量在定义后就不能被修改,所以定义时必须初始化。
非const变量默认为extern。要使const变量能够在其他文件中访问,必须在文件中显式地指定它为extern。
指针与const
const char * a; //指向const对象的指针或者说指向常量的指针。char const * a; //同上char * const a; //指向类型对象的const指针。或者说常指针、const指针。const char * const a; //指向const对象的const指针。- 小结:如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。const int *ptr;*ptr = 10; //error- ptr是一个指向int类型const对象的指针,const定义的是int类型,也就是ptr所指向的对象类型,而不是ptr本身,所以ptr可以不用赋初始值。但是不能通过ptr去修改所指对象的值。郑州妇科医院哪家好http://jbk.39.net/yiyuanzaixian/sysdfkyy/