语法初学易忘点
1、cout << << endl;
2、求数组长度 可用
length=sizeof(num)/sizeof(num[0]);
求数组首地址 可以直接输出 数组名
cout<< num<<endl;//二维数组同理
3、求二维数组内存占用,行数,列数
int num[4][5] = { };
cout << "二维数组占用总内存" << sizeof(num) << endl;
cout <<"行占用内存大小"<<sizeof(num[0]);
cout << "二维数组行数" << sizeof(num) / sizeof(num[0]) << endl;
cout << "二维数组列数" << sizeof(num[0]) / sizeof(num[0][0])<<endl;
```
4、地址强制转换成十进制可以用 (int)强制转换
5、 查看数组中的某个地址 用&num[1][3],然后打印即可
6、包含头文件<string>后 可以用string 关键字定义字符串或字符数组。
7、分文件步骤
(1)在新建的 .h头文件中写声明;
(2)在新建的 .app源文件中写定义;
(3)在头文件中包含新建源文件所需的头文件
(4)自己分的文件需用双引号
eg:
```c
#include“add.h”
(5)在新建源文件中要引用新建头文件
8、指针的创建
int * p;
p=&a;
//等价于
int * p = &a;
9、
int a =10;
int b =10;
const int * p =&a;//常量指针 值不可以改 指向可以改
//*p=20 错误
//p =&b 正确
int * const p =&a;//指针常量 值可以改 指向不能改
//*p=20 正确
// p=&b 错误
const int * const p = &a;// const修饰指针和常量 值 和指向都不能改
//*p=20 错误
// p=&b 错误
10、结构体数组
struct student{
string name;
int age;
int score;
};//结构体声明要写在主函数外 不然就是局部变量
结构体数组
student S1[];
s1[1].name="zhagnsan";//访问用.
结构体指针
student s;
student * p = & s;
p->name ="zhangsan";//访问用->
p->age = 18;
p->score = 100;
嵌套的结构体
struct student{
string name;
}
struct teacher{
string name;
student stu;
}
teacher.stu.name="zhangsan";
11、 string定义的字符串 可以互相“加减”对应字符
string name1="ABCDE";
string name2="A";
string name3;
name3=name2+name1[1];//name3=AA;
12、数组的删除操作 可以用覆盖
判断删除的数据位置然后依次覆盖
13、 在一个参数是指针的函数里调用一个参数是值传递的函数时,调用值传递的函数需要加上*
void deleInfo(person *p);
int locate(person p,string name);
void deleInfo(person * p)
{
string name;
int location;
if (p->n_size == 0)
cout << "记录为空" << endl;
cout << "请输入要删除的联系人名" << endl;
cin >> name;
location = locate( *p, name);//此处调用要加*
if (location == -1)
return;
else
{
for (int i = location; i < p->n_size; i++)
{
p->num[i] = p->num[i + 1];
}
}
cout << "删除成功" << endl;
p->n_size--;
system("pause");
system("cls");
};
14、 在头文件中的函数声明中 带结构体参数的函数声明需要加上struct!!!!!
void menu(struct person p);//如果写void menu(person p)则不行
15、用new 和 delete 创建数组
int *arr = new int[10];
delete[] arr;//释放时要加上[];
16、引用必须初始化 且不能更改;
如果函数的返回值是引用类型 则可以作为左值;
int & test();
test()=100;
//引用的实质是 创建一个指针常量 即
int a=10;
int & b= a;// 实际 编译器转化为 int * const b= &a 指针指向不能改 值可以改
17.函数重载 条件:
1、函数作用域相同(全局&局部);
2、函数名称相同;
3、函数的参数类型&顺序&个数不同;
4、函数的返回值不可以作为重载条件
void func();
int funcc();//编译会报错
18、函数的默认参数,占位参数
int func(int=10);//默认参数
int func(int);//占位参数
19、使用类的行为时 需要在后加括号;
20、类的权限
(1)public 类内类外都可以访问 ;
(2)proteced 类内可以 类外不可以访问;区别在于继承 子类可以访问父类的 保护内容
(3)private 类内可以 类外不可以访问;子类不可以访问父类的 私有内容
21、使用引用方式传参 可以节省内存空间;
22、类的文件拆分步骤:
(1)、将类全部复制到头文件中,标题#program once 只引用一次,防止重复引用,删除所有定义和功能实现,只保留函数、变量,权限声明,,注意分号保留;
#pragma once
#include<iostream>
#include"point.h"
using namespace std;
class cirlce
{
private:
int c_r;
point center;
public:
void setCP(point cen, int r);
int getc_x();
int getc_y();
int getr() ;
};
(2)、将类全部复制到文件中,包含头文件,删除类的名,结构 ,只保留函数和其定义,在函数名前要加上函数的作用域,语法为:
类名 :: 函数名(表示函数作用域在类下)
#include"circle.h"
#include"point.h"
void cirlce :: setCP(point cen, int r) {
center = cen;
c_r = r;
};
int cirlce::getc_x() {
return center.getx();
};
int cirlce::getc_y() {
return center.gety();
};
int cirlce::getr() {
return c_r;
};
(3)、类嵌套定义时 只需包含已定义的头文件类即可。
23、构造函数和析构函数
构造函数和析构函数都是必须有的,没有编译器会自动帮我们加上。
构造函数:
作用:类的 初始化,即使自己不写 编译器也会写。
语法:类名(){}
注:无返回值不用void;
函数名与类名相同;
构造函数可以有参数,即可以重载;
创建对象的时候构造函数会自己调用且只调用一次。
析构函数:类的清理工作(例如释放堆的申请的空间)。
语法:~类名(){}
注:无返回值不用void;
函数名与类名相同,在名称前加~;
构造函数无参数,不可以重载;
创建对象的时候构造函数会自己调用且只调用一次。
24、构造函数分类
(1)无参(默认)构造函数,有参构造函数
class person{
public:
person(){
}//无参(默认)构造函数
person(int a){
}//有参构造函数 有参/无参也叫普通构造函数
person(const person&p){
}//拷贝构造函数
}
(2)调用
void test01()
{
//1、括号法调用
person p1;//默认构造的调用 调用时不要加括号,否则编译器会认为是一个函数声明
person p2(10);//有参构造的调用
person p3(p2);//拷贝构造调用
//2、显示法调用
person p1;
person p2 = person(10);
//person(10)被称为匿名对象 执行完当前语句后 系统立即回收匿名对象
person p3 = person(p2);
//3、隐式转换
person p4=10;//相当于写了p4=person(10)
person p5=p4;//拷贝构造
}
25、拷贝构造函数使用时机
1、使用一个已经创建完毕的对象来初始化一个新对象
person p1(20);
person p2(p1);
2、值传递的方式给函数参数传值
void test1(person p)
{}
void test2()
{
person p;
test1(p);//此处调用p即调用的person的拷贝构造函数
}
3、值方式返回局部对象
person test3()
{
person p1;
return p1;//此处返回的是用拷贝构造函数创建的一个副本
}
void test4()
{
person p=test3();
}
26、要是自己写了有参构造,则编译器不会提供默认构造,但会提供拷贝构造;如过自己写了拷贝构造,则编译器不会提供 默认/有参构造。
27、深拷贝与浅拷贝(难点)
浅拷贝:简单的赋值操作
浅拷贝存在的问题:堆区内存重复释放。如果利用编译器提供的拷贝构造函数,会做浅拷贝操作。解决方式用深拷贝。
class per{
public:
per(){
}//默认构造
per(int age,int height){
m_Age=age;
m_Height = new int(height);
}//有参构造
//自己实现拷贝构造函数 解决浅拷贝带来的问题
per(const per &p){
m_age=p.m_age;
//m_height=p.m_height; 该句是编译器默认实现的浅拷贝操作
m_height=new int(*m.height);//深拷贝操作
}
~per(){
if(m_Height!=NULL)
{
delete m_Height;
m_height=NULL;
}
}//默认析构
int age;
int *m_Herght;
}
void test1(){
per p1(18,160);//有参构造
per p2(p1);//拷贝构造,且是浅拷贝,即将p1里m_Height的地址(改地址是申请的堆的地址,且在栈中,因为是局部类)直接拷贝到p2中,则析构p2时会出现再次析构p1里m_Height的地址,造成重复释放。
}
int main(){
test1();
}
深拷贝:在堆区重新申请空间,进行拷贝操作。
28、初始化列表:通过构造函数给类中的属性赋初值
语法:类名():属性1(初值),属性2(初值)…
{}
class person{
public:
person(int a,int b,int c):m_a(a),m_b(b),m_c(c)
{
}
}
27 成员初始化列表 在写构造函数的时候初始化
class person{
public:
person(int a,int b, int c):ma(a),mb(b),mc(c)
{
}
int ma,mb,mc;
}