当初自学C++时的笔记记录
编辑:刘风琛
最初编写日期:2020年4月11日下午 最新更新日期:2020年9月20日上午
标注:
- 从笔记开始截止到程序第四章“程序流程结构”,使用Joplin编写,其余部分为Typora编写。
- 笔记对应课程链接为:(https://www.bilibili.com/video/BV1et411b73Z) 作者:黑马程序员-
- 当前进度为
P107
:类和对象
1. 变量
给一段内存起名,方便使用。
2. 常量
用于记录程序中不可更改的数据。
- 定义常量的两种方式
- #define宏常量
#define 常量名 常量值
- 通常在文件上方定义,表示一个常量。
- const修饰的变量
const 数据类型 常量名=常量值
- 通常在变量定义前加const,修饰该变量为常量,不可更改。`
- #define宏常量
3. 数据类型
sizeof()
可以返回当前数据类型所占内存大小。
强制转换
语法:(数据类型)被转变量
举例:int main(){
char ch = 'a';
cout<<(int)ch<<endl;
return 0;
}
输出结果:
97
(字符a的ASCII码)转义字符
转义字符用反斜杠\
表示,可以用来表示ASCII码的特殊值。
转义字符 | 含义 | ASCII码值 |
---|---|---|
\a | 警报 | 007 |
\b | 退格(BS),将当前位置移到前一列 | 008 |
\f | 换页(FF),将当前位置移到下页开头 | 012 |
\n | 换行(LF),将当前位置移到下一行开头 | 010 |
\r | 回车(CR),将当前位置移到本行开头 | 013 |
3.1 整型
C++中可以用以下方式表示整型,区别在于所占内存空间不同
数据类型 | 占用空间 | 取值范围 |
---|---|---|
short(短整型) | 2字节 | -215~215-1 |
int(整型) | 4字节 | -231~231-1 |
long(长整型) | windows为4字节;Linux 32位4字节,64位8字节 | -231~231-1 |
long long(长长整型) | 8字节 | -263~263-1 |
3.2 浮点型(小数)
浮点型分为以下两种:
数据类型 | 占用空间 | 取值范围 |
---|---|---|
float(单精度) | 4字节 | 7位有效数字 |
double(双精度) | 8字节 | 15~16位有效数字 |
- 科学计数法
举例:
整数:3e1表示3*10^1,也就是30
小数:3e-1表示3*10^-1,也就是0.3
3.3 字符型
表示单个字符的数据类型,只占一个字节。
- 语法:
char ch = 'a'
- 注意:
- 字符需要用单引号括起。
- 且单引号中只能有一个字符。
- 计算机真正存放的不是字符,是ASCII码。
3.4 字符串
表示一串字符,可以有两种表示方式。
C语言中常用方式(数组):
char 变量名[] = "abcde"
示例:int main(){
char str[] = "Hello world!";
cout<<str<<endl;
return 0;
}
- 注意:
- 字符串内容要用单引号括起来。
- 变量名后必须加中括号表示数组。
- 注意:
当前标准方式:
string 变量名 = "abcde"
示例:#include <string>
int main(){
string str = "Hello World!";
cout<<str<<endl;
return 0;
}
- 注意:
- 使用
string
需要引入头文件:#include <string>
- 使用
- 注意:
3.5 布尔类型
代表"true(1)"或者"false(0)",表示逻辑。
- 所占内存:1字节。
- 本质上1代表真,0代表假。
- 使用cin输入时,非0表示真,0表示假,0~1之间的小数视为0。
3. 运算符
包括四则运算,取余等方法。
四则运算注意事项
- 除法符号为"
/
"注意不要和反斜杠"\
"混淆。 - 除法运算时,两个整数(这里指类型)相除,结果依然是整数,小数部分消除(不是四舍五入)。
- 0为除数时程序崩溃
- 除法符号为"
取模运算
- 符号为"
%
" - 取模运算作用是获取两数相除所得余数。
- 取模运算本质上也是除法的一种,除数不可为0。
- 小数不可以进行取模运算
- 符号为"
递增和递减
- 两者的功能类似,都是让变量加、减1
- 前置递增/递减为先加1,后运算;后置递增/递减为先运算,后加1.
赋值运算符
- 包括
=
、+=
、-=
、*=
、/=
、%=
。
示例:int main(){
int a=1;
a=3;
//此时a=3;
a+=2;
//此时a=5
a-=3;
//此时a=2
a*=2;
//此时a=4
a/=2;
//此时a=2
a%=1;
//此时a=0
cout<<a<<endl;
return 0;
}
- 包括
比较运算符
包括
==
、>=
、<=
、!=
、>
、<
。逻辑运算符
- 包括非
!
、与&&
、或||
。
- 包括非
三目运算符
- 用法:
表达式1 ? 表达式2 : 表达式3
- 含义:如果表达式1成立,则返回表达式2的运行结果,否则返回表达式3的运行结果。
示例:
int main(){
int a=1,b=10,c=0;
//用法一
c = (a > b ? a : b); //括号能提高三目运算的优先级防止运行出错
//将a和b中值较大的赋值给c //用法二
(a > b ? a : b) = 999;
//把999赋给a和b中较大的变量
return 0;
}
- 用法:
4. 程序流程结构
4.1 顺序结构
就是从头到尾顺序执行,没啥可记的。
4.2 选择结构
判断选择,可以实现跳过或者分支。
if语句
用法一:if(条件){满足条件执行的代码块}- 注意:
- 注意不要加入多余的分号。
- 示例:
int main(){
int score;
cout<<"Please input your score:";
cin>>score;
if (score>=600){
cout<<"Good!";
}
return 0;
}
用法二:if(条件){满足条件执行的代码块}else{不满足时执行的代码块}
- 注意:
else
为可选分支,删除后和用法一相同。- 注意不要加入多余的分号。
int main(){
int score;
cout<<"Please input your score:";
cin>>score;
if (score>=600){
cout<<"Good!";
}else{
cout<<"Bad!";
}
return 0;
}
用法三:if(条件1){满足条件执行的代码块}else if(条件2){不满足条件1但满足条件2时执行的代码块}
-。else
和else if
为可选分支.else if
可并列多次使用
int main(){
int score;
cout<<"Please input your score:";
cin>>score;
if (score>=600){
cout<<"Good!";
}
else if(score>=400){
cout<<"Bad!";
}
else{
cout<<"So Bad!";
}
return 0;
}
用法四:if语句的嵌套,我认为没啥高级的,所以不记了。
- 注意:
switch语句
- 用法:在示例中演示
- 意义:可以轻松实现多分支
示例:
int main(){
int level;
cin>>level;
switch(level){
case 1:
cout<<"Good";
break;
case 2:
cout<<"Normal";
break;
case 3;
cout<<"Bad";
break;
default :
cout<<"非法输入!请输入1~3之间的整数。";
break;
}
return 0;
}
- 注意:
- 需要使用break跳出分支。
- 缺点是无法使用区间视线分支。
4.3 循环结构
循环执行代码块。
4.3.1 while语句
条件满足时不断循环执行指定代码块,否则跳出循环。
用法:
while(条件){条件为真时循环执行的代码块}
注意:
- 可以使用
break
跳出循环。
- 可以使用
示例:
int main(){
int a=0;
while(a<10){
a++;
cout<<a;
}
return 0;
}
4.3.2 do...while语句
用法:
do{代码块}while(条件);
注意:
- 基本注意事项和
while
相同。
- 基本注意事项和
示例:
int main(){
int a=0;
do{
a++;
cout<<a<<endl;
}
while(a<10);
return 0;
}
4.3.3 for循环语句
用法:
for(起始表达式;条件表达式;末尾表达式){循环代码块}
注意:可以使用
break
跳出循环。示例:
int main(){
for(int i=1;i<10;i++){
cout<<i<<endl;
}
return 0;
}
4.4 跳转语句
用于跳出或者移动当前结构中的运行位置。
4.4.1 break语句
- 可以出现在switch语句中,用于跳出分支。
- 可以出现在循环语句中,用于跳出循环。
- 在位于嵌套循环结构时,用于跳出当前所在层的循环。
4.4.2 continue语句
作用:在循环语句中跳过余下尚未执行的语句,直接进入下一次循环。
示例:
int main(){
for (int i=1;i<=10;i++)
{
cout<<i<<endl;
continue;
cout<<"这段不被输出\n";
}
return 0;
}
4.4.3 goto语句
作用:可以跳转到任意标记的位置。
示例:
int main(){
for(int i=1;i<=10;i++){
cout<<"这是第一句话\n";
cout<<"这是第二句话\n";
goto flag;
cout<<"这句话我们不要了\n";
flag:
cout<<"这是第三句话\n";
}
return 0;
}
5. 数组
数组就是一个集合,里边存放了一组相同类型的数据。
- 特点
- 数组中每个元素都是相同的数据类型。
- 数组是由连续的内存位置组成的。
5.1 一维数组
一维数组的定义方式:
数据类型 数组名[数组长度];
数据类型 数组名 [数组长度]={值1,值2,...,值n};
数据类型 数组名[]={值1,值2,...,值n};
访问格式:
array [0]
注意事项:
- 访问时下标从0开始。
示例:
int main(){
int arr[5]={1,2,3,4};//只初始化了前四个,第五个值默认初始化为0
for(int i=0;i<=4;i++)
{
cout<<arr[i]<<endl;
}
arr[4]=5; //这是对数组中未初始化的第5个值赋值
cout<<arr[0];
return 0;
}
补充:
- 数组名的用途:
- 可以统计数组或数组中元素所占内存空间。(使用
sizeof(数组名/数组名[])
函数) - 可以获取数组在内存中的首地址。(
cout<<array;
)
- 可以统计数组或数组中元素所占内存空间。(使用
- 数组名为常量,不可直接赋值。
- 数组名的用途:
一维数组的倒置示例:
int main(){
int arr [5]={1,2,3,4,5};//创建一个数组
int temp,a,b;
a=0;b=sizeof(arr)/sizeof (arr[0])-1;//b为通过计算得出的数组中元素数量减1
while(a<b){
temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
a++;b--;
}
b=sizeof(arr)/sizeof (arr[0]);//为了节省内存,将b重置为数组元素个数
for(int i = 1;i<=b;i++){ //循环b次,依次输出数组中每个元素的值
cout<<arr[i-1]<<endl;
}
return 0;
}
一维数组的顺序排列示例(冒泡排序):
int main(){
int arr[5]={1,5,2,3,4};
for (int i = 0;i < 5;i++){
for(int j = 0;j<(5-i-1);j++){
if (arr[j]>arr[j+1]){
int temp;
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
} for (int q = 1; q<=5;q++){
cout<<arr[q-1]<<endl;
}
return 0;
}
5.2 二维数组
定义方式:
数据类型 数组名 [行数][列数]={{数值1,数值2...},{数值n,数值n+1...}};
数据类型 数组名 [行数][列数];
数据类型 数组名 [行数][列数]={数据1,数据2,数据3,数据4};
数据类型 数组名 [][列数]={数据1,数据2,数据3,数据4};
示例:
int main(){
//这是创建二维数组最直观的形式
int arr[2][3]={
{1,2,3},
{4,5,6}
};
//使用for循环嵌套遍历输出二位数组中每个元素
for (int i=0;i<2;i++){
for (int j=0;j<3;j++){
cout<<arr[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
二维数组名的用途
- 可以统计数组、数组中一行或数组中元素所占内存空间。(使用
sizeof(数组名/数组名[]/数组名[][])
) - 可以获取数组在内存中的首地址。(
cout<<array;
)
- 可以统计数组、数组中一行或数组中元素所占内存空间。(使用
注意:
- 为了程序的可读性,我们一般使用前两种定义方式。
- 第三种定义方式会自动分出行列。
- 第四种必须指定列数,行数会依据数据数量进行自动分配。
6. 函数
函数就是一个程序块,可以方便的进行调用,能很好的减少代码量,一个较大的程序往往分成好多模块,每个模块实现特定功能。
6.1函数的定义
函数的定义示例:
返回值类型 函数名(形参)
{
程序代码块;
retuen 返回值表达式;
}
注意:
- 必须返回一个正确的返回值类型。
- 若不需要返回值可以声明void函数。
6.2 函数的调用
- 语法:
函数名(参数)
- 形式参数也叫
形参
,是一个形式,调用的是使用函数时传递的实参
。 - 形参的值在函数中发生变化不会影响到实参。
6.3 函数的声明
语法
返回值类型 函数名(形参)
注意:
- 在main函数前声明函数防止程序运行时无法正常调用函数。
- 可以有多次声明,但是只能有一次定义
示例:
int max(int num1,int num2); //函数max的声明
int main(){
cout<<max(100,101)<<endl;
return 0;
}
int max(int num1,int num2){ //函数的定义
return num1 > num2 ? num1:num2;
}
//函数定义在main函数后需要在main函数前声明。
6.4 函数的分文件编写
为了防止单文件形势下代码量过大。
要素:
- 一个自定义的头文件(.h)
- 源文件(.cpp)
- 函数的声明写在头文件中
- 函数的定义写在源文件中
示例:
文件结构:
代码示例:
main.cpp
#include <iostream>
#include "max.h" using namespace std; int main(){
cout<<max(100,101)<<endl;
return 0;
}
max.h
#include <iostream>
using namespace std; int max(int num1,int num2);
max.cpp
#include "max.h" int max(int num1,int num2){
return num1 > num2 ? num1:num2;
}
输出结果:100
6.5 函数的默认值
语法:
返回值类型 函数名(参数名=默认值);
注意:
- 如果某个位置开始有默认参数,那么从该位置往后都应该有默认参数。
- 声明和实现只能有一个设置默认参数,不允许重定义默认参数。
示例:
void print(int a=10,int b=20,int c=30){ //给所有选项都设置了默认参数
cout<<a+b+c<<endl;
}
int main()
{
print(1,2,3);//调用函数是传递参数
//输出6
print();//调用函数时不传递参数,使用默认参数
//输出60
return 0;
}
6.6 函数的占位参数
语法:
返回值类型 函数名 (数据类型);
示例:
void print(int = 10){ //只有数据类型,没有变量名就是占位参数
cout<<"Hello World!";
}
int main(){
print(); //因为占位参数具有默认值,所以此处无需传递,否则必须传递一个相应类型的参数
}
6.7 函数的重载
6.7.1 概述
意义:函数名可以相同,提高函数复用性。
条件:
- 同一作用域下。
- 函数名称相同。
- 函数
参数名
或参数个数
或参数顺序
不同。
注意:函数的返回值不可用作函数重载的条件。
示例:
void print(){
cout<<"print()函数被调用\n";
}
void print(int a){
cout<<"print(int a)函数被调用\n";
}
int main()
{
print();//print()函数被调用
print(1);//print(int a)函数被调用
//其他例如参数名,参数个数,参数顺序不同 同理
return 0;
}
6.7.2 函数重载的细节问题
常量引用
示例:
void print(int& a){
cout<<"print()函数被调用\n";//如果传入数字1,则为int& a = 1 不合法
}
void print(const int& a){ //相当于const int& a = 1 合法
cout<<"print(int a)函数被调用\n";
}
int main()
{
int a=1;
print(a);
print(1);
return 0;
}
引入默认值导致的二义性
示例:
void print(int a){
cout<<"print()函数被调用\n";
} void print(int a,int b=1){
cout<<"print(int a,int b=1)函数被调用\n";
}
int main()
{
print(1);//这个会报错,因为产生了二义性
print(1,1);//会调用print(int a,int b=1)函数
return 0;
}
7. 指针
可以通过指针间接访问内存地址。
- 注意:
- 内存编号从0开始记录,一般使用十六进制数字保存
- 可以利用指针变量保存地址
- 不管什么指针,在32位系统下占用4字节,64位占用8字节。
7.1 指针的定义
- 语法:
数据类型 * 指针变量名
7.2 指针的使用
让指针记录一个地址:
语法:
指针变量名 = &变量名
注意:
&
为取址符,可以获取当前内存地址。
指针指向函数:
- 语法:
返回值 (*指针名)(参数列表);
- 语法:
指针的使用:
通过
解引用
影响指针指向内存区域所储存的值。示例:
int main(){
int a = 10;
int * p; //定义一个指针p
p=&a; //将变量a的地址赋给指针p
//int * p = &a; //这个方式可以将定义和赋值写在一起
*p=1000; //使用解引用影响指针p指向的内存区域,也就是变量a
cout<<a<<endl;
cout<<*p<<endl; //通过输出展示指针所产生的影响
return 0;
}
7.3 空指针
- 用途:给指针变量初始化。
- 特点:空指针指向的内存区域无权访问。
- 定义一个空指针:
int * p = NULL
7.4 野指针
- 定义:指向一块未申请的内存区域。
- 特点:
- 指向的内存区域通常无法读取或修改。
- 一旦尝试读取或修改,则会报错。
7.5 const修饰指针
三种方式:
- const修饰指针:常量指针
- 用法:
const int * p = NULL
- 作用:指针所指向的内存地址中的值为常量,不可更改;但是指针所指的地址可以更改。
- 用法:
- const修饰常量:指针常量
- 用法:
int * const p = NULL
- 作用:指针本身为常量,指向的内存地址不可更改,但是其值可以更改。
- 用法:
- const同时修饰指针和常量
- 用法:
const int * const p=NULL
- 作用:指针所指的内存地址不可更改,值也不可更改。
- 用法:
- const修饰指针:常量指针
7.6 指针和数组
用指针操作数组。
示例:
int main(){
int arr[5]={1,2,3,4,5};
int * p=arr; //将指针指向数组在内存中的首地址
for (int i=0;i<5;i++){
cout<<*p<<endl; //输出指针p指向的值
p++; //每次循环将指针p向后偏移4字节,实现指针在数组中的遍历
}
return 0;
}
7.7 指针和函数
利用指针作为函数的参数可以修改实参的值。
示例:
void swap(int *p1,int *p2){ //声明一个函数用来交换两个变量的值,形参为两个指针
//这部分直接影响了指针所指向的内存空间,也就是main函数中a,b两个变量的值
int temp=*p1;
*p1=*p2;
*p2=temp;
}
int main(){
int a=1,b=2;
cout<<"a="<<a<<" b="<<b<<endl;
swap(&a,&b); //引用函数,实参为两个变量的地址
cout<<"a="<<a<<" b="<<b<<endl;
return 0;
}
# 指针、函数、数组的搭配示例
利用冒泡循环对数组排序。
int bubbleSort(int * arr,int len){ //使用函数封装冒泡循环的算法
for (int i = 0;i<len;i++){
for(int j=0;j<len-i-1;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
int main(){
int arr []={1,5,3,2,7,8,3,5,2};
int len=sizeof(arr)/sizeof (arr[0]); //获取数组的元素数量
bubbleSort(arr,len); //调用函数,第一个实参为arr数组的内存地址
for(int i = 0;i<len;i++){
cout<<arr[i]<<endl;
}
}
8. 结构体
允许用户创建自定义数据类型
,储存不同的数据类型。
8.1 定义和使用
语法:
struck 结构体名 { 结构体成员列表 };
创建变量方式:
- struck 结构体名 变量名 = {成员1;成员2;...}
- struck 结构体名 变量名
- 定义结构体时顺便创建变量
使用变量的属性
- 格式:
变量名.属性
- 格式:
示例:
struct student //定义结构体(全局),struct关键字不可省略
{
string name;
int age;
int score;
}s3; //此处s3为使用方法三创建的结构体变量 int main(){
//方法一
struct student s1={"Maicss",19 , 650 } ; //struct关键字可以省略
cout<<"name:"<<s1.name<<"\tage:"<<s1.age<<"\tscore:"<<s1.score<<endl; //方法二
struct student s2; //struct关键字可以省略
s2.name="qian";
s2.age=18;
s2.score=600;
cout<<"name:"<<s2.name<<"\tage:"<<s2.age<<"\tscore:"<<s2.score<<endl; //方法三
//创建结构体变量在定义结构体之后
s3.name="son";
s3.age=1;
s3.score=700;
cout<<"name:"<<s3.name<<"\tage:"<<s3.age<<"\tscore:"<<s3.score<<endl;
return 0;
}
8.2 结构体数组
作用:将自定义的结构体放入数组中方便维护。
语法:struck 结构体名 数组名[成员数] = { { } , { } , { } }
示例:
struct student { //定义一个结构体
string name;
int age;
int score;
};
int main()
{
//创建一个结构体数组
struct student stuarr[3]{
{"Maicss",19,100},
{"Max",20,99},
{"Pig",10,30}
}; //给结构体数组中第三个成员的score修改为98
stuarr[2].score =98; //遍历输出结构体数组所有成员属性
for (int i=0 ;i<3;i++){
cout<<"name:"<<stuarr[i].name<<"\tage:"<<stuarr[i].age<<"\tscore:"<<stuarr[i].score<<endl;
}
return 0;
}
8.3 结构体指针
作用:通过指针访问结构体中的成员。
利用操作符
->
可以通过结构体指针访问结构体属性。示例:
struct student { //定义一个结构体
string name;
int age;
int score;
};
int main()
{
//创建一个结构体数组
student s{"Maicss",19,100}; //创建一个结构体指针
student * p = &s; //通过指针读取结构体变量属性
cout<<"name:"<<p->name<<"\tage:"<<p->age<<"\tscore:"<<p->score<<endl;
return 0;
}
8.4 结构体嵌套
作用:让一个结构体成为另一个结构体的成员。
示例:
struct student { //定义一个结构体
string name;
int age;
int score;
};
struct teacher { //定义另一个结构体
string name;
int id;
int age;
student std;
};
int main()
{
//创建一个结构体变量
student std1 {"max",18,100};
//创建另一个结构体变量
teacher thr1 {"maicss",197835,23,std1}; //创建一个结构体指针
teacher * p = &thr1; //修改老师maicss的学生max的年龄为19
thr1.std.age=19; //通过指针读取结构体变量属性
cout<<"name:"<<p->name
<<"\tID:"<<p->id
<<"\tage:"<<p->age
<<"\tstudent:"<<p->stds.name //读取嵌套在teacher结构体中的student的属性
<<"\tstudentAge:"<<p->stds.age //查看更改后的学生年龄
<<endl;
return 0;
}
8.5 将结构体作为函数参数传递
值传递
- 直接在函数参数中传递结构体变量。
- 特点:在函数内对参数值(结构体属性)的修改不会影响实参。
指针传递
- 在函数参数中传递结构体指针。
- 特点:对值(结构体属性)的修改会影响到实参。
const 保护
- 用const修饰指针,防止在函数中无意影响到函数实参。
示例:
struct student { //定义一个结构体
string name;
int age;
int score;
};
void print1(student a){ //结构体在函数参数中通过值传递
cout<<"name:"<<a.name<<" age:"<<a.age<<" score:"<<a.score<<endl;
}
void print2(student * p){ //结构体在函数参数中通过指针传递
p->age=100; //通过指针修改结构体属性的值可以影响到实参
cout<<"name:"<<p->name<<" age:"<<p->age<<" score:"<<p->score<<endl;
}
int main()
{
//创建一个结构体变量
student std1 {"max",18,100}; //创建一个结构体指针
student * p =&std1; //调用函数进行输出
print1(std1); //值传递
print2(&std1);//指针传递
cout<<"name:"<<std1.name<<" age:"<<std1.age<<" score:"<<std1.score<<endl; //验证print2函数的修改
return 0;
}
9. 联系人管理系统实例
10 程序的内存模型
10.1 内存分区模型
- 代码区:存放函数体的二进制代码,由操作系统进行管理。
- 全局区:存放全局变量和静态变量以及常量。
- 栈区:由编译器自动分配和释放,存放函数的参数值,局部变量等。
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由系统回收。
10.2 分区意义
- 不同区域存放的数据赋予不同的生命周期,更强大的灵活的编程。
10.3 程序运行前
程序编译后,生成exe
可执行程序,未执行该程序前分为两个区域。
- 代码区:
- 存放CPU执行的机器指令。
- 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。
- 全局区:
- 全局变量和静态变量存放在此。
- 全局区也包含了常量区,字符串常量和其他非局部常量也存放在此。
- 该区域的数据在程序结束后由操作系统释放。
10.4 程序运行后
栈区
由编译器自动分配和释放,存放函数的参数值,局部变量等。
注意:不要返回栈区的地址,栈区开辟的数据由编译器自动释放。
栈区的数据在函数执行完后自动释放。
示例:
int* integer(){
int a=1;
return &a; //返回局部变量a的内存地址
}
int main()
{
int * p=integer(); //将指针p指向局部变量a的地址
cout <<*p<< endl; //第一次解引用p
//这里之所以会输出a是因为编译器为程序保留了一次内存
cout <<*p<< endl;//第二次解引用p
//编译器不再为程序保留,所以不再是原来的数值
return 0;
}
堆区
由程序员分配和释放,若程序员不释放,程序结束时由系统回收。
使用
new
在堆区开辟内存。- 语法:
new 数据类型
- new创建的数据会返回该数据类型对应的指针。
- 语法:
使用
delect
释放内存。- 语法:
delect 指针
- 释放后不能继续访问。
- 语法:
为了防止出现
野指针
,在堆区内存空间被释放时要将指向该内存的指针指向NULL
。- 示例:
int main()
{
int * p = new int(10); //使用new开辟一块内存储存整数10并将地址给指针p
int * p2 = new int[10]; //创建一个数组
cout<<*p<<endl;//解引用指针p结果为10
//赋值部分省略
delete p;//释放内存
delete[] p2;//释放数组
}
- 示例:
11. C++中的引用
引用的本质是指针常量。
11.1 引用的基本使用
作用:给变量起别名。
语法:
&别名=原名
注意事项:
- 引用必须要初始化。
- 引用一旦初始化就不可以更改。
11.2 引用作函数参数
作用:就像指针一样,可以影响到实参。
示例:
//创建一个交换函数
void swap(int &a,int &b){ //使用引用传递参数
int temp;
temp=a;
a=b;
b=temp;
}
int main()
{
int a,b;
a=0;b=1;
swap(a,b);
cout<<a<<"\n"<<b<<endl;
}
11.2 引用作函数的返回值
作用:可以让函数的调用作为左值。
示例:
//创建一个函数
int& num(){
static int a=10; //创建静态变量,储存在全局区中
return a;
}
int main()
{
int& ref=num(); // 给num函数中的a搞一个引用
num()=1000;
cout<<ref<<endl; //验证将函数调用作为左值是否有效
return 0;
}
11.3 常量引用
作用:可以用来修饰形参,防止实参被影响。
示例:
void change(const int& a){ //使用const修饰形参
//此处不可修改a的值
cout<<a;
}
int main()
{
int a=1;
change(a);
return 0;
}
12. 类和对象
C++面向对象的三大特性:封装、继承、多态。
万物皆对象、对象上有其属性和行为。
12.1 封装
12.1.1 封装的意义
封装是c++面向对象三大特征之一
封装的意义:
- 将属性和行为作为一个整体来表现实物。
- 将属性和行为加以权限控制。
示例:
#include <iostream>
using namespace std; #define Pi 3.1415926 //定义一个宏常量Pi class circle{ //创建一个circle类
public: //定义公有部分
int r; //定义一个半径属性r
double circle_C(){ //定义一个成员函数,计算周长
return 2*r*Pi;
}
void set_r(double set_r){
r=set_r;
} };
int main()
{
circle yuan; //通过circle类实例化一个对象
yuan.r=10; //给对象的公有属性r赋值
cout << yuan.circle_C() << endl; //通过成员函数输出周长
yuan.set_r(5);
cout << yuan.circle_C() << endl; //通过成员函数输出周长验证修改
return 0;
}
12.1.2 访问权限控制
总共有三个权限
名称 意义 特点 public 公共权限 类内和类外都可以访问 protected 保护权限 类内可以访问,类外不可以访问,子可以访问父的保护内容 private 私有权限 类内可以访问,类外不可以访问,子不可访问父的私有内容 class
和struct
的区别:class
默认是私有权限,struct
默认是公有权限。
12.1.3 成员属性私有化
优点:
- 对成员属性私有化可以自己控制读写权限。
- 对于读写权限,可以检测数据的有效性。
示例:
#include <iostream>
using namespace std; class human{
public:
void setName(string set_name){ //定义一个用来设置姓名的成员函数
name=set_name;
}
string getName(){ //定义一个获取姓名的成员函数
return name;
}
void setAge(int set_age){ //定义一个用来设置年龄的成员函数
if (set_age<0 || set_age>150){ //使用if语句判断所给值是否合法
cout<<"非法数据!";
}else{
age=set_age;
}
}
int getAge(){ //定义一个用来获取年龄的成员函数
return age;
}
void setLover(string set_lover){ //定义一个用来设置爱人的成员函数
lover=set_lover;
}
private: //私有属性的定义
string name;
int age;
string lover;
};
int main()
{
human maicss; //实例化一个对象
//使用成员函数设置相关属性
maicss.setName("Maicss");
maicss.setAge(18);
maicss.setLover("qian");
//使用成员函数获取相关私有函数的值在
cout<<"name:"<<maicss.getName()<<" age:"<<maicss.getAge()<<endl;
return 0;
}
12.2 对象的初始化和清理
12.2.1 构造函数和析构函数
对象的
初始化
和清理
是两个重要的问题。- 一个对象或者变量没有初始化状态,其使用后果是未知的。
- 使用完一个对象或者变量,没有及时的清理,也会造成一定的安全问题。
注意:
- 构造函数和析构函数可以解决上述问题,由编译器自动调用,完成对象的初始化和清理工作。对象的初始化和清理是必须要做的事情。因此不必要提供构造和析构函数,编辑器会提供,但是编译器提供的构造函数和析构函数是
空实现
。 - 一个空对象所占用的内存为1字节,因为对象必须要有一个首地址。
- 构造函数和析构函数可以解决上述问题,由编译器自动调用,完成对象的初始化和清理工作。对象的初始化和清理是必须要做的事情。因此不必要提供构造和析构函数,编辑器会提供,但是编译器提供的构造函数和析构函数是
作用:
- 构造函数:主要用在创建对象时给对象的成员属性赋值,由编译器自动调用。
- 析构函数:主要用于对象销毁前的自动调用,负责清理工作。
语法:
构造函数:
类名(){}
- 构造函数,没有返回值,也不用写void。
- 函数名称和类名相同。
- 构造函数可以有参数,因此可以发生重载。
- 程序在调用对象的时候自动调用构造函数,并且只会调用一次,无需手动调用。
析构函数:
~类名(){}
- 析构函数,没有返回值,也不用写void。
- 函数名称和类名相同,在名称前加上
~
。 - 析构函数不可以有参数,因此无法发生重载。
- 程序在对象销毁前自动调用析构函数,并且只会调用一次,无需手动调用。
- 手动释放在堆区申请的空间要用
delete
语句。
示例:
class human{
public: //为了保证构造函数和析构函数能被全局调用,所以需要设置为public权限
human(){ //创建一个构造函数
cout<<"human的构造函数被调用\n";
}
~human(){ //创建一个析构函数
cout<<"human的析构函数被调用\n";
} };
void hum(){ //函数中实例化一个对象,函数运行结束后对象被销毁
human m;
}
int main()
{
human maicss;//创建对象同时运行构造函数
hum(); //调用hum函数来创建对象,同时运行构造函数
//hum函数运行结束时对象m被销毁,同时运行析构函数
return 0;//mian函数返回0,程序结束前会运行析构函数
}
12.2.2 构造函数的分类以及调用
两种分类方式:
- 按参数分为:有参构造和无参构造
- 按类型分为:普通构造和拷贝构造
- 拷贝构造函数是用来将一个对象的所有属性拷贝到新对象中。
三种调用方式:
- 括号法
- 显示法
- 隐式转换法
注意事项:
- 使用默认构造函数时,不要用
()
,否则会被认为是函数定义。 - 不要利用拷贝构造函数初始化匿名对象,编译器会认为是参数对象的声明。
- 使用默认构造函数时,不要用
示例(有点长):
class human{
public:
human(){
cout<<"human的无参(默认)构造函数被调用\n";
}
human(int a){
age=a;
cout<<"human的有参构造函数被调用\n";
}
human(const human &p){ //const的意义是不允许在构造函数中修改传入对象的属性,只读。
age=p.age;
cout<<"human的拷贝构造函数被调用\n";
}
~human(){
cout<<"human的析构函数被调用\n";
}
int age; };
void hum1(){ //括号法调用
human m1; //无参构造
human m2(10); //有参构造
human m3(m1); //拷贝构造
}
void hum2(){ //显示法
human m1; //无参构造
human m2=human(10); //有参构造
human m3=human(m1); //拷贝构造
}
void hum3(){ //隐式转换法
human m1; //无参构造
human m2=10; //有参构造
human m3=m2; //拷贝构造
}
int main()
{
hum1();
hum2();
hum3();
return 0;
}
12.2.3 拷贝构造函数的调用时机
C++中拷贝构造函数的调用时机通常由三种情况:
- 使用一个创建完毕的对象来初始化一个新的对象。
- 以值传递的方式给函数的参数传值
- 以值方式返回局部对象
12.2.4 构造函数的调用规则
默认情况下,C++编译器至少给一个类添加三个函数:
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对其属性值进行拷贝。
构造函数调用规则:
- 如果用户自定义有构造函数,编译器不再提供默认无参构造函数,但是会提供默认拷贝构造。
- 如果用户定义拷贝构造函数,编译器不再提供其他构造函数。
- 总结:写了有参必须写无参,写了拷贝就得有参无参都写上。
12.2.5 深拷贝与浅拷贝
定义:
- 浅拷贝:简单的赋值操作。如果是用编译器提供的拷贝函数会利用浅拷贝。
- 深拷贝:在堆区重新申请一块内存空间,进行拷贝操作。
注意:
- 浅拷贝可能导致堆区内存重复释放。
示例(浅拷贝):
class person{
public:
person(){
cout<<"无参构造函数被调用\n";
}
person(int age,int height){
m_height=new int (height); //在堆区申请一块内存区域用来存放height
m_age=age;
cout<<"有参构造函数被调用\n";
}
~person(){
if(m_height!=NULL){
delete m_height; //释放m_height指向的内存区域
//析构函数会被执行两次,因为两个对象在man()函数结束后被销毁,但是由于浅拷贝将指针拷贝给第二个对象,因此两个对象的m_height指针指向了堆区的同一块内存区域,这块内存区域释放两次,会报错。 m_height=NULL; //将指针指向NULL,防止野指针的出现。
}
cout<<"析构函数被调用\n";
}
private:
int m_age;
int * m_height; //创建一个int指针指向有参构造申请的内存区域
};
void man(){
person one(16,160);
person two(one);//浅拷贝
}
int main()
{
man();
cout << "Hello World!" << endl;
return 0;
}
示例(深拷贝):
class person{
public:
person(){
cout<<"无参构造函数被调用\n";
}
person(int age,int height){
m_height=new int (height); //在堆区申请一块内存区域用来存放height
m_age=age;
cout<<"有参构造函数被调用\n";
}
person(const person &p){
m_age=p.m_age;
m_height=new int (*p.m_height);//在堆区重新申请一块内存实现深拷贝
}
~person(){
if(m_height!=NULL){
delete m_height; //释放m_height指向的内存,此时不会出现多次释放同一内存空间的问题
m_height=NULL; //将指针指向NULL,防止野指针的出现。
}
cout<<"析构函数被调用\n";
} int m_age;
int * m_height; //创建一个int指针指向有参构造申请的内存区域
};
void man(){
person one(16,160);
person two(one);//由于定义了拷贝函数,所以此处会通过定义实现深拷贝
cout<<one.m_age<<" "<<*one.m_height<<endl;
cout<<two.m_age<<" "<<*two.m_height<<endl;
}
int main()
{
man();
cout << "Hello World!" << endl;
return 0;
}
12.2.6 初始化列表
作用:初始化列表语法可以用来初始化对象属性。
语法:
构造函数():属性1(值1),属性2(值2), ...
示例:
class person{
public:
person(int a,int b):age(a),height(b){}
int age;
int height;
};
void man(){
person one(18,180);
cout<<"age:"<<one.age<<" height:"<<one.height<<endl;
}
int main()
{
man();
return 0;
}
12.2.7 类对象作为类成员
定义:一个类声明的对象成为另一个类的属性成员。
例如:
class A{}
class B{
A a;
}
注意:
- 构造时先构造作为属性成员的对象(A)再构造对象本身(B)。
- 析构时先析构对象本身(B)再析构各个属性成员(A)。
12.2.8 静态成员
静态成员可以看作属于类的作用域,被所有对象公用。
静态成员变量和静态成员函数都有权限控制。
静态成员变量
作用:所有成员公用一个成员变量。
语法:
static 数据类型 变量名
注意:
- 静态成员变量要在类内声明,类外初始化。
- 在编译阶段会分配内存
示例:
class human{
public:
static int age;//在类内的声明
};
int human::age=100;//在类外的初始化
int main()
{
human a;
cout<<a.age<<endl;
human b;
b.age=18;//使用对象b给静态变量重新赋值
//也可以通过类名操作成员变量
human::age=18;
cout<<a.age<<endl;//此时对象a的age值也会随b变成18
return 0;
}
静态成员函数
作用:所有成员公用一个成员函数。属于类的作用域。
语法:
static 函数返回值类型 函数名();
注意:静态成员函数属于类的作用域,只能操作静态成员变量。
示例:
class human{
public:
static void func(){
age=1;
}
static int age;//在类内的声明
};
int human::age=100;//在类外的初始化
int main()
{
human a;
cout<<a.age<<endl;
human b;
//访问静态成员函数,下面两种方式效果完全相同
b.func();//通过对象访问
human::func();//通过类的作用域访问 cout<<a.age<<endl;
return 0;
}
12.3 C++对象模型和this指针
12.3.1 成员变量和成员函数分开储存
- 非静态成员变量属于类的对象
- 静态成员变量不属于类的对象。
- 非静态成员函数不属于类的对象。
- 静态成员函数不属于类的对象。
12.3.2 this指针概念
作用:this指针指向被调用的成员函数所属的对象。
特点:
- 隐含在每一个非静态成员函数内的一种特殊指针。
- this指针不需要定义,直接用即可。
使用场景:
- 当形参名和成员变量名相同时,可以用this指针区分。
- 在类的非静态成员函数中返回对象本身,可以用
return *this
。
示例:
class human{
public:
void c_age(int age){
this->age=age;//用this指针表示成员变量
}
human& addage(human &p){ //函数返回值要用引用的方式返回,否则会创建新对象
this->age+=p.age;
return *this;
}
int age;
};
void func(){
human maicss;
human p1;
p1.age=10;
maicss.c_age(18);
maicss.addage(p1).addage(p1).addage(p1); //链式编程思想
cout<<"maicss的年龄是:"<<maicss.age<<endl;
}
int main()
{
func();
return 0;
}
12.3.3 空指针调用成员函数
空指针可以调用成员,但是为了防止崩溃,要避免访问成员变量。
class human{
public:
void printname(){
cout<<"name is maicss\n";
}
void printage(){
if (this==NULL){//防止程序崩溃进行的保险措施
return ;
}
cout<<"age is "<<this->age<<endl;
}
int age;
};
void func(){
human * maicss=NULL;
maicss->printname();//使用空指针访问成员函数
maicss->printage();//使用空指针在成员函数中访问成员变量
}
int main()
{
func();
return 0;
}
12.3.4 const修饰成员函数
常函数:
- 成员函数后加
const
,我们称这个函数为常函数。 - 常函数内不可以修改成员属性。
- 成员属性加关键字
mutable
后,在常函数中依然可以修改。
常对象:
- 声明对象前加
const
称该对象为常对象。 - 常对象只能调用常函数。
示例:
class human{
public:
human(){}//新建一个无参构造函数,为了创建常对象
void func() const{
//age=18; //由于成员函数末尾加了const,所以函数体内不允许修改成员变量
height=180; //由于成员变量前加了mutable关键字,所以该变量可以在函数中修改
}
void func2(){}
int age;
mutable int height;
};
int main()
{
human maicss;
const human maicss2;
//maicss2.func2(); //由于是常对象,所以只能调用常函数。也只能修改带有mutable关键字的成员变量
maicss.func();
return 0;
}
12.4 友元
作用:让一个函数或类,访问另一个类中的私有成员。
关键字:
friend
三种实现方式:
- 全局函数作友元
- 类作友元
- 成员函数作友元
示例:
class room; //声明类
class goodgay2{
public:
goodgay2();
void visit();
room * m_room; //创建一个指针
};
class goodgay{
public:
goodgay(); //声明构造函数
void visit(); //声明成员函数用于访问room的私有成员
room * m_room; //创建一个指针
}; class room{
friend void text(); //将全局函数作为友元
friend class goodgay; //将另一个类作为友元
friend void goodgay2::visit();
public:
string sittingroom="客厅";
private:
string bedroom="卧室";
}; goodgay::goodgay(){ //类外定义构造函数
m_room=new room; //在构造函数中于堆区创建一个对象
}
goodgay2::goodgay2(){
m_room=new room;
}
void goodgay::visit(){ //类外定义成员函数
cout<<"b在访问:"<<m_room->bedroom<<endl;
cout<<"b在访问:"<<m_room->sittingroom<<endl;//访问room的私有成员
};
void goodgay2::visit(){
cout<<"c在访问:"<<m_room->bedroom<<endl;//访问room的私有成员
}
void text(){
room a;
cout<<"a访问了:"<<a.bedroom<<endl;
goodgay b;
b.visit(); //通过访问visit成员函数访问room的私有成员
goodgay2 c;
c.visit();
} int main()
{
text();
return 0;
}
12.5 运算符的重载
12.5.1 加号运算符的重载
方式:
- 使用成员函数重载
- 使用全局函数重载
示例:
//使用成员函数重载
class Person{
public:
int age;
int height;
public:
Person operator+(Person &p); //使用成员函数对加号的重载
};
Person Person::operator+(Person &p){//定义重载函数
Person temp;
temp.age=this->age+p.age;
temp.height=this->height+p.height;
return temp;
}
int main(){
Person p1;
Person p2;
p1.age=10;
p2.age=18;
p1.height=159;
p2.height=180;
Person p3=p1+p2;
cout<<"P3的年龄为:"<<p3.age<<" P3的身高为:"<<p3.height<<endl;
return 0;
}
//使用全局函数重载
class Person{
public:
int age;
int height;
};
Person operator+(Person &p1,Person &p2){ //使用成员函数对加号的重载
Person temp;
temp.age=p1.age+p2.age;
temp.height=p1.height+p2.height;
return temp;
}
int main(){
Person p1;
Person p2;
p1.age=10;
p2.age=18;
p1.height=159;
p2.height=180;
Person p3=p1+p2;
cout<<"P3的年龄为:"<<p3.age<<" P3的身高为:"<<p3.height<<endl;
return 0;
}
12.6 继承
继承使面向对象三大特性之一
定义某些了类时,下一级别的成员拥有上一级别的共性,还有自己的特性。
使用继承可以尽量减少代码
用法:
class A : public B;
说明:上述A为子类(派生类),B为父类(基类)。
示例:
class base{ //创建一个基类
public:
int age;
string name;
};
class human : public base{ //创建一个以base为基类的派生类
public:
int score;
};
class dog : public base{//另一个以base为基类的派生类
public:
human master;
};
void test1(){ //对派生类中属性的访问示例
human maicss;
dog dazhuang;
dazhuang.age=4;
maicss.age=20;
dazhuang.name="DAZ";
maicss.name="Maicss";
dazhuang.master=maicss;
maicss.score=100;
}
int main()
{
void test1();
return 0;
}
注意:
- 经过测试,若定义基类时关键字改为private,那么所继承的所有属性全为私有属性;若为public,则正常继承。
(这是依我自己理解的)
- 被定义为
protected
的成员变量为保护权限,此时子类可以访问这种成员变量,但是如果是private
则无法访问,这也是两者的唯一区别。
- 经过测试,若定义基类时关键字改为private,那么所继承的所有属性全为私有属性;若为public,则正常继承。
13. 文件操作
使用文件操作需要包含头文件<fstream>
文件类型分为两种:
- 以ASCII码形式储存的文本数据。
- 二进制文件形式储存的,用户一般读不懂。
操作文件三大类:
ofstream
写文件ifstream
读文件fstream
读写文件
13.1文本文件
13.1.1写文件的基本操作
写文件的基本步骤:
//1.包含头文件
#include <fstream>
//2.创建流对象
ofstream ofs;
//3.打开文件
ofs.open("文件路径",打开方式);
//4.写数据
ofs<<"文本文件";
//5.关闭文件
ofs.close();
打开方式 | 解释 |
---|---|
ios::in | 为读文件而打开文件 |
ios::out | 为写文件而打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 追加方式写文件 |
ios::trunc | 如果文件存在,先删除再创建 |
ios::binary | 二进制方式 |
文件打开方式配合使用需要|
符号
示例:
#include <iostream>
#include <fstream> //包含文件流头文件
using namespace std;
int main()
{
std::ofstream ofs; //创建一个ofstream类对象,实现写文件
ofs.open("text.txt",ios::out); //打开文件
ofs<<"你好世界"; //写到文件
return 0;
}
13.1.2读文件的基本操作
写文件的基本步骤:
//包含头文件
#include <fstream>
//创建流对象
std::ifstream ifs;
//打开文件
ifs.open("文件路径",打开方式);
if (!ifs.is_open()){
cout<<"文件打开失败"<<endl;
return ;
}
//读入文件
//第一种方式
char text1[1024]={0};
while (ifs>>text1) {
cout<<text1<<endl;
}
//第二种方式
char text2[1024]={0};
while (ifs.getline(text2,sizeof(text2))){
cout<<text2<<endl;
}
//第三种方式
string text3;
while (getline(ifs,text3)) {
cout<<text3<<endl;
}
//第四种方式
char text4;
while ((text4=ifs.get())!=EOF){
cout<<text4;
}
//关闭文件
close
14. C++中的STL
STL是为了提高软件代码的复用性而产生的一种标准模板库
14.1 STL的基本概念
- STL(Standard Template Library,标准模板库)
- STL从广义上分为:容器(container)、算法(algorithm)、迭代器(iterator)
- 容器和算法之间通过迭代器无缝连接。
- STL几乎所有代码都采用了模板类或模板函数。
14.2 vector容器的基本使用
容器:
vector
算法:
for_each
迭代器:
vector<int>::iterator
示例:
#include <iostream>
using namespace std;
#include <vector>//使用容器必须引入头文件
void print(int i) {//第三种遍历方法要用到
cout << i << endl;
}
int main() {
vector<int> v;
v.push_back(1);//使用尾插添加元素
v.push_back(2);
v.push_back(3);
v.push_back(4); //遍历容器的第一种方法
vector<int>::iterator head = v.begin();//begin()会返回指向容器中第一个元素的指针
vector<int>::iterator tail = v.end();//end()会返回指向容器中最后一个元素的下一个位置的指针
while (head != tail)
{
cout << *head << endl;
head++;
}
//遍历容器的第二种方法(是第一种方式的简化)
for (vector<int>::iterator h = v.begin(); h != v.end(); h++) {
cout << *h << endl;
}
//遍历容器的第三种方法(使用标准算法库中的for_each)
for_each(v.begin(),v.end(),print); getchar();
return 0;
}
14.3 string容器的基操
string
和char *
的区别- 本质上两者区别不大,前者是后者的封装,可以管理字符串。
- 构造函数
string();
无参构造,创建一个空的字符串。string(const char* s);
使用字符串s进行初始化。string(const string& str);
使用字符串str初始化。string(int n,char c);
使用n个字符c初始化。
# 其他内容
随机数生成
- rand()函数
- 用法:
rand()%10
可以生成0~9的随机数。 - 置随机数种子:
srand((unsigned int)time(NULL))
(需要#include <ctime>
)
- 用法:
内存
获取内存地址
- 数组的首地址可以直接使用数组的名字。
- 或者使用取址符“&”。
注意:
- 0~255之间的内存是无法访问的。
静态变量
- 在普通变量前加
static
为静态变量。 - 静态变量储存在内存的全局区中。
当初自学C++时的笔记记录的更多相关文章
- Activiti 学习笔记记录(2016-8-31)
上一篇:Activiti 学习笔记记录(二) 导读:上一篇学习了bpmn 画图的常用图形标记.那如何用它们组成一个可用文件呢? 我们知道 bpmn 其实是一个xml 文件
- Activiti 学习笔记记录(二)
上一篇:Activiti 学习笔记记录 导读:对于工作流引擎的使用,我们都知道,需要一个业务事件,比如请假,它会去走一个流程(提交申请->领导审批---(批,不批)---->结束),Act ...
- datagrid返回记录为0时显示“没有记录”
datagrid返回记录为0时显示“没有记录”,此问题的 <script>var myview = $.extend({},$.fn.datagrid.defaults.view,{ on ...
- u-boot从nand 启动时的问题解决记录
u-boot从nand 启动时的问题解决记录 问题描述: 使用u-boot-1.1.6版本u-boot移植到JZ2440开发板上,当前已经能够从Nor启动,但是不能从Nand正常启动(u-boot大小 ...
- delphi 中Adoquery ,在打开时能否让记录指针不移动? [问题点数:40分,结帖人microd]
delphi 中Adoquery ,在打开时能否让记录指针不移动?由于数据集Adoquery 时,它的针指称动会废时,能否在打开完成之前不让记录指针不移动.打开完毕之后再回复移动? 这样用:self. ...
- JVM 学习笔记记录
JVM 学习笔记记录 Sun JDK 监控和故障处理工具 名称 主要作用 jps JVM Process Status Tool, 显示指定系统内所有的HotSpot虚拟机进程 jstat JVM S ...
- vue 自学笔记记录
vue 自学笔记(一): 知识内容: 安装vue ,创建vue实例,安装第一个组件,单项数据流 https://www.cnblogs.com/baili-luoyun/p/10763163.htm ...
- C++ 编程技巧笔记记录(持续更新)
C++是博大精深的语言,特性复杂得跟北京二环一样,继承乱得跟乱伦似的. 不过它仍然是我最熟悉且必须用在游戏开发上的语言,这篇文章用于挑选出一些个人觉得重要的条款/经验/技巧进行记录总结. 文章最后列出 ...
- UWP学习开发笔记记录(开篇)
零零散散开发微软移动2年多了,基本上从未记录或写过任何笔记.所以打算写一些自己的心得和技术的分享,大家一起来共同探讨.虽然现在UWP的工作几乎没有了,但是我感觉大家都是在观望,再看接下来微软的动作,所 ...
随机推荐
- 前端 vs 后端
前端 vs 后端 前端与后端: 有什么区别? 前端和后端是计算机行业中最常用的两个术语. 在某种程度上,它们成了流行语. 它们决定了您作为软件开发人员所从事的工作类型,所使用的技术以及所获得的收入. ...
- Dart & basic
Dart & basic 2.4.0 Dart SDK https://github.com/dart-lang/sdk/releases https://github.com/dart-la ...
- css delete line text & html del
css delete line text & html del html <del>¥720</del> demo <span class="ticke ...
- react hooks & component will unmount & useEffect & clear up
react hooks & component will unmount & useEffect & clear up useEffect & return === u ...
- 新手不能忽视的MFC编程之CString
首发文章 | 公众号:lunvey 作为一个新手,刚接触C++没多久.赶鸭子上架完成项目,鉴于之前有几年编程基础,所以很快就接触到了界面开发,由于用的是VC++6.0,所以自然而然就将MFC作为图形界 ...
- 深入剖析 ConcurrentHashMap
自建博客地址:https://bytelife.net,欢迎访问! 本文为博客自动同步文章,为了更好的阅读体验,建议您移步至我的博客 本文作者: Jeffrey 本文链接: https://bytel ...
- 03.从0实现一个JVM语言系列之语法分析器-Parser-03月01日更新
从0实现JVM语言之语法分析器-Parser 相较于之前有较大更新, 老朋友们可以复盘或者针对bug留言, 我会看到之后答复您! 源码github仓库, 如果这个系列文章对你有帮助, 希望获得你的一个 ...
-
转: 微信已支持发送最大 200MB 的视频了,并且不会被压缩 来自腾讯微信团队的视频消息,目前 iOS 版本的微信已支持发送最大 200MB 的视频与图片了,并且不会被压缩.安卓版本未来一段时间会支 ...
- KeyboardDemo - Android身份证号、车牌号快捷输入键盘
Android身份证号.车牌号快捷输入键盘 项目地址 Github 键盘部分在 keyboard module 中 键盘与EditText绑定参照 MainActivity
- C++指针的算术运算 、关系运算
下面随笔是关于指针的算术运算 .关系运算. 指针类型的算术运算 指针与整数的加减运算 指针++,--运算 指针类型的算术运算 指针p加上或减去n 其意义是指针当前指向位置的前方或后方第n个数据的起始位 ...