环境:VC6
数据类型
函数定义
返回类型 函数名(参数列表)
{
return;
}
int 4个字节
short 2个字节
char 1个字节
参数传递 堆栈传参 从右向左
函数调用 call
返回值 存储在eax
变量(内存编号)
1.声明变量
变量类型 变量名
2.全局变量
编译时就确定内存地址和宽度,变量名就是内存地址的别名
如果不重写编译,全局变量的内存地址不变。游戏外挂中的找“基址”,其实就是找全局变量
全局变量中的值任何程序都可以改,是公用的
3.局部变量
局部变量是函数内部申请的,如果函数没有执行,局部变量就没有内存空间
局部变量的内存是在堆栈中分配的,程序执行时才分配,我们无法预知程序何时执行,这也就意味着,我们无法确定局部变量的内存地址。
因为局部变量地址内存是不确定的,局部变量只能在函数内部使用,其他函数不可使用
函数嵌套使用(在下面一个函数中调用上面一个函数)
变量类型(数据宽度+数据格式)
整型
char 8 1字节
short 16 2字节
int 32 4字节
long 32 4字节
P.S. 有符号数和无符号数在内存中没有区别,只是看你怎么用它
赋值时无差别,拓展(有符号数补符号位,无符号数补0)和比较(转成十进制)时有差别
字符与字符串 ascll码转化
误区:很多人认为char是字符型 其实不是 它就是整型 是因为ascll码最高到127 十六进制就是7F 只需要一个字节就可以表示 而char刚好可以表示一个字节。
printf(“%d %u %x \n”,x,x,x)
%d 有符号数 %u无符号数 %x十六进制
中文字符 查表(GB2312或GB2312-80)
两个字节(ascll值大于127)代表一个汉字(全角) |||||||||| 一个字节代表一个字符(半角)
运算符与表达式
如果运算中有多个数据类型参与运算 参考下表
自加自减(X++和++X的区别) 逻辑运算&&(只要有一个不符合立刻终止判断)的效率高于&(逐个判断得出每个式子0或1 每个0或1再运算判断)
分支语句
if语句 ---->等值判断+区间判断
if+else if+else if if语句嵌套
switch语句 —> 等值判断
switch(表达式)
{
case 常量表达式1:
语句;
break;
case 常量表达式2:
语句;
break;
case 常量表达式3:
语句;
break;
…
case 常量表达式n:
语句;
break;
default:
语句;
break;
}
1.表达式结果不能是浮点数
2.case后的值不能一样
3.csae后的值必须是常量
注:条件合并写法 遇到break才跳出 default位置随意但放到开头时要加break不然后面都会被执行
循环语句
while
P.S.break语句跳出最近的while或switch语句 continue以下的命令不会执行直接跳到最近的while那里再次执行
do while语句——>一直执行直到遇到什么就不执行了
do
{
//要执行的代码
}while(表达式)
特点:表达式即使不成立,也会被执行一次
for语句
for(表达式1,表达式2,表达式3)
{
//要执行的代码4
}
执行顺序1 2 4 3 然后2 4 3 然后2 4 3 直到2不成立 跳出循环
表达式1 3可以有逗号
数组
数组类型 变量名[常量]
数组初始化
1.int arr[10]={1,2,3,4,5,6,7,8,9,10}
2.int arr[]={1,2,3,4,5,6,7,8,9,10}
多维数组
int arry[3][4]={
{{1,2,3},{1,2,3},{1,2,3},{1,2,3}},
{{1,2,3},{1,2,3},{1,2,3},{1,2,3}},
{{1,2,3},{1,2,3},{1,2,3},{1,2,3}}
};
多维数组和一维数组存储一样,只是在使用时多维数组便捷 (arry[0][0]迅速找到第一行第一个数)
获取第2个班级、第3组、第2个人的年龄 arry[1][2][1]
编译器如何计算 arr[143+2*3+1]
结构体 = 容器
结构体是定义一个新类型,这时不占用内存,当你用新类型定义变量时,才占用内存
结构体类型定义
struct 类型名{
int a;
char b;
short c;
int arr[10]; //可定义数组
st1 s;//可定义其他新类型结构体
}
struct stStudent
{
int stucode;
char stuName[20];
int stuAge;
char stuSex;
};
struct stStudent student={101,“张三”,18,‘M’}
a=point.x;//读
point.x=100;//写
字节对齐:目的:牺牲空间提升程序运行效率
一个变量占用n个字节,则该变量的起始地址是n的整数倍
如果是结构体,则结构体的起始地址是最宽数据类型成员的整数倍
可以改变结构体成员的对齐方式-
#pragma pack(1)
struct Test {8
char a;
int b;
};
#pragma pack()
#pragma pack(n)可设置以n字节对齐方式对齐,可设定1、2、4、8,VC编译器默认是8
结构体成员按照"n与成员宽度类型比较,谁小用谁"原则,确定起始位置是按照”小“的整数倍
结构体总大小:N=Min(最大成员,对齐参数) 是N的整数倍
结构体数组
struct stStudent{
int Age;
int Level;
} //定义新类型
赋值方法一 :struct stStudent arr[5]={{0,0},{1,1},{2,2},{3,3},{4,4},}
赋值方法二 :
arr[0].Age=100;
arr[0].Level=100;
使用: 格式:结构体数组名[下标].成员名
指针(只考虑 宽度 和 加减运算)
任何类型都可带*,带*之后是新的类型,统称为 指针类型
*可以是任意多个
例如:char* x
赋值:
char* x
x=(char*)1 //明确告诉编译器1是什么类型,其实以前int x的赋值简写了(int)
指针类型的数据宽度永远四个字节,无论类型是什么,无论有几个*
指针类型自加自减
带*类型的变量,++或–新增(减少)的数量是去掉一个 * 后变量的宽度
指针类型只可以加减一个整数,不可以乘或除
& 取地址符
&变量 可以得到当前变量的内存编号
取地址符会改变它后面变量的类型,改成原本变量类型后面加一颗*
取值运算符
*+ 指针类型的变量 就是把指针变量里的值作为地址取里面的值
星+指针类型 的 类型是 指针类型减去一个星(*=星)
数组中作为参数传递的是第一个元素的地址
数组作为参数传递时要传数组长度
arr[i]=*(p+i)
字符串的几种表示方法
char str[6]={‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,}; //遇到‘\0’或者0才,但编译器不会自动补0
char str[]=“ABCDE”; // 常量区 编译器末尾填0
char* str=”ABCDE“; //常量区
常用的字符串函数
int strlen(chars)
返回值是字符串s的长度。不包括结束符‘/0’
char strcpy(char星dest,char星src);
复制字符串src到dest中。返回指针为dest的值。
char星strcat(char星dest,char星src);
将字符串src添加到dest尾部。返回指针为dest的值。
int strcmp(chars1,chars2);
一样返回0,不一样返回非0
指针取值的两种方式
ikmwt为偏移
结构体指针
用指针表示结构体的值 int x=px->x
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
struct point{
int x;
int y;
};
void main()
{
point p={1,2};
point* px=&p;
int x=px->x
return;
}
指针数组与数组指针
指针数组本质是指针,只不过里面存储的是指针
数组指针无论怎么变终究是个指针
int(*px)[5];
char(*px)[3]; //一维数组指针
int(*px)[2][2]; //二维数组指针
char(*px)[3][3][3]; //三维数组指针
数组指针的赋值
px1=(int (星)[5])1;
px2=(char (星)[3])1;
px3=(int (星)[2][2])1;
px4=(int (星)[3][3][3])1;
调用约定
告诉编译器,怎么传递参数,怎么传递返回值,怎么平衡堆栈。
函数指针 用来使用别人写好的函数
函数指针的本义:按照你要求的方式来调用你给的地址
函数指针变量定义的格式;
返回类型 (调用约定 *变量名)(参数列表);
10这里是要执行函数的地址,写一个10不太恰当,比如00401234这种地址
预处理:宏定义 文件包含 条件编译 (文件编译前有一个预处理器,会提前看文件要做什么处理再编译)
宏定义 本质是 替换
宏比较节省空间,它不会提升堆栈(但是宏每次用一遍都会再写一次)
条件编译
文件包含
A.CPP放函数本体 A.H放函数声明(这块目前我是小项目,用不到:p)
解决重复包含 前置声明