1、指针大小
sizeof(int *)为4,sizeof(float *)为4, sizeof(char *)也为4,存放地址4个字节就够了,int、float、char指的是地址上的数据的类型。
2、空指针,如int * buf = NULL
空指针指向内存编号为0x00000000的地方,此处是不可以读写的,一般用于指针初始化。其实0x00000000~0x000000FF之间的内存都是系统占用的,都不可以读写。
3、野指针,如int * buf=(int *)0x00001100
0x00001100这个地址我们不认识,如此赋值可能导致程序运行异常。空指针和野指针都不是我们申请的空间,因此不要访问。
4、常量指针,如int a=10; int b=10; const int * p = &a; p=&b;
指针的指向可以修改,但指针指向的值不可以修改。
5、指针常量,如int a=10; int * const p = &a; *p=20;
指针的指向不可以修改,但指针指向的值可以修改。
6、修饰常量,如int a=10; const int * const p = &a;
指针的指向不可以修改,指针指向的值也不可以修改。
7、结构体
结构体,自建数据类型,如学生数据类型
struct student{
string name;
int age;
int score;
}s3;
// 方式1,类似于int a;a=3;
student s1;
s1.name = "张三";
s1.age = 28;
s1.score = 98;
// 方式2,类似于int a=3;
student s2={"李四",29,99};
// 方式3
s3.name = "王五";
s3.age = 30;
s3.score = 100;
// 结构体指针,类似于int a;a=3;int *p=&a;
student *p1 = &s1;
cout<<p1->name<<p1->age<<p1->score<<endl;
8、结构体嵌套结构体
# include <iostream>
# include <string>
using namespace std;
struct student
{
string name;
int age;
int score;
};
struct teacher
{
string name;
int age;
student stu;
};
int main(){
teacher t;
t.name = "老王";
t.age = 50;
t.stu.name = "小王";
t.stu.age = 20;
t.stu.score = 100;
cout << t.name << " " << t.age << " " << t.stu.name << " " << t.stu.age << " " << t.stu.score << endl;
// 命令行窗口不要关闭
system("pause");
return 0;
}
9、形参与实参
定义函数时,括号里的参数是形参,调用函数时,括号里的参数是实参。不管传递值还是传递地址,形参都是实参的复制,当实参很大很大时,如一个学校全体学生的数据,复制一个同样大小的形参,电脑内存可能溢出,如果传递地址,则只需要4个字节的空间,显然更好。但也要注意,传递地址时地址上的数据可能在子函数中被无意篡改,为了预防这个隐患,形参可以使用常量指针。
10、随机数
srand((unsigned int)time(NULL));//随机数种子
int random = rand()%21+80; //80~100
11、全局区
写在函数体外面的变量是全局变量。
在全局变量前面加上const就是全局常量。
在局部变量前面加上static就是静态变量。
全局变量、全局常量、静态变量存放在全局区。
全局区的数据在程序执行结束后自动释放。
12、栈区
写在函数体里面的变量是局部变量。
在局部变量前面加上const就是局部常量。
局部变量、局部常量存放在栈区。
栈区的数据在函数执行结束后自动释放,所以函数不要返回局部变量或局部常量的地址,因为这样得不到我们想要的数据。
13、堆区
new创建的数据存放在堆区,并返回一个地址,如int *p = new int(10);int* arr = new int[10];
。
堆区的数据由程序员释放,如delete p;delete[] arr;
,如果程序员没有释放,在程序执行结束后自动释放。
14、引用
引用的作用是给变量起别名。
引用必须初始化,初始化之后不可以更改。
不能返回局部变量引用。
如果函数的返回值是引用,那么这个函数调用可以作为左值。
引用本质上是一个指针常量。
常量引用本质上是一个修饰常量。
int a =10;
int &b = a;
b = 20;
cout<<a<<endl;//结果为20
# include <iostream>
# include <string>
using namespace std;
int& test()
{
//不能返回局部变量引用,所以需要定义为静态变量
static int a = 10;
return a;
}
int main(){
int &b = test();
cout << b << endl;//结果为10
cout << b << endl;//结果为10
test() = 1000;
cout << b << endl;//结果为1000
cout << b << endl;//结果为1000
// 命令行窗口不要关闭
system("pause");
return 0;
}
# include <iostream>
# include <string>
using namespace std;
void show(const int & val)
{
// val = 1000;//不允许修改常量引用的值
cout << val << endl;//结果是10
}
int main(){
int a = 10;
show(a);
// 命令行窗口不要关闭
system("pause");
return 0;
}
15、万事万物皆为对象,对象有其属性和行为。具有相同性质的对象可以抽象称为类。
16、构造函数:主要作用在于创建对象时为对象的成员属性赋值,由编译器自动调用,无需手动调用。
析构函数:主要作用在于对象销毁前执行一些清理工作,由编译器自动调用,无需手动调用。
# include <iostream>
# include <string>
using namespace std;
class Person
{
public:
Person()
{
cout << "Person的无参构造函数" << endl;
}
Person(int age, int height)
{
m_age = age;
m_height = new int(height);
cout << "Person的有参构造函数" << endl;
}
Person(const Person &p)
{
m_age = p.m_age;
m_height = new int(*p.m_height);
cout << "Person的拷贝构造函数" << endl;
}
~Person()
{
delete m_height;
cout << "Person的析构函数" << endl;
}
int m_age;
int * m_height;
};
void test()
{
Person p1;
Person p2(10, 160);
Person p3(p2);
cout << "p3.m_age = " << p3.m_age << " *p3.m_height = " << *p3.m_height << endl;
}
int main(){
test();
// 命令行窗口不要关闭
system("pause");
return 0;
}
17、默认情况下,C++编译器至少给一个类提供3个函数:
(1)默认无参构造函数,函数体为空;
(2)默认拷贝构造函数,对属性进行值拷贝;
(3)默认析构函数,函数体为空;
如果用户定义有参构造函数,C++不再提供无参构造函数;
如果用户定义拷贝构造函数,C++不再提供无参构造函数,也不再提供有参构造函数;
18、静态变量与静态函数
# include <iostream>
# include <string>
using namespace std;
class Person
{
public:
static void fun()
{
m_A = 200;
// m_B = 200; 静态函数只能调用静态变量
}
static int m_A;
int m_B;
};
// 静态变量在类外初始化
int Person::m_A = 100;
void test()
{
Person p1;
cout << "p1.m_A=" << p1.m_A << endl; //100
cout << "Person::m_A=" << Person::m_A << endl; //100
p1.fun(); // 对象调用静态函数
Person::fun(); // 类调用静态函数
cout << "p1.m_A=" << p1.m_A << endl; //200
cout << "Person::m_A=" << Person::m_A << endl; //200
Person p2;
p2.m_A = 300; // 所有对象共用静态变量
cout << "p1.m_A=" << p1.m_A << endl; //300
cout << "Person::m_A=" << Person::m_A << endl; //300
}
int main(){
test();
// 命令行窗口不要关闭
system("pause");
return 0;
}
19、只有非静态成员变量属于类的对象上
# include <iostream>
# include <string>
using namespace std;
class Person
{
public:
int m_A; //非静态成员变量 属于 类的对象上
static int m_B; //静态成员变量 不属于 类的对象上
int get_A(){ return m_A; } //非静态成员函数 不属于 类的对象上
static int get_B(){ return m_B; } //静态成员函数 不属于 类的对象上
};
int Person::m_B = 0;
void test()
{
Person p;
cout << "sizeof(p)=" << sizeof(p) << endl; //sizeof(p)=4
}
int main(){
test();
// 命令行窗口不要关闭
system("pause");
return 0;
}
20、this指针指向被调用的成员函数所属的对象
# include <iostream>
# include <string>
using namespace std;
class Person
{
public:
Person(int age)
{
this->age = age; //this指针指向被调用的成员函数所属的对象
//m_age = age;
}
Person& PersonAddAge(Person p) // 返回的是对象的引用,不会重新创建一个对象
{
this->age += p.age;
return *this; // *this为被调用的成员函数所属的对象
}
int age;
//int m_age;
};
void test()
{
Person p1(10);
Person p2(10);
cout << "p1.age=" << p1.age << endl; // p1.age=10
cout << "p2.age=" << p2.age << endl; // p2.age=10
p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
cout << "链式调用后p2.age=" << p2.age << endl; // p2.age=40
}
int main(){
test();
// 命令行窗口不要关闭
system("pause");
return 0;
}
21、常对象与常函数
# include <iostream>
# include <string>
using namespace std;
class Person
{
public:
void fun()
{
m_A = 100;
}
// this指针的本质是指针常量,类似于Person * const this
// 在成员函数后面加上const,this指针的本质就是修饰指针,类似于const Person * const this
void showPerson() const //常函数
{
// this = NULL; // this指针的指向不可以修改
// this->m_A = 100; // this指针指向的值不可以修改
this->m_B = 100;
}
int m_A;
mutable int m_B; // 特殊变量,在常函数中可以修改
};
void test()
{
const Person p; // 常对象
// p.fun(); // 常对象只能调用常函数
p.showPerson();
}
int main(){
test();
// 命令行窗口不要关闭
system("pause");
return 0;
}