《c 新经典笔记
- 第一章c 详细介绍语言课程
- 第二章
-
- 2-1语言特征、工程构成、执性
- 2-2auto、头文件防卫、引用、常量
- 2-3命名空间简介,基本输入输出精解
- 2-4范围for、new动态分配内存,nullptr
- 2-5结构、权限修饰符、类简介
- 2-6函数的新特性,内联函数,const详解
- 2-7string类型介绍
- 2-8vector类型介绍
- 2-9迭代器的精彩演绎、故障分析和弥补
- 2-10类型转换:static_cast等
第一章c 详细介绍语言课程
第二章
2-1语言特征、工程构成、执性
2-2auto、头文件防卫、引用、常量
- 局部变量及初始化
int a[] {
11,12,34};//注意这里没有等号,{}包含一组数据 //int abc = 3.5f;//丢了.5, 被系统截断 //int abc{3.5f}; ///无法成功编译,系统实现了从浮点数到整数的转换
- auto
//二:auto:自动类型推断变量 //auto在声明变量时,可以根据变量初始值的类型自动选择匹配的变量类型;声明中给予初始值[初始化]) //auto编译期间发生了自动类型推断。因此使用auto不会降低程序效率。 auto bvalue true;//bool auto ch ='a';//char auto dv =1.2f; auto iv 5;
- 头文件防卫声明
//#ifdef,ifndef条件编译 //#ifndef标识符 /define定义),编译程序段。 //程序段 //#endif
- 引用
//四:引用 //引用理解为:另一个名称是为变量起的,通常使用&符号表示。起晚别名后,我们将这个别名和变量本身视为相同的变量; int value = 10; int &refval = value://value的别名就是refval,&这里不是地址操作符,而是标识。 //定义引用,不占用额外的内存,或理解为引用和原始变量占用相同的内存。 //定义引用时必须初始化,否则你会给谁起别名。 refval = 3; cout <<value <<endl; cout <<refval <<endl; //int &refval2: //int &refva13=10://引用必须绑定到变量上,也可以绑定到对象上。常量不能绑定。 //f1oat &refval.2=value://不,类型应相同。 int a =3; int &b=a://引用,注意&符号在=的左边。 int p=a://注意&符号在=右边。
- 常量
//五:常量:不变的量
//13;24.5
//consti关键字:表示不变的意思
const int var = 7;//一种承诺,表示这个变量的值我不会去改变(命名常量)。
//var=15;编译时报错,编译器会检查这个const.承诺
int &var2 = (int &)var;
var2 = 18;
cout <<var <<endl;//7
cout <<var2 <<endl;//18,
//constexpr关键字:c++11才引入,它也是个常量的概念,在编译的时候求值,肯定能提升性能。
constexpr int var = 1;
int b = 5
constexpr int func(int abc)
{
abc = 14;
int a4 = 6;
for(int i = 0;i < 100; i++){
cout<<i<<endl;
}
}
//constexpr int var2 = func(12)//这样调用编译器会报错//如果去掉cout<<i<<endl;就不报错
int k2 = func(56);//这样正常不报错
2-3命名空间简介、基本输入输出精解
- 命名空间
//一:命名空间概念简介
//radius():radius();
//命名空间就是为了防止名字冲突而引入的一种机制。系统中可以定义多个命名空间,每个命名空间都有自己的名字,不可以同名:
//大家就可以把这个命名空间看成一个作用域,我们在这个命名空间里定义函数,跟你另外一个命名空间里定义的函数,即便同名,也互不影响。
//(1)命名空间的定义:
//namespace命名空间名
//{
// ......
//}
//(2)命名空间的定义可以不连续,甚至可以写在多个文件中。如果以往没有定义这个命名空间,那么“namespace命名空间名”这种写法
//就相当于定义了一个命名空间,如果以往你已经定义了这个命名空间,那么“namespace命名空间”这种写法 就相当于 打开已经存在的
//命名空间并向其添加新的成员声明
//(3)外界如何访问这个 某个命名空间中的radius()函数
//格式:命名空间名::实体名 -----其中这::叫“作用域运算符”
//zhangsan::radius();
- 基本输入输出
//二:基本输入输出cin、cout精解 //c+中,我们不用printf,而是用c++提供的标准库。 //不要排斥c+标准库,与c++语言一起学习。 //iostream库(输入输出流)什么叫流:流就是一个字符序列。 std::cout<<"很高兴大家和老师一起学习c++n“: //(1)td:命名空间,标准库命名空间。大家要记这个名字 //(2)cout,发音c out(console output),是个对象,“标准输出”对象,我们就认为这个对象是屏幕。 //c语言中叫结构,c++中我们叫类 //c语言中我们定义一个结构变里,在c++中,我们不叫结构变里,我们就他对象。 //(3)<<:“输出”运算符。直接扎到cout去了,就表示将《<右边的值写到cout去了;。 //<<可以当成函数,有参数。第一个参数在左边,就是cout对象。 //“很高兴大家和老师一起学习c++“"当成<<的第二个参数,在<<右边 //(4)\n:换行符,跟c语言中一个意思 int x 3; //std::cout<<x<<"的平方是"<<x*x<<"n":/f“%d.. std::cout<<x<<“的平方是"x*x<<std::endl: x++: std::cout<<x<<“的平方是“<<x*x<<std::endl: //std::endl:也是个对象,也可以当成一个操作符 是一个模板函数名,相当于函数指针 之后会详细讲解 //能看到std::cout的地方,就能看到std::endl //std::endl一般都位于std::cout语句的末尾。 //作用: //(1)输出换行符\n //(2)强制刷新输出缓冲区,缓冲区中所有数据都被系统清除了。 //输出缓冲区:一段内存。cout输出的时候实际是往输出缓冲区输出内容,那么输出缓冲区什么时候把内容输出到屏幕去的呢? //a)缓冲区满了 //b)程序执行到main的return语句; //c)调用了这个std::endl了,能够 强制 刷新 输出缓冲区(把缓冲区内的内容往屏幕上写) //d)当系统不太繁忙的时候,系统也会查看缓冲区内容,发现新内容也会正常输出到屏幕 //ostream &std::cout.operator<(); //<<定义,<<返回的是一个写入了给定值的cout对象。 //std::cout<<"很高兴大家和老师一起学习c++\n"://返回的是cout /*std::cout<<x<<“的平方是"<<xx<<std::endl:等价于 (std::cout<<x)<<“的平方是”<<x*x<<std::endl:等价于 (std::cout<<x)<<“的平方是“)<<x*x<<std::endl:等价于 ((std::cout<x)<<“的平方是“)<<x*x)<<std::endl:*/ int i=3; //std:cout<<i--<<i--; //2,3,其他编译器中 //要尽量避免 在一个表达式中多次的(超过1次的)改变一个变量值; //i--; //std::cout<<i; //i--; //std::cout<<i; //std::cin 基本输入; //cin:(c in),这也是个对象,叫标准输入。scanf & std::cout<<"请输入两个数:"<<std::endl; int value1 = 0, value2 = 0; std::cin >> value1 >> value2; std::cout<<value1 <<"和"<< value2 << "相加结果为:"<< value1 + value2<<std::endl; //(1)cin也是一个iostream相关对象。叫“标准输入”。理解为键盘 //(2) >> 是一个“输入”运算符 //(3)返回其左侧运算对象作为其计算结果 /*std::cin >> value1 >> value2; 相当于 (std::cin >> value1) >> value2;*/ //<<:运算符重载
2-4范围for、new内存动态分配、nullptr
- 范围for语句:用于遍历一个序列
int v[]{
12, 13, 14, 16, 18}
//for(auto x: v)//数组v中每个元素,依次放入x中并打印x值。把v每个元素拷贝到x中,打印x值;
for(auto &x:v)//省了拷贝这个动作, 提高了系统效率
{
cout<<x<<endl;
}
- 动态内存分配问题:供程序使用的存储空间,有程序区,静态存储区,动态存储区。
//c++中,我们把内存进一步详细分为5个区域;
//(1)栈:一般函数内的局部变量都会放在这里,由编译器自动分配和释放
//(2)堆:程序员malloc/new分配,用free/delete来释放。忘记释放后,系统会回收
//(3)全局/静态存储区:放全局变量和静态变量static。程序结束时系统释放。
//(4)常量存储区:"I love China"
//(5)程序代码区
//堆和栈不同的用途和区别
//(1)栈 空间有限。这是系统 int a = 4; 分配速度快,程序员也控制不了
//(2)堆 只要不超过实际的物理内存,也在操作系统允许能够分配的最大内存大小之内,都可以分配给你
//分配速度比栈慢,可以随时使用new/malloc来分配,free/delete。非常灵活
//malloc和free 在c语言中,用malloc和free从堆中来分配和释放内存用,malloc()和free()是函数
//malloc(memory allocation):动态内存分配
//一般形式:
//void *malloc(int MumBytes);//NumBytes:要分配的字节数。分配成功则返回指向被分配内存的指针,分配失败则返回NULL。
//当这段分配的内存你不使用的时候,你应该用free()函数来将内存释放掉,供其他地方使用。
//free:
//void free(void FirstByte);将之前用malloc分配的内存空间还给程序(操作系统》,也就是说释放了这块内存,这样这块内存
//就被系统回牧,并在需要的时候由系统分配出去再给其他释放。
int p = NULL://c语言写法―等价于数字0
p = (int *)malloc(sizeof(int));//在堆中分配4个字节
if(p != NULL)
{
//分配成功
*p = 5;
cout<<*p<<endl;
free(p);
}
char *point = NULL:
point = (char *)malloc(100 * sizeof(char)) ;//100个位置
if (point != NULL)//if(point)
{
//strcpy(point,"hello world!");
strcpy_s(point,100,"hello world!");//比strcpy安全的多
cout << point << endl;
free(point);
}
int*p= (int*)malloc(sizeof(int) * 100);//分配可以放得下100个整数的内存空间
if (p != NULL)
{
int*q= p;
*q++ = 1;//==>*(q++); -->*q= 1; q++;
*q++= 5;
cout << *布p << endl;//1
cout<<*(p +1]<< endl;//5
free(p):
}
//new和delete :是运算符(标识符)。c++t中就用new/delete分配和释放内存,不再使用malloc和free来分配和释放内存
//new, delete也和malloc, free干了一样的事就是分配和释放内存。同时new, delete还干了更多的事。
//new—般使用格式:
//(1)指针变量名= new类型标识符;
//(2)指针类型名= new类型标识符(初始值);//注意这里是圆括号括起来,表示初始值
//(3)指针类型名= new类型标识符[内存单元个数]://注意,这里[]
int *myint = new int: //int p = (int *)malloc(sizeof(int)):
if (myint != NULL)
{
*myint = 8;//*myint带包指针指向的变量
cout<<*myint<< endl;
delete myint;//释放单个myint的空间
}
int *pa = new int[100];//开辟一个大小为100的整型数组空间
if (pa != NULL)
{
int *q= pa;
*q++ =12://[0]=12
*q++ = 18;//[1] =18 ,执行完这行,这个q其实已经指向[2]
cout<<*pa << endl;//12
cout<<*(pa+1)<< endl;//18
//释放内存了
delete[] pa; //释放int pa数组空间
//new时候我们用[],那么delete就必须用[],[]不写数组大小
}
//额外补充知识
//(1)配对使用 有malloc成功必然有free,有new成功必然有delete
//(2)free/delete,不要重复调用
//malloc/free和new/delete区别;
3.nullptr
//nullptr代表的也是空指针
char *p = NULL;//NULL实际就是0
char *q = nullptr;
int *p = nullptr;
//int a = nullptr;//直接报错,nullptr与NULL并不相同,不能混用
//int b = NULL;//可以
if(p == nullptr)
{
cout<<"good"<<endl;
}
if(q == NULL)
{
cout<<"good"<<endl;
}
//使用nullptr能够避免在整数和指针之间发生混淆。
cout << typeid(NULL).name() << endl;
cout << typeid(nullptr).name() << endl;
//NULL和nullptr实际上不是同一类型
//结论:对于指针的初始化,和大家以往用到的和指针有关的NULL的场合,能用nullptr的大家全部用nullptr取代NULL
int *myint = new int(18); //int p = (int *)malloc(sizeof(int));
if(myint != nullptr)
{
cout<"good2"<< endl;
}
2-5结构、权限修饰符、类简介
- 结构回顾
//结构:自定义的数据类型 //回顾 struct student{ //成员变量 int number;//学号 char name[100];//学生名 void func() { number++; return; } }; void func(student &tmpstu)//结构体引用作为参数 { tmpstu.number = 2000; strcpy_s(tmpstu.name, sizeof(tmpstu.name), "who"); return; } void func(student *ptmpstu)//指向结构体的指针做函数参数 { ptmpstu->number = 2000; strcpy_s(ptmpstu->name, sizeof(ptmpstu->name), "who"); return; } student student1; student1.number = 1001; strcpy_s(student1.name, sizeof(student1.name), "zhangsan"); student1.func(); //c++中的结构和c中的结构有什么区别呢 //c++中的结构除了具备c中的结构的所有功能外,还增加了很多扩展功能,其中最突出的扩展功能之一就是: //c++中的结构不仅仅有成员变量,还可以在其中定义成员函数(方法);
- public和private权限修饰符
//二:public和private权限修饰符public(公有),private(私有),protected(保护),本节课只谈public,private。
//pub1ic:公共的意思,用这个修饰符修饰结构/类中的成员变量/成员函数,就可以被外界访问。
//一般我们需要能够被外界访问的东西,就定义为pub1ic。就好像是该类的外部接口一样。
//private:私有的意思,用这个☒饰符修饰结构/类中的成员变量成员函数,只有被内定义的成员函数才能使用。
- 类简介
//三:类简介:类也是用户自定义的数据类型
//大家已经道了:
//(1)不管c还是c++,结构都用struct定义
//(2)老师为了方便大家理解,曾经说过:大家就把c语言中的结构当成c++中的类;这个话并不全面,知识为了方便大家理解。
//那么结构和类到底有什么区别呢?
//(2.1)类这个东西,只在c++中才有这个概念,c中没有类这个概念
//(2.2)结构用struct定义,类用class定义。
//在c中,我们定义一个属于该结构的变量,我们叫结构变量。
//在c++中,我们定义了一个属于该类的变量,我们叫对象。
//说白了,结构变量也好,对象也好,他们都是一块能的够存储镂数据并且具有某种类型的内存空间。
//(2.3)c++中,结构和类极其类似,区别有两点:
//a)c++结构内部的成员变量以及成员函数 默认的防问级别都是pub1ic。
//c++类内部的成员变量以及成员函数 默认的防问级别是private。
//b)c++结构体继承默认的是public,而c++类的继承默认都是private
- 类组织
//四:类的组织,书写规苑:
//类的定义代码会放在一个.h头文件中,头文件名可以眼类名相同,student.h
//类的具体实现代码,放在一个.cpp文件中,student.cpp
2-6函数新特性、内联函数、const详解
- 函数回顾与后置返回类型
//void func123(int, int);//函数声明(函数原型)
//void func123(int a, int b)//函数定义
//auto:变量自动类型推断
auto func123(int a, int b) -> void;//函数声明
auto func123(int a, int b) -> void;//函数定义
{
return;
}
//函数定义中,形参如果在函数体内用不到的话,可以不给形参变量名字,只给其类型
//函数声明,可以只有形参类型,没有形参名
//把函数返回类型放到函数名字之前,这种写法,叫前置返回类型
//func123(12, 13);
//c++11中,后置返回类型, 就是在函数声明和定义中,把返回类型写在参数列表之后
//前面放auto,表示函数返回类型放到参数列表之后,而放在参数列表之后的返回值类型是通过->开始的
- 内联函数
inline int myfunc(int testv)//函数定义前加inline,这个普通函数就变成了内联函数
{
return 1;
}
//二:内联函数:在函数定义前增加了关键字inline,导致该函数变成内联函数。
//函数体很小,调用有很频繁的这种函数。咱们引入inline(内联函数)
//(1)inline响编译器,在编译阶段对inline这种函数进行处理,系统尝试将调用该函数的动作替换为函数本体。通过这种方式,来提升性能
//int a = func(5);//int a = 1;
//(2)inline只是开发者对编译器的一个建议,编译器可以尝试去做,也可以不去做,这取决于编译器的诊断功能,也就是说,决定权在编译器,我们控制不了。
//(3)内联函数的定义就要放在头文件。这样需要用到这个内联函数的.cpp文件能够通过#include把这个内联函数的源代码#include。把这个内联函数的源代码#include进来。
//以便找到这个函数的本体源代码并尝试将该函数的调用替换为函数体内的语句
//优缺点:
//代码膨胀的问题;所以内联函数函数体尽量要小。
//注意:各种编译器对nline的处理各不相同。inline函数尽量简单,代码尽可能少。循环,分支,递归调用尽量不要出现在inlinel函数中。
//否则的话,编译器很可能会因为你写这些代码的原因拒绝让这个函数成为一个inline函数。
//constexpr函数,可以看成是更严格的一种内联函数
//#define宏展开也类似于inline
- 函数杂合用法总结
//(1)函数返回类型为void,表示函数不返回任何类型,但是我们可以调用一个 返回类型是void的函数 让 它作为另一个 返回类型是void的函数的返回值
void func()
{
}
void funcb()
{
return func(); //这也可以
}
//(2)函数返回指针和返回引用的情况
//(3)没有形参可以保持形参列表为空(),或者int myfunc(void)
//(4)如果一个函数我们不调用的话,则该函数可以只有声明部分,没有定义部分
//(5)普通函数,定义只能定义一次(定义放在.cpp文件中),声明可以声明多次。 一般函数定义.cpp文件会#include自己的函数声明文件(.h)
//(6)void func(int &ta, int &tb), 在c++中,更习惯用引用类型的形参来取代指针类型的形参。提倡在c++中,多使用引用类型的形参。
//(7)c++中,函数允许重名,但是形参列表的参数类型或者数量应该用明显的区别。
//void fs(const int i){}
//void fs(int i){}//这两个函数会冲突,会报错
- const char*、char const*、char* const三者的区别
//四:const char*、char const*、char*const三者的区别
//const int abc 12:
//char*p; const混用;
//4.1:const char *p;
//char str[]="I Love China!";
//const char *p;//p指向的东西不能通过p来修改(p所指向的目标,那个目标中的内容不能通过p来改变):
//char const *p;
//p =str;
p* = 'Y';//语法错
//p+:
//p+:
//stx[0]='Y:/这是oK的。
char const *等价于 const char*p:
char str[] = "I Love China!";
char * const p = str; //定义的时候必须初始化
//p一旦指向了一个东西之后,就不可以在指向其他的东西了
//p++; //不可以,p一旦指向了一个东西之后,就不可以再指向其他的东西了
*p = 'Y';//但可以修改p指向的目标的内容。
//const char * const p = str;
char const * const p = str; //p的指向也不能变,p指向的内容也不能通过p来改变
//--
int i = 100;
const int &a = i;//代表a的内容不能通过a自己来修改
i = 100;
//a = 500;//不合法
//int &b = 31;//错误
const int &b = 31; //分配了内存的
cout<<b<<endl;
- 函数形参中带const
//函数形参中使用const
//把形参写成const 的形式有很多的好处
//(1)可以防止你无意中修改了形参值导致实参值被无意修改
//(2)实参类型更加灵活
void fs2(const student &sut)
{
}
student abc;
abc.num = 200;
fs2(abc);
cont<< abc.num << endl;
const student &def = abc;
fs2(def);//这里若是fs2的定义为void fs2(student &sut)就会报错,出现无法从“const student”转化为“student &”
fs2(12);//这里也是同上面,void fs2(const student &sut)这种定义方式是对的,void fs2(student &sut)这种就会报错
2-7string类型介绍
- 前言
//一:前言int ,float, char ,c++标准库:string, vectoro
//string:可变长字符串的处理。vector一种集合或者容器的概念,。
- string类型简介
//二:string类型简介:c++标准库中的类型,代表一个可变长字符串;
//string这个类型,看成一个类类型(类似于struct) ;
//char str[100]="I Love China"; //c语言中用法
- 定义和初始化string对象
//三:定义和初始化string对象
string s1;//默认初始化,s1 ="":""空串,表示里边没有字符;
string s2 = "I Love China!";//把I Love China!这个字符串内容拷贝到了s2代表的一段内存中。拷贝时不包括末尾的\0。
string s3("I Love China");//跟s2的写法效果—样
string s4 = s2;//把s2中的内容拷贝到了s2所代表的一段内存中。
int num = 6;
string s5(num, 'a');//aaaaaa, 把s5初始化为连续num个字符'a'组成的字符串,这种方式不太推荐,因为在系统内部创建临时对象。
- string对象上的操作
//四:string对象上的操作 //a)判断是否为空empty(),返回的布尔值 //string s1; //if(s1.empty())//成立 //{ //cout <<"s1为空”<< endl ; //} //b)size()/length():返回字节/字符数量代表该字符串的长度。unsigned int string s1; cout << s1.size()<< endl; cout << s1.length(<< endl; string s2="我爱中国"; cout << s2.size() << endl; cout << s2.length() << endl; //c)s[n]:返回s中的第n个字符(n是个整型值),n代表的是一个位置,位置从0开始,到.size()-1; //如果用下标n超过这个范围的内容,或者本来人家一个空字符串,你也用s[n]去访问,都会产生不可预测的结果; string s3 ="I Love China!": if (s3.size( >4) { cout < s3[4]<< endl;//vs3[4] = 'w'; cout << s3<< endl;//I Lowe China! } //d)s1+s2;字符串的连接,返回连接后的结果,其实就是得到一个新的string对象。 string s4 = "abcd"; string s5 = "hijk"; string s5 = s4 + s5; cout < s6 << endl; //e)s1 = s2;字符串对象赋值,用s2里边的内容取代原来s1里的内容 string s7 = "abcd"; string s8 = "de"; s7 = s8; cout << s7 << endl; //f) s1 == s2:判断两个字符串是否相等。大小写敏感:也就是大小字符跟小写字符是两个不同的字符。abc abC //相等:长度相同。字符全相同。 string s9 =