HelloWorld!
#include <iostream>
using namespace std;
int main(){
cout << "Hello World!" << "\n";
return 0;
}
编译&执行C++程序
- 打开命令提示符,进入文件所在目录;
- 编译文件,生成可执行程序;
- 执行可执行程序。
$ g++ hello.cpp
$ ./a.out
Hello World!
数据类型
bool
char
int
float
double
void
wchar_t 宽字符型
typedef short int wchar_t;
一些基本类型可以使用一个或多个类型修饰符进行修饰:
signed unsigned short long
<< 用于向屏幕传多个值
sizeof() 用于获取给中数据类型的大小
typedef声明
可以为一个已有的类型取一个新名字
typrdef type newname;
枚举类型
枚举是C++的一种派生数据类型;
创建枚举
enum color {red, green, blue } c;
c = blue;
默认情况下,第一个名称的值为0,第二个名称的值为1,…但是可以赋予特殊的值;
enum color {red, green=5, blue};
blue的值就变为6。
类型转换
类型转换是将一个数据类型的值转换为另一种数据类型的值。
静态转换【static_cast】
int i=10;
float f = static_cast<float>(i);
动态转换【dynamic_cast】
class Base {};
class Derived : public Base {};
Base* ptr_base = new Derived;
Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base); // 将基类指针转换为派生类指针
常量转换【const_cast】
用于将const类型的对象转换为非const类型的对象。
常量转换只能用韩语转换掉const属性,不能改变对象的类型。
const int i=10;
int& r = const_cast<int&>(i);
重新解释转换【reinterpred_cast】
重新解释转换将一个数据类型的值重新解释为另一个数据类型的值,通常用于在不同的数据类型之间进行转换。
重新解释转换不进行任何类型检查,因此可能会导致未定义的行为。
int i=10;
float f = reinterpred_cast<float&>(i); // int -> float
变量类型
有效声明
int i,j,k,l;
char c,ch;
float f,salary;
double d;
函数调用
// 函数声明
int func();
int main(){
int i = func();
}
// 函数定义
int func(){
return 0;
}
C++中的左值和右值
左值:指向内存位置的表达式被称为左值表达式;
右值:值得是存储在内存中某些地址的数值。
int g = 20;
变量作用域
三个地方可以定义变量:
- 局部变量
- 形式参数
- 全局变量
作用域: - 局部作用域
- 全局作用域
- 块作用域
- 类作用域
如果在内部作用域中声明的变量与外部作用域中的变量同名,则内部作用域中的变量将覆盖外部作用域中的变量。
初始化局部变量和全局变量
#include<iostream>
int main(){
int a=10;
{
int a=5;
std::cout << "块变量" << a << std::endl;
}
std::cout << "外部变量" << a << std::endl;
return 0;
}
类作用域
# include <iostream>
class MyClass{
public:
static int class_var;
};
int MyClass::class_var = 30;
int main(){
std::cout << "类变量" << MyClass::class_var << std::endl;
return 0;
}
可以使用类名和作用域解析运算符 :: 来访问这个变量。
常量
整数常量
常量是固定值,在程序执行期间。
整数常量可以是十进制、八进制、十六进制
212
215u // 表示无符号整数
0xFeeL // L表示长整数
// 后缀可以是大写,也可以是小写,U和L的顺序任意
布尔常量
不能将true的值看成1,false的值看成0。
字符常量【转义】
字符串常量
字符串常量是扣在双引号 “” 中的,可以使用 \ 做分隔符,把一个很长的字符串常量进行分行。
定义常量
在c++中有两种简单的定义常量的方式
- 使用#define预处理器
- 使用const关键字
define预处理器
#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关键字
#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;
}
常常把常量定义写为大写字母形式
C++修饰符类型
C++允许在char、int和 double 数据类型前放置修饰符。
修饰符是用于改变变量类型的行为的关键字。
C++类型限定符
C++存储类
存储类定义C++程序中变量、函数的范围和生命周期。这些说明符放置在他们所修饰的类型之前。下面列出C++程序中可用的存储类:
- auto
- register
- static
- extern
- mutable
- thread_local (C++11)
auto
自C++11以来,auto用于两种情况:声明变量时根据初始化表达式推断该变量的类型、声明函数时函数返回值的占用符。
auto f = 3.14; // double
auto s("hello"); // const char*
auto z = new auto(9); // int
auto x1 = 5, x2 = 5.0, x3 = 'r'; // 错误,必须初始化为同一类型
register
{
register int miles;
}
register存储类用于定义存储在寄存器中而不是RAM中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 & 运算符(因为没有内存位置)。
寄存器只用于需要快速访问的变量,比如计数器。
定义register并不意味着变量被存在寄存器中,意味着变量可能存在寄存器中,取决于硬件和实现的限制。
static
static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
#include<iostream>
void func(void);
static int count=10; // 全局变量
int main(){
while(count--){
func();
}
return 0;
}
void func(void){
static int i=5;
i++;
std::cout << i;
std::cout << count << std::endl;
}
extern【挖坑】
extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 ‘extern’ 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
mutable
仅适用于类的对象,允许对象的成员替代常量,也就是说,mutable成员可以通过const成员函数修改。
thread_local
使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。
thread_local 说明符可以与 static 或 extern 合并。
可以将 thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。
thread_local int x; // 命名空间下的全局变量
class X{
static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string X::s; // X::s需要定义
void foo(){
thread_local std::vector<int> v; // 本地变量
}
运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 杂项运算符
循环
while
for
do … while
嵌套
break
continue
goto 不建议使用
判断
if
if … else
if … else if
swith
? : 可以用if else 替代
函数
形式
return_type function_name (parameter list){
body of the function
}
Lambda函数与表达式【挖坑】
[capture](parameters)->return-type{body}
C++数字
定义数字
#include<iostream>
using namespace std;
int main(){
short s;
int i;
long l;
float f;
double d;
// 数字赋值
s = 10;
i = 1000;
l = 1000000;
f = 230.47;
d = 30949.374;
// 数字输出
cout << "short s :" << s << endl;
cout << "int i :" << i << endl;
cout << "long l :" << l << endl;
cout << "float f :" << f << endl;
cout << "double d :" << d << endl;
return 0;
}
数学运算
#include<iostream>
#include<math>
using namespace std;
int main(){
// 数字定义
short s = 10;
int i = -1000;
long l = 100000;
float f = 230.47;
double d = 200.374;
// 数学运算
cout << "sin(d) :" << sin(d) << endl;
cout << "abs(i) :" << abs(i) << endl;
cout << "floor(d) :" << floor(d) << endl;
cout << "sqrt(f) :" << sqrt(f) << endl;
cout << "pow( d, 2) :" << pow(d, 2) << endl;
return 0;
}
C++随机数
在许多情况喜爱,需要生成随机数。关于随机数生成器,又来那个函数。
rand() 该函数只返回一个伪随机数。生成随机数之前必须先调用srand()函数。
#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;
int main(){
int i, j;
// 设置种子
srand((unsigned)time(NULL));
for (i=0; i<10; i++) {
j = rand();
cout << j << endl;
}
return 0;
}
数组
c++可以存储一个固定大小的相同类型的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
#include<iostream>
using namespace std;
#include<iomanip>
using std::setw;
int main(){
int n[10];
for (int i=0; i<10; i++) {
n[i] = i+100;
}
cout << "Element" << setw(13) << "value" << endl;
for (int j=0; j<10; j++) {
cout << setw(7) << j << setw (13) << n[j] << endl;
}
return 0;
}
多维数组
#include<iostream>
using namespace std;
int main(){
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6}, {4,8} };
for (int i=0; i<5; i++) {
for (int j=0; j<2; j++) {
cout << "a[" << i << "][" << j << "]:";
cout << a[i][j] << endl;
}
}
return 0;
}
从键盘输入数据:
#include<iostream>
using namespace std;
int main(){
int n;
cin >> n;
int a[n+3][n+3];
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
cin >> a[i][j];
}
}
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
cout << a[i][j] << " ";
cout << endl;
}
}
return 0;
}
指向数组的指针
#include<iostream>
using namespace std;
int main(){
double runoobAarray[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
p = runoobAarray;
cout << "使用指针的数组值" <<endl;
for (int i=0; i<5; i++) {
cout << "*(p+" << i << "):";
cout << *(p+i) <<endl;
}
cout << "使用runoobAarray作为地址的数组值" << endl;
for (int i=0; i<5; i++) {
cout << "*(runoobAarray + )" << i << "):";
cout << *(runoobAarray + i) << endl;
}
return 0;
}
传递数组给函数
#include<iostream>
using namespace std;
// 函数声明
double getAverage(int arr[], int size);
int main(){
int balance[5] = {1000, 2, 3, 17, 50}
double avg;
avg = getAverage(balance, 5);
cout << avg <<endl;
return 0;
}
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++不允许返回一个完整的数组作为函数的参数。但是,可以通过指定不带索引的数组名来返回一个指向数组的指针。
想从函数返回一个一维数组,必须声明一个返回指针的函数:
int* myFunction(){
int myArray[3] = {1, 2, 3};
return myArray;
}
note:不能简单地返回指向局部数组的指针,因为当函数结束时,局部数组将被销毁,指向它的指针将无效。
C++不支持在函数外返回局部变量的地址,除非定义局部变量为static变量。
使用静态数组需要再函数内部创建一个静态数组,并将其地址返回:
int* myFunction(){
static int myArray[3] = {1, 2, 3};
return myArray;
}
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int* getRandom(){
static int r[10];
// 设置种子
srand((unsigned)time(NULL));
for (int i=0;l i<10; i++) {
r[i] = rand();
cout << r[i] <<endl;
}
return r;
}
int main(){
int *p;
p = getRandom();
for (int i=0; i<10; i++) {
cout << "*(p+" << i << "):";
cout << *(p+i) <<endl;
}
return 0;
}
使用动态分配数组需要再函数内部使用new运算符来分配一个数组,并在函数结束时使用delete运算符释放该数组:
int* myFunction(){
int * myArray = new int[3];
myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 3;
return myArray;
}
int main(){
int* result = myFunction();
delete[] result;
return 0;
}
应用实例:
#include<iostream>
using namespace std;
int* createArray(int size) {
int* arr = new int[size];
for (int i=0; i<size; i++) {
arr[i] = i+1;
}
return arr;
}
int main(){
int* myArray = createArray(5);
for (int i=0; i<5; i++) {
cout << myArray[i] << " ";
}
cout <<endl;
delete[] myArray; // 释放内存
return 0;
}
字符串
C风格字符串
字符串实际上是使用null字符 \0 终止的一维字符数组。
#include<iostream>
using namespace std;
int main(){
char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};
cout << site<<endl;
return 0;
}
#include<iostream>
#include<cstring>
using namespace std;
int main(){
char str1[13] = "runoob";
char str2[13] = "google";
char str3[13];
int len;
strcpy(str3, str1);
cout << str3 <<endl;
strcat(str1, str2);
cout << str1 <<endl;
len = strlen(str1);
coout << len <<endl;
return 0;
}
C++ 引入string类类型
#include<iostream>
#include<string>
using namespace std;
int main(){
string str1 = "runoob";
string str2 = "google";
string str3;
int len;
str3 = str1;
cout << str3 <<endl;
str3 = str1 + str2;
cout << str3 <<endl;
len = str3.size();
coout << len <<endl;
return 0;
}
C++指针
每一个变量都有一个内存地址,每一个内存地址都定义了可使用连字号 & 运算符访问的地址,它表示了在内存中的一个地址。
#include<iostream>
using namespace std;
int main(){
int var1;
char var2[10];
cout << &var1 <<endl; // var1变量的地址
cout << &var2 <<endl; // var2变量的地址
return 0;
}
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,使用指针存储其他变量之前,必须声明。
#include<iostream>
using namespace std;
int main(){
int var = 20;
int *ip;
ip = &var;
cout << var <<endl; // 变量值
cout << ip <<endl; // 地址值
cout << *ip <<endl; // 通过地址访问变量值
return 0;
}
C++Null指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个NULL值是一个良好的变成习惯。
#include<iostream>
using namespace std;
int main(){
int *ptr=NULL;
cout << "ptr的值是" << ptr;
return 0;
}
// ptr的值是0
C++指针的算数运算
#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 << ptr <<endl;
cout <<*ptr <<endl;
ptr++;
}
return 0;
}
// ptr–
C++指针vs数组
指针和数组在很多情况下是可以互换的。
#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 << ptr << endl;
cout << *ptr <<endl;
ptr++;
}
return 0;
}
C++指针数组
#include<iostream>
using namespace std;
const int MAX=3;
int main(){
int var[MAX] = {10, 100, 200};
int *ptr[MAX];
for (int i=0; i<MAX; i++) {
ptr[i] = &var[i];
}
for (int i=0; i<MAX; i++) {
cout << *ptr[i] <<endl;
}
return 0;
}
C++指向指针的指针
int **var;
#include<iostream>
using namespace std;
int main(){
int var;
int *ptr;
int **pptr;
var = 3000;
ptr = &var;
pptr = &ptr;
cout << var <<endl;
cout << *ptr <<endl;
cout <<**pptr<<endl;
return 0;
}
C++传递指针给函数
#include<iostream>
#include<ctime>
using namespace std;
void getSeconds(unsigned long *par);
int main(){
unsigned long sec;
getSeconds( &sec );
cout << sec <<endl;
return 0;
}
void getSeconds(unsigned long *par){
*par = time(NULL);
return;
}
// Number of seconds :1294450468
C++从函数返回指针
#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;
// 要生成和返回随机数的函数
int * getRandom(){
static int r[10];
srand((unsigned)time(NULL));
for (int i=0; i<10; i++) {
r[i] = rand();
cout << r[i] <<endl;
}
return r;
}
int main(){
int *p;
p = getRandom();
for (int i=0; i<10; i++) {
cout << *(p+i) <<endl;
}
return 0;
}
C++引用
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字,一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
C++中创建引用:
int i=17;
int & r = i;
double& s = d;
#include<iostream>
using namespace std;
int main(){
int i;
double d;
int& r = i;
double& s = d;
i=5;
cout << r << endl;
d = 5.20;
cout << s <<endl;
}
C++把引用作为参数
#include<iostream>
using namespace std;
void swap(int& x, int& y);
int main(){
int a = 100;
int b = 200;
swap(a, b);
cout << a <<endl;
cout << b <<endl;
return 0;
}
void swap(int&x, int& y){
int temp;
temp = x;
x = y;
y = temp;
return;
}
C++引用作为返回值
通过使用引用来替代指针,会使C++程序更容易阅读和维护。C++函数可以返回一个引用,方式与返回一个指针类似。
#include<iostream>
using namespace std;
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues(int i) {
double& ref = vals[i];
return ref;
}
int main(){
cout << "改变前的值" <<endl;
for(int i=0; i<5; i++) {
cout << vals[i] <<endl;
}
setValues(1) = 30.8;
setValues(3) = 6.66;
cout << "改变后的值" <<endl;
for(int i=0; i<5; i++) {
cout << vals[i] <<endl;
}
return 0;
}
C++日期 & 时间
C++ 标准库没有提供所谓的日期类型。C++ 继承了 C 语言用于日期和时间操作的结构和函数。为了使用日期和时间相关的函数和结构,需要在 C++ 程序中引用 头文件。
有四个与时间相关的类型:clock_t、time_t、size_t 和 tm。类型 clock_t、size_t 和 time_t 能够把系统时间和日期表示为某种整数。
struct tm {
int tm_sec; // 秒,正常范围从 0 到 59,但允许至 61
int tm_min; // 分,范围从 0 到 59
int tm_hour; // 小时,范围从 0 到 23
int tm_mday; // 一月中的第几天,范围从 1 到 31
int tm_mon; // 月,范围从 0 到 11
int tm_year; // 自 1900 年起的年数
int tm_wday; // 一周中的第几天,范围从 0 到 6,从星期日算起
int tm_yday; // 一年中的第几天,范围从 0 到 365,从 1 月 1 日算起
int tm_isdst; // 夏令时
};
C++基本的输入输出
#include <iostream>
using namespace std;
int main( )
{
char name[50];
cout << "请输入您的名称: ";
cin >> name;
cout << "您的名称是: " << name << endl;
}
标准错误流
#include <iostream>
using namespace std;
int main( )
{
char str[] = "Unable to read....";
cerr << "Error message : " << str << endl;
}
标准日志流
#include <iostream>
using namespace std;
int main( )
{
char str[] = "Unable to read....";
clog << "Error message : " << str << endl;
}
C++数据结构
结构是C++中另一种用户自定义的可用的数据类型,它允许存储不同类型的数据项。
定义结构
struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
type_name 是结构体类型的名称,member_type1 member_name1 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在结构定义的末尾,最后一个分号之前,您可以指定一个或多个结构变量,这是可选的。
指向结构的指针
#include<iostream>
#include<cstring>
using namespace std;
void printBook(struct Books *book);
struct Books{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main() {
Books Book1;
Books Book2;
// Book1 详述
strcpy( Book1.title, "C++ 教程");
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "编程语言");
Book1.book_id = 12345;
// Book2 详述
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技术");
Book2.book_id = 12346;
// 通过传 Book1 的地址来输出 Book1 信息
printBook( &Book1 );
// 通过传 Book2 的地址来输出 Book2 信息
printBook( &Book2 );
return 0;
}
// 该函数以结构指针作为参数
void printBook( struct Books *book ) {
cout << "书标题 : " << book->title <<endl;
cout << "书作者 : " << book->author <<endl;
cout << "书类目 : " << book->subject <<endl;
cout << "书 ID : " << book->book_id <<endl;
}