Ruby3 流程控制
if/else/elsif
|
|
unless
unless相当于if的反向断言
|
|
ruby 没有++和–操作符
|
|
unless相当于if的反向断言
|
|
ruby 没有++和–操作符
3,222
3.14
hello,world
true(TrueClass),false(FalseClass)
[1,2],["hello","hello world"]
{"name"=>"luo","age"=>24},{:name=>"daoyi",:age=>24}
:a,:hello,:"hello world"
1..10,1...10
(三个点不包括10本身)/hello/i
|
|
|
|
|
|
当a 使用replace时候仍然是原本的引用地址,所以Object_id不变
但是当a重新赋值为hello 的时候,a的引用地址发生了变化 object_id就改变了
|
|
|
|
凡有方法都有返回值,方法体最后一行代码的返回值默认会做为方法的返回值,也可以显式的使用return关键字
|
|
总结:
#include "stdafx.h"
class Person
{
public:
int Age;
int Sex;
void Word()
{
printf("Person:Work");
}
};
class Teacher:public Person
{
public:
int Level;
};
int main()
{
Teacher t;
t.Age = -1; //合法但是不合理
t.Sex = 2;
t.Level = 3;
return 0;
}
为什么要隐藏数据成员
#阿里云kali源
deb http://mirrors.aliyun.com/kali kali-rolling main non-free contrib
deb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib
deb http://mirrors.aliyun.com/kali-security kali-rolling/updates main contrib non-free
deb-src http://mirrors.aliyun.com/kali-security kali-rolling/updates main contrib non-free
#中科大kali源
deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib
deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib
deb http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free
deb-src http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free
全局变量区
Person p;
栈
void Max() { Person p; }
堆 new
和 delete
//在堆中创建对象: Person* p = new Person(); //释放对象占用的内存 delete p;
在头文件中只留下声明代码
Test.h
struct sclass
{
int x;
int y;
int Bigger(int x,int y);
int Max(int x,int y,int z);
};
Test.cpp
struct Person
{
int age;
int sex;
};
struct Teacher
{
int age;
int sex;
int level;
int classId;
};
struct Teacher:Person
{
int level;
int classId;
};
总结:
1、什么是继承?
继承就是数据的复制
2、为什么要用继承?
减少重复代码的编写
3、Person 称为父类或者基类
#include "stdafx.h"
#include
struct Sclass {
int a;
int b;
int c;
int d;
Sclass()//构造函数
{
printf("观察这个函数 \n");
}
Sclass(int a,int b,int c,int d)//构造函数
{
this->a=a;
this->b=b;
this->c=c;
this->d=d;
printf("观察这个函数 2\n");
}
int Plus()
{
return a+b+c+d;
}
};
int main(int argc, char* argv[])
{
Sclass s;
Sclass s2(1,2,3,4);
return 0;
}
//反汇编:
Sclass s;
0040D408 lea ecx,[ebp-10h]
0040D40B call @ILT+5(Sclass::Sclass) (0040100a)
Sclass s2(1,2,3,4);
0040D770 push 4
0040D772 push 3
0040D774 push 2
0040D776 push 1
0040D778 lea ecx,[ebp-20h]
0040D77B call @ILT+10(Sclass::Sclass) (0040100f)
//观察发现,分配一个对象,构造函数 方法直接就会被调用
总结特点:
预处理一般是指在程序源代码被转换为二进制代码之前,由预处理器对程序源代码文本进行处理,处理后的结果再由编译器进一步编译。
struct Student
{
char name[10];
int score;
}
struct Node
{
Student Element;
Node* next;
}
每一个节点包含此节点信息和下一个节点的指针
C++是对C的补充扩展,C原有的语法C++都支持,并在此基础上扩展了一些新的语法:
继承、封装、多态、模板等等
就是告诉编译器:怎么传递参数,怎么传递返回值,怎么平衡堆栈
int method(int x,int y)
{
return x+y;
}
//调用
method(1,2);
调用约定 | 参数压栈顺序 | 平衡堆栈 |
---|---|---|
__cdecl | 从右至左入栈 | 调用者清理栈 |
__stdcall | 从右至左入栈 | 自身清理堆栈 |
__fastcall | ECX/EDX 传送前两个,剩下:从右至左入栈 | 自身清理堆栈 |
int __stdcall method(int x,int y)
{
return x+y;
}
//调用
method(1,2);
//观察反汇编堆栈变化
PS:一般情况下自带库默认使用 __stdcall
我们写的代码默认使用 __cdecl
char arr[10]; //10 char
char* arr[10]; //10 指针(char*)
Point* arr[10]; //10 指针(Point*)
int******** arr[10];
char* a = "Hello";
char* b = "World";
//方式1:
char* arr[2]= {a,b};
//方式2:
char* arr[2];
arr[0]=a;
arr[1]=b;
struct Point
{
int x;
int y;
}
Point p; //8字节 一个结构体
Point arr[10]; //8字节 * 10 结构体数组
Point* arrPoint[10]; //4字节 * 10 结构体指针数组
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int* p =&arr[0]; //数组首个元素地址
int* p = arr; //数组首个元素地址 跟上面的表达方式是一样的 也可以说是简写形式
int* p =&arr; //什么情况? --编译失败 (int(*)[10] 类型 不可以转换为 int* 类型)
//我们使用显式声明类型来躲避编译器检查
int* x = (int*)&arr;
//我们编译后发现 此时的x 值和上面的p值是一样的
//那么区别是什么呢
//当我们使用&arr 获得的类型就是 int(*)[10] 类型 也就是数组指针类型
//定义数组指针的写法
int(*px)[5];//一维数组指针 px 这里就是当前指针的名字
char(*px)[3]; //px 就是指针的名字
int(*px)[2][2]; //二维数组指针 px 就是指针的名字
char(*px)[3][3][3]; //三维数组指针 px 就是指针的名字
//思考:
//int *p[5] 与 int(*p)[5] 有什么区别?
int(*px1)p[5]; //一维数组指针
char(*px2)[3];
int(*px3)[2][2]; //二维数组指针
char(*px4)[3][3][3]; //三维数组指针
printf("%d %d %d %d\n",sizeof(px1),sizeof(px2),sizeof(px3),sizeof(px4));
// 4 4 4 4
px1 = (int (*)[5])1;
px2 = (char (*)[3])2;
px3 = (int (*)[2][2])3;
px4 = (char (*)[3][3][3])4;
int(*px1)p[5]; //一维数组指针
char(*px2)[3];
int(*px3)[2][2]; //二维数组指针
char(*px4)[3][3][3]; //三维数组指针
px1 = (int (*)[5])1;
px2 = (char (*)[3])1;
px3 = (int (*)[2][2])1;
px4 = (char (*)[3][3][3])1;
px1++; //int(4) *5 +20 =21
px2++; //char(1) *3 +3 =4
px3++; //int(4) *2 *2 +16 =17
px4++; //char(1) *3 *3 *3 +9 =10
printf("%d %d %d %d \n",px1,px2,px3,px4);
//第一种:
int arr[] = {1,2,3,4,5,6,7,8,9,0}
int(*px)[10]=&arr
//*px 是啥类型? => int[10] 数组类型
//px[0] 等价于 *px 所以 *px 也等于 int[10]数组
printf("%d %d \n",(*px)[0],px[0][0]);
px++; //后 (*px)[0]就访问整个数组地址后的地址内的数据
//第二种:
int arr[3][3] = {
{1,2,3},
{4,5,6},
{7,8,9}
};
//此时的 px指针 指向的 {1,2,3}这个数组的首地址
int(*px)[3] = &arr[0];
// *px -> 此时就是数组{1,2,3}本身
//越过第一个数组 此时px指针指向 {4,5,6}的首地址
px++;
printf("%d %d \n",(*px)[0],px[0][0]);
//这里打印的就是 4 4
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int(*px)[2][2] = (int(*)[2][2])arr;
//思考:
// *px 是什么类型
//int[2][2] 二维数组
//(*px)[1][1]的值是什么? px[0][1][1]的值是什么
//4
struct Point
{
int x;
int y;
}
//创建结构体
Point p;
p.x=10;
p.y=20;
//声明结构体指针
Point* ps;
//为结构体指针赋值
ps = &p;
//通过指针读取数据
printf("%d \n",ps->x);
//通过指针修改数据
ps->y=100;
printf("%d\n",ps=>y);
struct Point
{
int x;
int y;
}
int arr[10]={1,2,3,4,5,6,7,8,9,10}
Point* p = (Point*)arr;
for(int i = 0;i < 5;i++,p++)
{
printf("%d %d\n",p->x,p->y);
}
int i =100;
int* p1 = &i;
int** p2 = &p1;
int*** p3 = &p2;
int**** p4 = &p3;
int***** p5 = &p4
int****** p6 = &p5;
int******* p7 = &p6;
int****** px1 = *(p7);
int***** px2 = *(px1);
int**** px3 = *(px2);
int*** px4 = *(px3);
int** px5 = *(px4);
int* px6 = *(px5);
int px7 = *(px6);
int px7 = *(*(*(*(*(*(*(p7)))))));
int* p = (int*)1;
printf("%d %d \n",p[0],*p); //p[0] = *(p+0) = *p
int** p = (int**)1;
printf("%d %d \n",p[0][0],**p);
printf("%d %d \n",p[1][2],*(*(p+1)+2));
int*** p = (int***)1;
printf("%d %d \n",p[1][2][3],*(*(*(p+1)+2)+3));
同理:
*(*(*(*(*(*(*(p7))))))))
= *(*(*(*(*(*(p7+0)+0)+0)+0)+0)+0)
= p7[0][0][0][0][0][0][0]
*(p+i) = p[i]
*(*(p+i)+k) = p[i][k]
*(*(*(p+i)+k)+m) = p[i][k][m]
*(*(*(*(*(p+i)+k)+m)+w)+t) = p[i][k][m][w][t]
*() 与 []可以相互转换
char str[6] = {"A","B","C","D","E","F"}; //"\0" 或者0 --堆栈中 局部变量
char str[] = "ABCDE"; //编译器末尾填0 常量区
char* str= "ABCDE"; //常量区
//打印
printf("%s \n",str);
//字符串打印时 遇到 0 才会停止
1、int strlen(char* s)
返回值是字符串S的长度,不包括结束符"/0"
弊端:字符串中英文混合的话。返回的长度有问题,因为中文占用两个字节
2、char* strcpy(char* dest, char* src)
复制字符串src到dest中。返回指针为dest的值
3、char* strcat(char* dest, char* src)
将字符串src添加到dest尾部。返回指针为dest的值
4、int strcmp(char* s1, char* s2)
字符串对比,一样返回0 不一样返回非0
本质就是函数,只不过函数的返回类型是某一类型的指针
如:
int x =1;
void plus(int p)
{
p = p+1;
}
printf("%d \n",x);
//x的值是多少?
编写一个函数,能够打印任意整形数组的值
乘法运算符
int x = 1; int y = 2; int z = x * y;
定义新的类型
char x; char* x;
取值运算符
int*** a;
int***** b;
int******* c;
int* d;
//int x = *(a+1);
//int x = *(b++);
//int x = *(c-5);
//int x = *(d+6);
//总结
// *加指针类型 的类型是 指针类型减去一个*
int x=1; int x =1;
int* p = &x; int* p = &x;
printf("%x %x \n",p,*(p)); int** p2 = &p;
*(p)=2; int*** p3 = &p2;
printf("%d \n",x); int r = *(*(*(p3)));
printf("%d \n",r);