2022 C++学习笔记
提示:本笔记为作者在大一学习所记,笔记不全,陆续更新
学习的开发环境为VC++6.0,安装见博客http://t.csdn.cn/85boN
一、程序的概念
1、什么是程序
程序是为实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合。
2、计算机编程语言类型
1、结构化程序设计2、面向对象程序设计。
二、C++概述
1、C++的简史及特点
1、C++语言简史:
2、C++语言特点
封装:把函数和数据封藏起来,把它看成一个有机整体。
抽象:忽略一个主题中与当前目标无关的哪些方面,以便充分的注意与当前目标有关的方面。
继承:将共性保留下来就是继承,如矩形继承四边形这个累是公共属性。
多态:值不同类的对象对同一消息作出不同的响应。
3、第一个C++程序
#include <iostream.h>
//引入头文件
void main(){
cout << "This is a C++ program.\n";
//输出
}
C++注释
1、//注释内容
2、/*注释内容*/
4、C++语言的基本组成
每个C++程序由注释、编译预处理和程序主题组成。
5、程序的编辑,编译,连接,运行
编辑:编辑C++源文件。
编译:必须编译器编译。
运行:编译和连接后生成的可执行文件。
三、C++基础知识
1、C++的词法单位
1、C++的常用字符集
ASCII码、汉字国标码、Unicode字符集
2、C++的单词
构成C++的词法单位有:
1、标识符
2、关键字
3、符号常量
4、操作符(运算符)
5、标点符号
3、标识符
由程序员定义的单词用来给变量、常量、数据类型、函数命名。
合法的标识符由字母或下划线开头,由字母、数字、下划线组成。
4、关键字
关键字又称为保留字,是由系统定义的具有特定作用和含义的英文单词,不能另做他用。
5、标点符号
# () {} " ' [] : 等。
6、运算符
又称操作符用于描述运算如:+ 、- 、* 、 / 、 = 、==、!=等。
2、数据类型、常量和变量
1、数据类型
-
基本数据类
- 逻辑bool
- 字符型char
- 实型(float、double)
- 整型int
- 空类型void 非基本数据类
- 数组type[]
- 指针type*
- 引用type&(c没有)
- 结构struct
- 联合union
- 枚举cnum
- 类(c没有)
2、C++数据类型
C++为强类型语言,所有类型数据的使用严格遵从“先说明后使用”以便编译器去编译。
3、常量
1、整型常量的表示形式:十进制,八进制,二进制
可在整形常量后加上I或L表示long int型
加u表示unsigned int 。也可以同时加ul
2、实型常量表示方法:一般形式(1.4、-1.2)
指数形式:尾部x10的次方形式-->123E12
3、字符型常量:用单引号扩起,一ascii码保存
转义字符:\n 换行,// 斜杠,\101 为A(8进制),/0 是null , \x61 为a(16进制)
4、字符串常量:用双引号扩起来若干字符
4、变量
变量说明的一般格式为:[存储类型] 数据类型 变量名 [变量名1,变量名2,变量名3,......]
3、运算符、优先级和结合性
1、运算符
对常量或变量处理或运算的符号叫运算符
分为单目、双目、三目。
2、基本运算符及表达式
1、自增自减
2、sizeof()
3、算数运算
4、关系和逻辑运算
5、条件运算
6、赋值运算
7、逗号运算
8、位运算
1、自增自减
符号在前:先增减后引用
符号在后:先引用后增减
#include <iostream.h>
void main(){
int a = 1;
cout << ++a;//结果为2
cout << a++;//结果仍为2但执行完语句后a变为3
}
2、sizeof()
sizeof()可以计算数据所占内存大小
#include <iostream.h>
void main(){
char a = 'A';
cout << sizeof(A);//输出为1,char类型占用1个字节
}
3、算数运算
优先级 | 运算符 | 名称 |
---|---|---|
2 | + | 正,单目 |
2 | - | 负,单目 |
3 | * | 乘,双目 |
3 | / | 除,双目 |
3 | % | 求余,双目 |
4 | + | 加,双目 |
4 | - | 减,双目 |
整型除完还是整形,出现小数取整数
实数运算时,只要有一个为实型,两个操作数均转化为double型
4、关系和逻辑运算
关系运算符:>、 >= 、<、 <=、 == 、!=。
#include <iostream.h>
void main(){
int a = 1;
int b = 2;
int c = 1;
cout <<(a > b);//结果为false输出0
cout <<(a == c);//结果我true输出1
cout <<(a != b);//结果我true输出1
}
三个数比较:a > b && b > c,这并不等同于连着写
应避免两个实数进行"=="和"!="运算
优先级 | 运算符 | 名称 | 语义 |
---|---|---|---|
2 | ! | 逻辑非,单目 | 操作数的值为真则结果为假,反之… |
11 | && | 逻辑与,双目 | 全为真时才是真,有一个假则为假 |
12 | || | 逻辑或,双目 | 有一个为真时结果为真 |
计算时,逻辑非优先级最高其次关系运算,与和或最低
5、条件运算
条件运算符:“?” , “:”
格式:表达式1 ? 表达式2 : 表达式3
#include <iostream.h>
void main(){
int a = 1;
int b = 2;
a > b ? a = 2 : a = 3;//a并不大于b => 执行表达式a = 3
cout << a;//结果为3
}
6、赋值运算
#include <iostream.h>
void main(){
int a = 1;
a = 5 + 6;//将5+6赋值给a
b = c = a + 1;//从右向左依次赋值
}
复合赋值运算符:+= 、/=、 -=、 *= 、 <<= 、 >>= 、&= 、 |= 、^ =
#include <iostream.h>
void main(){
int a = 0;
a += 1;//a = a + 1
a -= 1;//a = a - 1
a /= 1;//a = a / 1
......
}
7、逗号运算
格式:表达式1 , 表达式2 , 表达式3,........,表达式n
最终取值为最后一个表达式的值
#include <iostream.h>
void main(){
int a;
a = (x = 3 , x += 6 , 5 + 6);
cout << a ;//a取最后一个表达式值:11
}
8、位运算
1、按位取反"~"
按位取反运算符:对数据的每个二进制位取反,即把0变成1,把1变成0.
注:负数的二进制表示为他的正数取反+1
例如:8的二进制数位为00001000,则取反后为11110111 = -9
规律:~x=-(x+1);
2、按位与运算"&"
只有两个数的二进制同时为1,结果才为1,否则为0。(负数按补码形式参加按位与运算)
即 0 & 0= 0 ,0 & 1= 0,1 & 0= 0, 1 & 1= 1。
8 & 3 = 0000 1000 & 0000 0011 = 0000 0000 = 0
3、按位或运算"|"
参加运算的两个数只要两个数中的一个为1,结果就为1。
即 0 | 0= 0 , 1 | 0= 1 , 0 | 1= 1 , 1 | 1= 1 。
2 | 4 = 0000 0001 | 0000 0010 = 0000 0011 = 3
4、异或运算"^"
参加运算的两个数,如果两个相应位值不同,则该位结果为1,否则为0。
即 0 ^ 0=0 , 0 ^ 1= 1 , 1 ^ 0= 1 , 1 ^ 1= 0 。
5 ^ 3 = 0000 0101 ^ 0000 0011 = 0000 0110 = 6
5、左右移动运算符"<<" , “>>”
a << n :a向左移n位。
4 << 2 ==> 0000 0100 向左移2位 ==> 0001 0000 = 16
方法:被移动的数*2的n次方
a >> n :a向右移n位。
4 >> 2 ==> 0000 0100 向右移2位 ==> 0000 0001 = 1
方法:被移动的数/2的n次方
3、表达式的副作用
设x = 1
(x + 1) * (++x)
由于没有定义应该先算哪个括号里的,就会产生不同的结果:4 或 6
为了避免这种情况我们要把表达式分出来单独写
4、表达式求解中的数据类型转换
1、自动类型转换(隐式转换):由编译程序按照某种预定的规则进行自动转换。
short转int,int转long,float转double
2、强制类型转换(强制转换):由程序员在程序中使用类型转换操作符来指出转换。
强制类型转换格式:(要转换的数据类型)(被转换的表达式)。当表达式为简单表达式时括号可以缺省
//强制类型转换
(double) (a); //将a转化为double型
(int) (x * y);//将x*y转化为int型
(float) 5 / 2;//先将5转化为float再除2得2.5
(float) (5 / 2);//先算5/2=2再转化为float得2.0
5、15级优先级、运算顺序表
运算符 | 解释 | 结合方式 |
---|---|---|
() [] -> . | 括号(函数),数组,两种结构成员访问 | 由左向右 |
! ~ ++ – + - * & (类型)sizeof | 否定,按位否定,增量,减量,正负号,间接,取地址,类型转换,求大小 | 由右向左 |
x* / % | 乘,除,取模 | 由左向右 |
➕ - | 加,减 | 由左向右 |
<< >> | 左移,右移 | 由左向右 |
< <= >= > | 小于,小于等于,大于等于,大于 | 由左向右 |
== != | 等于,不等于 | 由左向右 |
& | 按位与 | 由左向右 |
^ | 按位异或 | 由左向右 |
| | 按位或 | 由左向右 |
&& | 逻辑与 | 由左向右 |
|| | 逻辑或 | 由左向右 |
? : | 条件 | 由右向左 |
= += -= *= /= &= |= <<= >>= | 各种赋值 | 由右向左 |
, | 逗号(顺序) | 由左向右 |
四、数组
1、一维数组
1、定义
定义形式:数据类型 数组名 [常量表达式]
例如:int a[];
2、引用
引用方式:数组名[下标];
例如:a [ 5 ]; a [ i + j ];
其中下标只能为张姓常量或整形表达式
3、初始化
初始化形式:int a [10] = {0,1,2,3,4,5,6,7,8,9};
也可以只给前面部分元素赋值
只能给元素逐个赋值,不能给数组整体赋值。
例如给十个元素全部赋1值,只能写为:int a[10]={1,1,1,1,1,1,1,1,1,1};
而不能写为: int a[10]=1
如给全部元素赋值,则在数组说明中, 可以不给出数组元素的个数。例如: int a[5]={1,2,3,4,5};
可写为:int a[ ]={1,2,3,4,5};
4、例子:冒泡排序
#include <iostream>
using namespace std;
int main() {
int nums[10];
int temp;
for (int i = 0; i < 10; i++) {
cout << "请输入第" << i + 1 << "个数:";
cin >> nums[i];
}
for (int j = 0; j < 9; j++) {
for (int k = 0; k < 9 - j; k++) {
if (nums[k] > nums[k + 1]) {
temp = nums[k];
nums[k] = nums[k + 1];
nums[k + 1] = temp;
}
}
}
cout << "排序结果为:";
for (int x = 0; x < 10; x++) {
cout << nums[x]<<" ";
}
2、二维数组
1、定义
二维数组定义的一般形式是:
数据类型 数组名[常量表达式1][常量表达式2];
例如:
int a[3][4]; 说明了一个三行四列的数组,数组名为a,
其下标变量的类型为整型。该数组的下标变量共有3×4
个,即:
a[0][0],a[0][1],a[0][2],a[0][3]
a[1][0],a[1][1],a[1][2],a[1][3]
a[2][0],a[2][1],a[2][2],a[2][3]
2、引用
二维数组的元素也称为双下标变量,其表示的形式为:
数组名[下标][下标]
其中下标应为整型常量或整型表达式。
3、初始化
二维数组初始化也是在类型说明时给各下标变量赋以初值。二维数组可按行分段赋值,也可按行连续赋值,例如对数组a[5][3]:
(1)按行分段赋值可写为
int a[5][3]={ {80,75,92},{61,65,71},{59,63,70},{85,87,90},{76,77,85} };
(2)按行连续赋值可写为
int a[5][3]={ 80,75,92,61,65,71,59,63,70,85,87,90,76,77,85 };
这两种赋初值的结果是完全相同的。
只赋值部分元素,未赋值部分自动取0
3、字符数组
1、定义
char c[10];
char c[5][10];//即为二维字符数组
2、初始化
字符数组也允许在类型说明时作初始化赋值。例如:
char c1[4]={'a','b','c','d'};
char c2[ ]=“abcd”;
3、常用函数
以下函数包含在stdio.h和string.h中
字符串输出函数puts:puts(ch);//在较新的编译器中用puts_s();
字符串输入函数gets:gets(ch);
字符串连接函数strcat :strcat(st1,st2);
字符转拷贝函数strcpy:strcpy(st1,st2);//把st2拷贝到st1
字符串比较函数:strcmp(str1,str2);
//按照ASCII码顺序比较两个数组中的字符串,并由函数返回值返回比较结果。
// 字符串1=字符串2,返回值=0;
// 字符串1>字符串2, 返回值>0;
// 字符串1<字符串2, 返回值<0。
字符串长度函数strlen:strken(st1);//获取长度
五、函数
1、函数的定义与声明
函数的定义就是在程序中编写函数, C++规定函数定义的格式是任何函数都由函数首部和函数体组成
<函数类型> 函数名(<形参列表>){
函数体
}
声明:被调用函数在mian函数后面时需要在前面声明
格式:<函数类型> 函数名(<形参列表>);
2、函数的类型与函数值
类型:void,int,double等
默认为int。
returen语句:
函数的返回值是通过return语句获得的。return语句的一般格式如下:
return (<表达式>);
3、函数的参数传递
C++有三种向函数传递参数的办法:传值、传地址和引用传递。
调用默认参数值函数的时候,编译器按从左至右的顺序将实参与形参结合,当实参数目不足时,编译器将按同样的顺序用声明中或定义中的默认值来补足缺少的实参
用数组名作函数的参数,在主调函数和被调用函数分别定义数组,例中的array是形参数组名,arr是实参数组名。
实参数组和形参数组大小可以不一致,其中形参数组也可以不指定大小。C++语言的编译器对数组的大小不作检查,只将实参数组的首地址传递给形参数组。
4、函数的调用
函数名(参数);
函数语句 有些函数没有返回值,调用这类函数的时候往往是要完成一系列操作,所以经常把这类函数作为一个独立语句
函数表达式 函数可以出现在表达式中,并且称这类表达式为函数表达式。这时函数必须有一个确定的返回值
函数参数 函数可以作为参数存在于另一个函数中
5、递归
递归的过程可以分为两个阶段:“递推”阶段和“回归”阶段。“递推”阶段是将原问题不断地分解为新的子问题,逐渐从未知到已知,最终达到已知条件,即递归的结束条件,这时递归结束。“回归”阶段是从已知的条件,按“递推”的逆过程,逐步求值返回,最后达到“递推”的开始处,结束回归过程,完成递归调用。以4的阶乘为例。
例子:计算某个正整数的阶乘
#include <iostream.h>
long int fac(int n)
{ int total;
if (n= =1|| n= =0) total=1;
else total= fac(n-1)* n;
return total;
}
void main( )
{ int n;
cout<<"please input a integer :";
cin>>n;
cout<<n<<"! is "<<fac(n)<<endl;
}
6、内联函数
内联函数也称内嵌函数。引入内联函数的目的是为了提高程序中函数调用的效率。
定义:
inline 函数名 (形参)
{
//函数体
}
7、函数重载
例如求两个整数之和的函数与求两个实数之和的函数可以声明如下形式:
int int_add(int , int );
double double_add(double , double);
这种方法要求程序员要对函数间传递的数据类型详细掌握,否则就可能出错。C++提供了函数重载的功能
重载是指同一个函数名对应多个函数的现象,也就是说,多个函数具有同一个函数名。
int add(int , int );
double add(double , double);
参数匹配问题:
一般重载函数匹配有下面三种情况:
1)寻找一个严格的匹配,如果找到了,就用那个函数。
2)通过内部转换寻求一个匹配,只要找到了,就用那个函数。
3)通过用户定义的转换寻求一个匹配,若能查出有唯一的一组转换,
就用那个函数。
例如,重载函数add ( )的匹配:
cout<<add(1,2)<<endl; //匹配int add(int , int);
cout<<add(1.2,3.4)<<endl; // 匹配double add(double , double);
cout<< add('a' , 'b')<<endl; // 匹配int add(int , int);
8、变量和函数的作用域
1、变量的作用域
1.局部变量 局部变量是指定义在函数或程序块内的变量,它们的作用域分别在所定义的函数体或程序块内。
void main( )
{int x ; //x为定义在main( )函数中的局部变量其作用域为main( )函数内
… …
{int y ; //y为定义在块内的局部变量,其作用域为块内
… …
}
}
void fun( )
{ char ch ;
//ch为定义在fun( )函数的局部变量,其作用域为fun()函数内
}
2.全局变量 全局变量是定义在函数以外的变量(也称外部变量),并且对于整个文件的函数都是可见的。全局变量的作用域是从定义变量的位置到本文件的结束。
#include <iostream.h>
int a=0; //a的作用域为整个文件
void main()
{ cout<<a<<endl;
fun1( );
}
void fun1()
{ cout<<a<<endl; }
存储类别可以分为:动态存储方式与静态存储方式。具体的包含四种:自动的(auto)、寄存器的(register)、静态的(static)和外部的(extern)。
存储类型 数据类型 变量名[=初值]
1.动态存储方式 使用动态存储方式的变量有两种:自动类变量和寄存器类变量。
(1)自动变量:
int fun( )
{auto int a; // a为自动类变量 }
int fun( )
{int a; }
(2)寄存器变量:
#include <iostream.h>
void main( )
{ register int i;
int sum=0;
for(i=1;i<=100;i++)
sum+=i;
cout<<"1+2+...+100="<<sum<<endl;
}
2.静态存储方式 使用静态存储方式的变量有两种:外部变量和静态变量。
例:在一个文件中声明外部变量,扩展外部变量使用范围。
void fun1( );
extern x; //外部变量声明
void main()
{ x=4;
cout<<x<<endl;
}
int x; //外部变量定义
例:将外部变量的作用域扩展到其他文件。
//文件file1.cpp中:
#include <iostream.h>
extern w;
void main( )
{
cout<<w<<endl;
}
文件file2.cpp中:
int w=10;
程序运行结果如下:
10
外部变量的生命周期为程序执行过程,而作用域为从定义到文件结束和外部声明之后的文件中
2、函数的作用域
函数按其存储类别可以分为两类:内部函数和外部函数。
1.内部函数 也称为静态函数,格式如下:
static <函数类型> <函数名>(<参数列表>)
{
<函数体>
}
//内部函数的作用域只限于定义它的文件,所以在同一个程序的不同文件中可以有相同命名的函数,它们互不干扰。
2.外部函数 外部函数是可以在整个程序各个文件中被调用的函数。外部函数定义时,在函数类型前加extern,格式如下:
extern <函数类型> <函数名>(<参数列表>)
{
<函数体>
}
//如果定义时没有声明函数的存储类型,系统默认为extern型。
9、宏定义
不带参数宏定义的格式如下:
#define <宏名> <字符串>
#define PI 3.14159
//其中,define是关键字,<宏名>是一个标识符,<字符串>是字符序列
//宏定义可以嵌套
带参数宏定义的格式如下:
#define <宏名>(参数列表) <字符串>
//带参数宏定义不仅是简单的文本替换,还要进行参数替换。
#include <iostream.h>
#define PI 3.14159
#define S(r) PI*r*r//单参数宏定义
void main( )
{ float s,r;
r=3.0;
cout<<"the result is :"<<S(r)<<endl;//调用
}
10、文件包含
文件包含的命令格式如下:
#include <文件名> 或 #include "文件名"