目录
一、类与结构体
1.类的使用:
2.构造函数:
二、指针
1.程序在操作系统里运行的时候的一些基本概念
2. 指针和引用
三、链表
1.链表的表示
2.链表的建立
3.添加元素
4.删除元素
一、类与结构体
1.类的使用:
类中的变量和函数被统一称为类的成员变量。
private后面的内容是私有成员变量,在类的外部不能访问;public后面的内容是公有成员变量,在类的外部可以访问。
#includeusing namespace std; const int N = 1000010; class Person { private: int age, height; double money; string books[100]; public: string name; void say() { cout << "I'm " << name << endl; } int set_age(int a) { age = a; } int get_age() { return age; } void add_money(double x) { money += x; } } person_a, person_b, persons[100]; int main() { Person c; c.name = "yxc"; // 正确!访问公有变量 c.age = 18; // 错误!访问私有变量 c.set_age(18); // 正确!set_age()是共有成员变量 c.add_money(100); c.say(); cout << c.get_age() << endl; return 0; }
结构体和类的作用是一样的。不同点在于类默认是private,结构体默认是public。
但是在习惯上,我们一般把只有数据的,而且函数少的,一些短的与数据相关的把它打包成结构体,把一些复杂的,含义混乱的,代码比较长的把它打包成类。
2.构造函数:
1.这样写只有一种写法:
struct person { int age, height; double money; person(int _age, int _height, double _money)//构造函数 函数名与结构体名一样 { age = _age; height = _height; money = _money; } }; int main() { person p(18, 180, 100.0);//这样写必须要有参数。 //person p()这样写会报错 return 0; }
2.由1.可得应该要加上person(){};
struct person { int age, height; double money; person() {} person(int _age, int _height, double _money)//构造函数 函数名与结构体名一样 { age = _age; height = _height; money = _money; } }; int main() { //person p(18, 180, 100.0);//这样写必须要有参数。 person p();//这样写就不会报错 return 0; }
3.易错情况:构造函数的参数个数要与主函数里输入的参数个数相匹配。否则就只有一个0参数的构造函数。
这样会报错:
struct person { int age, height; double money; person() {}//这里0个参数 person(int _age, int _height, double _money)//这里是3个参数 { age = _age; height = _height; money = _money; } }; int main() { person p(18, 180);//2个参数。易错情况:以为会自动放到3个参数的函数里,money的值自动赋0 cout << p.money;//这里就会报错,因为在结构体里只有0或3个参数的 return 0; }
这样不会报错,money会输出结果(但我在VS2022里的结果很小,不为0,y总上课输出的结果为0):
struct person { int age, height; double money; person() {}//这里0个参数 person(int _age, int _height){} person(int _age, int _height, double _money)//这里是3个参数 { age = _age; height = _height; money = _money; } }; int main() { person p(18, 180);//2个参数。易错情况:以为会自动放到3个参数的函数里,money的值自动赋0 cout << p.money;//这里就会报错,因为在结构体里只有0或3个参数的 return 0; }
4. 构造函数里赋值的简便写法,这样运行速度也更快些
在写构造函数之前一般先要加个public:
struct person { int age, height; double money; person() {}//这里0个参数 person(int _age, int _height){} person(int _age, int _height, double _money):age(_age),height(_height),money(_money){} };
二、指针
1.程序在操作系统里运行的时候的一些基本概念
每一个程序都有一个进程,每一个代码写好后点击运行都会弹出一个黑框,这个黑框就是一个进程。每个进程之间都是完全独立的。开数组需要空间,而空间指的是内存,平常所说的内存有4GB,8GB,16GB等。比如一个8GB的电脑,每个进程的空间大小就是8GB,就好像一个从0到8GB的数组,是用16进制编码,用0或1来表示。现在电脑一般是64位,但实际运行的时候并没有达到64,但一定大于32。
寻找一个变量地址(用两种方法写):
局部变量
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; int main() { char c = 'a'; //两种表示方式: cout << (void*)&c << endl; printf("%p\n", &c); char d; cout << (void*)&d << endl; return 0; }
输出结果:
0x7fff7c0df9ce
0x7fff7c0df9ce
0x7fff7c0df9cf
表明:局部变量在栈里面是从上往下存的。
全局变量:
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; char a, b;//全局 int main() { char c = 'a'; //两种表示方式: cout << (void*)&c << endl; printf("%p\n", &c); char d; cout << (void*)&d << endl; cout << (void*)&a << endl; cout << (void*)&b << endl; return 0; }
结果:
0x7fff7c0df9ce
0x7fff7c0df9ce
0x7fff7c0df9cf
0x60191
0x60192
表明:全局变量在堆里面是从下往上存的。
2. 指针和引用
指针指向存放变量的值的地址。因此我们可以通过指针来修改变量的值。
int main() { int a = 10; int* p = &a;//这里的*是指一个int类型的指针变量 cout << *p << endl;//这里的*是找到a的地址然后得到a的数值 *p = 5; cout << a << endl;//也能够通过地址来修改数值 return 0; }
输出结果:10 5
以下这种在算法里不怎么用,所以没用详细讲。其中指针的用法难就难在多颗*的使用。
int main() { int a = 10; int* p = &a;//这里的*是指一个int类型的指针变量 int** q = &p;//通过q找到p的地址,p是一颗*,q就得再加一颗* cout << (void*)q << endl; return 0; }
数组名是一种特殊的指针。指针可以做运算,a+1不是指数值加1,而是指加1个变量长度,下面例子是int类型。所以a+1是加了4个字节,a+2是加了8个字节。
int main() { int a[5] = {1, 2, 3, 4, 5}; for (int i = 0; i < 5; i ++ ) cout << *(a + i) << endl; return 0; }
int main() { int a[5] = { 1, 2, 3, 4, 5 }; int* p = &a[0]; int* q = &a[1]; cout << q - p; return 0; }
输出结果:1
数组名其实就是数组里第一个变量的地址,本质就是一个指针。并且整个数组在内存里是顺序连续存储的。
int main() { int a[5] = { 1, 2, 3, 4, 5 }; cout << a << endl; for (int i = 0; i < 5; i++) { cout << (void*)&a[i] << endl; } return 0; }
运行结果: int占4个字节,所以相邻两个地址相差4。
0000008CB20FFC78
0000008CB20FFC78
0000008CB20FFC7C
0000008CB20FFC80
0000008CB20FFC84
0000008CB20FFC88
引用:
int main() { int a = 10; int* p = &a;//c的指针 int& q = a;//引用,是c++写法里对c的指针的简化。q相当于a的别名 return 0; }
三、链表
1.链表的表示
struct Node { int val; Node* next;//可以在结构体里面定义一个自己的指针,这是一个递归,但不可以定义一个变量。 //Node next;就不可以,这样会报错。 //第一种定义方式: Node(int _val) :val(_val),next(NULL){} } *head; int main() { //第一种定义方式: Node node = Node(1);//这样表明定义了一个Node变量 Node* p = new Node(1);//一般喜欢这样写,用指针写,生成一个结构体。 //不加new时,指生成了一个Node变量,加new指不仅生成了一个Node变量,且返回值是其的地址,用时加new //还可以写auto p = new Node(1);因为知道返回值类型是Node* p->next = p;//就使p指向了自己 //p是指针,所以调用时用-> 当为变量时,调用用. eg:Node q=Node(1);q.next=q; return 0; }
2.链表的建立
代码如下:
struct Node { int val; Node* next;//可以在结构体里面定义一个自己的指针,这是一个递归,但不可以定义一个变量。 //Node next;就不可以,这样会报错。 //第一种定义方式: Node(int _val) :val(_val),next(NULL){} } *head; int main() { //第一种定义方式: Node* p = new Node(1); Node* q = new Node(2); Node* o = new Node(3); p->next = q; q->next = o; o->next = NULL;//指向空 for (Node* r = p; r; r = r->next) { cout << r->val << ' '; } return 0; }
输出结果:1 2 3
3.添加元素
在算法中用的最多的是在链表前面加一个元素。
struct Node { int val; Node* next;//可以在结构体里面定义一个自己的指针,这是一个递归,但不可以定义一个变量。 //Node next;就不可以,这样会报错。 //第一种定义方式: Node(int _val) :val(_val),next(NULL){} } *head; int main() { //第一种定义方式: Node* p = new Node(1); Node* q = new Node(2); Node* o = new Node(3); p->next = q; q->next = o; o->next = NULL;//指向空 //头插法增加元素: Node* head = p; Node* u = new Node(4); u->next = head; head = u;//此时head应该指向u //打印链表: for (Node* r = head; r; r = r->next) { cout << r->val << ' '; } return 0; }
输出结果:4 1 2 3
4.删除元素
只需找到要删除元素的前一个元素的位置,让前面的这一个元素的next直接指向删除元素的下一个元素,跳过需要删除的元素,这样需要删除的元素就不会打印出来了。
以删除2为例:已经知道2的前一个元素是head
int main() { //第一种定义方式: Node* p = new Node(1); Node* q = new Node(2); Node* o = new Node(3); p->next = q; q->next = o; o->next = NULL;//指向空 Node* head = p; head->next = head->next->next;//删除2 //打印链表: for (Node* r = head; r; r = r->next) { cout << r->val << ' '; } return 0; }
参考y总的语法基础课,这是我的笔记。习题没加在里面。