• C/C++学习笔记汇总


    ^函数重载的匹配:

              当函数名被重载后,函数的匹配过程:首先寻找能精确匹配的函数,如果未能精确匹配,则尝试找一个可以模糊匹配的函数。

    1)精确匹配:参数个数相同,类型相同。

    2)模糊匹配:参数个数相同,类型不同,但支持隐式转换。

    ^参数默认值

    1)具有默认值的参数必须要放在后面。

    2)当函数声明与定义分开时,应把默认写在声明里,不能写在定义里。          

        void show(int x,int y,int z=1);  //默认值加在函数声明里              

        int main()             

     {            

              ...          

        }      

    void show(int x,int y,int z)      //函数定义之处不能加默认值   

       {        

    ...     

     }

     ^内联函数:

    在函数前加一个inline关键字,该函数称为内联函数。

    ^函数的递归调用:

    1)将高阶问题转化为低阶相同问题。

    2)必须设置终止条件,避免无限制递归。

    3)可以替换为非递归算法,改善循环语法。

    4)控制递归深度。

    ***指针^内存地址的表示:  a在内存中对应4个字节;            

      unsigned int a=0xA0A0A0A0;    //a内存中的值:A0 A0 A0 A0            

      a = 0xB1B1B1B1;              //a内存中的值:B1 B1 B1 B1  变量地址是一个整数,可以用操作符&来取得。

    例如:      inta = 0;  

                    double b = 0;      

                    printf("%08X "&a);          //把地址按十六进制来打印    

                    printf("%08X "&b);          /*把址按照十六进制来打印^指针的概念:    XXX* 表示XXX型变量的地址。可以为char,int,double等,这种带*的类型叫做指针类型。*/

      指针(Pointer)意思是Point to an address.例如:         

       int a = 1;  

      int *p = &a;                //定义了一个int*型变量p,其值为a的地址。

    1)指针变量也是变量。

    2)不同类型的指针,不能互相赋值。

    3)指针是一个整数类型。    在用printf打印时,通常使用的格式符为%p,p代表pointer。

    4)*位置比较随意。

    5)同类型指针可以混合定义。

    ^星号操作  “*”可以用来修改内存值,用在指针变量上可以直接读写内存的值。星号操作是一种按地址访问的技术,只要知道了这块内存的地址,就可以直接修改这块内存的值。

    1)只有指针类型才支持星号操作。              int addrress = 0x12345678;        *addr = 0                      //编译错误!只有指针才支持星号操作

    2)其他指针类型的用法是一样的。

    3)区分星号的上下文^指针与数组    数组在内存中就相当于一串紧密排列的变量,数组名代表的就是这一块内存的首地址。

    ^指针加减法^指针与数组的转换

    1)p指向arr的任意一个值;              p = arr+3;                      //指向arr[3]      p = &arr[3];                    //指向arr[3]

    2)给数组元素赋值;              arr[3] = 10;      或:      *(arr+3) = 10;      或:      int* p=arr+3;      *p = 10;

    3)把p当成数组使用              int* p = &arr[1];              //p指向arr[1]      p[0] = 0xAA;                    //p[0]:自p开始的第0号元素      p[1] = 0xBB;                  //p[1]:即arr[2]

    4)长度为1的数组;    普通变量int a可以视为长度为1的数组来操作。            int a = 10;    int* p = &a;    p[1] = 11;              //长度为1的数组5)

    数组的遍历;

    方法一:            int arr[4] = {1,2,3,4};    for(int i = 0;i<4;i++)    {        printf("%d ",arr[i]);    }

    方法二:用指针遍历,注意终止条件为P来访问对象的成员,例如:            p->id = 20141011;                //使用->访问对象成员    strcpy(p->phone,"15928682083");  //使用->访问对象成员    也可以使用(*p).id,但是不常用。

    3)做为函数参数    和基本类型一样,结构体也可以作为函数参数

    4)做为函数返回值

    5)作为结构体成员^结构体的特殊写法    结构体定义允许放在函数内部,这么定义的类型只能在函数内可见。由于struct语法的初衷是要定义一个呗多处使用的自定义类型,正常情况下应该定义在函数体之外。

    ^结构体的命名    结构体命名:“数字、字母、下划线的组合,不能以字母开头”。其次,命名要有意义,一个好的名字应该直接反映其意义。下面有两种常见的格式:

    1)纯小写,以下划线分开每个单词,例如good_job,large_buffer.

    2)每个单词以大写开头,在C++中推荐使用这种风格,结构体内成员变量,通常是小写,并以下划线分割每个单词。

    ^传值与传地址    在传输参数时,如果传入的是一个对象的值,叫“传值”方式,如果传入的是一个对象的地址,叫做“传地址”方式。

    1)传值方式

    2)传地址方式:

    ***联合体

    1)概念:

    ***动态内存分配

    1)动态内存分配malloc申请内存    应用程序调用malloc函数可以申请一块指定大小的内存,函数原型为:            #includevoid* malloc(int size);    参数:size:内存空间的大小,以字节为单位。    返回值:申请出来的这块内存首地址。    用法示例:            char* p = (char*) malloc(84);  //申请一块84字节的空间    内存管理空间并不关心这一块内存的用途,所以malloc的返回值是void* ,仅表示内存的地址。应用程序可以用来存储任何类型的数据。例如申请一块100个int型数据,示例如下            int* p = (int*)malloc(100*4);  //申请100*4内存    for(int i = 0;i<100;i++)    {        p[i] = i * i;              //使用这块内存    }  

      free释放内存          

      #includevoid free(void* ptr);    在使用完毕后,应用程序应当调用free函数来释放内存,当内存交给内存管理器,传入的参数就是先前用malloc得到的指针.

    2)内存管理器与堆    内存管理器(MM)的职责就是提供内存服务,它管理的区域称为堆,malloc得到的内存的位置是在堆区。原则:尽可能少的申请内存,尽可能快的释放。    

    堆内部管理:MM对借出的内存块进行标识:            (p0,n0)(p1,n1)(p2,n2)...    它内部已经保证任意两块不会交叠,不会把一块内存同时借给两个应用程序使用。    内存泄漏

    3)对象的生命期    对象的分类:全局对象,局部对象,动态对象。    ①当定义一个变量时:Object a;,则变量a对应了一个对象,类型为Object,地址为&a,如果这个变量是全局变量,则a称为全局对象,如果这个变量是局部变量,则a称为局部对象。    当用malloc动态申请内存时:Object* p = (Object*)malloc(sizeof(Object));此时p指向了一个对象。该对象内存使动态分配的,称为动态对象。    一个对象总是对应了一块内存,对象的值就是内存里的数据。    对象生命期:全局对象生命期是永恒的,只有程序退出时才失效;局部对象生命期是临时的在超出作用域后对象立即消失;动态对象生命期是动态的,在malloc时生命生效,在free时失效。

    4)常见问题  用malloc申请的内存,用完以后要用free释放。  不适用malloc得到的内存不能用free释放。  及时归还,再借不难。  不能只free一部分。  程序退出时,malloc内存都会自动释放归还给MM。***链表^概念    把若干对象用指针串联起来,形成一个链状数据结构,称为“链表”。            struct Student    {        int id; char name[16]; Student* naxt;    }    其中添加一个成员变量next,用于指向下一个对象。

    ^链表的构造

    1)先准备好四个对象            Student ss[4]=    {        {201501,"John",0}, {201502,"Jennifer",0}, {201503,"Anxi",0}, {201504,"Unnamed",0}    };

    2)把这个对象“串“起来            ss[0].next = &ss[0];    ss[1].next = &ss[1];    ss[2].next = &ss[2];    ss[3].next = 0;    一个链表构造完毕。

    3)头节点与末节点    当若干个对象被串起来以后,只要知道第一个对象,就可以访问链表中的每一个对象。把链表中每个对象,称为“节点”。第一个节点也叫“头节点”

    4)链表头的作用:可以用于代表整个链表:Student* stu_list = &ss[0];

    ^有头链表

    1)概念:用一个固定的头节点来指代整个链表,所有的对象挂在这个头节点下面,而头节点本身并不包含有效数据。2)定义一个有头链表    只需要定义一个对象作为其节点,将成员next初始化为NULL。            Student m_head = {0,"head",NULL};    或者写:            Student m_head = {0};    当有对象加入时,直接加在后面就可以,当他的next为NULL时表示该节点没有数据节点(链表长度为0)。

    3)添加一个节点            void add(Student* obj)    {          obj->next = m_head.next;  m_head.next = obj->next;    }    创建一个对象,然后调用add函数插入列表中。            Student* obj = (Student*)malloc(sizeof(Student));    obj->id = 12;    strcpy(obj->name,"X");    add(obj);                            上面的add函数直接把新的节点插在最前面,也可以把节点插到末尾,代码如下:            void add(Student* obj)    {          Student* p = &m_head;  while(p->next)        p = p->next;          p->next = obj;  obj->next = NULL;    }

    4)有头链表的遍历    在遍历时,有头链表的头节点由于不含有数据,是不参与遍历的实际遍历时,只访问链表中的数据节点。            void show_all()    {                Student* p = m_head.next;  while(p)  {        printf("ID: %d,name: %s ",p->id,p->name);p = p->next;  }    }

    5)按顺序插入节点    先遍历链表,并比较ID的值,找到目标位置,并记录前一个节点为pre,找到位置后,把新的节点直接挂在pre后面。            obj->next = next->next;    pre->next = obj;6)查找和删除节点***引用^定义    在类型之后加上一个&符号,该变量即为引用类型。    引用只相当于对象的一个别名。

    ^与指针的区别    引用在定义时必须初始化关联到一个对象,例如:Object* p = NULL;      //允许在定义的时候不指向任何一个对象,如果在定义一个引用时不初始化,则编译器就会报错,例如:Object a;  Object& r;  //语法错,定义引用时必须初始化!    引用与某个对象绑定,中途无法解绑,而指针的使用较为灵活,一个指针可以先指向对象a,再指向对象b,引用可以视为功能受限的指针。

    ^简单的例子^作为函数参数   

     引用类型可以作为函数的参数,可以达到与指针相同的效果。

    ^做为函数返回值   

     引用也可以作为函数返回值,指针作为返回值是把某个对象的地址返回,^const引用    const引用限定被引用的对象为只读的,不能修改的对象,常用作函数的参数。***字符串^字符串的三种形式

    1)字符数组    当以char型数组来存放字符串时,数组名时字符串的首地址。

    2)动态字符串    可以动态分配一块内存,然后在这块内存里存放一串字符。也就是说,这个字符串对象在堆上。

    3)字符串常量    在代码中用双引号包括,包含0..N个字符,称为字符串常量。^字符串常量多行表示    当一个字符串常量要表达的内容特别长时,在单独一行代码中可能书写不下,可以用两种方法分成多行。   

     第一种:使用双引号将多段文本连接起来,两个字符串之间可以被空格分开,不影响最终效果。例如              const char* str = "hello" "world";相当于:const char* str = "helloworld";   

     第二种:在末尾添加一个反斜线,例如:              const char* poem = "江山定       风雨遮前路,冰火伴我行.       一度波澜惊,而今江山定. ;

    ^字符串与与普通数据    

    字符串是以char*表示的,它指向了字符串的首地址。实际上仅当这块内存用于存储字符串的时候,才把它称作字符串,如果只是把它用于存储一些普通数据则不能把它称作字符串。

    ^字符串的遍历    

    遍历字符串指的是从前往后访问每一个字符,有两种方法:索引遍历和指针遍历。都需要检测结束符''来判断是否结束。

    ^字符串长度    

    是指从第一个字符开始,一直到末尾的结束符,中间的有效字符的个数,长度不包含末尾的''在内。^字符串复制    字符串的复制,是指将源字符串的每一个字符挨个复制到目标缓存区,最终保证目标缓冲区的字符串末尾有一个''字符。    

    注意事项:目标缓冲区要足够大;目标缓冲区保证以0结束。可以使用里的strcpy函数。   

     区分深拷贝和浅拷贝:例如              char* p1 = "hello,world";      char* p2 = p1;    这种简单的这振赋值,就叫做浅拷贝,一句话表示:两个指针指向了同一个字符串对象。              char* p2 = (char*)malloc(strlen(p1)+1);      strcpy(2,p1);    这段代码新申请一块相同大小的内存,然后把字符串内容复制到这块内存,那么这两个字符串对象(两块内存),他们的内容相同,这种拷贝叫做深拷贝,一句话表示:两个指针(p1,p2),分别指向两个字符串对象。

    ^字符串比较    

    字符串也可以比较是否相等,以及大小关系,只有当所有字符全部相同时才认为两者相等。两个字符则是按它们的ASCII码值大小进行比较。   

     一般直接使用里的strcmp函数来比较两个字符串。strcmp(a,b),当相等时返回值为0,当ab时返回值为1.

    ^字符串插入与删除

    1)删除字符

    函数Erase用于字符串中某个字符的删除。

    2)插入字符

    函数Insert用于在源字符中插入一个字符。

    ^字符串分割

    一个字符串由若干信息组成,每一段信息中间用分隔符分开,解析这个字符串,得到一段内容称之为字符串的分割。

    ^用数组还是指针

    数组方式:

    指针方式:

    **标准C函数库

    1)stdio.h

    标准输入/输出函数

    2)math.h

    3)time.h

    4)stdib.h

    5)string.h

    ***文件操作

    ^认识文件

    文件的作用是持久化存储数据。所谓持久化是指当关闭计算机电源后数据依然存在,再次打开计算机时,还可以重新加载显示这些数据。

    ^保存数据

    使用ANSI C中的stdio.h里的相关数据来进行文件读写操作。步骤如下;

    1)fopen:打开文件。

    fopen函数用于打开文件,得到一个FILE*指针,该指针指代该文件,后续的fwrite/fclose等函数都需要传入这个文件指针。其原型为:

    FILE fopen(const char *filename,const char *mode);

    其中,filename:表示要打开的文件路径;mode:固定使用"wb"(w表示write,b表示binary);

    用法示例:FILE* fp = fopen("c:/aaa.txt","wb");

    if(fp == NULL)

    {

    printf("文件打开失败 ");

    }

    2)fwrite:写入数据。

    当数据写入完毕,该文件不再被指针使用时,要及时调用fclose函数来关闭文件,其原型为:

    int fclose(FILE* stream);

    参数:stream就是前面fopen的返回值。用法示例:

    fclose(p);

    3)fclose:关闭文件。

    fwrite用于向文件中写入数据,其原型为:

    size_t fwrite(const void * buf,size_t size,size__t nelem,FILE * stream);

    参数:stream就是前面fopen的返回值;buf:要写入的数据首地址;size:总是传1;nelem:数据长度。用法示例:

    char buf[] = "hello";

    fwrite(buf,1,5,fp);

    ^读取数据:就是把曾经写入的文件读取出来。

    读取数据分为三步。

    1)fopen打开文件

    2)fread读取文件

    fread函数原型为:

    size_t fread(void * buf,size_t size,size_t nelem,FILE * stream);

    参数:stream:前面fopen函数的返回值;buf:内存缓冲区,用于存储数据的内存位置;size:恒为1;nelem:最多读取多少字节;返回值:实际读取字节,如果

    返回-1,则读取失败。用法示例:

    char buf[128];

    int n = fread(buf,1,128,fp);

    如果文件中的数据不超过128字节,则返回值n就是实际的字节数。如果文件中的数据超过128字节,那这次操作只能读取128个字节。

    3)fclose关闭文件

    ^数据的存储格式

    第一种方式:

    int x = 100;

    int y = 100;

    fwrite(&x,1,2,fp);

    fwrite(&y,1,4,fp);

    当以这种方式写入时,一共8个字节。可以用相应的代码,从文件中读取数据,并恢复x,y坐标。

    int x,y;

    fread(&x,1,4,fp);

    fread(&y,1,4,fp);

    第二种方式:

    int x = 100;

    int y = 200;

    char buf[128];

    sprintf*(buf,"x = %d,y = %d",x,y);

    fwrite(buf,1,strlen(buf),fp);

    这种方式把一个字符串“x = 100,y = 200”写入文件。

    第三种方式:

    int x = 123;

    int y = 456;

    char buf[128];

    sprintf(buf,"%d%d",x,y);

    fwrite(buf,1,strlen(buf),fp);

    ^存储格式:按字节存储

    1)存储char类型

    char ch = 12;

    fwrite(&ch,1,1,fp);    //存

    fread(&ch,1,1,fp);    //取

    2)存储int类型

    int n = 12;

    fwrite(&n,1,sizeof(int),fp);    //存

    fread(&n,1,sizeof(int),fp);      //取

    3)存储double类型

    double val = 123.456;

    fwrite(&val,1,sizeof(val),fp);

    fread(&val,1,sizeof(val),fp)

    4)存储结构体类型

    Object obj = {123};

    fwrite(&obj,1,sizeof(obj),fp);

    fread(&obj,1,sizeof(obj),fp);

    5)存储字符串

    char name[32] = "shaofa";

    fwrite(name,1,32,fp);

    fread(name,1,32,fp);

    ^存储格式:文本化存储

    当数据量比较少时,可以把数据格式化为文本的形式来存储。

    1)fprintf按行格式化写入

    2)fgets按行读取

    ^文件的随机访问

    在描述一个文件的可访问属性时,有两个术语。

    顺序访问:不能跳跃。

    随机访问:随意跳到一个位置访问。

    1)fseek

    2)文件位置指示器

    3)随机访问实例

    4)fseek的物理限制

    5)文件被重复打开的情况

    ^文件打开模式

    rb:读模式。当读一个文件使用。如果该文件不存在,则fopen返回NULL.

    wb:写模式。再写一个文件时使用。

    ab:附加模式。表示打开文件但不清空里面的内容。

    ***多文件项目及编译过程

    ^extern

    1)extern声明全局函数

    想要在main.cpp中调用其他.cpp中定义的函数,那么就必须在main.cpp里用extern声明这个函数,写法如下:

    extern double get_area(double r);

    以关键字extern修饰,在后面加上函数的原型,关键字extern不仅可以声明一个外部函数,还可以声明一个外部的全局变量。在声明全局时,关键字extern是

    可以声明不写的。

    2)extern声明全局变量

    也可以在A.cpp里访问B.cpp里的全局变量,需要在A.cpp里用extern声明这个全局变量。

    注意:在声明变量时不能加初始值;必须要在前面加上extern。

    3)深入理解全局变量

    extern的作用是通知编译器在本cpp中要用到某个符号,这个符号可能不在本cpp中定义,它表示在某个cpp文件中存在这么一个全局变量/函数,这个符号可以

    再别的cpp中定义,亦可以在本cpp中定义

    ^多文件项目的生成

    1)第一阶段:编译

    编译,这一阶段是处理每个cpp文件,把cpp文件中的代码转换为中间文件(*.obj),可以再debug文件夹中找到这个中间文件,A.cpp->A.object,C.cpp->B.obj。

    在变异过程中各个cpp文件都不区分顺序,谁先谁后都一样,只要声明了一个函数为extern,编译器就不检测是否真的存在这个符号。

    2)第二阶段:链接

    如果迁移阶段编译成功,则进行连接过程。此过程作用是将各个obj文件综合在一起,生成可执行程序。A.obj,B.obj,..->test.exe。

    在连接阶段编译器会检测所有extern的福海是否真的存在。

    3)用伪代码表示整个过程

    可以用一段伪代码来表示编译器和连接过程,并非真正的c++代码,仅用于解释说明。

    4)全量编译与增量编译

    全量编译是将所有的cpp文件重新编译一下,“重新生成解决方案”就是全量编译。

    增量编译是指对有改动的文件进行执行,当执行生成解决方案时执行的是增量编译,这也是大多数编译器的默认动作。

    ^头文件#include指令

    头文件的后缀名一般为.h,相应的把.cpp文件叫做头文件。

    1)为什么需要头文件

    同一结构的定义要在不同的cpp里重复好几遍。如果不写,就是语法错误。由于每个cpp时独立编译的,在other.cpp中定义的结构类型对main.cpp没有任何

    影响

    2)使用头文件

    吓死项目中新增一个头文件Objeect.h,然后把Object的类型定义写在里面,然后在需要它的cpp里加上#include"Object.h",这样就解决了前面所说的问题,需

    要扩展Object结构时,只需要修改Object.h即可。头文件写法:后缀一般为.h;内容一般为几种:类型定义,extern函数声明,extern变量声明。

    3)#include指令的原理

    #include"Object"

    其中,#include称为一条“预处理指令”。"Object.h"表示要包含的头文件的路径,以双引号包围。预处理过程是:编译器过程的作用是,编译器在处理每个cpp

    之前,首先将文件里的所有预处理指令进行处理,形成一个中间文件,然后对这个中间文件进行编译。

    4)头文件的重复包含问题

    5)头文件里的内容

    头文件里,一般放以下内容:

    公用类型定义:如果一个类型要在多个cpp中使用,可以放在头文件里。

    extern函数声明:extern变量声明。

    嵌入包含其他文件。

    ^宏定义#define指令

    所有已#开头的行,称为预处理指令。#define指令通常称为宏定义。两个用法:

    1)#define的一个数值

    使用#define可以起到定义一个“常量”的效果。

    2)#define的一个算式

    使用#define可以定义一个类似“函数”的东西,它不是函数。学这些东西只是为了能够看懂一些老旧的代码。

    3)几个常见宏定义

    NULL空指针:#define NULL 0

    RAND_MAX的宏定义:见16章。

    ^条件编译指令

    1)#if...#endif

    2)#ifdef...#endif

    #ifdef表示如果对应的宏有定义,则相应的代码被编译。可以使用#undef指令去定义。

    #ifndef表示的意思和#ifdef恰好相反:当相应的宏不存在时,才编译相应的代码。

    3)结局头文件重复包含的问题

    通常要对头文件用条件编译指令对其进行保护,之后便可以对其重复包含了。

    ^main函数的参数和返回值

    1)main函数的参数

    2)main函数的返回值

    ^static的用法

    1)static修饰变量

    2)static修饰函数

    ***面向对象编程

    ^面向对象设计的过程

    ^实例演示

    ^封装

    ***类

    ^类和成员变量

    ^类和成员函数

    ^变量名字和覆盖

    ^命名规范

    ^类的封装

    ^类的分离式写法

    ^const对象与const函数

    ***构造与析构

    ^构造函数

    ^析构函数

    ^自动生成构造/析构函数

    ^默认构造函数

    ^混合使用两种初始化方式

    ^构造与析构的顺序

    ^分离式写法

    ^无名对象

    ^构造函数与类型转换

    ***动态创建对象

    ^回顾malloc/free

    ^用new和delete创建/销毁对象

    ^new/delete与malloc/free的区别

    ^为new指定初始化对象

    ^默认构造函数的必要性

    ^注意事项

    ***继承

    ^继承的概念

    ^访问修饰符protected

    ^成员函数重写

    ^虚拟继承

    ^虚函数virtual

    ^继承关系下的构造与析构

    ^多重继承

    ^继承函数与纯虚类

    ^以protected/private方式继承

    ***拷贝构造函数

    ^定义

    ^拷贝构造函数的调用

    ^默认拷贝构造函数

    ^定义拷贝构造函数

    ^深度拷贝

    ***静态成员

    ^static定义全局变量

    ^static定义全局函数

    ^与普通成员函数的区别

    ^static语法的特点

    ^实例

    ***朋友成员

    ^类的朋友

    ^friend的语法

    ^实例

    ***重载操作符

    ^算术操作符

    ^赋值操作符=

    ^自增操作符++与自减操作符--

    ^关系操作符

    ^逻辑操作符

    ^类型转换操作符()

    ^元素操作符

    ^输入/输出操作符>>与<<

    ^操作符new与delete

    ***内部类和名字空间

    ^内部类

    ^名字空间

    **模板

    ^函数模板

    ^类模板

    ^模板参数

    ^实例

    ***标准函数库

    ^一般使用方法

    ^向量vector

    ^list

    ^string

    ^map

    ^stack

    ^queue

    ***异常

    ^

    天上我才必有用,千金散尽还复来!
  • 相关阅读:
    Codeforces Round #461 (Div. 2)B-Magic Forest+位运算或优雅的暴力
    动态规划:树形DP
    动态规划:划分DP
    动态规划:状压DP
    图论:树的直径
    图论:点分治
    图论:2-SAT
    数据结构&图论:K短路-可持久化可并堆
    图论:次短路
    图论:曼哈顿距离最小生成树
  • 原文地址:https://www.cnblogs.com/lutaishi/p/13436342.html
Copyright © 2020-2023  润新知