c++语言学习

一、基本的c++语法

1.1 数据类型

1. 基本的内置类型

7种基本的数据类型

关键字内存 (Linux-64)
bool1个字节
char1个字节
int4个字节
float4个字节
double8个字节
void
wchar_t4个字节
    cout << "bool: \t\t" << "所占字节数:" << sizeof(bool);  
    cout << "\t最大值:" << (numeric_limits<bool>::max)();  
    cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl;  
    // bool: 所占字节数:1   最大值:1    最小值:0

2. typedef 声明

使用 typedef 为一个已有的类型取一个新的名字

    typedef int feet;
    feet distance;  //创建了一个整型变量 distance:

3. 枚举类型

如果一个变量只有几种可能的值,可以定义为枚举(enumeration)类型。所谓"枚举"是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内。

// 定义一个颜色枚举,变量 c 的类型为 color。c 被赋值为 "blue"。
enum color { red, green, blue } c;
c = blue;

// 默认情况下,每个名称都会比它前面一个名称大 1, 以此类推。
enum color { red, green=5, blue };   // blue 的值为 6,red仍为0

4. 类型转换

C++ 中有四种类型转换:静态转换、动态转换、常量转换和重新解释转换。

静态转换(Static Cast)

强制类型转换
静态转换不进行任何运行时类型检查,因此可能会导致运行时错误。

int i = 10;
float f = static_cast<float>(i); // 静态将int类型转换为float类型
动态转换(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); // 常量转换,将const int转换为int
重新解释转换(Reinterpret Cast)

重新解释转换将一个数据类型的值重新解释为另一个数据类型的值,通常用于在不同的数据类型之间进行转换。
重新解释转换不进行任何类型检查,因此可能会导致未定义的行为。

int i = 10;
float f = reinterpret_cast<float&>(i); // 重新解释将int类型转换为float类型

1.2 常量

1. 定义常量

  • 使用 #define 预处理器,在预处理阶段起作用。字符替换不进行内存分配,存储于代码段。
  • 使用 const 关键字,在编译、运行阶段起作用。会进行内存分配,存储于程序的数据段中。定义成 const 后的常量,程序对其中只能读不能修改。。
#define LENGTH 10   
#define WIDTH  5
#define NEWLINE '\n'

const int  LENGTH = 10;   // 在一个类里建立const时不能给初值
const int  WIDTH  = 5;
const char NEWLINE = '\n';

// 指针常量
const *p; //修饰*p,指针指向的对象不可变
* const p; //修饰p,指针不可变

2. 定义静态变量

static:用于定义静态变量,表示该变量的作用域仅限于当前文件或当前函数内,不会被其他文件或函数访问。

void example_function() {
    static int count = 0; // static 关键字使变量 count 存储在程序生命周期内都存在
    count++;
}

1.3 指针

指针是一个变量,其值为另一个变量的地址

int    *ip;    // 一个整型的指针

1. c++指针操作

int  var = 20;   // 实际变量的声明
int  *ip;        // 指针变量的声明
ip = &var;       // 在指针变量中存储 var 的地址

// 输出在指针变量中存储的地址
cout << ip << endl;
// 访问指针中地址的值
cout << *ip << endl;

2. c++ 指针的算术运算

递增一个指针

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,执行:

    ptr++;

ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。

指针的比较

指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。

3. 指针和数组

#include <iostream>
using namespace std;

int main ()
{
    int var[3] = {10,100,200};
    int *p=var;

    for (int i = 0; i < 3; i++)
    {
        cout << *(var++)<< endl;    //编译错误,因为var是数组名(也是数组首元素地址),不是一个变量,不可修改其值
        cout << *(var+i)<< endl; //编译正确,因为没有对var进行赋值,只是通过与i相加访问变量地址
        cout <<  *(p++)<< endl;        ///编译正确,p为指针变量可赋值
    }

    // 输出:10 10 100 100 200 200
    return 0;
}

4. c++ 指向指针的指针(多级间接寻址)

指针的指针就是将指针的地址存放在另一个指针里面。


int  var;
int  *ptr;
int  **pptr;
var = 3000;

// 获取 var 的地址
ptr = &var;
 
// 使用运算符 & 获取 ptr 的地址
pptr = &ptr;
  • var、*ptr、**pptr 值为3000;
  • &var、ptr、*pptr 值为地址0x7ffeec7a65e8。

c++ 传递指针给函数

5. c++ 从函数返回指针

C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static变量。

// 要生成和返回随机数的函数
int * getRandom( )
{
  static int  r[10];
 
  // 设置种子,当srand()的参数值固定的时候,rand()获得的数也是固定的
  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;
}

1.4 引用

引用变量是一个别名

1. 引用和指针

三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

2. 创建引用

语法:

int i = 17;
int&  r = i;

注意:

  • 引用必须在声明时将其初始化,不能先声明后赋值
  • 引用更接近const指针,必须在创建时进行初始化,一旦引用和某个变量关联起来,该引用就会一直指向该变量。

3. 把引用作为参数

传递变量的引用。形参是引用变量,和实参是一个变量,调用函数时,形参(引用变量)指向实参变量单元。这种通过形参引用可以改变实参的值。

int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;
 
   cout << "交换前,a 的值:" << a << endl;
   cout << "交换前,b 的值:" << b << endl;
 
   /* 调用函数来交换值 */
   swap(a, b);
 
   cout << "交换后,a 的值:" << a << endl;
   cout << "交换后,b 的值:" << b << endl;
 
   return 0;
}
 
// 函数定义
void swap(int& x, int& y)
{
   int temp;
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */
  
   return;
}

/* 输出:
交换前,a 的值: 100
交换前,b 的值: 200
交换后,a 的值: 200
交换后,b 的值: 100
*/

1.5 c++ 存储类

存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。
下面列出 C++ 程序中可用的存储类:auto、register、static、extern、mutable、thread_local (C++11)
(从 C++ 17 开始,auto 关键字不再是 C++ 存储类说明符,且 register 关键字被弃用。)

1. static 存储类

  • static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
  • static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
  • 在 C++ 中,当 static 用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。
#include <iostream>
 
// 函数声明 
void func(void);
 
static int count = 2; /* 全局变量 */
 
int main()
{
    while(count--)
    {
       func();
    }
    return 0;
}
// 函数定义
void func( void )
{
    static int i = 10; // 局部静态变量
    i++;
    std::cout << "变量 i 为 " << i ;
    std::cout << " , 变量 count 为 " << count << std::endl;
}

/*
变量 i 为 10 , 变量 count 为 1
变量 i 为 11 , 变量 count 为 0
*/

(1) static 修饰类的成员变量

  • 静态成员变量是先于类的对象而存在
  • 这个类的所有对象共用一个静态成员
  • 如果静态成员是公有的,那么可以直接通过类名调用
  • 静态成员数据在声明时候类外初始化
// 类
class Data
{
public:
    Data(){}
    ~Data(){}
    void show()
    {
        cout<<this->data<<" "<<number<<endl;
    }

    static void showData()//先于类的对象而存在
    {
        //这方法调用的时候不包含this指针
        cout<<" "<<number<<endl;
    }

private:
    int data;
public:
    static int number; //静态数据在声明时候类外初始化
};
int Data::number=0;//静态成员初始化
int main()
{
    Data::showData();//通过类名直接调用


    Data::number = 100;//通过类名直接使用
    Data d;
    d.show();
    d.showData();//通过对象调用

    cout << "Hello World!" << endl;
    return 0;
}

(2).static 修饰类的成员方法

  • 静态成员函数是先于类的对象而存在
  • 可用类名直接调用(公有)
  • 在静态成员函数中没有this指针,所以不能使用非静态成员

2. extern 存储类

extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。extern 是用来在另一个文件中声明一个全局变量或函数。

// 文件1 :main.cpp
int count ;
extern void write_extern();
 
int main()
{
   count = 5;
   write_extern();
}

// 文件2:support.cpp
extern int count;
 
void write_extern(void)
{
   std::cout << "Count is " << count << std::endl;
}

/*
    第二个文件中的 extern 关键字用于声明已经在第一个文件 main.cpp 中定义的 count。
    输出:Count is 5
*/

3. thread_local 存储类

  • 使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。

  • thread_local 说明符可以与 static 或 extern 合并。

  • 可以将 thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。

thread_local int x;  // 命名空间下的全局变量

class A
{
    static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string A::s;  // A::s 是需要定义的
 
void foo()
{
    thread_local std::vector<int> v;  // 本地变量
}

1.6 c++ 运算符

算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、杂项运算

1. 逻辑运算符

运算符描述
&&逻辑与运算符。如果两个操作数都 true,则条件为 true
||逻辑或运算符。如果两个操作数中有任意一个 true,则条件为 true。
!逻辑非运算符。用来逆转操作数的逻辑状态

2. 位运算符

运算符描述
&按位与,0&0=0; 0&1=0; 1&0=0; 1&1=1
|按位或, 0|0=0; 0|1=1; 1|0=1; 1|1=1
^异或运算符
~取反运算符,按二进制位进行"取反"运算。~1=-2
<<二进制左移运算符。左边的二进制位丢弃,右边补0
>>二进制右移运算符。正数左补0,负数左补1,右边丢弃。

1.7 c++数组

1. 声明初始化数组

double arr[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

// 省略数组的大小,则数组的大小为初始化时元素的个数
double arr[] = {1000.0, 2.0, 3.4, 7.0, 50.0};

2. 传递数组给函数

(1) 形参为指针

void myFunction(int *arr)
{

}

(2) 形参为固定大小的数组

void myFunction(int arr[10])
{

}

(3) 形参为未定义大小的数组

void myFunction(int arr[])
{

}

3. 从函数返回数组

C++ 不允许返回一个完整的数组作为函数的参数。可以返回一个指向数组的指针。

  • C++ 不支持在函数外返回局部变量的地址,可以定义局部变量为 static 变量。
int* myFunction()
{
   static int Arr[3] = {1, 2, 3};
   return Arr;
}

1.8 c++字符串

C++ 标准库提供了 string类 类型

1. string类的输入输出

(1) cin
接收一个字符串,但是遇到“空格”, “TAB”, "回车"结束。

(2) getline()
可以接收空格并输出

#include<iostream>
#include<string>
using namespace std;
int main()
{
	string s;
	getline(cin,s);
	cout << s;
	return 0;
}

2. 字符数组的输入输出

(1) cin.get()
可以用来接收字符和字符数组,定义的数组的个数是10,则实际上只能接收9个字符,还要加上’\0’。

#include<iostream>
#include<string>
using namespace std;
int main()
{
	char ch, arr[10];
	ch = cin.get();  //或者是cin.get(ch);
	cout << ch;

    cin.get(arr, 10);
    cout << arr;
	return 0;
}

(2) cin.getline()
可以接收空格,并且输出。这个函数有三个参数,分别是字符串的位置,接受个数,结束字符。
cin.getline(m, 5, ‘a’):输入jkalj时,输出jk。

char a[20];
cin.getline(a, 20);
cout << a;
函数字符数组string是否包含空格
cin×
cin.get()×
cin.getline()×
getline()

1.9 日期和时间

C++ 标准库没有提供所谓的日期类型。C++ 继承了 C 语言用于日期和时间操作的结构和函数。
有四个与时间相关的类型:clock_t、time_t、size_t 和 tm。
类型 clock_t、size_t 和 time_t 能够把系统时间和日期表示为某种整数。

(1)time_t time(time_t * time);
该函数返回系统的当前日历时间,自 1970 年 1 月 1 日以来经过的秒数。如果系统没有时间,则返回 -1。

(2)clock_t clock(void);
该函数返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。如果时间不可用,则返回 -1。

(3)size_t strftime();
该函数可用于格式化日期和时间为指定的格式。

(4)char * asctime ( const struct tm * time );
该函数返回一个指向字符串的指针,字符串包含了 time 所指向结构中存储的信息,返回形式为:day month date hours:minutes:seconds year\n\0。

1. 获取当前的日期和时间

#include <iostream>
#include <ctime>
 
using namespace std;
 
int main( )
{
   // 基于当前系统的当前日期/时间
   time_t now = time(0);
   
   // 把 now 转换为字符串形式
   char* dt = ctime(&now);
 
   cout << "本地日期和时间:" << dt << endl;
 
   // 把 now 转换为 tm 结构
   tm *gmtm = gmtime(&now);
   dt = asctime(gmtm);
   cout << "UTC 日期和时间:"<< dt << endl;
}

/*
本地日期和时间:Sat Jan  8 20:07:41 2011

UTC 日期和时间:Sun Jan  9 03:07:41 2011
*/

2. 使用结构 tm 格式化时间
tm 结构以 C 结构的形式保存日期和时间。

#include <iostream>
#include <ctime>
using namespace std;
 
int main( )
{
   // 基于当前系统的当前日期/时间
   time_t now = time(0);
 
   cout << "1970 到目前经过秒数:" << now << endl;
 
   tm *ltm = localtime(&now);
 
   // 输出 tm 结构的各个组成部分
   cout << "年: "<< 1900 + ltm->tm_year << endl;
   cout << "月: "<< 1 + ltm->tm_mon<< endl;
   cout << "日: "<<  ltm->tm_mday << endl;
   cout << "时间: "<< ltm->tm_hour << ":";
   cout << ltm->tm_min << ":";
   cout << ltm->tm_sec << endl;
   /*
    1970 到目前时间:1503564157
    年: 2017
    月: 8
    日: 24
    时间: 16:42:37
   */
}

自学记录,部分来源:菜鸟教程


二、c++ 算法学习

2.1 C++ 按位操作(与、或、异或)

1. 异或运算

异或运算:参加运算的两个数据,按二进制位进行 “异或” 运算。即 位异 结果为1, 否则为0

int main(){
   // 3^5 即 0000 0011 ^ 0000 0101 = 0000 0111  因此,3|5的值得6
   int a = 3, b = 5;
   cout<< a ^ b <<endl;
   return 0;
}
  • 性质

    • 任何数和0做异或运算,结果仍然是原来的数,即 a ⊕ 0=a
    • 任何数和其自身做异或运算,结果是0,即 a ⊕ a = 0
    • 异或运算满足交换律和结合律,即 a ⊕ b ⊕ a = b ⊕ a ⊕ a = b ⊕ ( a ⊕ a ) = b ⊕ 0 = b
  • 应用

    • 使特定位翻转:
      找一个数,对应X要翻转的各位,该数的对应位为1,其余位为零,此数与X对应位异或即可。
    • 保留原值
      和 0 做 异或 运算

2. 与运算

按二进制位进行 “与” 运算。

  • 性质
    运算规则:0 & 0 = 0; 0 &1 = 0; 1 & 0 = 0; 1 & 1 = 1;
    即:两位同时为“1”,结果才为“1”,否则为0
  • 应用
    • 清零
      将数字与0相‘与’
    • 取一个数的指定位
      指定位置为1,其余为0。
    • 判断奇偶
      根据末位是0还是1来决定,为0就是偶数,为1就是奇数。
      因此可以用if (a & 1 == 0)代替if (a % 2 == 0)来判断a是不是偶数。

3. 或运算

按二进制位进行 “或” 运算。

  • 性质
    运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;
    即 :参加运算的两个对象只要有一个为1,其值为1。
  • 应用
    • 将数据的指定位置为1。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值