1. C++简介
面向对象程序设计的四大特性:
- 封装
- 抽象
- 继承
- 多态
标准C++由三个重要部分组成:
- 核心语言:提供所有构件块,如变量、数据类型和常量等
- C++标准库:提供大量函数,用于操作文件,字符串等
- 标准模板库(STL):提供大量方法,用于操作数据结构;
(函数和方法的区别?)
1.1 C++基本语法
C++程序可认为是对象的集合,对象间利用调用彼此的方法进行交互。
-
对象 - 具有状态和行为。例如:一只狗的状态 - 颜色、名称、品种;行为 - 摇动、叫唤、吃。对象是类的实例。
-
类 - 类可以定义为描述对象行为/状态的模板/蓝图。
-
方法 - 从基本上说,一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据以及执行所有的动作。
-
即时变量 - 每个对象都有其独特的即时变量。对象的状态是由这些即时变量的值创建的。
1.2 C++数据类型
1.2.1 数据类型
基本类型:
类型修饰符:
- signed
- unsigned
- short
- long
1个字节:char(-128~127或0-255), unsigned char(0-255), signed char(-128~127)
2个字节:short int等
4个字节:int, float 等
8个字节:long int, double等
16个字节:long double
**typedef声明 **
typedef type newname
typedef int feet; // 令feet为int的另一个名称
枚举类型enum
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数]
} 枚举变量;
enum colorEnum {
red,
green,
blue
} color;
color = blue;
- 注:可以给其中的名称赋值,例如green=5; 则后续的默认为前者+1,即blue=6;
extern关键字: 用于声明全局变量
声明可以和定义分开。例如可以在代码前声明函数名,最后再定义函数。
1.2.2 常量
- 0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。
- 整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。
- 浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
- 当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。带符号的指数是用 e 或 E 引入的。
定义常量
两种方式:(常用,且一般定义为大写字母形式)
- 使用#define预处理器:#define identifier value
#include <iostream>
using namespace std;
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main()
{
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
- 使用const关键字:const type variable = value;
#include <iostream>
using namespace std;
int main()
{
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
字符常量
一般字符常量括在单引号‘ ’中。
注意,加了反斜杠,可能有特殊含义,例如:
1.2.3 存储类
- static存储类
- static可以应用于全局变量,当static修饰全局变量时,使变量的作用域限制在声明它的文件中;
- C++中,static用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。(?)
- static存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。(即在函数中声明后,不会每一次调用函数都重新对这个变量赋值)
- extern存储类
- 用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。
- 如果一个全局变量或函数已经在别的文件中用extern声明了,则可以在另一个文件中使用extern来得到已定义的变量或函数的引用。
- 即extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候
其余类型暂时省略,以后用到再补充
1.2.4 运算符
https://www.runoob.com/cplusplus/cpp-operators.html
需要时直接参考
指针运算符:&和*
优先级普遍规律:
自增自减运算符 > 逻辑非和按位非 > 算数运算符 > 比较运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符
同类运算符的优先级:
-
算数运算符:乘,除,求余的优先级相同,高于加,减
-
自增自减运算符:后自增/自减的优先级,高于前自增/自减
(前自增:先+1再使用;后自增:先使用再+1)
-
赋值运算符:所有赋值运算符的优先级相同
-
逻辑运算符:逻辑非的优先级最高,其次是逻辑与,最后是逻辑或
-
比较运算符:大于/大于等于,小于/小于等于的优先级高于,等于和不等于
-
位运算符:按位取反的优先级最高,其次是按位与,再其次是按位异或,最后是按位或
-
成员和成员指针运算符:成员运算符的优先级要高于成员指针运算符
不同类运算符的优先级:
-
1,自增自减运算符的优先级高于所有逻辑运算符和算数运算符。
-
2,除逻辑非和按位非运算符优先级相同以外,所有的位运算符的优先级高于逻辑运算符。
-
3,算数运算符的优先级要高于比较运算符和逻辑运算符。
-
4,比较运算符的优先级要高于逻辑运算符。
-
5,逻辑运算符的优先级要高于赋值运算符。
-
6,赋值运算符的优先级要高于逗号运算符
原文链接:https://blog.csdn.net/Light_of_cc/article/details/120657754
1.3 C++逻辑
C++三种循环:
- while
while(condition)
{
statement(s);
}
while循环可能一次都不会执行
- for
for ( init; condition; increment )//注意两个分号
{
statement(s);
}
- do… while
do
{
statement(s);
}while( condition );
do…while循环至少实现一次
C++循环控制语句:
- break; 终止loop或switch语句,程序流将执行紧接着的下一条语句;
- continue; 令循环跳过主体的剩余部分;
C++判断
- if
- if…else
- switch…case
switch(expression){
case constant-expression :
statement(s);
break; // 可选的
case constant-expression :
statement(s);
break; // 可选的
// 您可以有任意数量的 case 语句
default : // 可选的
statement(s);
}
- Exp1 ? Exp2 : Exp3; 如果1真则计算2,如果1假则计算3。
1.4 C++函数
一般形式为:
return_type function_name(parameter list)
{
body of the function
}
函数声明告诉编译器函数的名称、返回类型和参数
-
在parameter list中可以缺省参数名;可以给参数赋一个默认值,当缺省该参数时自动使用;
-
若要跨文件调用函数,必须在调用函数文件的顶部声明函数;
1.5 数字,数组与字符串
1.5.1 数字与随机数
注意数字的类型(int, float, double, short, long…).
**数学运算可以利用库函数<cmath> **
例如:
-
三角函数sin, cos, tan;
-
自然对数log;
-
幂pow;
-
平方根sqrt;
-
整数绝对值abs: int abs(int);
-
浮点数绝对值fabs: double fabs(double);
-
向下取整floor: double floor(double);
C++随机数
rand()和srand(). 前者返回一个伪随机数。生成随机数之前必须先调用srand()函数。
使用时需要包含头文件
#include <iostream>
#include <ctime>
#include <cstdlib>
可以使用cstdlib头文件中的rand()函数来获得随机整数;
这个函数返回0~RAND_MAX之间的随机整数;
rand()函数生成的是伪随机数。即每次在同一个系统上执行这个函数的时候,rand()函数生成同一序列的数。
rand()函数的算法使用一个叫种子的值来控制生成数字。默认情况下,种子的值是1,。如果改变种子为不同值,随机数也会不同。(只要随机数种子不变,其生成的随机数序列就不会改变。)
可以使用cstdlib头文件中的srand(seed)函数来改变种子的值。为确保程序中每一次种子的值不同,可以使用time(0)作为种子,即srand(time(0))
调用time(0)需要**<ctime>**头文件;srand(time(0))只需执行一次,放置于主函数内rand()上方或rand()所在的循环外面(若置于循环内,所有循环将得到相同的值)
原文链接:https://blog.csdn.net/EmileJiao/article/details/123351432
获取指定范围内的随机数(含指定位数)
(其实就是对rand获得的随机数进行求余)
取得 [ 0 , x ) 的随机整数:rand()%x ;
取得 [ 0 , x ] 的随机整数:rand()%(x+1) ;
取得 [ a , b ) 的随机整数:rand()%(b-a) + a ;
取得 ( a , b ] 的随机整数:rand()%(b-a) + a+1 ;
取得 [ a , b ] 的随机整数:rand()%(b-a+1) +a ;
取得 0 - 1 之间的浮点数:rand()/double(RAND_MAX)。
1.5.2 数组
声明一个数组变量,然后利用索引访问特定的数组元素。
声明数组
/* 一维数组 */
//type arrayName [arraySize];
double a_1[10]; //现在a_1是一个可容纳10个double数字的数组
/* 多维数组 */
//type arrayName[size1][size2]...[sizeN];
double a_2[3][4];//现在a_2是一个三行四列的数组
1.5.3 字符串
字符串实际上是使用null字符\0终止的一维字符数组。
C风格字符串:
char word1[]="ABCDEFG";//数组的大小比ABCDEFG大1,即8。
C++中可以用来操作以null结尾的字符串的函数:
# include <cstring>
strcpy(s1,s2); //复制字符串s2到s1.
strcat(s1,s2);//连接字符串s2到s1末尾。
string str=str1+str2;//与上式等效;
strlen(s1); //返回字符串s1的长度(注意此处不包含空字符)
strcmp(s1,s2); //比较两个字符串,相同返回0;
//如果s1<s2,返回值小于 0;s1>s2,返回值大于0;
strchr(s1,ch); //返回一个指针,指向字符串s1中字符ch第一次出现的位置;
strstr(s1,s2);//返回一个指针,指向字符串s1中字符串s2的第一次出现的位置;
C++风格字符串:
C++标准库提供了string类型,功能丰富。例子如下:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 = "runoob";
string str2 = "google";
string str3;
int len ;
// 复制 str1 到 str3
str3 = str1;
cout << "str3 : " << str3 << endl;
// 连接 str1 和 str2
str3 = str1 + str2;
cout << "str1 + str2 : " << str3 << endl;
// 连接后,str3 的总长度
len = str3.size();
cout << "str3.size() : " << len << endl;
return 0;
}
1.6 C++指针与引用
1.6.1 指针
指针是一个变量,其值为另一个变量的地址。
指针占用内存:32位系统中为4字节;64位系统中为8字节。
每一个变量都有一个内存地址,每一个内存位置都定义了可使用 & 访问的地址。
- &:获取变量的地址;【取址】
- *****:访问指针地址对应的变量值;【取值】
声明指针的一般形式:
//type *var-name;
int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
// 注意,此处的int,double等类型,代表指针的基类型,它必须是一个有效的C++数据类型。此处*用来指定该变量为指针。
// 所有指针的值的实际数据类型,实际上都是一样的,都是一个代表内存地址的十六进制数。指针前的基类型代表指针所指向的变量或常量的数据类型不同。
-
在指针声明时,如果没有确切的地址可以赋值,建议赋NULL,即空指针。
-
数组可以视为一个常量指针。
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr;// 声明一个指针
ptr = var;// 将数组地址赋给指针(直接用数组名)
for (int i = 0; i < MAX; i++)
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// 移动到下一个位置
ptr++;
}
return 0;
}
- 可以给函数传递指针,即声明函数参数为指针类型。能接受指针的函数,等价于可以接收数组作为参数
...
int main(){
int balance[5]={1,2,3,4,5};
double avg;
avg=getAverage(balance,5);//此处传递的为数组名
...
}
double getAverage(int *arr, int size)
{
int i,sum=0;
double avg;
for(i=0;i<size;++i)
{
sum += arr[i];
}
avg=double(sum)/size;
return avg;
}
- 也可以令函数返回指针,但C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static变量。
int *myFunc(){
static int r[10];
...
return r;
}
1.6.2 引用
引用变量相当于一个别名。引用与指针的主要区别有:
- 不能空引用。引用必须连接到一块合法内存。
- 当引用被初始化为一个对象后,就不能再被指向另一个对象。而指针可以更改。
- 引用必须在创建时被初始化。
声明引用:
//type & referName=name;
int i=17;
int& r=i; //引用
int *z=&i;//指针
C++引用类型的主要作用:用于给函数传参(比指针方便)。
引用作为函数参数
C++之所以增加引用类型, 主要是把它作为函数参数,以扩充函数传递数据的功能。
C++ 函数传参:
(1)将变量名作为实参和形参。这时传给形参的是变量的值,传递是单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。// 同 C
(2) 传递变量的指针。形参是指针变量,实参是一个变量的地址,调用函数时,形参(指针变量)指向实参变量单元。这种通过形参指针可以改变实参的值。// 同 C
(3) C++提供了 传递变量的引用。形参是引用变量,和实参是一个变量,调用函数时,形参(引用变量)指向实参变量单元。这种通过形参引用可以改变实参的值。
- 当函数返回值为引用类型时,相当于返回一个变量的别名,所以这个函数可以出现在等号左边。
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues(int i) {
double& ref = vals[i];
return ref; // 返回第 i 个元素的引用,ref 是一个引用变量,ref 引用 vals[i]
}
// 要调用上面定义函数的主函数
int main ()
{
cout << "改变前的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
setValues(1) = 20.23; // 改变第 2 个元素
setValues(3) = 70.8; // 改变第 4 个元素
cout << "改变后的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
return 0;
}
// 输出结果成功改变了。
- 在返回一个引用时,要注意被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。
int& func() {
int q;
//! return q; // 在编译时发生错误
static int x;
return x; // 安全,x 在函数作用域外依然是有效的
}